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_URIDECODEBIN3(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 somthing 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 tranlated 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)
490 MMMessageParamType msg_param;
491 gchar *msg_src_element = NULL;
492 GstStructure *s = NULL;
494 gchar *error_string = NULL;
498 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
499 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
501 s = gst_structure_copy(gst_message_get_structure(message));
504 if (!gst_structure_get_uint(s, "error_id", &error_id))
505 error_id = MMPLAYER_STREAMING_ERROR_NONE;
508 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
509 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
511 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
512 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
514 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
515 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
517 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
518 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
520 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
521 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
523 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
524 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
526 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
527 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
529 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
530 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
532 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
533 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
535 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
536 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
538 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
539 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
541 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
542 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
544 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
545 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
547 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
548 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
550 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
551 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
553 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
554 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
556 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
557 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
559 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
560 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
562 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
563 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
565 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
566 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
568 case MMPLAYER_STREAMING_ERROR_GONE:
569 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
571 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
572 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
574 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
575 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
577 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
578 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
580 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
581 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
583 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
584 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
586 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
587 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
589 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
590 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
592 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
593 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
595 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
596 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
598 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
599 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
601 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
602 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
604 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
605 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
607 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
608 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
610 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
611 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
613 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
614 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
616 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
617 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
619 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
620 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
622 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
623 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
625 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
626 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
628 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
629 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
631 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
632 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
634 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
635 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
637 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
638 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
640 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
641 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
645 gst_structure_free(s);
646 return MM_ERROR_PLAYER_STREAMING_FAIL;
650 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
652 msg_param.data = (void *)error_string;
655 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
657 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
658 msg_src_element, msg_param.code, (char *)msg_param.data);
661 /* post error to application */
662 if (!player->msg_posted) {
663 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
665 /* don't post more if one was sent already */
666 player->msg_posted = TRUE;
668 LOGD("skip error post because it's sent already.");
671 gst_structure_free(s);
672 MMPLAYER_FREEIF(error_string);
680 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
682 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
683 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
684 gst_tag_list_get_string(tags, "stitching_software",
685 &metadata->stitching_software);
686 gst_tag_list_get_string(tags, "projection_type",
687 &metadata->projection_type_string);
688 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
689 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
690 gst_tag_list_get_int(tags, "init_view_heading",
691 &metadata->init_view_heading);
692 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
693 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
694 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
695 gst_tag_list_get_int(tags, "full_pano_width_pixels",
696 &metadata->full_pano_width_pixels);
697 gst_tag_list_get_int(tags, "full_pano_height_pixels",
698 &metadata->full_pano_height_pixels);
699 gst_tag_list_get_int(tags, "cropped_area_image_width",
700 &metadata->cropped_area_image_width);
701 gst_tag_list_get_int(tags, "cropped_area_image_height",
702 &metadata->cropped_area_image_height);
703 gst_tag_list_get_int(tags, "cropped_area_left",
704 &metadata->cropped_area_left);
705 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
706 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
707 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
708 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
712 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
715 /* macro for better code readability */
716 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
718 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
719 if (string != NULL) { \
720 SECURE_LOGD("update tag string : %s", string); \
721 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
722 char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
723 strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
724 new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
725 mm_player_set_attribute((MMHandleType)player, NULL,\
726 playertag, new_string, strlen(new_string), NULL); \
727 MMPLAYER_FREEIF(new_string); \
729 mm_player_set_attribute((MMHandleType)player, NULL,\
730 playertag, string, strlen(string), NULL); \
732 MMPLAYER_FREEIF(string); \
737 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
739 GstSample *sample = NULL;\
740 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
741 GstMapInfo info = GST_MAP_INFO_INIT;\
742 buffer = gst_sample_get_buffer(sample);\
743 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
744 LOGD("failed to get image data from tag");\
745 gst_sample_unref(sample);\
748 SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
749 MMPLAYER_FREEIF(player->album_art);\
750 player->album_art = (gchar *)g_malloc(info.size);\
751 if (player->album_art) {\
752 memcpy(player->album_art, info.data, info.size);\
753 mm_player_set_attribute((MMHandleType)player, NULL,\
754 playertag, (void *)player->album_art, info.size, NULL); \
755 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
756 msg_param.data = (void *)player->album_art;\
757 msg_param.size = info.size;\
758 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
759 SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
762 gst_buffer_unmap(buffer, &info);\
763 gst_sample_unref(sample);\
767 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
769 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
772 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
773 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
774 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
775 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
776 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
778 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
779 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
780 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
781 mm_player_set_attribute((MMHandleType)player, NULL,\
782 "content_audio_bitrate", v_uint, NULL); \
783 player->bitrate[track_type] = v_uint; \
784 player->total_bitrate = 0; \
785 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
786 player->total_bitrate += player->bitrate[i]; \
787 mm_player_set_attribute((MMHandleType)player, NULL,\
788 playertag, player->total_bitrate, NULL); \
789 SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
790 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
791 player->maximum_bitrate[track_type] = v_uint; \
792 player->total_maximum_bitrate = 0; \
793 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
794 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
795 mm_player_set_attribute((MMHandleType)player, NULL,\
796 playertag, player->total_maximum_bitrate, NULL); \
797 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
799 mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
806 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
808 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
810 string = g_strdup_printf("%d", g_date_get_year(date));\
811 mm_player_set_attribute((MMHandleType)player, NULL,\
812 playertag, string, strlen(string), NULL); \
813 SECURE_LOGD("metainfo year : %s", string);\
814 MMPLAYER_FREEIF(string);\
820 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
822 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
823 if (datetime != NULL) {\
824 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
825 mm_player_set_attribute((MMHandleType)player, NULL,\
826 playertag, string, strlen(string), NULL); \
827 SECURE_LOGD("metainfo year : %s", string);\
828 MMPLAYER_FREEIF(string);\
829 gst_date_time_unref(datetime);\
835 GstTagList *tag_list = NULL;
840 GstDateTime *datetime = NULL;
842 GstBuffer *buffer = NULL;
844 MMMessageParamType msg_param = {0, };
846 /* currently not used. but those are needed for above macro */
847 //guint64 v_uint64 = 0;
848 //gdouble v_double = 0;
850 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
852 /* get tag list from gst message */
853 gst_message_parse_tag(msg, &tag_list);
855 /* store tags to player attributes */
856 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
857 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
858 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
859 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
860 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
861 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
862 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
863 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
864 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
865 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
866 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
867 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
868 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
869 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
870 MMPLAYER_UPDATE_TAG_LOCK(player);
871 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
872 MMPLAYER_UPDATE_TAG_UNLOCK(player);
873 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
875 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
876 if (player->video360_metadata.is_spherical == -1) {
877 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
878 mm_player_set_attribute((MMHandleType)player, NULL,
879 "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
880 if (player->video360_metadata.is_spherical == 1) {
881 LOGD("This is spherical content for 360 playback.");
882 player->is_content_spherical = TRUE;
884 LOGD("This is not spherical content");
885 player->is_content_spherical = FALSE;
888 if (player->video360_metadata.projection_type_string) {
889 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
890 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
892 LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
893 player->is_content_spherical = player->is_video360_enabled = FALSE;
897 if (player->video360_metadata.stereo_mode_string) {
898 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
899 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
900 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
901 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
902 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
903 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
905 LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
906 player->is_content_spherical = player->is_video360_enabled = FALSE;
912 gst_tag_list_unref(tag_list);
917 /* if retval is FALSE, it will be dropped for perfomance. */
919 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
921 gboolean retval = FALSE;
923 if (!(player->pipeline && player->pipeline->mainbin)) {
924 LOGE("player pipeline handle is null");
928 switch (GST_MESSAGE_TYPE(message)) {
929 case GST_MESSAGE_TAG:
930 case GST_MESSAGE_EOS:
931 case GST_MESSAGE_ERROR:
932 case GST_MESSAGE_WARNING:
933 case GST_MESSAGE_CLOCK_LOST:
934 case GST_MESSAGE_NEW_CLOCK:
935 case GST_MESSAGE_ELEMENT:
936 case GST_MESSAGE_DURATION_CHANGED:
937 case GST_MESSAGE_ASYNC_START:
938 case GST_MESSAGE_STREAM_COLLECTION:
941 case GST_MESSAGE_ASYNC_DONE:
942 case GST_MESSAGE_STATE_CHANGED:
943 /* we only handle messages from pipeline */
944 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
949 case GST_MESSAGE_BUFFERING:
951 gint buffer_percent = 0;
954 gst_message_parse_buffering(message, &buffer_percent);
955 if (buffer_percent != MAX_BUFFER_PERCENT) {
956 LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
960 if (!MMPLAYER_CMD_TRYLOCK(player)) {
961 LOGW("can't get cmd lock, send msg to bus");
965 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
966 LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
967 player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
970 MMPLAYER_CMD_UNLOCK(player);
974 case GST_MESSAGE_STREAMS_SELECTED:
976 if (!MMPLAYER_USE_URIDECODEBIN3(player))
977 break; /* drop msg */
979 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
980 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
981 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
983 gint64 dur_bytes = 0L;
985 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
986 LOGE("fail to get duration.");
988 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
989 * use file information was already set on Q2 when it was created. */
990 _mm_player_streaming_set_queue2(player->streamer,
991 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
992 TRUE, /* use_buffering */
993 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
994 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
997 LOGD("GST_MESSAGE_STREAMS_SELECTED");
998 player->no_more_pad = TRUE;
999 _mmplayer_pipeline_complete(NULL, player);
1012 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1014 guint64 data_size = 0;
1015 gint64 pos_nsec = 0;
1017 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1019 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1021 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1022 data_size = player->http_content_size;
1025 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1026 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1032 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1034 int ret = MM_ERROR_NONE;
1035 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1036 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1037 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1038 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1040 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1041 LOGW("do nothing for buffering msg");
1042 ret = MM_ERROR_PLAYER_INVALID_STATE;
1046 prev_state = MMPLAYER_PREV_STATE(player);
1047 current_state = MMPLAYER_CURRENT_STATE(player);
1048 target_state = MMPLAYER_TARGET_STATE(player);
1049 pending_state = MMPLAYER_PENDING_STATE(player);
1051 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1052 MMPLAYER_STATE_GET_NAME(prev_state),
1053 MMPLAYER_STATE_GET_NAME(current_state),
1054 MMPLAYER_STATE_GET_NAME(pending_state),
1055 MMPLAYER_STATE_GET_NAME(target_state),
1056 player->streamer->buffering_state);
1058 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1059 /* NOTE : if buffering has done, player has to go to target state. */
1060 switch (target_state) {
1061 case MM_PLAYER_STATE_PAUSED:
1063 switch (pending_state) {
1064 case MM_PLAYER_STATE_PLAYING:
1065 _mmplayer_gst_pause(player, TRUE);
1068 case MM_PLAYER_STATE_PAUSED:
1069 LOGD("player is already going to paused state, there is nothing to do.");
1072 case MM_PLAYER_STATE_NONE:
1073 case MM_PLAYER_STATE_NULL:
1074 case MM_PLAYER_STATE_READY:
1076 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1082 case MM_PLAYER_STATE_PLAYING:
1084 switch (pending_state) {
1085 case MM_PLAYER_STATE_NONE:
1087 if (current_state != MM_PLAYER_STATE_PLAYING)
1088 _mmplayer_gst_resume(player, TRUE);
1092 case MM_PLAYER_STATE_PAUSED:
1093 /* NOTE: It should be worked as asynchronously.
1094 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1096 if (current_state == MM_PLAYER_STATE_PLAYING) {
1097 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1098 * The current state should be changed to paused purposely to prevent state conflict.
1100 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1102 _mmplayer_gst_resume(player, TRUE);
1105 case MM_PLAYER_STATE_PLAYING:
1106 LOGD("player is already going to playing state, there is nothing to do.");
1109 case MM_PLAYER_STATE_NULL:
1110 case MM_PLAYER_STATE_READY:
1112 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1118 case MM_PLAYER_STATE_NULL:
1119 case MM_PLAYER_STATE_READY:
1120 case MM_PLAYER_STATE_NONE:
1122 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1126 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1127 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1129 switch (pending_state) {
1130 case MM_PLAYER_STATE_NONE:
1132 if (current_state != MM_PLAYER_STATE_PAUSED) {
1133 /* rtsp streaming pause makes rtsp server stop sending data. */
1134 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1135 LOGD("set pause state during buffering");
1136 _mmplayer_gst_pause(player, TRUE);
1142 case MM_PLAYER_STATE_PLAYING:
1143 /* rtsp streaming pause makes rtsp server stop sending data. */
1144 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1145 _mmplayer_gst_pause(player, TRUE);
1148 case MM_PLAYER_STATE_PAUSED:
1151 case MM_PLAYER_STATE_NULL:
1152 case MM_PLAYER_STATE_READY:
1154 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1163 static stream_variant_t *
1164 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1166 stream_variant_t *var_info = NULL;
1167 g_return_val_if_fail(self != NULL, NULL);
1169 var_info = g_new0(stream_variant_t, 1);
1170 if (!var_info) return NULL;
1171 var_info->bandwidth = self->bandwidth;
1172 var_info->width = self->width;
1173 var_info->height = self->height;
1178 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1184 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1185 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1187 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1188 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1189 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1191 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1192 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1193 player->http_content_size = (bytes > 0) ? bytes : 0;
1196 /* handling audio clip which has vbr. means duration is keep changing */
1197 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1206 __mmplayer_eos_timer_cb(gpointer u_data)
1208 mmplayer_t *player = NULL;
1209 MMHandleType attrs = 0;
1212 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1214 player = (mmplayer_t *)u_data;
1215 attrs = MMPLAYER_GET_ATTRS(player);
1217 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1221 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1222 if (ret_value != MM_ERROR_NONE)
1223 LOGE("seeking to 0 failed in repeat play");
1226 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1229 /* we are returning FALSE as we need only one posting */
1234 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1236 MMPLAYER_RETURN_IF_FAIL(player);
1238 /* post now if delay is zero */
1239 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1240 LOGD("eos delay is zero. posting EOS now");
1241 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1243 if (player->audio_decoded_cb)
1244 _mmplayer_cancel_eos_timer(player);
1249 /* cancel if existing */
1250 _mmplayer_cancel_eos_timer(player);
1252 /* init new timeout */
1253 /* NOTE : consider give high priority to this timer */
1254 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1256 player->eos_timer = g_timeout_add(delay_in_ms,
1257 __mmplayer_eos_timer_cb, player);
1259 player->context.global_default = g_main_context_default();
1260 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1262 /* check timer is valid. if not, send EOS now */
1263 if (player->eos_timer == 0) {
1264 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1265 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1270 __mmplayer_gst_pending_seek(mmplayer_t *player)
1272 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1273 int ret = MM_ERROR_NONE;
1277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1279 if (!player->pending_seek.is_pending) {
1280 LOGD("pending seek is not reserved. nothing to do.");
1284 /* check player state if player could pending seek or not. */
1285 current_state = MMPLAYER_CURRENT_STATE(player);
1287 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1288 LOGW("try to pending seek in %s state, try next time. ",
1289 MMPLAYER_STATE_GET_NAME(current_state));
1293 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1295 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1296 if (ret != MM_ERROR_NONE)
1297 LOGE("failed to seek pending postion. just keep staying current position.");
1299 player->pending_seek.is_pending = false;
1307 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1309 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1311 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1313 audiobin = player->pipeline->audiobin; /* can be null */
1314 videobin = player->pipeline->videobin; /* can be null */
1315 textbin = player->pipeline->textbin; /* can be null */
1317 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1319 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1320 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1322 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1323 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1325 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1326 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1332 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1334 mmplayer_gst_element_t *textbin;
1337 MMPLAYER_RETURN_IF_FAIL(player &&
1339 player->pipeline->textbin);
1341 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1343 textbin = player->pipeline->textbin;
1346 LOGD("Drop subtitle text after getting EOS");
1348 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1349 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1351 player->is_subtitle_force_drop = TRUE;
1353 if (player->is_subtitle_force_drop == TRUE) {
1354 LOGD("Enable subtitle data path without drop");
1356 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1357 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1359 LOGD("non-connected with external display");
1361 player->is_subtitle_force_drop = FALSE;
1367 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1369 MMHandleType attrs = 0;
1374 /* NOTE : EOS event is comming multiple time. watch out it */
1375 /* check state. we only process EOS when pipeline state goes to PLAYING */
1376 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1377 LOGD("EOS received on non-playing state. ignoring it");
1381 if (player->pipeline && player->pipeline->textbin)
1382 __mmplayer_drop_subtitle(player, TRUE);
1384 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1385 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1387 /* rewind if repeat count is greater then zero */
1388 /* get play count */
1389 attrs = MMPLAYER_GET_ATTRS(player);
1391 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1393 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1395 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1396 if (player->playback_rate < 0.0) {
1397 player->resumed_by_rewind = TRUE;
1398 _mmplayer_set_mute((MMHandleType)player, false);
1399 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1402 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1405 player->sent_bos = FALSE;
1407 LOGD("do not post eos msg for repeating");
1412 if (player->pipeline)
1413 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1415 /* post eos message to application */
1416 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1418 /* reset last position */
1419 player->last_position = 0;
1426 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1428 GError *error = NULL;
1429 gchar *debug = NULL;
1433 /* generating debug info before returning error */
1434 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1436 /* get error code */
1437 gst_message_parse_error(msg, &error, &debug);
1439 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1440 /* Note : the streaming error from the streaming source is handled
1441 * using __mmplayer_handle_streaming_error.
1443 __mmplayer_handle_streaming_error(player, msg);
1445 /* dump state of all element */
1446 _mmplayer_dump_pipeline_state(player);
1448 /* traslate gst error code to msl error code. then post it
1449 * to application if needed
1451 __mmplayer_handle_gst_error(player, msg, error);
1454 LOGE("error debug : %s", debug);
1457 MMPLAYER_FREEIF(debug);
1458 g_error_free(error);
1465 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1467 MMMessageParamType msg_param = {0, };
1468 int bRet = MM_ERROR_NONE;
1471 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1473 if (!MMPLAYER_IS_STREAMING(player)) {
1474 LOGW("this is not streaming playback.");
1478 MMPLAYER_CMD_LOCK(player);
1480 if (!player->streamer) {
1481 LOGW("Pipeline is shutting down");
1482 MMPLAYER_CMD_UNLOCK(player);
1486 /* ignore the remained buffering message till getting 100% msg */
1487 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1488 gint buffer_percent = 0;
1490 gst_message_parse_buffering(msg, &buffer_percent);
1492 if (buffer_percent == MAX_BUFFER_PERCENT) {
1493 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1494 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1495 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1497 MMPLAYER_CMD_UNLOCK(player);
1501 /* ignore the remained buffering message */
1502 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1503 gint buffer_percent = 0;
1505 gst_message_parse_buffering(msg, &buffer_percent);
1507 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1508 player->streamer->buffering_percent, buffer_percent);
1510 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1511 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1512 player->streamer->buffering_req.is_pre_buffering = FALSE;
1514 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1516 LOGD("interrupted buffering - ignored the remained buffering msg!");
1517 MMPLAYER_CMD_UNLOCK(player);
1522 __mmplayer_update_buffer_setting(player, msg);
1524 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1526 if (bRet == MM_ERROR_NONE) {
1527 msg_param.connection.buffering = player->streamer->buffering_percent;
1528 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1530 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1531 player->pending_resume &&
1532 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1534 player->is_external_subtitle_added_now = FALSE;
1535 player->pending_resume = FALSE;
1536 _mmplayer_resume((MMHandleType)player);
1539 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1540 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1542 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1543 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1544 player->seek_state = MMPLAYER_SEEK_NONE;
1545 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1546 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1547 /* Considering the async state trasition in case of RTSP.
1548 After getting state change gst msg, seek cmpleted msg will be posted. */
1549 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1553 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1554 if (!player->streamer) {
1555 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1556 MMPLAYER_CMD_UNLOCK(player);
1560 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1562 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1563 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1565 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1566 msg_param.connection.buffering = player->streamer->buffering_percent;
1567 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1569 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1572 msg_param.connection.buffering = player->streamer->buffering_percent;
1573 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1576 MMPLAYER_CMD_UNLOCK(player);
1584 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1586 mmplayer_gst_element_t *mainbin;
1587 const GValue *voldstate, *vnewstate, *vpending;
1588 GstState oldstate = GST_STATE_NULL;
1589 GstState newstate = GST_STATE_NULL;
1590 GstState pending = GST_STATE_NULL;
1593 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1595 mainbin = player->pipeline->mainbin;
1597 /* we only handle messages from pipeline */
1598 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1601 /* get state info from msg */
1602 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1603 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1604 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1606 if (!voldstate || !vnewstate) {
1607 LOGE("received msg has wrong format.");
1611 oldstate = (GstState)voldstate->data[0].v_int;
1612 newstate = (GstState)vnewstate->data[0].v_int;
1614 pending = (GstState)vpending->data[0].v_int;
1616 LOGD("state changed [%s] : %s ---> %s final : %s",
1617 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1618 gst_element_state_get_name((GstState)oldstate),
1619 gst_element_state_get_name((GstState)newstate),
1620 gst_element_state_get_name((GstState)pending));
1622 if (newstate == GST_STATE_PLAYING) {
1623 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1625 int retVal = MM_ERROR_NONE;
1626 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1628 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1630 if (MM_ERROR_NONE != retVal)
1631 LOGE("failed to seek pending postion. just keep staying current position.");
1633 player->pending_seek.is_pending = false;
1637 if (oldstate == newstate) {
1638 LOGD("pipeline reports state transition to old state");
1643 case GST_STATE_PAUSED:
1645 gboolean prepare_async = FALSE;
1647 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1648 // managed prepare async case
1649 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1650 LOGD("checking prepare mode for async transition - %d", prepare_async);
1653 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1654 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1656 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1657 _mm_player_streaming_set_content_bitrate(player->streamer,
1658 player->total_maximum_bitrate, player->total_bitrate);
1660 if (player->pending_seek.is_pending) {
1661 LOGW("trying to do pending seek");
1662 MMPLAYER_CMD_LOCK(player);
1663 __mmplayer_gst_pending_seek(player);
1664 MMPLAYER_CMD_UNLOCK(player);
1670 case GST_STATE_PLAYING:
1672 if (MMPLAYER_IS_STREAMING(player)) {
1673 // managed prepare async case when buffering is completed
1674 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1675 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1676 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1677 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1679 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1681 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1682 if (player->streamer->buffering_percent < 100) {
1684 MMMessageParamType msg_param = {0, };
1685 LOGW("Posting Buffering Completed Message to Application !!!");
1687 msg_param.connection.buffering = 100;
1688 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1693 if (player->gapless.stream_changed) {
1694 _mmplayer_update_content_attrs(player, ATTR_ALL);
1695 player->gapless.stream_changed = FALSE;
1698 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1699 player->seek_state = MMPLAYER_SEEK_NONE;
1700 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1704 case GST_STATE_VOID_PENDING:
1705 case GST_STATE_NULL:
1706 case GST_STATE_READY:
1716 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1718 const gchar *structure_name;
1719 gint count = 0, idx = 0;
1722 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1724 if (gst_message_get_structure(msg) == NULL)
1727 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1728 if (!structure_name)
1731 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1733 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1734 const GValue *var_info = NULL;
1736 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1737 if (var_info != NULL) {
1738 if (player->adaptive_info.var_list)
1739 g_list_free_full(player->adaptive_info.var_list, g_free);
1741 /* share addr or copy the list */
1742 player->adaptive_info.var_list =
1743 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1745 count = g_list_length(player->adaptive_info.var_list);
1747 stream_variant_t *temp = NULL;
1749 /* print out for debug */
1750 LOGD("num of variant_info %d", count);
1751 for (idx = 0; idx < count; idx++) {
1752 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1754 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1760 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1761 gint num_buffers = 0;
1762 gint extra_num_buffers = 0;
1764 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1765 LOGD("video_num_buffers : %d", num_buffers);
1766 mm_player_set_attribute((MMHandleType)player, NULL,
1767 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1770 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1771 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1772 mm_player_set_attribute((MMHandleType)player, NULL,
1773 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1778 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1779 _mmplayer_track_update_text_attr_info(player, msg);
1781 /* custom message */
1782 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1783 MMMessageParamType msg_param = {0,};
1784 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1785 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1788 /* custom message for RTSP attribute :
1789 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1790 sdp which has contents info is received when rtsp connection is opened.
1791 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1792 if (!strcmp(structure_name, "rtspsrc_properties")) {
1793 gchar *audio_codec = NULL;
1794 gchar *video_codec = NULL;
1795 gchar *video_frame_size = NULL;
1797 gst_structure_get(gst_message_get_structure(msg),
1798 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1799 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1800 player->streaming_type = _mmplayer_get_stream_service_type(player);
1802 gst_structure_get(gst_message_get_structure(msg),
1803 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1804 LOGD("rtsp_audio_codec : %s", audio_codec);
1806 mm_player_set_attribute((MMHandleType)player, NULL,
1807 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1809 gst_structure_get(gst_message_get_structure(msg),
1810 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1811 LOGD("rtsp_video_codec : %s", video_codec);
1813 mm_player_set_attribute((MMHandleType)player, NULL,
1814 "content_video_codec", video_codec, strlen(video_codec), NULL);
1816 gst_structure_get(gst_message_get_structure(msg),
1817 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1818 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1819 if (video_frame_size) {
1820 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1821 mm_player_set_attribute((MMHandleType)player, NULL,
1822 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1823 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1825 g_strfreev(res_str);
1834 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1836 mmplayer_gst_element_t *mainbin;
1839 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1841 mainbin = player->pipeline->mainbin;
1843 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1845 /* we only handle messages from pipeline */
1846 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1849 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1850 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1851 player->seek_state = MMPLAYER_SEEK_NONE;
1852 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1853 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1854 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1855 LOGD("sync %s state(%s) with parent state(%s)",
1856 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1857 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1858 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1860 /* In case of streaming, pause is required before finishing seeking by buffering.
1861 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1862 Because the buffering state is controlled according to the state transition for force resume,
1863 the decodebin state should be paused as player state. */
1864 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1867 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1868 (player->streamer) &&
1869 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1870 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1871 GstQuery *query = NULL;
1872 gboolean busy = FALSE;
1875 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1876 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1877 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1878 gst_query_parse_buffering_percent(query, &busy, &percent);
1879 gst_query_unref(query);
1881 LOGD("buffered percent(%s): %d",
1882 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1886 __mmplayer_handle_buffering_playback(player);
1889 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1898 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1900 GValue val = { 0, };
1902 guint indent = GPOINTER_TO_UINT(user_data);
1904 if (!gst_tag_list_copy_value(&val, tags, tag))
1907 if (G_VALUE_HOLDS_STRING(&val))
1908 str = g_value_dup_string(&val);
1910 str = gst_value_serialize(&val);
1912 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1914 g_value_unset(&val);
1918 __mmplayer_dump_collection(GstStreamCollection * collection)
1921 GstTagList *tags = NULL;
1922 GstCaps *caps = NULL;
1924 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1925 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1926 LOGD ("collection: Stream %u type %s flags 0x%x\n", i,
1927 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1928 gst_stream_get_stream_flags(stream));
1929 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1931 caps = gst_stream_get_caps(stream);
1933 gchar *caps_str = gst_caps_to_string(caps);
1934 LOGD (" caps: %s\n", caps_str);
1936 gst_caps_unref(caps);
1939 tags = gst_stream_get_tags(stream);
1942 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1943 gst_tag_list_unref(tags);
1949 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1950 GstStream *stream, GParamSpec *pspec, gpointer data)
1952 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1953 gst_stream_get_stream_id(stream), pspec->name, collection);
1954 if (g_str_equal(pspec->name, "caps")) {
1955 GstCaps *caps = gst_stream_get_caps(stream);
1956 gchar *caps_str = gst_caps_to_string(caps);
1957 LOGD (" New caps: %s\n", caps_str);
1959 gst_caps_unref(caps);
1962 if (g_str_equal (pspec->name, "tags")) {
1963 GstTagList *tags = gst_stream_get_tags(stream);
1966 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1967 gst_tag_list_unref(tags);
1973 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1975 mmplayer_t *player = (mmplayer_t *)(data);
1977 MMPLAYER_RETURN_IF_FAIL(player);
1978 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1980 switch (GST_MESSAGE_TYPE(msg)) {
1981 case GST_MESSAGE_UNKNOWN:
1982 LOGD("unknown message received");
1985 case GST_MESSAGE_EOS:
1986 LOGD("GST_MESSAGE_EOS received");
1987 __mmplayer_gst_handle_eos_message(player, msg);
1990 case GST_MESSAGE_ERROR:
1991 _mmplayer_set_reconfigure_state(player, FALSE);
1992 __mmplayer_gst_handle_error_message(player, msg);
1995 case GST_MESSAGE_WARNING:
1998 GError *error = NULL;
2000 gst_message_parse_warning(msg, &error, &debug);
2002 LOGD("warning : %s", error->message);
2003 LOGD("debug : %s", debug);
2005 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2007 MMPLAYER_FREEIF(debug);
2008 g_error_free(error);
2012 case GST_MESSAGE_TAG:
2014 LOGD("GST_MESSAGE_TAG");
2015 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2016 LOGW("failed to extract tags from gstmessage");
2020 case GST_MESSAGE_BUFFERING:
2021 __mmplayer_gst_handle_buffering_message(player, msg);
2024 case GST_MESSAGE_STATE_CHANGED:
2025 __mmplayer_gst_handle_state_message(player, msg);
2028 case GST_MESSAGE_CLOCK_LOST:
2030 GstClock *clock = NULL;
2031 gboolean need_new_clock = FALSE;
2033 gst_message_parse_clock_lost(msg, &clock);
2034 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2036 if (!player->videodec_linked)
2037 need_new_clock = TRUE;
2038 else if (!player->ini.use_system_clock)
2039 need_new_clock = TRUE;
2041 if (need_new_clock) {
2042 LOGD("Provide clock is TRUE, do pause->resume");
2043 _mmplayer_gst_pause(player, FALSE);
2044 _mmplayer_gst_resume(player, FALSE);
2049 case GST_MESSAGE_NEW_CLOCK:
2051 GstClock *clock = NULL;
2052 gst_message_parse_new_clock(msg, &clock);
2053 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2057 case GST_MESSAGE_ELEMENT:
2058 __mmplayer_gst_handle_element_message(player, msg);
2061 case GST_MESSAGE_DURATION_CHANGED:
2063 LOGD("GST_MESSAGE_DURATION_CHANGED");
2064 if (!__mmplayer_gst_handle_duration(player, msg))
2065 LOGW("failed to update duration");
2069 case GST_MESSAGE_ASYNC_START:
2070 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2073 case GST_MESSAGE_ASYNC_DONE:
2074 __mmplayer_gst_handle_async_done_message(player, msg);
2076 case GST_MESSAGE_STREAM_COLLECTION:
2078 GstStreamCollection *collection = NULL;
2079 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2081 gst_message_parse_stream_collection(msg, &collection);
2083 __mmplayer_dump_collection(collection);
2084 if (player->collection && player->stream_notify_id) {
2085 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2086 player->stream_notify_id = 0;
2088 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2089 if (player->collection) {
2090 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2091 (GCallback)__mmplayer_stream_notify_cb, player);
2093 gst_object_unref(collection);
2096 case GST_MESSAGE_STREAMS_SELECTED:
2098 GstStreamCollection *collection = NULL;
2099 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2101 gst_message_parse_streams_selected(msg, &collection);
2103 guint i = 0, len = 0;
2104 len = gst_message_streams_selected_get_size(msg);
2105 for (i = 0; i < len; i++) {
2106 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2107 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2108 gst_object_unref(stream);
2110 gst_object_unref (collection);
2115 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2116 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2117 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2118 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2119 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2120 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2121 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2122 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2123 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2124 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2125 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2126 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2127 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2128 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2129 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2136 /* should not call 'gst_message_unref(msg)' */
2140 static GstBusSyncReply
2141 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2143 mmplayer_t *player = (mmplayer_t *)data;
2144 GstBusSyncReply reply = GST_BUS_DROP;
2146 if (!(player->pipeline && player->pipeline->mainbin)) {
2147 LOGE("player pipeline handle is null");
2148 return GST_BUS_PASS;
2151 if (!__mmplayer_gst_check_useful_message(player, message)) {
2152 gst_message_unref(message);
2153 return GST_BUS_DROP;
2156 switch (GST_MESSAGE_TYPE(message)) {
2157 case GST_MESSAGE_TAG:
2158 __mmplayer_gst_extract_tag_from_msg(player, message);
2162 GstTagList *tags = NULL;
2164 gst_message_parse_tag(message, &tags);
2166 LOGE("TAGS received from element \"%s\".",
2167 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2169 gst_tag_list_foreach(tags, print_tag, NULL);
2170 gst_tag_list_unref(tags);
2178 case GST_MESSAGE_DURATION_CHANGED:
2179 __mmplayer_gst_handle_duration(player, message);
2181 case GST_MESSAGE_ELEMENT:
2183 const gchar *klass = NULL;
2184 klass = gst_element_factory_get_metadata
2185 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2186 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2187 reply = GST_BUS_PASS;
2190 __mmplayer_gst_handle_element_message(player, message);
2193 case GST_MESSAGE_ASYNC_DONE:
2194 /* NOTE:Don't call gst_callback directly
2195 * because previous frame can be showed even though this message is received for seek.
2198 reply = GST_BUS_PASS;
2202 if (reply == GST_BUS_DROP)
2203 gst_message_unref(message);
2209 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2211 GstElement *appsrc = element;
2212 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2213 GstBuffer *buffer = NULL;
2214 GstFlowReturn ret = GST_FLOW_OK;
2217 MMPLAYER_RETURN_IF_FAIL(element);
2218 MMPLAYER_RETURN_IF_FAIL(buf);
2220 buffer = gst_buffer_new();
2222 if (buf->offset < 0 || buf->len < 0) {
2223 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2227 if (buf->offset >= buf->len) {
2228 LOGD("call eos appsrc");
2229 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2233 if (buf->len - buf->offset < size)
2234 len = buf->len - buf->offset;
2236 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2237 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2238 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2241 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2243 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2249 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2251 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2253 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2255 buf->offset = (int)size;
2261 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2263 mmplayer_t *player = (mmplayer_t *)user_data;
2264 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2265 MMMessageParamType msg_param = {0,};
2266 guint64 current_level_bytes = 0;
2268 MMPLAYER_RETURN_IF_FAIL(player);
2270 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2271 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2272 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2273 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2275 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2279 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2281 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2283 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2284 msg_param.buffer_status.stream_type = stream_type;
2285 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2286 msg_param.buffer_status.bytes = current_level_bytes;
2288 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2292 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2294 mmplayer_t *player = (mmplayer_t *)user_data;
2295 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2296 MMMessageParamType msg_param = {0,};
2297 guint64 current_level_bytes = 0;
2299 MMPLAYER_RETURN_IF_FAIL(player);
2301 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2302 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2303 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2304 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2306 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2310 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2312 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2314 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2315 msg_param.buffer_status.stream_type = stream_type;
2316 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2317 msg_param.buffer_status.bytes = current_level_bytes;
2319 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2323 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2325 mmplayer_t *player = (mmplayer_t *)user_data;
2326 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2327 MMMessageParamType msg_param = {0,};
2329 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2331 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2332 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2333 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2334 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2336 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2340 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2342 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2343 msg_param.seek_data.stream_type = stream_type;
2344 msg_param.seek_data.offset = position;
2346 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2352 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2354 #define MAX_LEN_NAME 20
2356 gboolean ret = FALSE;
2357 GstPad *sinkpad = NULL;
2358 gchar *prefix = NULL;
2359 gchar dec_name[MAX_LEN_NAME] = {0, };
2360 main_element_id_e elem_id = MMPLAYER_M_NUM;
2362 mmplayer_gst_element_t *mainbin = NULL;
2363 GstElement *decodebin = NULL;
2364 GstCaps *dec_caps = NULL;
2368 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2370 player->pipeline->mainbin, FALSE);
2371 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2373 mainbin = player->pipeline->mainbin;
2375 case MM_PLAYER_STREAM_TYPE_AUDIO:
2377 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2379 case MM_PLAYER_STREAM_TYPE_VIDEO:
2381 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2384 LOGE("invalid type %d", type);
2388 if (mainbin[elem_id].gst) {
2389 LOGE("elem(%d) is already created", elem_id);
2393 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2395 /* create decodebin */
2396 decodebin = gst_element_factory_make("decodebin", dec_name);
2398 LOGE("failed to create %s", dec_name);
2402 mainbin[elem_id].id = elem_id;
2403 mainbin[elem_id].gst = decodebin;
2405 /* raw pad handling signal */
2406 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2407 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2409 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2410 before looking for any elements that can handle that stream.*/
2411 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2412 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2414 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2415 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2416 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2418 /* This signal is emitted when a element is added to the bin.*/
2419 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2420 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2422 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2423 LOGE("failed to add new decodebin");
2427 dec_caps = gst_pad_query_caps(srcpad, NULL);
2430 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2432 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2433 gst_caps_unref(dec_caps);
2436 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2438 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2439 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2442 gst_object_unref(GST_OBJECT(sinkpad));
2444 gst_element_sync_state_with_parent(decodebin);
2450 gst_object_unref(GST_OBJECT(sinkpad));
2452 if (mainbin[elem_id].gst) {
2453 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2454 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2455 gst_object_unref(mainbin[elem_id].gst);
2456 mainbin[elem_id].gst = NULL;
2464 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2466 #define MAX_LEN_NAME 20
2467 mmplayer_gst_element_t *mainbin = NULL;
2468 gchar *prefix = NULL;
2469 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2471 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2472 GstElement *src = NULL, *queue = NULL;
2473 GstPad *srcpad = NULL;
2476 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2477 player->pipeline->mainbin, FALSE);
2479 mainbin = player->pipeline->mainbin;
2481 LOGD("type(%d) path is creating", type);
2483 case MM_PLAYER_STREAM_TYPE_AUDIO:
2485 if (mainbin[MMPLAYER_M_SRC].gst)
2486 src_id = MMPLAYER_M_2ND_SRC;
2488 src_id = MMPLAYER_M_SRC;
2489 queue_id = MMPLAYER_M_A_BUFFER;
2491 case MM_PLAYER_STREAM_TYPE_VIDEO:
2493 src_id = MMPLAYER_M_SRC;
2494 queue_id = MMPLAYER_M_V_BUFFER;
2496 case MM_PLAYER_STREAM_TYPE_TEXT:
2497 prefix = "subtitle";
2498 src_id = MMPLAYER_M_SUBSRC;
2499 queue_id = MMPLAYER_M_S_BUFFER;
2502 LOGE("invalid type %d", type);
2506 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2507 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2510 src = gst_element_factory_make("appsrc", src_name);
2512 LOGF("failed to create %s", src_name);
2516 mainbin[src_id].id = src_id;
2517 mainbin[src_id].gst = src;
2519 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2520 "caps", caps, NULL);
2522 /* size of many video frames are larger than default blocksize as 4096 */
2523 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2524 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2526 if (player->media_stream_buffer_max_size[type] > 0)
2527 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2529 if (player->media_stream_buffer_min_percent[type] > 0)
2530 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2532 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2533 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2535 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2536 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2537 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2538 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2539 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2540 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2543 queue = gst_element_factory_make("queue2", queue_name);
2545 LOGE("failed to create %s", queue_name);
2548 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2550 mainbin[queue_id].id = queue_id;
2551 mainbin[queue_id].gst = queue;
2553 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2554 LOGE("failed to add src");
2558 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2559 LOGE("failed to add queue");
2563 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2564 LOGE("failed to link src and queue");
2568 /* create decoder */
2569 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2571 LOGE("failed to get srcpad of queue");
2575 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2576 _mmplayer_gst_create_decoder(player, srcpad, caps);
2578 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2579 LOGE("failed to create decoder");
2580 gst_object_unref(GST_OBJECT(srcpad));
2584 gst_object_unref(GST_OBJECT(srcpad));
2588 if (mainbin[src_id].gst) {
2589 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2590 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2591 gst_object_unref(mainbin[src_id].gst);
2592 mainbin[src_id].gst = NULL;
2595 if (mainbin[queue_id].gst) {
2596 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2597 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2598 gst_object_unref(mainbin[queue_id].gst);
2599 mainbin[queue_id].gst = NULL;
2606 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2608 GstPad *sinkpad = NULL;
2609 GstCaps *caps = NULL;
2610 GstElement *new_element = NULL;
2611 GstStructure *str = NULL;
2612 const gchar *name = NULL;
2614 mmplayer_t *player = (mmplayer_t *)data;
2618 MMPLAYER_RETURN_IF_FAIL(element && pad);
2619 MMPLAYER_RETURN_IF_FAIL(player &&
2621 player->pipeline->mainbin);
2623 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2624 * num_dynamic_pad will decreased after creating a sinkbin.
2626 player->num_dynamic_pad++;
2627 LOGD("stream count inc : %d", player->num_dynamic_pad);
2629 caps = gst_pad_query_caps(pad, NULL);
2630 MMPLAYER_CHECK_NULL(caps);
2632 str = gst_caps_get_structure(caps, 0);
2633 name = gst_structure_get_string(str, "media");
2635 LOGE("cannot get mimetype from structure.");
2639 if (strstr(name, "video")) {
2641 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2643 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2644 if (player->v_stream_caps) {
2645 gst_caps_unref(player->v_stream_caps);
2646 player->v_stream_caps = NULL;
2649 new_element = gst_element_factory_make("fakesink", NULL);
2650 player->num_dynamic_pad--;
2655 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2656 LOGE("failed to autoplug for caps");
2660 gst_caps_unref(caps);
2665 /* excute new_element if created*/
2667 LOGD("adding new element to pipeline");
2669 /* set state to READY before add to bin */
2670 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2672 /* add new element to the pipeline */
2673 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2674 LOGE("failed to add autoplug element to bin");
2678 /* get pad from element */
2679 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2681 LOGE("failed to get sinkpad from autoplug element");
2686 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2687 LOGE("failed to link autoplug element");
2691 gst_object_unref(sinkpad);
2694 /* run. setting PLAYING here since streamming source is live source */
2695 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2699 gst_caps_unref(caps);
2705 STATE_CHANGE_FAILED:
2707 /* FIXIT : take care if new_element has already added to pipeline */
2709 gst_object_unref(GST_OBJECT(new_element));
2712 gst_object_unref(GST_OBJECT(sinkpad));
2715 gst_caps_unref(caps);
2717 /* FIXIT : how to inform this error to MSL ????? */
2718 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2719 * then post an error to application
2724 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2726 mmplayer_t *player = (mmplayer_t *)data;
2730 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2731 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2732 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2733 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2735 * [1] audio and video will be dumped with filesink.
2736 * [2] autoplugging is done by just using pad caps.
2737 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2738 * and the video will be dumped via filesink.
2740 if (player->num_dynamic_pad == 0) {
2741 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2743 if (!_mmplayer_gst_remove_fakesink(player,
2744 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2745 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2746 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2747 * source element are not same. To overcome this situation, this function will called
2748 * several places and several times. Therefore, this is not an error case.
2753 /* create dot before error-return. for debugging */
2754 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2756 player->no_more_pad = TRUE;
2762 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2764 GstElement *element = NULL;
2765 gchar *user_agent = NULL;
2766 MMHandleType attrs = 0;
2769 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2771 /* get profile attribute */
2772 attrs = MMPLAYER_GET_ATTRS(player);
2774 LOGE("failed to get content attribute");
2778 element = gst_element_factory_make("rtspsrc", "rtsp source");
2780 LOGE("failed to create rtspsrc element");
2785 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2787 SECURE_LOGD("user_agent : %s", user_agent);
2789 /* setting property to streaming source */
2790 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2792 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2794 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2795 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2796 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2797 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2803 void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2805 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2807 mmplayer_t *player = (mmplayer_t *)data;
2808 MMHandleType attrs = 0;
2809 gchar *user_agent, *cookies, **cookie_list;
2810 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2811 user_agent = cookies = NULL;
2815 MMPLAYER_RETURN_IF_FAIL(player);
2817 LOGD("source element %s", GST_ELEMENT_NAME(source));
2819 /* get profile attribute */
2820 attrs = MMPLAYER_GET_ATTRS(player);
2822 LOGE("failed to get content attribute");
2827 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2828 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2830 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2831 http_timeout = player->ini.http_timeout;
2834 SECURE_LOGD("cookies : %s", cookies);
2835 SECURE_LOGD("user_agent : %s", user_agent);
2836 LOGD("timeout : %d", http_timeout);
2838 /* setting property to streaming source */
2839 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2841 /* parsing cookies */
2842 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2843 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2844 g_strfreev(cookie_list);
2848 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2855 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2857 mmplayer_t *player = (mmplayer_t *)data;
2858 GstElement *source = NULL;
2861 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2863 g_object_get(orig, pspec->name, &source, NULL);
2865 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2866 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2868 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2869 __mmplayer_http_src_setup(source, data);
2870 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2871 gchar *user_agent = NULL;
2874 mm_attrs_get_string_by_name(player->attrs, "streaming_user_agent", &user_agent);
2876 SECURE_LOGD("user_agent : %s", user_agent);
2878 /* setting property to streaming source */
2880 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2881 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2882 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2883 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2884 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2885 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2887 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2888 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2889 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2890 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2896 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2897 GstStream * stream, gpointer data)
2899 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2900 GstStreamType stype = gst_stream_get_stream_type(stream);
2901 mmplayer_t *player = (mmplayer_t *)data;
2902 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2903 GstCaps *caps = gst_stream_get_caps(stream);
2904 gchar *caps_str = NULL;
2906 LOGD("Stream type %s flags 0x%x",
2907 gst_stream_type_get_name(stype),
2908 gst_stream_get_stream_flags(stream));
2909 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2912 caps_str = gst_caps_to_string(caps);
2913 LOGD(" caps: %s", caps_str);
2917 case GST_STREAM_TYPE_AUDIO:
2919 GstStructure *caps_structure = NULL;
2920 gint samplerate = 0;
2923 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2926 caps_structure = gst_caps_get_structure(caps, 0);
2927 gst_structure_get_int(caps_structure, "rate", &samplerate);
2928 gst_structure_get_int(caps_structure, "channels", &channels);
2930 if (channels > 0 && samplerate == 0) {
2931 LOGW("Skip corrupted audio stream");
2935 if (g_strrstr(caps_str, "mobile-xmf"))
2936 mm_player_set_attribute((MMHandleType)player, NULL,
2937 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2941 case GST_STREAM_TYPE_VIDEO:
2943 GstStructure *caps_structure = NULL;
2947 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2949 /* do not support multi track video */
2950 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2953 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2955 /* don't make video because of not required */
2956 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2957 (!player->set_mode.video_export)) {
2958 LOGD("no need video decoding, skip video stream");
2963 caps_structure = gst_caps_get_structure(caps, 0);
2964 gst_structure_get_int(caps_structure, "width", &width);
2967 if (player->v_stream_caps) {
2968 gst_caps_unref(player->v_stream_caps);
2969 player->v_stream_caps = NULL;
2972 player->v_stream_caps = gst_caps_copy(caps);
2973 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
2978 case GST_STREAM_TYPE_TEXT:
2979 type = MM_PLAYER_TRACK_TYPE_TEXT;
2982 LOGW("Skip not supported stream type");
2986 _mmplayer_track_update_stream(player, type, stream);
2988 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
2989 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
2990 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
2991 _mmplayer_set_audio_attrs(player, caps);
2997 gst_caps_unref(caps);
2999 LOGD("ret %d", ret);
3004 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3005 GstStream * stream, gpointer data)
3007 mmplayer_t *player = (mmplayer_t *)data;
3008 GstStreamType stype = gst_stream_get_stream_type(stream);
3011 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3013 LOGD("stream type %s", gst_stream_type_get_name(stype));
3015 /* public does not support audio hw decoder at the moment */
3017 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3018 LOGW("video decoder resource is already acquired, skip it.");
3022 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3023 LOGE("failed to acquire video decoder resource");
3026 player->interrupted_by_resource = FALSE;
3032 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3034 gchar *factory_name = NULL;
3035 mmplayer_t *player = (mmplayer_t *)data;
3036 mmplayer_gst_element_t *mainbin = NULL;
3039 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3041 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3042 mainbin = player->pipeline->mainbin;
3044 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3045 factory_name, GST_ELEMENT_NAME(element));
3047 /* keep the first typefind reference only */
3048 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+
3049 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3050 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3052 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3053 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3054 LOGD("typefind reference is added");
3058 if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3059 /* update queue2 setting */
3060 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3061 gint64 dur_bytes = 0L;
3062 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3064 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3065 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3067 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3068 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3070 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3071 /* NOTE : in case of ts streaming, player could not get the correct duration info *
3072 * skip the pull mode(file or ring buffering) setting. */
3073 if (dur_bytes > 0) {
3074 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
3075 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3076 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3082 _mm_player_streaming_set_queue2(player->streamer,
3086 (guint64)dur_bytes); /* no meaning at the moment */
3090 /* update mq setting */
3091 if (g_strrstr(factory_name, "parsebin") && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3092 GstIterator *iter = NULL;
3093 GValue item = {0, };
3094 GstElement *ch_element = NULL;
3095 GstElementFactory *ch_factory = NULL;
3097 iter = gst_bin_iterate_recurse(child);
3099 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3100 ch_element = g_value_get_object(&item);
3101 ch_factory = gst_element_get_factory(ch_element);
3102 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3103 if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) {
3104 LOGD("get multiqueue");
3105 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3106 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3108 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3109 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3110 g_value_reset(&item);
3113 g_value_reset(&item);
3115 gst_iterator_free(iter);
3120 if (g_strrstr(factory_name, "parsebin")) {
3121 int video_codec_type = 0;
3122 int audio_codec_type = 0;
3124 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3125 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3127 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3128 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3130 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3131 and codec default type in ini has to be hw.
3133 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3134 g_object_set(G_OBJECT(child), "force-sw-decoder-for-video", TRUE, NULL);
3135 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3136 g_object_set(G_OBJECT(child), "force-sw-decoder-for-audio", TRUE, NULL);
3138 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3139 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3140 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3141 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3143 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3144 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3146 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3147 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3149 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3150 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3153 _mmplayer_gst_element_added((GstElement *)child, element, data);
3159 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3161 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3166 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3168 GstElement *uridecodebin3 = NULL;
3171 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3173 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3174 if (!uridecodebin3) {
3175 LOGE("failed to create uridecodebin3");
3180 SECURE_LOGD("uri : %s", player->profile.uri);
3182 /* setting property to streaming source */
3183 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3184 "message-forward", TRUE,
3185 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3187 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3188 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3190 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3191 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3193 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3194 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3196 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3197 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3199 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3200 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3202 /* FIXME: need to be added for gapless playback
3203 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3204 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
3207 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3208 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3210 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3211 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3213 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3214 LOGW("[DASH] this is still experimental feature");
3217 return uridecodebin3;
3221 __mmplayer_gst_make_http_src(mmplayer_t *player)
3223 #define MAX_RETRY_COUNT 10
3224 GstElement *element = NULL;
3225 MMHandleType attrs = 0;
3226 gchar *user_agent, *cookies, **cookie_list;
3227 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3229 user_agent = cookies = NULL;
3233 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3235 /* get profile attribute */
3236 attrs = MMPLAYER_GET_ATTRS(player);
3238 LOGE("failed to get content attribute");
3242 LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
3244 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3246 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3251 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3252 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3254 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3255 http_timeout = player->ini.http_timeout;
3258 SECURE_LOGD("location : %s", player->profile.uri);
3259 SECURE_LOGD("cookies : %s", cookies);
3260 SECURE_LOGD("user_agent : %s", user_agent);
3261 LOGD("timeout : %d", http_timeout);
3263 /* setting property to streaming source */
3264 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3265 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3266 "retries", MAX_RETRY_COUNT, NULL);
3268 /* parsing cookies */
3269 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3270 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3271 g_strfreev(cookie_list);
3275 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3277 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3278 LOGW("[DASH] this is still experimental feature");
3285 __mmplayer_gst_make_file_src(mmplayer_t *player)
3287 GstElement *element = NULL;
3290 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3292 LOGD("using filesrc for 'file://' handler");
3293 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3294 LOGE("failed to get storage info");
3298 element = gst_element_factory_make("filesrc", "source");
3300 LOGE("failed to create filesrc");
3304 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3311 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3313 mmplayer_t *player = (mmplayer_t *)data;
3315 g_return_val_if_fail(player, FALSE);
3316 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3317 gst_message_ref(msg);
3319 g_mutex_lock(&player->bus_msg_q_lock);
3320 g_queue_push_tail(player->bus_msg_q, msg);
3321 g_mutex_unlock(&player->bus_msg_q_lock);
3323 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3324 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3325 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3329 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3331 mmplayer_t *player = (mmplayer_t *)(data);
3332 GstMessage *msg = NULL;
3335 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3337 player->pipeline->mainbin &&
3338 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3341 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3343 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3344 while (!player->bus_msg_thread_exit) {
3345 g_mutex_lock(&player->bus_msg_q_lock);
3346 msg = g_queue_pop_head(player->bus_msg_q);
3347 g_mutex_unlock(&player->bus_msg_q_lock);
3349 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3352 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3353 /* handle the gst msg */
3354 __mmplayer_gst_bus_msg_callback(msg, player);
3355 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3356 gst_message_unref(msg);
3359 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3366 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3368 gint64 dur_nsec = 0;
3371 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3373 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3374 return MM_ERROR_NONE;
3376 /* NOTE : duration cannot be zero except live streaming.
3377 * Since some element could have some timing problemn with quering duration, try again.
3379 if (player->duration == 0) {
3380 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3381 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3382 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3383 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3384 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3385 player->pending_seek.is_pending = true;
3386 player->pending_seek.pos = position;
3387 player->seek_state = MMPLAYER_SEEK_NONE;
3388 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3389 return MM_ERROR_PLAYER_NO_OP;
3391 player->seek_state = MMPLAYER_SEEK_NONE;
3392 return MM_ERROR_PLAYER_SEEK;
3395 player->duration = dur_nsec;
3398 if (player->duration > 0 && player->duration < position) {
3399 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3400 return MM_ERROR_INVALID_ARGUMENT;
3404 return MM_ERROR_NONE;
3408 __mmplayer_gst_check_seekable(mmplayer_t *player)
3410 GstQuery *query = NULL;
3411 gboolean seekable = FALSE;
3413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3417 query = gst_query_new_seeking(GST_FORMAT_TIME);
3418 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3419 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3420 gst_query_unref(query);
3423 LOGW("non-seekable content");
3424 player->seek_state = MMPLAYER_SEEK_NONE;
3428 LOGW("failed to get seeking query");
3429 gst_query_unref(query); /* keep seeking operation */
3436 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3438 GstState element_state = GST_STATE_VOID_PENDING;
3439 GstState element_pending_state = GST_STATE_VOID_PENDING;
3440 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3444 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3445 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3447 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3450 ret = gst_element_set_state(element, state);
3451 if (ret == GST_STATE_CHANGE_FAILURE) {
3452 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3454 /* dump state of all element */
3455 _mmplayer_dump_pipeline_state(player);
3457 return MM_ERROR_PLAYER_INTERNAL;
3460 /* return here so state transition to be done in async mode */
3462 LOGD("async state transition. not waiting for state complete.");
3463 return MM_ERROR_NONE;
3466 /* wait for state transition */
3467 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3468 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3469 LOGE("failed to change [%s] element state to [%s] within %d sec",
3470 GST_ELEMENT_NAME(element),
3471 gst_element_state_get_name(state), timeout);
3473 LOGE(" [%s] state : %s pending : %s",
3474 GST_ELEMENT_NAME(element),
3475 gst_element_state_get_name(element_state),
3476 gst_element_state_get_name(element_pending_state));
3478 /* dump state of all element */
3479 _mmplayer_dump_pipeline_state(player);
3481 return MM_ERROR_PLAYER_INTERNAL;
3484 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3488 return MM_ERROR_NONE;
3492 _mmplayer_gst_start(mmplayer_t *player)
3494 int ret = MM_ERROR_NONE;
3495 gboolean async = FALSE;
3499 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3501 /* NOTE : if SetPosition was called before Start. do it now
3502 * streaming doesn't support it. so it should be always sync
3503 * !!create one more api to check if there is pending seek rather than checking variables
3505 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3506 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3507 ret = _mmplayer_gst_pause(player, FALSE);
3508 if (ret != MM_ERROR_NONE) {
3509 LOGE("failed to set state to PAUSED for pending seek");
3513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3514 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3515 LOGW("failed to seek pending postion. starting from the begin of content");
3518 LOGD("current state before doing transition");
3519 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3520 MMPLAYER_PRINT_STATE(player);
3522 /* set pipeline state to PLAYING */
3523 ret = _mmplayer_gst_set_state(player,
3524 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3525 if (ret != MM_ERROR_NONE) {
3526 LOGE("failed to set state to PLAYING");
3530 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3532 /* generating debug info before returning error */
3533 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3541 _mmplayer_gst_stop(mmplayer_t *player)
3543 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3544 MMHandleType attrs = 0;
3545 gboolean rewind = FALSE;
3547 int ret = MM_ERROR_NONE;
3551 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3552 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3554 LOGD("current state before doing transition");
3555 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3556 MMPLAYER_PRINT_STATE(player);
3558 attrs = MMPLAYER_GET_ATTRS(player);
3560 LOGE("cannot get content attribute");
3561 return MM_ERROR_PLAYER_INTERNAL;
3564 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3565 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3567 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3568 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3571 if (player->es_player_push_mode)
3572 /* disable the async state transition because there could be no data in the pipeline */
3573 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3576 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3578 if (player->es_player_push_mode) {
3579 /* enable the async state transition as default operation */
3580 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3583 /* return if set_state has failed */
3584 if (ret != MM_ERROR_NONE) {
3585 LOGE("failed to set state.");
3591 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3592 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3593 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3594 LOGW("failed to rewind");
3595 ret = MM_ERROR_PLAYER_SEEK;
3600 player->sent_bos = FALSE;
3602 if (player->es_player_push_mode) //for cloudgame
3605 /* wait for seek to complete */
3606 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3607 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3608 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3610 LOGE("fail to stop player.");
3611 ret = MM_ERROR_PLAYER_INTERNAL;
3612 _mmplayer_dump_pipeline_state(player);
3615 /* generate dot file if enabled */
3616 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3624 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
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_PAUSED;
3635 MMPLAYER_PRINT_STATE(player);
3637 /* set pipeline status to PAUSED */
3638 ret = _mmplayer_gst_set_state(player,
3639 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3644 if (ret != MM_ERROR_NONE) {
3645 GstMessage *msg = NULL;
3646 GTimer *timer = NULL;
3647 gdouble MAX_TIMEOUT_SEC = 3;
3649 LOGE("failed to set state to PAUSED");
3651 if (!player->bus_watcher) {
3652 LOGE("there is no bus msg thread. pipeline is shutting down.");
3656 if (player->msg_posted) {
3657 LOGE("error msg is already posted.");
3661 timer = g_timer_new();
3662 g_timer_start(timer);
3664 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3667 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3669 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3670 GError *error = NULL;
3672 /* parse error code */
3673 gst_message_parse_error(msg, &error, NULL);
3675 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3676 /* Note : the streaming error from the streaming source is handled
3677 * using __mmplayer_handle_streaming_error.
3679 __mmplayer_handle_streaming_error(player, msg);
3682 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3684 if (error->domain == GST_STREAM_ERROR)
3685 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3686 else if (error->domain == GST_RESOURCE_ERROR)
3687 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3688 else if (error->domain == GST_LIBRARY_ERROR)
3689 ret = __mmplayer_gst_handle_library_error(player, error->code);
3690 else if (error->domain == GST_CORE_ERROR)
3691 ret = __mmplayer_gst_handle_core_error(player, error->code);
3693 g_error_free(error);
3695 player->msg_posted = TRUE;
3697 gst_message_unref(msg);
3699 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3701 gst_object_unref(bus);
3702 g_timer_stop(timer);
3703 g_timer_destroy(timer);
3708 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3709 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3710 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3711 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3714 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3717 /* generate dot file before returning error */
3718 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3726 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3728 int ret = MM_ERROR_NONE;
3733 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3734 MM_ERROR_PLAYER_NOT_INITIALIZED);
3736 LOGD("current state before doing transition");
3737 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3738 MMPLAYER_PRINT_STATE(player);
3741 LOGD("do async state transition to PLAYING");
3743 /* set pipeline state to PLAYING */
3744 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3746 ret = _mmplayer_gst_set_state(player,
3747 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3748 if (ret != MM_ERROR_NONE) {
3749 LOGE("failed to set state to PLAYING");
3754 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3757 /* generate dot file */
3758 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3765 /* sending event to one of sinkelements */
3767 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3769 GstEvent *event2 = NULL;
3770 GList *sinks = NULL;
3771 gboolean res = FALSE;
3774 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3775 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3777 /* While adding subtitles in live feeds seek is getting called.
3778 Adding defensive check in framework layer.*/
3779 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3780 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3781 LOGE("Should not send seek event during live playback");
3786 if (player->play_subtitle)
3787 event2 = gst_event_copy((const GstEvent *)event);
3789 sinks = player->sink_elements;
3791 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3793 if (GST_IS_ELEMENT(sink)) {
3794 /* keep ref to the event */
3795 gst_event_ref(event);
3797 if ((res = gst_element_send_event(sink, event))) {
3798 LOGD("sending event[%s] to sink element [%s] success!",
3799 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3801 /* rtsp case, asyn_done is not called after seek during pause state */
3802 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3803 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3804 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3805 LOGD("RTSP seek completed, after pause state..");
3806 player->seek_state = MMPLAYER_SEEK_NONE;
3807 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3813 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3814 sinks = g_list_next(sinks);
3821 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3822 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3825 sinks = g_list_next(sinks);
3828 /* Note : Textbin is not linked to the video or audio bin.
3829 * It needs to send the event to the text sink seperatelly.
3831 if (player->play_subtitle && player->pipeline) {
3832 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3834 if (GST_IS_ELEMENT(text_sink)) {
3835 /* keep ref to the event */
3836 gst_event_ref(event2);
3838 if ((res = gst_element_send_event(text_sink, event2)))
3839 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3840 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3842 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3843 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3845 gst_event_unref(event2);
3849 gst_event_unref(event);
3857 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3858 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3859 gint64 cur, GstSeekType stop_type, gint64 stop)
3861 GstEvent *event = NULL;
3862 gboolean result = FALSE;
3866 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3868 if (player->pipeline && player->pipeline->textbin)
3869 __mmplayer_drop_subtitle(player, FALSE);
3871 event = gst_event_new_seek(rate, format, flags, cur_type,
3872 cur, stop_type, stop);
3874 result = _mmplayer_gst_send_event_to_sink(player, event);
3882 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3884 int ret = MM_ERROR_NONE;
3885 gint64 pos_nsec = 0;
3886 gboolean accurated = FALSE;
3887 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3890 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3891 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3893 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3894 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3897 ret = __mmplayer_gst_check_duration(player, position);
3898 if (ret != MM_ERROR_NONE) {
3899 LOGE("failed to check duration 0x%X", ret);
3900 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3903 if (!__mmplayer_gst_check_seekable(player))
3904 return MM_ERROR_PLAYER_NO_OP;
3906 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3907 position, player->playback_rate, player->duration);
3909 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3910 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3911 This causes problem is position calculation during normal pause resume scenarios also.
3912 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3913 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3914 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3915 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3916 LOGW("getting current position failed in seek");
3918 player->last_position = pos_nsec;
3919 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3922 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3923 LOGD("not completed seek");
3924 return MM_ERROR_PLAYER_DOING_SEEK;
3927 if (!internal_called)
3928 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3930 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3931 that's why set position through property. */
3932 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3933 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3934 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3935 (!player->videodec_linked) && (!player->audiodec_linked)) {
3937 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3938 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3940 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3941 player->seek_state = MMPLAYER_SEEK_NONE;
3942 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3944 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3946 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3948 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3950 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3951 GST_FORMAT_TIME, seek_flags,
3952 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3953 LOGE("failed to set position");
3958 /* NOTE : store last seeking point to overcome some bad operation
3959 * (returning zero when getting current position) of some elements
3961 player->last_position = position;
3963 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3964 if (player->playback_rate > 1.0)
3965 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3967 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3968 LOGD("buffering should be reset after seeking");
3969 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3970 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3974 return MM_ERROR_NONE;
3977 player->pending_seek.is_pending = true;
3978 player->pending_seek.pos = position;
3980 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3981 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3982 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3983 player->pending_seek.pos);
3985 return MM_ERROR_NONE;
3988 player->seek_state = MMPLAYER_SEEK_NONE;
3989 return MM_ERROR_PLAYER_SEEK;
3993 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3995 #define TRICKPLAY_OFFSET GST_MSECOND
3997 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3998 gint64 pos_nsec = 0;
3999 gboolean ret = TRUE;
4001 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4002 MM_ERROR_PLAYER_NOT_INITIALIZED);
4004 current_state = MMPLAYER_CURRENT_STATE(player);
4006 /* NOTE : query position except paused state to overcome some bad operation
4007 * please refer to below comments in details
4009 if (current_state != MM_PLAYER_STATE_PAUSED)
4010 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4012 /* NOTE : get last point to overcome some bad operation of some elements
4013 *(returning zero when getting current position in paused state
4014 * and when failed to get postion during seeking
4016 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4017 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4019 if (player->playback_rate < 0.0)
4020 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4022 pos_nsec = player->last_position;
4025 pos_nsec = player->last_position;
4027 player->last_position = pos_nsec;
4029 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4032 if (player->duration > 0 && pos_nsec > player->duration)
4033 pos_nsec = player->duration;
4035 player->last_position = pos_nsec;
4038 *position = pos_nsec;
4040 return MM_ERROR_NONE;
4044 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4046 #define STREAMING_IS_FINISHED 0
4047 #define BUFFERING_MAX_PER 100
4048 #define DEFAULT_PER_VALUE -1
4049 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4051 mmplayer_gst_element_t *mainbin = NULL;
4052 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4053 gint64 buffered_total = 0;
4054 gint64 position = 0;
4055 gint buffered_sec = -1;
4056 GstBufferingMode mode = GST_BUFFERING_STREAM;
4057 gint64 content_size_time = player->duration;
4058 guint64 content_size_bytes = player->http_content_size;
4060 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4062 player->pipeline->mainbin,
4063 MM_ERROR_PLAYER_NOT_INITIALIZED);
4065 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4070 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4071 /* and rtsp is not ready yet. */
4072 LOGW("it's only used for http streaming case");
4073 return MM_ERROR_PLAYER_NO_OP;
4076 if (content_size_time <= 0 || content_size_bytes <= 0) {
4077 LOGW("there is no content size");
4078 return MM_ERROR_NONE;
4081 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4082 LOGW("fail to get current position");
4083 return MM_ERROR_NONE;
4086 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4087 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4089 mainbin = player->pipeline->mainbin;
4090 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4092 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4093 GstQuery *query = NULL;
4094 gint byte_in_rate = 0, byte_out_rate = 0;
4095 gint64 estimated_total = 0;
4097 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4098 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4099 LOGW("fail to get buffering query from queue2");
4101 gst_query_unref(query);
4102 return MM_ERROR_NONE;
4105 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4106 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4108 if (mode == GST_BUFFERING_STREAM) {
4109 /* using only queue in case of push mode(ts / mp3) */
4110 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4111 GST_FORMAT_BYTES, &buffered_total)) {
4112 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4113 end_per = 100 * buffered_total / content_size_bytes;
4116 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4118 guint num_of_ranges = 0;
4119 gint64 start_byte = 0, stop_byte = 0;
4121 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4122 if (estimated_total != STREAMING_IS_FINISHED) {
4123 /* buffered size info from queue2 */
4124 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4125 for (idx = 0; idx < num_of_ranges; idx++) {
4126 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4127 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4129 buffered_total += (stop_byte - start_byte);
4132 end_per = BUFFERING_MAX_PER;
4135 gst_query_unref(query);
4138 if (end_per == DEFAULT_PER_VALUE) {
4139 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4141 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4143 /* buffered size info from multiqueue */
4144 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4145 guint curr_size_bytes = 0;
4146 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4147 "curr-size-bytes", &curr_size_bytes, NULL);
4148 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4149 buffered_total += curr_size_bytes;
4152 if (avg_byterate > 0)
4153 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4154 else if (player->total_maximum_bitrate > 0)
4155 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4156 else if (player->total_bitrate > 0)
4157 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4159 if (buffered_sec >= 0)
4160 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4164 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4165 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4167 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4168 buffered_total, buffered_sec, *start_pos, *end_pos);
4170 return MM_ERROR_NONE;
4174 _mmplayer_gst_create_source(mmplayer_t *player)
4176 GstElement *element = NULL;
4179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4180 player->pipeline->mainbin, NULL);
4182 /* setup source for gapless play */
4183 switch (player->profile.uri_type) {
4185 case MM_PLAYER_URI_TYPE_FILE:
4186 element = __mmplayer_gst_make_file_src(player);
4188 case MM_PLAYER_URI_TYPE_URL_HTTP:
4189 element = __mmplayer_gst_make_http_src(player);
4192 LOGE("not support uri type %d", player->profile.uri_type);
4197 LOGE("failed to create source element");
4206 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4209 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4210 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4212 SECURE_LOGD("uri : %s", player->profile.uri);
4214 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4216 if ((player->v_stream_caps) &&
4217 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4218 return MM_ERROR_PLAYER_INTERNAL;
4220 if ((player->a_stream_caps) &&
4221 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4222 return MM_ERROR_PLAYER_INTERNAL;
4224 if ((player->s_stream_caps) &&
4225 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4226 return MM_ERROR_PLAYER_INTERNAL;
4229 return MM_ERROR_NONE;
4233 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4235 mmplayer_gst_element_t *mainbin = NULL;
4236 GstElement *autoplug_elem = NULL;
4239 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4240 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4242 mainbin = player->pipeline->mainbin;
4244 LOGD("uri type %d", player->profile.uri_type);
4246 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4247 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4248 return MM_ERROR_PLAYER_INTERNAL;
4251 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4252 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4255 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4256 if (!autoplug_elem) {
4257 LOGE("failed to create uridecodebin3 element");
4261 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4262 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4263 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4265 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4266 LOGE("failed to add uridecodebin to pipeline");
4270 /* FIXME: required ?*/
4271 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4272 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4273 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4275 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4276 LOGE("failed to create fakesink");
4279 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4281 /* take ownership of fakesink. we are reusing it */
4282 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4284 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4285 LOGE("failed to add fakesink to bin");
4286 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4291 return MM_ERROR_NONE;
4295 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4296 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4298 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4299 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4301 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4302 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4304 return MM_ERROR_PLAYER_INTERNAL;
4308 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4310 mmplayer_gst_element_t *mainbin = NULL;
4311 GstElement *src_elem = NULL;
4312 GstElement *autoplug_elem = NULL;
4313 GList *element_bucket = NULL;
4314 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4317 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4318 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4320 LOGD("uri type %d", player->profile.uri_type);
4322 /* create source element */
4323 switch (player->profile.uri_type) {
4324 case MM_PLAYER_URI_TYPE_URL_RTSP:
4325 src_elem = __mmplayer_gst_make_rtsp_src(player);
4327 case MM_PLAYER_URI_TYPE_URL_HTTP:
4328 src_elem = __mmplayer_gst_make_http_src(player);
4330 case MM_PLAYER_URI_TYPE_FILE:
4331 src_elem = __mmplayer_gst_make_file_src(player);
4333 case MM_PLAYER_URI_TYPE_SS:
4335 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4336 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4338 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4342 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4343 LOGD("get timeout from ini");
4344 http_timeout = player->ini.http_timeout;
4347 /* setting property to streaming source */
4348 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4351 case MM_PLAYER_URI_TYPE_MEM:
4353 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4355 src_elem = gst_element_factory_make("appsrc", "mem-source");
4357 LOGE("failed to create appsrc element");
4361 g_object_set(src_elem, "stream-type", stream_type,
4362 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4364 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4365 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4366 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4367 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4371 LOGE("not support uri type");
4376 LOGE("failed to create source element");
4377 return MM_ERROR_PLAYER_INTERNAL;
4380 mainbin = player->pipeline->mainbin;
4382 /* take source element */
4383 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4385 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4386 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4387 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4389 /* create next element for auto-plugging */
4390 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4391 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4392 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4393 if (!autoplug_elem) {
4394 LOGE("failed to create typefind element");
4398 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4399 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4400 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4401 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4402 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4403 if (!autoplug_elem) {
4404 LOGE("failed to create decodebin");
4408 /* default size of mq in decodebin is 2M
4409 * but it can cause blocking issue during seeking depends on content. */
4410 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4413 if (autoplug_elem) {
4414 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4415 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4416 mainbin[autoplug_elem_id].gst = autoplug_elem;
4418 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4421 /* add elements to pipeline */
4422 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4423 LOGE("failed to add elements to pipeline");
4427 /* linking elements in the bucket by added order. */
4428 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4429 LOGE("failed to link some elements");
4433 /* FIXME: need to check whether this is required or not. */
4434 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4435 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4436 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4437 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4438 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4440 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4441 LOGE("failed to create fakesink");
4444 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4446 /* take ownership of fakesink. we are reusing it */
4447 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4449 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4450 LOGE("failed to add fakesink to bin");
4451 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4456 g_list_free(element_bucket);
4459 return MM_ERROR_NONE;
4462 g_list_free(element_bucket);
4464 if (mainbin[MMPLAYER_M_SRC].gst)
4465 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4467 if (mainbin[autoplug_elem_id].gst)
4468 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4470 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4471 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4473 mainbin[MMPLAYER_M_SRC].gst = NULL;
4474 mainbin[autoplug_elem_id].gst = NULL;
4475 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4477 return MM_ERROR_PLAYER_INTERNAL;
4481 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4484 mmplayer_gst_element_t *mainbin = NULL;
4487 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4488 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4490 mainbin = player->pipeline->mainbin;
4492 /* connect bus callback */
4493 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4495 LOGE("cannot get bus from pipeline");
4496 return MM_ERROR_PLAYER_INTERNAL;
4499 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4500 (GstBusFunc)__mmplayer_gst_msg_push, player,
4501 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4502 if (player->bus_watcher == 0) {
4503 LOGE("failed to add bus watch");
4504 return MM_ERROR_PLAYER_INTERNAL;
4507 g_mutex_init(&player->bus_watcher_mutex);
4508 g_cond_init(&player->bus_watcher_cond);
4510 player->context.thread_default = g_main_context_get_thread_default();
4511 if (player->context.thread_default == NULL) {
4512 player->context.thread_default = g_main_context_default();
4513 LOGD("thread-default context is the global default context");
4515 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4517 /* set sync handler to get tag synchronously */
4518 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4519 gst_object_unref(GST_OBJECT(bus));
4521 /* create gst bus_msb_cb thread */
4522 g_mutex_init(&player->bus_msg_thread_mutex);
4523 g_cond_init(&player->bus_msg_thread_cond);
4524 player->bus_msg_thread_exit = FALSE;
4525 player->bus_msg_thread =
4526 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4527 if (!player->bus_msg_thread) {
4528 LOGE("failed to create gst BUS msg thread");
4529 g_mutex_clear(&player->bus_msg_thread_mutex);
4530 g_cond_clear(&player->bus_msg_thread_cond);
4531 return MM_ERROR_PLAYER_INTERNAL;
4535 return MM_ERROR_NONE;
4539 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4541 mmplayer_gst_element_t *mainbin = NULL;
4542 MMMessageParamType msg_param = {0,};
4543 GstElement *element = NULL;
4544 MMHandleType attrs = 0;
4546 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4550 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4551 LOGE("player is not initialized");
4555 mainbin = player->pipeline->mainbin;
4556 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4558 attrs = MMPLAYER_GET_ATTRS(player);
4560 LOGE("fail to get attributes");
4564 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4566 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4567 LOGE("failed to parse profile");
4568 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4572 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4573 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4574 LOGE("dash or hls is not supportable");
4575 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4579 element = _mmplayer_gst_create_source(player);
4581 LOGE("no source element was created");
4585 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4586 LOGE("failed to add source element to pipeline");
4587 gst_object_unref(GST_OBJECT(element));
4592 /* take source element */
4593 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4594 mainbin[MMPLAYER_M_SRC].gst = element;
4598 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4599 if (player->streamer == NULL) {
4600 player->streamer = _mm_player_streaming_create();
4601 _mm_player_streaming_initialize(player->streamer, TRUE);
4604 elem_idx = MMPLAYER_M_TYPEFIND;
4605 element = gst_element_factory_make("typefind", "typefinder");
4606 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4607 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4609 elem_idx = MMPLAYER_M_AUTOPLUG;
4610 element = _mmplayer_gst_make_decodebin(player);
4613 /* check autoplug element is OK */
4615 LOGE("can not create element(%d)", elem_idx);
4619 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4620 LOGE("failed to add sinkbin to pipeline");
4621 gst_object_unref(GST_OBJECT(element));
4626 mainbin[elem_idx].id = elem_idx;
4627 mainbin[elem_idx].gst = element;
4629 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4630 LOGE("Failed to link src - autoplug(or typefind)");
4634 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4635 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4636 LOGE("Failed to change state of src element");
4640 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4641 LOGE("Failed to change state of decodebin");
4646 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4647 LOGE("Failed to change state of src element");
4651 player->gapless.stream_changed = TRUE;
4652 player->gapless.running = TRUE;
4658 _mmplayer_set_reconfigure_state(player, FALSE);
4659 if (!player->msg_posted) {
4660 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4661 player->msg_posted = TRUE;