4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36 #include "mm_player_tracks.h"
38 /*===========================================================================================
40 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
42 ========================================================================================== */
44 /*---------------------------------------------------------------------------
45 | LOCAL CONSTANT DEFINITIONS: |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
49 /*===========================================================================================
51 | FUNCTION DEFINITIONS |
53 ========================================================================================== */
56 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
60 count = gst_tag_list_get_tag_size(list, tag);
62 LOGD("count = %d", count);
64 for (i = 0; i < count; i++) {
67 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
68 if (!gst_tag_list_get_string_index(list, tag, i, &str))
69 g_assert_not_reached();
71 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
75 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
77 g_print(" : %s", str);
85 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
87 /* check whether the error is posted from not-activated track or not */
89 gint active_index = 0;
91 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
93 active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
94 LOGD("current active pad index -%d", active_index);
96 if (src_element_name) {
99 if (player->audio_decoders) {
100 GList *adec = player->audio_decoders;
101 for (; adec ; adec = g_list_next(adec)) {
102 gchar *name = adec->data;
104 LOGD("found audio decoder name = %s", name);
105 if (g_strrstr(name, src_element_name)) {
112 LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos);
115 if (active_index != msg_src_pos) {
116 LOGD("skip error because error is posted from no activated track");
124 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
126 /* Demuxer can't parse one track because it's corrupted.
127 * So, the decoder for it is not linked.
128 * But, it has one playable track.
130 if (g_strrstr(klass, "Demux")) {
131 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
132 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
133 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
134 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
136 if (player->pipeline->audiobin) { // PCM
137 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
139 LOGD("not found any available codec. Player should be destroyed.");
140 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
145 return MM_ERROR_PLAYER_INVALID_STREAM;
149 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
151 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
152 LOGE("Not supported subtitle.");
153 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
155 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
159 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
161 /* Decoder Custom Message */
162 if (!strstr(error->message, "ongoing"))
163 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
165 if (strncasecmp(klass, "audio", 5)) {
166 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
167 LOGD("Video can keep playing.");
168 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
170 } else if (strncasecmp(klass, "video", 5)) {
171 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
172 LOGD("Audio can keep playing.");
173 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
177 LOGD("not found any available codec. Player should be destroyed.");
178 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
182 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
184 if (strstr(error->message, "rights expired"))
185 return MM_ERROR_PLAYER_DRM_EXPIRED;
186 else if (strstr(error->message, "no rights"))
187 return MM_ERROR_PLAYER_DRM_NO_LICENSE;
188 else if (strstr(error->message, "has future rights"))
189 return MM_ERROR_PLAYER_DRM_FUTURE_USE;
190 else if (strstr(error->message, "opl violation"))
191 return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
193 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
196 /* NOTE : decide gstreamer state whether there is some playable track or not. */
198 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
200 gchar *src_element_name = NULL;
201 GstElement *src_element = NULL;
202 GstElementFactory *factory = NULL;
203 const gchar *klass = NULL;
207 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
208 MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
209 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
210 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
212 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
214 src_element = GST_ELEMENT_CAST(message->src);
215 src_element_name = GST_ELEMENT_NAME(src_element);
216 if (!src_element_name)
217 return MM_ERROR_PLAYER_INTERNAL;
219 factory = gst_element_get_factory(src_element);
221 return MM_ERROR_PLAYER_INTERNAL;
223 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
225 return MM_ERROR_PLAYER_INTERNAL;
227 LOGD("error code=%d, msg=%s, src element=%s, class=%s",
228 error->code, error->message, src_element_name, klass);
230 if (MMPLAYER_USE_DECODEBIN(player) &&
231 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
232 return MM_ERROR_NONE;
234 switch (error->code) {
235 case GST_STREAM_ERROR_DECODE:
236 return __mmplayer_gst_transform_error_decode(player, klass);
237 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
238 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
239 case GST_STREAM_ERROR_WRONG_TYPE:
240 return __mmplayer_gst_transform_error_type(player, src_element);
241 case GST_STREAM_ERROR_FAILED:
242 return __mmplayer_gst_transform_error_failed(player, klass, error);
243 case GST_STREAM_ERROR_DECRYPT:
244 case GST_STREAM_ERROR_DECRYPT_NOKEY:
245 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
246 return __mmplayer_gst_transform_error_decrypt(player, error);
253 return MM_ERROR_PLAYER_INVALID_STREAM;
257 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
259 gint trans_err = MM_ERROR_NONE;
263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
266 case GST_CORE_ERROR_MISSING_PLUGIN:
267 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
268 case GST_CORE_ERROR_STATE_CHANGE:
269 case GST_CORE_ERROR_SEEK:
270 case GST_CORE_ERROR_NOT_IMPLEMENTED:
271 case GST_CORE_ERROR_FAILED:
272 case GST_CORE_ERROR_TOO_LAZY:
273 case GST_CORE_ERROR_PAD:
274 case GST_CORE_ERROR_THREAD:
275 case GST_CORE_ERROR_NEGOTIATION:
276 case GST_CORE_ERROR_EVENT:
277 case GST_CORE_ERROR_CAPS:
278 case GST_CORE_ERROR_TAG:
279 case GST_CORE_ERROR_CLOCK:
280 case GST_CORE_ERROR_DISABLED:
282 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
292 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
294 gint trans_err = MM_ERROR_NONE;
298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
301 case GST_LIBRARY_ERROR_FAILED:
302 case GST_LIBRARY_ERROR_TOO_LAZY:
303 case GST_LIBRARY_ERROR_INIT:
304 case GST_LIBRARY_ERROR_SHUTDOWN:
305 case GST_LIBRARY_ERROR_SETTINGS:
306 case GST_LIBRARY_ERROR_ENCODE:
308 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
318 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
320 gint trans_err = MM_ERROR_NONE;
324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
327 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
328 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
330 case GST_RESOURCE_ERROR_NOT_FOUND:
331 case GST_RESOURCE_ERROR_OPEN_READ:
332 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
333 || MMPLAYER_IS_RTSP_STREAMING(player)) {
334 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
337 case GST_RESOURCE_ERROR_READ:
338 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
339 || MMPLAYER_IS_RTSP_STREAMING(player)) {
340 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
342 } else if (message != NULL && message->src != NULL) {
343 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
344 mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
346 if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
347 path_type = MMPLAYER_PATH_VOD;
348 else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
349 path_type = MMPLAYER_PATH_TEXT;
351 if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
352 /* check storage state */
353 storage_get_state(player->storage_info[path_type].id, &storage_state);
354 player->storage_info[path_type].state = storage_state;
355 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
358 case GST_RESOURCE_ERROR_WRITE:
359 case GST_RESOURCE_ERROR_FAILED:
360 case GST_RESOURCE_ERROR_SEEK:
361 case GST_RESOURCE_ERROR_TOO_LAZY:
362 case GST_RESOURCE_ERROR_BUSY:
363 case GST_RESOURCE_ERROR_OPEN_WRITE:
364 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
365 case GST_RESOURCE_ERROR_CLOSE:
366 case GST_RESOURCE_ERROR_SYNC:
367 case GST_RESOURCE_ERROR_SETTINGS:
369 trans_err = MM_ERROR_PLAYER_INTERNAL;
379 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
381 gint trans_err = MM_ERROR_NONE;
385 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
386 MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
387 MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
389 switch (error->code) {
390 case GST_STREAM_ERROR_FAILED:
391 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
392 case GST_STREAM_ERROR_DECODE:
393 case GST_STREAM_ERROR_WRONG_TYPE:
394 case GST_STREAM_ERROR_DECRYPT:
395 case GST_STREAM_ERROR_DECRYPT_NOKEY:
396 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
397 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
400 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
401 case GST_STREAM_ERROR_TOO_LAZY:
402 case GST_STREAM_ERROR_ENCODE:
403 case GST_STREAM_ERROR_DEMUX:
404 case GST_STREAM_ERROR_MUX:
405 case GST_STREAM_ERROR_FORMAT:
407 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
417 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
419 MMMessageParamType msg_param;
420 gchar *msg_src_element;
424 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
425 MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
427 /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
429 memset(&msg_param, 0, sizeof(MMMessageParamType));
431 if (error->domain == GST_CORE_ERROR) {
432 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
433 } else if (error->domain == GST_LIBRARY_ERROR) {
434 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
435 } else if (error->domain == GST_RESOURCE_ERROR) {
436 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
437 } else if (error->domain == GST_STREAM_ERROR) {
438 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
440 LOGW("This error domain is not defined.");
442 /* we treat system error as an internal error */
443 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
447 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
449 msg_param.data = (void *)error->message;
451 LOGE("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is translated to error code : [0x%x]",
452 msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
456 if (msg_param.code == MM_ERROR_NONE)
459 /* skip error to avoid duplicated posting */
460 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
461 (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
462 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
463 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
465 /* The error will be handled by mused.
466 * @ref _mmplayer_manage_external_storage_state() */
468 LOGW("storage is removed, skip error post");
472 /* post error to application */
473 if (!player->msg_posted) {
474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
475 /* don't post more if one was sent already */
476 player->msg_posted = TRUE;
478 LOGD("skip error post because it's sent already.");
487 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
490 MMMessageParamType msg_param = {0, };
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 performance. */
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_DECODEBIN(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_set_reconfigure_state(player, FALSE);
1000 _mmplayer_pipeline_complete(NULL, player);
1013 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1015 guint64 data_size = 0;
1016 gint64 pos_nsec = 0;
1018 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1020 _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1022 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1023 data_size = player->http_content_size;
1026 _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1027 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1033 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1035 int ret = MM_ERROR_NONE;
1036 mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1037 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1038 mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1039 mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1041 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1042 LOGW("do nothing for buffering msg");
1043 ret = MM_ERROR_PLAYER_INVALID_STATE;
1047 prev_state = MMPLAYER_PREV_STATE(player);
1048 current_state = MMPLAYER_CURRENT_STATE(player);
1049 target_state = MMPLAYER_TARGET_STATE(player);
1050 pending_state = MMPLAYER_PENDING_STATE(player);
1052 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1053 MMPLAYER_STATE_GET_NAME(prev_state),
1054 MMPLAYER_STATE_GET_NAME(current_state),
1055 MMPLAYER_STATE_GET_NAME(pending_state),
1056 MMPLAYER_STATE_GET_NAME(target_state),
1057 player->streamer->buffering_state);
1059 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1060 /* NOTE : if buffering has done, player has to go to target state. */
1061 switch (target_state) {
1062 case MM_PLAYER_STATE_PAUSED:
1064 switch (pending_state) {
1065 case MM_PLAYER_STATE_PLAYING:
1066 _mmplayer_gst_pause(player, TRUE);
1069 case MM_PLAYER_STATE_PAUSED:
1070 LOGD("player is already going to paused state, there is nothing to do.");
1073 case MM_PLAYER_STATE_NONE:
1074 case MM_PLAYER_STATE_NULL:
1075 case MM_PLAYER_STATE_READY:
1077 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1083 case MM_PLAYER_STATE_PLAYING:
1085 switch (pending_state) {
1086 case MM_PLAYER_STATE_NONE:
1088 if (current_state != MM_PLAYER_STATE_PLAYING)
1089 _mmplayer_gst_resume(player, TRUE);
1093 case MM_PLAYER_STATE_PAUSED:
1094 /* NOTE: It should be worked as asynchronously.
1095 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1097 if (current_state == MM_PLAYER_STATE_PLAYING) {
1098 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1099 * The current state should be changed to paused purposely to prevent state conflict.
1101 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1103 _mmplayer_gst_resume(player, TRUE);
1106 case MM_PLAYER_STATE_PLAYING:
1107 LOGD("player is already going to playing state, there is nothing to do.");
1110 case MM_PLAYER_STATE_NULL:
1111 case MM_PLAYER_STATE_READY:
1113 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1119 case MM_PLAYER_STATE_NULL:
1120 case MM_PLAYER_STATE_READY:
1121 case MM_PLAYER_STATE_NONE:
1123 LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1127 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1128 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1130 switch (pending_state) {
1131 case MM_PLAYER_STATE_NONE:
1133 if (current_state != MM_PLAYER_STATE_PAUSED) {
1134 /* rtsp streaming pause makes rtsp server stop sending data. */
1135 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1136 LOGD("set pause state during buffering");
1137 _mmplayer_gst_pause(player, TRUE);
1143 case MM_PLAYER_STATE_PLAYING:
1144 /* rtsp streaming pause makes rtsp server stop sending data. */
1145 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1146 _mmplayer_gst_pause(player, TRUE);
1149 case MM_PLAYER_STATE_PAUSED:
1152 case MM_PLAYER_STATE_NULL:
1153 case MM_PLAYER_STATE_READY:
1155 LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1164 static stream_variant_t *
1165 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1167 stream_variant_t *var_info = NULL;
1168 g_return_val_if_fail(self != NULL, NULL);
1170 var_info = g_new0(stream_variant_t, 1);
1171 if (!var_info) return NULL;
1172 var_info->bandwidth = self->bandwidth;
1173 var_info->width = self->width;
1174 var_info->height = self->height;
1179 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1185 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1186 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1188 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1189 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1190 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1192 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1193 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1194 player->http_content_size = (bytes > 0) ? bytes : 0;
1197 /* handling audio clip which has vbr. means duration is keep changing */
1198 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1207 __mmplayer_eos_timer_cb(gpointer u_data)
1209 mmplayer_t *player = NULL;
1210 MMHandleType attrs = 0;
1213 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1215 player = (mmplayer_t *)u_data;
1216 attrs = MMPLAYER_GET_ATTRS(player);
1218 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1222 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1223 if (ret_value != MM_ERROR_NONE)
1224 LOGE("seeking to 0 failed in repeat play");
1227 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1230 /* we are returning FALSE as we need only one posting */
1235 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1237 MMPLAYER_RETURN_IF_FAIL(player);
1239 /* post now if delay is zero */
1240 if (delay_in_ms == 0 || player->audio_decoded_cb) {
1241 LOGD("eos delay is zero. posting EOS now");
1242 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1244 if (player->audio_decoded_cb)
1245 _mmplayer_cancel_eos_timer(player);
1250 /* cancel if existing */
1251 _mmplayer_cancel_eos_timer(player);
1253 /* init new timeout */
1254 /* NOTE : consider give high priority to this timer */
1255 LOGD("posting EOS message after [%d] msec", delay_in_ms);
1257 player->eos_timer = g_timeout_add(delay_in_ms,
1258 __mmplayer_eos_timer_cb, player);
1260 player->context.global_default = g_main_context_default();
1261 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1263 /* check timer is valid. if not, send EOS now */
1264 if (player->eos_timer == 0) {
1265 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1266 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1271 __mmplayer_gst_pending_seek(mmplayer_t *player)
1273 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1274 int ret = MM_ERROR_NONE;
1278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1280 if (!player->pending_seek.is_pending) {
1281 LOGD("pending seek is not reserved. nothing to do.");
1285 /* check player state if player could pending seek or not. */
1286 current_state = MMPLAYER_CURRENT_STATE(player);
1288 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1289 LOGW("try to pending seek in %s state, try next time. ",
1290 MMPLAYER_STATE_GET_NAME(current_state));
1294 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1296 ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1297 if (ret != MM_ERROR_NONE)
1298 LOGE("failed to seek pending position. just keep staying current position.");
1300 player->pending_seek.is_pending = false;
1308 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type type)
1310 mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1312 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1314 audiobin = player->pipeline->audiobin; /* can be null */
1315 videobin = player->pipeline->videobin; /* can be null */
1316 textbin = player->pipeline->textbin; /* can be null */
1318 LOGD("Async will be set to %d about 0x%X type sink", async, type);
1320 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1321 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1323 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1324 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1326 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1327 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1333 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1335 mmplayer_gst_element_t *textbin;
1338 MMPLAYER_RETURN_IF_FAIL(player &&
1340 player->pipeline->textbin);
1342 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1344 textbin = player->pipeline->textbin;
1347 LOGD("Drop subtitle text after getting EOS");
1349 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1350 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1352 player->is_subtitle_force_drop = TRUE;
1354 if (player->is_subtitle_force_drop == TRUE) {
1355 LOGD("Enable subtitle data path without drop");
1357 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1358 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1360 LOGD("non-connected with external display");
1362 player->is_subtitle_force_drop = FALSE;
1368 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1370 MMHandleType attrs = 0;
1375 /* NOTE : EOS event is coming multiple time. watch out it */
1376 /* check state. we only process EOS when pipeline state goes to PLAYING */
1377 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1378 LOGD("EOS received on non-playing state. ignoring it");
1382 if (player->pipeline && player->pipeline->textbin)
1383 __mmplayer_drop_subtitle(player, TRUE);
1385 if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1386 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1388 /* rewind if repeat count is greater then zero */
1389 /* get play count */
1390 attrs = MMPLAYER_GET_ATTRS(player);
1392 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1394 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1396 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1397 if (player->playback_rate < 0.0) {
1398 player->resumed_by_rewind = TRUE;
1399 _mmplayer_set_mute((MMHandleType)player, false);
1400 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1403 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1406 player->sent_bos = FALSE;
1408 LOGD("do not post eos msg for repeating");
1413 if (player->pipeline)
1414 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1416 /* post eos message to application */
1417 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1419 /* reset last position */
1420 player->last_position = 0;
1427 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1429 GError *error = NULL;
1430 gchar *debug = NULL;
1434 /* generating debug info before returning error */
1435 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1437 /* get error code */
1438 gst_message_parse_error(msg, &error, &debug);
1440 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1441 /* Note : the streaming error from the streaming source is handled
1442 * using __mmplayer_handle_streaming_error.
1444 __mmplayer_handle_streaming_error(player, msg);
1446 /* dump state of all element */
1447 _mmplayer_dump_pipeline_state(player);
1449 /* translate gst error code to msl error code. then post it
1450 * to application if needed
1452 __mmplayer_handle_gst_error(player, msg, error);
1455 LOGE("error debug : %s", debug);
1458 MMPLAYER_FREEIF(debug);
1459 g_error_free(error);
1466 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1468 MMMessageParamType msg_param = {0, };
1469 int bRet = MM_ERROR_NONE;
1472 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1474 if (!MMPLAYER_IS_STREAMING(player)) {
1475 LOGW("this is not streaming playback.");
1479 MMPLAYER_CMD_LOCK(player);
1481 if (!player->streamer) {
1482 LOGW("Pipeline is shutting down");
1483 MMPLAYER_CMD_UNLOCK(player);
1487 /* ignore the remained buffering message till getting 100% msg */
1488 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1489 gint buffer_percent = 0;
1491 gst_message_parse_buffering(msg, &buffer_percent);
1493 if (buffer_percent == MAX_BUFFER_PERCENT) {
1494 LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1495 __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1496 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1498 MMPLAYER_CMD_UNLOCK(player);
1502 /* ignore the remained buffering message */
1503 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1504 gint buffer_percent = 0;
1506 gst_message_parse_buffering(msg, &buffer_percent);
1508 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1509 player->streamer->buffering_percent, buffer_percent);
1511 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1512 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1513 player->streamer->buffering_req.is_pre_buffering = FALSE;
1515 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1517 LOGD("interrupted buffering - ignored the remained buffering msg!");
1518 MMPLAYER_CMD_UNLOCK(player);
1523 __mmplayer_update_buffer_setting(player, msg);
1525 bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1527 if (bRet == MM_ERROR_NONE) {
1528 msg_param.connection.buffering = player->streamer->buffering_percent;
1529 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1531 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1532 player->pending_resume &&
1533 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1535 player->is_external_subtitle_added_now = FALSE;
1536 player->pending_resume = FALSE;
1537 _mmplayer_resume((MMHandleType)player);
1540 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1541 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1543 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1544 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1545 player->seek_state = MMPLAYER_SEEK_NONE;
1546 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1547 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1548 /* Considering the async state transition in case of RTSP.
1549 After getting state change gst msg, seek completed msg will be posted. */
1550 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1554 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1555 if (!player->streamer) {
1556 LOGW("player->streamer is NULL, so discarding the buffering percent update");
1557 MMPLAYER_CMD_UNLOCK(player);
1561 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1563 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1564 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1566 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1567 msg_param.connection.buffering = player->streamer->buffering_percent;
1568 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1570 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1573 msg_param.connection.buffering = player->streamer->buffering_percent;
1574 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1577 MMPLAYER_CMD_UNLOCK(player);
1585 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1587 mmplayer_gst_element_t *mainbin;
1588 const GValue *voldstate, *vnewstate, *vpending;
1589 GstState oldstate = GST_STATE_NULL;
1590 GstState newstate = GST_STATE_NULL;
1591 GstState pending = GST_STATE_NULL;
1594 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1596 mainbin = player->pipeline->mainbin;
1598 /* we only handle messages from pipeline */
1599 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1602 /* get state info from msg */
1603 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1604 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1605 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1607 if (!voldstate || !vnewstate) {
1608 LOGE("received msg has wrong format.");
1612 oldstate = (GstState)voldstate->data[0].v_int;
1613 newstate = (GstState)vnewstate->data[0].v_int;
1615 pending = (GstState)vpending->data[0].v_int;
1617 LOGD("state changed [%s] : %s ---> %s final : %s",
1618 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1619 gst_element_state_get_name((GstState)oldstate),
1620 gst_element_state_get_name((GstState)newstate),
1621 gst_element_state_get_name((GstState)pending));
1623 if (newstate == GST_STATE_PLAYING) {
1624 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1626 int retVal = MM_ERROR_NONE;
1627 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1629 retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1631 if (MM_ERROR_NONE != retVal)
1632 LOGE("failed to seek pending position. just keep staying current position.");
1634 player->pending_seek.is_pending = false;
1638 if (oldstate == newstate) {
1639 LOGD("pipeline reports state transition to old state");
1644 case GST_STATE_PAUSED:
1646 gboolean prepare_async = FALSE;
1648 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1649 // managed prepare async case
1650 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1651 LOGD("checking prepare mode for async transition - %d", prepare_async);
1654 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1655 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1657 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1658 _mm_player_streaming_set_content_bitrate(player->streamer,
1659 player->total_maximum_bitrate, player->total_bitrate);
1661 if (player->pending_seek.is_pending) {
1662 LOGW("trying to do pending seek");
1663 MMPLAYER_CMD_LOCK(player);
1664 __mmplayer_gst_pending_seek(player);
1665 MMPLAYER_CMD_UNLOCK(player);
1671 case GST_STATE_PLAYING:
1673 if (MMPLAYER_IS_STREAMING(player)) {
1674 // managed prepare async case when buffering is completed
1675 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1676 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1677 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1678 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1680 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1682 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1683 if (player->streamer->buffering_percent < 100) {
1685 MMMessageParamType msg_param = {0, };
1686 LOGW("Posting Buffering Completed Message to Application !!!");
1688 msg_param.connection.buffering = 100;
1689 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1694 if (player->gapless.stream_changed) {
1695 _mmplayer_update_content_attrs(player, ATTR_ALL);
1696 player->gapless.stream_changed = FALSE;
1699 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1700 player->seek_state = MMPLAYER_SEEK_NONE;
1701 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1705 case GST_STATE_VOID_PENDING:
1706 case GST_STATE_NULL:
1707 case GST_STATE_READY:
1717 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1719 const gchar *structure_name;
1720 gint count = 0, idx = 0;
1723 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1725 if (gst_message_get_structure(msg) == NULL)
1728 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1729 if (!structure_name)
1732 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1734 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1735 const GValue *var_info = NULL;
1737 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1738 if (var_info != NULL) {
1739 if (player->adaptive_info.var_list)
1740 g_list_free_full(player->adaptive_info.var_list, g_free);
1742 /* share addr or copy the list */
1743 player->adaptive_info.var_list =
1744 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1746 count = g_list_length(player->adaptive_info.var_list);
1748 stream_variant_t *temp = NULL;
1750 /* print out for debug */
1751 LOGD("num of variant_info %d", count);
1752 for (idx = 0; idx < count; idx++) {
1753 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1755 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1761 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1762 gint num_buffers = 0;
1763 gint extra_num_buffers = 0;
1765 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1766 LOGD("video_num_buffers : %d", num_buffers);
1767 mm_player_set_attribute((MMHandleType)player, NULL,
1768 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1771 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1772 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1773 mm_player_set_attribute((MMHandleType)player, NULL,
1774 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1779 if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1780 _mmplayer_track_update_text_attr_info(player, msg);
1782 /* custom message */
1783 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1784 MMMessageParamType msg_param = {0,};
1785 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1786 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1789 /* custom message for RTSP attribute :
1790 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1791 sdp which has contents info is received when rtsp connection is opened.
1792 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1793 if (!strcmp(structure_name, "rtspsrc_properties")) {
1794 gchar *audio_codec = NULL;
1795 gchar *video_codec = NULL;
1796 gchar *video_frame_size = NULL;
1798 gst_structure_get(gst_message_get_structure(msg),
1799 "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1800 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1801 player->streaming_type = _mmplayer_get_stream_service_type(player);
1803 gst_structure_get(gst_message_get_structure(msg),
1804 "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1805 LOGD("rtsp_audio_codec : %s", audio_codec);
1807 mm_player_set_attribute((MMHandleType)player, NULL,
1808 "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1810 gst_structure_get(gst_message_get_structure(msg),
1811 "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1812 LOGD("rtsp_video_codec : %s", video_codec);
1814 mm_player_set_attribute((MMHandleType)player, NULL,
1815 "content_video_codec", video_codec, strlen(video_codec), NULL);
1817 gst_structure_get(gst_message_get_structure(msg),
1818 "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1819 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1820 if (video_frame_size) {
1821 gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1822 mm_player_set_attribute((MMHandleType)player, NULL,
1823 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1824 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1826 g_strfreev(res_str);
1835 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1837 mmplayer_gst_element_t *mainbin;
1840 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1842 mainbin = player->pipeline->mainbin;
1844 LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1846 /* we only handle messages from pipeline */
1847 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1850 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1851 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1852 player->seek_state = MMPLAYER_SEEK_NONE;
1853 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1854 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1855 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1856 LOGD("sync %s state(%s) with parent state(%s)",
1857 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1858 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1859 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1861 /* In case of streaming, pause is required before finishing seeking by buffering.
1862 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1863 Because the buffering state is controlled according to the state transition for force resume,
1864 the decodebin state should be paused as player state. */
1865 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1868 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1869 (player->streamer) &&
1870 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1871 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1872 GstQuery *query = NULL;
1873 gboolean busy = FALSE;
1876 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1877 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1878 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1879 gst_query_parse_buffering_percent(query, &busy, &percent);
1880 gst_query_unref(query);
1882 LOGD("buffered percent(%s): %d",
1883 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1887 __mmplayer_handle_buffering_playback(player);
1890 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1899 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1901 GValue val = { 0, };
1903 guint indent = GPOINTER_TO_UINT(user_data);
1905 if (!gst_tag_list_copy_value(&val, tags, tag))
1908 if (G_VALUE_HOLDS_STRING(&val))
1909 str = g_value_dup_string(&val);
1911 str = gst_value_serialize(&val);
1913 LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1915 g_value_unset(&val);
1919 __mmplayer_dump_collection(GstStreamCollection * collection)
1922 GstTagList *tags = NULL;
1923 GstCaps *caps = NULL;
1925 for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1926 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1927 LOGD ("collection: Stream %u type %s flags 0x%x\n", i,
1928 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1929 gst_stream_get_stream_flags(stream));
1930 LOGD (" ID: %s\n", gst_stream_get_stream_id(stream));
1932 caps = gst_stream_get_caps(stream);
1934 gchar *caps_str = gst_caps_to_string(caps);
1935 LOGD (" caps: %s\n", caps_str);
1937 gst_caps_unref(caps);
1940 tags = gst_stream_get_tags(stream);
1943 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1944 gst_tag_list_unref(tags);
1950 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1951 GstStream *stream, GParamSpec *pspec, gpointer data)
1953 LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1954 gst_stream_get_stream_id(stream), pspec->name, collection);
1955 if (g_str_equal(pspec->name, "caps")) {
1956 GstCaps *caps = gst_stream_get_caps(stream);
1957 gchar *caps_str = gst_caps_to_string(caps);
1958 LOGD (" New caps: %s\n", caps_str);
1960 gst_caps_unref(caps);
1963 if (g_str_equal (pspec->name, "tags")) {
1964 GstTagList *tags = gst_stream_get_tags(stream);
1967 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1968 gst_tag_list_unref(tags);
1974 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1976 mmplayer_t *player = (mmplayer_t *)(data);
1978 MMPLAYER_RETURN_IF_FAIL(player);
1979 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1981 switch (GST_MESSAGE_TYPE(msg)) {
1982 case GST_MESSAGE_UNKNOWN:
1983 LOGD("unknown message received");
1986 case GST_MESSAGE_EOS:
1987 LOGD("GST_MESSAGE_EOS received");
1988 __mmplayer_gst_handle_eos_message(player, msg);
1991 case GST_MESSAGE_ERROR:
1992 _mmplayer_set_reconfigure_state(player, FALSE);
1993 __mmplayer_gst_handle_error_message(player, msg);
1996 case GST_MESSAGE_WARNING:
1999 GError *error = NULL;
2001 gst_message_parse_warning(msg, &error, &debug);
2003 LOGD("warning : %s", error->message);
2004 LOGD("debug : %s", debug);
2006 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2008 MMPLAYER_FREEIF(debug);
2009 g_error_free(error);
2013 case GST_MESSAGE_TAG:
2015 LOGD("GST_MESSAGE_TAG");
2016 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2017 LOGW("failed to extract tags from gstmessage");
2021 case GST_MESSAGE_BUFFERING:
2022 __mmplayer_gst_handle_buffering_message(player, msg);
2025 case GST_MESSAGE_STATE_CHANGED:
2026 __mmplayer_gst_handle_state_message(player, msg);
2029 case GST_MESSAGE_CLOCK_LOST:
2031 GstClock *clock = NULL;
2032 gboolean need_new_clock = FALSE;
2034 gst_message_parse_clock_lost(msg, &clock);
2035 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2037 if (!player->videodec_linked)
2038 need_new_clock = TRUE;
2039 else if (!player->ini.use_system_clock)
2040 need_new_clock = TRUE;
2042 if (need_new_clock) {
2043 LOGD("Provide clock is TRUE, do pause->resume");
2044 _mmplayer_gst_pause(player, FALSE);
2045 _mmplayer_gst_resume(player, FALSE);
2050 case GST_MESSAGE_NEW_CLOCK:
2052 GstClock *clock = NULL;
2053 gst_message_parse_new_clock(msg, &clock);
2054 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2058 case GST_MESSAGE_ELEMENT:
2059 __mmplayer_gst_handle_element_message(player, msg);
2062 case GST_MESSAGE_DURATION_CHANGED:
2064 LOGD("GST_MESSAGE_DURATION_CHANGED");
2065 if (!__mmplayer_gst_handle_duration(player, msg))
2066 LOGW("failed to update duration");
2070 case GST_MESSAGE_ASYNC_START:
2071 LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2074 case GST_MESSAGE_ASYNC_DONE:
2075 __mmplayer_gst_handle_async_done_message(player, msg);
2077 case GST_MESSAGE_STREAM_COLLECTION:
2079 GstStreamCollection *collection = NULL;
2080 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2082 gst_message_parse_stream_collection(msg, &collection);
2084 __mmplayer_dump_collection(collection);
2085 if (player->collection && player->stream_notify_id) {
2086 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2087 player->stream_notify_id = 0;
2089 gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2090 if (player->collection) {
2091 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2092 (GCallback)__mmplayer_stream_notify_cb, player);
2094 gst_object_unref(collection);
2097 case GST_MESSAGE_STREAMS_SELECTED:
2099 GstStreamCollection *collection = NULL;
2100 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2102 gst_message_parse_streams_selected(msg, &collection);
2104 guint i = 0, len = 0;
2105 len = gst_message_streams_selected_get_size(msg);
2106 for (i = 0; i < len; i++) {
2107 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2108 LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2109 gst_object_unref(stream);
2111 gst_object_unref (collection);
2116 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2117 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break;
2118 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break;
2119 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS"); break;
2120 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY"); break;
2121 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2122 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2123 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE"); break;
2124 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2125 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2126 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2127 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION"); break;
2128 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break;
2129 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2130 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break;
2137 /* should not call 'gst_message_unref(msg)' */
2141 static GstBusSyncReply
2142 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2144 mmplayer_t *player = (mmplayer_t *)data;
2145 GstBusSyncReply reply = GST_BUS_DROP;
2147 if (!(player->pipeline && player->pipeline->mainbin)) {
2148 LOGE("player pipeline handle is null");
2149 return GST_BUS_PASS;
2152 if (!__mmplayer_gst_check_useful_message(player, message)) {
2153 gst_message_unref(message);
2154 return GST_BUS_DROP;
2157 switch (GST_MESSAGE_TYPE(message)) {
2158 case GST_MESSAGE_TAG:
2159 __mmplayer_gst_extract_tag_from_msg(player, message);
2163 GstTagList *tags = NULL;
2165 gst_message_parse_tag(message, &tags);
2167 LOGE("TAGS received from element \"%s\".",
2168 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2170 gst_tag_list_foreach(tags, print_tag, NULL);
2171 gst_tag_list_unref(tags);
2179 case GST_MESSAGE_DURATION_CHANGED:
2180 __mmplayer_gst_handle_duration(player, message);
2182 case GST_MESSAGE_ELEMENT:
2184 const gchar *klass = NULL;
2185 klass = gst_element_factory_get_metadata
2186 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2187 if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2188 reply = GST_BUS_PASS;
2191 __mmplayer_gst_handle_element_message(player, message);
2194 case GST_MESSAGE_ASYNC_DONE:
2195 /* NOTE:Don't call gst_callback directly
2196 * because previous frame can be showed even though this message is received for seek.
2199 reply = GST_BUS_PASS;
2203 if (reply == GST_BUS_DROP)
2204 gst_message_unref(message);
2210 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2212 GstElement *appsrc = element;
2213 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2214 GstBuffer *buffer = NULL;
2215 GstFlowReturn ret = GST_FLOW_OK;
2218 MMPLAYER_RETURN_IF_FAIL(element);
2219 MMPLAYER_RETURN_IF_FAIL(buf);
2221 buffer = gst_buffer_new();
2223 if (buf->offset < 0 || buf->len < 0) {
2224 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2228 if (buf->offset >= buf->len) {
2229 LOGD("call eos appsrc");
2230 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2234 if (buf->len - buf->offset < size)
2235 len = buf->len - buf->offset;
2237 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2238 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2239 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2242 LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2244 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2250 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2252 mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2254 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2256 buf->offset = (int)size;
2262 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2264 mmplayer_t *player = (mmplayer_t *)user_data;
2265 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2266 MMMessageParamType msg_param = {0,};
2267 guint64 current_level_bytes = 0;
2269 MMPLAYER_RETURN_IF_FAIL(player);
2271 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2272 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2273 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2274 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2276 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2280 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2282 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2284 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2285 msg_param.buffer_status.stream_type = stream_type;
2286 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2287 msg_param.buffer_status.bytes = current_level_bytes;
2289 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2293 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2295 mmplayer_t *player = (mmplayer_t *)user_data;
2296 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2297 MMMessageParamType msg_param = {0,};
2298 guint64 current_level_bytes = 0;
2300 MMPLAYER_RETURN_IF_FAIL(player);
2302 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2303 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2304 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2305 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2307 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2311 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
2313 LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2315 msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2316 msg_param.buffer_status.stream_type = stream_type;
2317 msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2318 msg_param.buffer_status.bytes = current_level_bytes;
2320 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2324 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2326 mmplayer_t *player = (mmplayer_t *)user_data;
2327 mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2328 MMMessageParamType msg_param = {0,};
2330 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2332 if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2333 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2334 } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2335 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2337 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2341 LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2343 msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2344 msg_param.seek_data.stream_type = stream_type;
2345 msg_param.seek_data.offset = position;
2347 MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2353 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2355 #define MAX_LEN_NAME 20
2357 gboolean ret = FALSE;
2358 GstPad *sinkpad = NULL;
2359 gchar *prefix = NULL;
2360 gchar dec_name[MAX_LEN_NAME] = {0, };
2361 main_element_id_e elem_id = MMPLAYER_M_NUM;
2363 mmplayer_gst_element_t *mainbin = NULL;
2364 GstElement *decodebin = NULL;
2365 GstCaps *dec_caps = NULL;
2369 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2371 player->pipeline->mainbin, FALSE);
2372 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2374 mainbin = player->pipeline->mainbin;
2376 case MM_PLAYER_STREAM_TYPE_AUDIO:
2378 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2380 case MM_PLAYER_STREAM_TYPE_VIDEO:
2382 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2385 LOGE("invalid type %d", type);
2389 if (mainbin[elem_id].gst) {
2390 LOGE("elem(%d) is already created", elem_id);
2394 snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2396 /* create decodebin */
2397 decodebin = gst_element_factory_make("decodebin", dec_name);
2399 LOGE("failed to create %s", dec_name);
2403 /* raw pad handling signal */
2404 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2405 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2407 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2408 before looking for any elements that can handle that stream.*/
2409 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2410 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2412 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2413 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2414 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2416 /* This signal is emitted when a element is added to the bin.*/
2417 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2418 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2420 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2421 LOGE("failed to add new decodebin");
2425 dec_caps = gst_pad_query_caps(srcpad, NULL);
2428 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2430 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2431 gst_caps_unref(dec_caps);
2434 sinkpad = gst_element_get_static_pad(decodebin, "sink");
2436 if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2437 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2440 gst_object_unref(GST_OBJECT(sinkpad));
2442 gst_element_sync_state_with_parent(decodebin);
2444 mainbin[elem_id].id = elem_id;
2445 mainbin[elem_id].gst = decodebin;
2452 gst_object_unref(GST_OBJECT(sinkpad));
2455 gst_element_set_state(decodebin, GST_STATE_NULL);
2456 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2457 gst_object_unref(decodebin);
2465 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2467 #define MAX_LEN_NAME 20
2468 mmplayer_gst_element_t *mainbin = NULL;
2469 gchar *prefix = NULL;
2470 main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2472 gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2473 GstElement *src = NULL, *queue = NULL;
2474 GstPad *srcpad = NULL;
2477 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2478 player->pipeline->mainbin, FALSE);
2480 mainbin = player->pipeline->mainbin;
2482 LOGD("type(%d) path is creating", type);
2484 case MM_PLAYER_STREAM_TYPE_AUDIO:
2486 if (mainbin[MMPLAYER_M_SRC].gst)
2487 src_id = MMPLAYER_M_2ND_SRC;
2489 src_id = MMPLAYER_M_SRC;
2490 queue_id = MMPLAYER_M_A_BUFFER;
2492 case MM_PLAYER_STREAM_TYPE_VIDEO:
2494 src_id = MMPLAYER_M_SRC;
2495 queue_id = MMPLAYER_M_V_BUFFER;
2497 case MM_PLAYER_STREAM_TYPE_TEXT:
2498 prefix = "subtitle";
2499 src_id = MMPLAYER_M_SUBSRC;
2500 queue_id = MMPLAYER_M_S_BUFFER;
2503 LOGE("invalid type %d", type);
2507 snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2508 snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2511 src = gst_element_factory_make("appsrc", src_name);
2513 LOGF("failed to create %s", src_name);
2517 mainbin[src_id].id = src_id;
2518 mainbin[src_id].gst = src;
2520 g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2521 "caps", caps, NULL);
2523 /* size of many video frames are larger than default blocksize as 4096 */
2524 if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2525 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2527 if (player->media_stream_buffer_max_size[type] > 0)
2528 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2530 if (player->media_stream_buffer_min_percent[type] > 0)
2531 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2533 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2534 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2536 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2537 G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2538 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2539 G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2540 _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2541 G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2544 queue = gst_element_factory_make("queue2", queue_name);
2546 LOGE("failed to create %s", queue_name);
2549 g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2551 mainbin[queue_id].id = queue_id;
2552 mainbin[queue_id].gst = queue;
2554 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2555 LOGE("failed to add src");
2559 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2560 LOGE("failed to add queue");
2564 if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2565 LOGE("failed to link src and queue");
2569 /* create decoder */
2570 srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2572 LOGE("failed to get srcpad of queue");
2576 if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2577 _mmplayer_gst_create_decoder(player, srcpad, caps);
2579 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2580 LOGE("failed to create decoder");
2581 gst_object_unref(GST_OBJECT(srcpad));
2585 gst_object_unref(GST_OBJECT(srcpad));
2589 if (mainbin[src_id].gst) {
2590 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2591 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2592 gst_object_unref(mainbin[src_id].gst);
2593 mainbin[src_id].gst = NULL;
2596 if (mainbin[queue_id].gst) {
2597 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2598 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2599 gst_object_unref(mainbin[queue_id].gst);
2600 mainbin[queue_id].gst = NULL;
2607 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2609 GstPad *sinkpad = NULL;
2610 GstCaps *caps = NULL;
2611 GstElement *new_element = NULL;
2612 GstStructure *str = NULL;
2613 const gchar *name = NULL;
2615 mmplayer_t *player = (mmplayer_t *)data;
2619 MMPLAYER_RETURN_IF_FAIL(element && pad);
2620 MMPLAYER_RETURN_IF_FAIL(player &&
2622 player->pipeline->mainbin);
2624 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2625 * num_dynamic_pad will decreased after creating a sinkbin.
2627 player->num_dynamic_pad++;
2628 LOGD("stream count inc : %d", player->num_dynamic_pad);
2630 caps = gst_pad_query_caps(pad, NULL);
2631 MMPLAYER_CHECK_NULL(caps);
2633 str = gst_caps_get_structure(caps, 0);
2634 name = gst_structure_get_string(str, "media");
2636 LOGE("cannot get mimetype from structure.");
2640 if (strstr(name, "video")) {
2642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2644 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2645 if (player->v_stream_caps) {
2646 gst_caps_unref(player->v_stream_caps);
2647 player->v_stream_caps = NULL;
2650 new_element = gst_element_factory_make("fakesink", NULL);
2651 player->num_dynamic_pad--;
2656 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2657 LOGE("failed to autoplug for caps");
2661 gst_caps_unref(caps);
2666 /* execute new_element if created*/
2668 LOGD("adding new element to pipeline");
2670 /* set state to READY before add to bin */
2671 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2673 /* add new element to the pipeline */
2674 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2675 LOGE("failed to add autoplug element to bin");
2679 /* get pad from element */
2680 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2682 LOGE("failed to get sinkpad from autoplug element");
2687 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2688 LOGE("failed to link autoplug element");
2692 gst_object_unref(sinkpad);
2695 /* run. setting PLAYING here since streaming source is live source */
2696 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2700 gst_caps_unref(caps);
2706 STATE_CHANGE_FAILED:
2708 /* FIXIT : take care if new_element has already added to pipeline */
2710 gst_object_unref(GST_OBJECT(new_element));
2713 gst_object_unref(GST_OBJECT(sinkpad));
2716 gst_caps_unref(caps);
2718 /* FIXIT : how to inform this error to MSL ????? */
2719 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2720 * then post an error to application
2725 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2727 mmplayer_t *player = (mmplayer_t *)data;
2731 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2732 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2733 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2734 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2736 * [1] audio and video will be dumped with filesink.
2737 * [2] autoplugging is done by just using pad caps.
2738 * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2739 * and the video will be dumped via filesink.
2741 if (player->num_dynamic_pad == 0) {
2742 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2744 if (!_mmplayer_gst_remove_fakesink(player,
2745 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2746 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2747 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2748 * source element are not same. To overcome this situation, this function will called
2749 * several places and several times. Therefore, this is not an error case.
2754 /* create dot before error-return. for debugging */
2755 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2757 player->no_more_pad = TRUE;
2763 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2765 GstElement *element = NULL;
2766 gchar *user_agent = NULL;
2767 MMHandleType attrs = 0;
2770 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2772 /* get profile attribute */
2773 attrs = MMPLAYER_GET_ATTRS(player);
2775 LOGE("failed to get content attribute");
2779 element = gst_element_factory_make("rtspsrc", "rtsp source");
2781 LOGE("failed to create rtspsrc element");
2786 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2788 SECURE_LOGD("user_agent : %s", user_agent);
2790 /* setting property to streaming source */
2791 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2793 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2795 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2796 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2797 _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2798 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2804 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2806 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2808 mmplayer_t *player = (mmplayer_t *)data;
2809 MMHandleType attrs = 0;
2810 gchar *user_agent, *cookies, **cookie_list;
2811 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2812 user_agent = cookies = NULL;
2816 MMPLAYER_RETURN_IF_FAIL(player);
2818 LOGD("source element %s", GST_ELEMENT_NAME(source));
2820 attrs = MMPLAYER_GET_ATTRS(player);
2822 LOGE("failed to get content attribute");
2826 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2827 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2829 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2830 http_timeout = player->ini.http_timeout;
2832 SECURE_LOGD("cookies : %s", cookies);
2833 SECURE_LOGD("user_agent : %s", user_agent);
2834 LOGD("timeout : %d", http_timeout);
2836 g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2838 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2839 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2840 g_strfreev(cookie_list);
2844 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2850 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2852 mmplayer_t *player = (mmplayer_t *)data;
2853 gchar *user_agent = NULL;
2854 MMHandleType attrs = 0;
2857 MMPLAYER_RETURN_IF_FAIL(player);
2859 attrs = MMPLAYER_GET_ATTRS(player);
2861 LOGE("failed to get content attribute");
2865 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2867 SECURE_LOGD("user_agent : %s", user_agent);
2870 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2876 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2878 mmplayer_t *player = (mmplayer_t *)data;
2879 GstElement *source = NULL;
2882 LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2884 g_object_get(orig, pspec->name, &source, NULL);
2886 player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2887 player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2889 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2890 __mmplayer_http_src_setup(source, data);
2891 } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2892 __mmplayer_rtsp_src_setup(source, data);
2893 } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2894 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2895 } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2896 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2897 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2899 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2900 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2901 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2902 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2904 gst_object_unref (source);
2910 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2911 GstStream * stream, gpointer data)
2913 gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2914 GstStreamType stype = gst_stream_get_stream_type(stream);
2915 mmplayer_t *player = (mmplayer_t *)data;
2916 mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2917 GstCaps *caps = gst_stream_get_caps(stream);
2918 gchar *caps_str = NULL;
2920 LOGD("Stream type %s flags 0x%x",
2921 gst_stream_type_get_name(stype),
2922 gst_stream_get_stream_flags(stream));
2923 LOGD(" ID: %s", gst_stream_get_stream_id(stream));
2926 caps_str = gst_caps_to_string(caps);
2927 LOGD(" caps: %s", caps_str);
2931 case GST_STREAM_TYPE_AUDIO:
2933 GstStructure *caps_structure = NULL;
2934 gint samplerate = 0;
2937 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2940 caps_structure = gst_caps_get_structure(caps, 0);
2941 gst_structure_get_int(caps_structure, "rate", &samplerate);
2942 gst_structure_get_int(caps_structure, "channels", &channels);
2944 if (channels > 0 && samplerate == 0) {
2945 LOGW("Skip corrupted audio stream");
2949 if (g_strrstr(caps_str, "mobile-xmf"))
2950 mm_player_set_attribute((MMHandleType)player, NULL,
2951 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2955 case GST_STREAM_TYPE_VIDEO:
2957 GstStructure *caps_structure = NULL;
2961 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2963 /* do not support multi track video */
2964 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2967 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2969 /* don't make video because of not required */
2970 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2971 (!player->set_mode.video_export)) {
2972 LOGD("no need video decoding, skip video stream");
2977 caps_structure = gst_caps_get_structure(caps, 0);
2978 gst_structure_get_int(caps_structure, "width", &width);
2981 if (player->v_stream_caps) {
2982 gst_caps_unref(player->v_stream_caps);
2983 player->v_stream_caps = NULL;
2986 player->v_stream_caps = gst_caps_copy(caps);
2987 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
2992 case GST_STREAM_TYPE_TEXT:
2993 type = MM_PLAYER_TRACK_TYPE_TEXT;
2996 LOGW("Skip not supported stream type");
3000 _mmplayer_track_update_stream(player, type, stream);
3002 if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3003 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3004 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3005 _mmplayer_set_audio_attrs(player, caps);
3012 gst_caps_unref(caps);
3014 LOGD("ret %d", ret);
3019 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3020 GstStream * stream, gpointer data)
3022 mmplayer_t *player = (mmplayer_t *)data;
3023 GstStreamType stype = gst_stream_get_stream_type(stream);
3026 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3028 LOGD("stream type %s", gst_stream_type_get_name(stype));
3030 /* public does not support audio hw decoder at the moment */
3032 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3033 LOGW("video decoder resource is already acquired, skip it.");
3037 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3038 LOGE("failed to acquire video decoder resource");
3041 player->interrupted_by_resource = FALSE;
3047 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3049 GstIterator *iter = NULL;
3050 GValue item = {0, };
3051 GstElement *ch_element = NULL;
3052 GstElementFactory *ch_factory = NULL;
3055 MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3057 iter = gst_bin_iterate_recurse(bin);
3059 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3060 ch_element = g_value_get_object(&item);
3061 ch_factory = gst_element_get_factory(ch_element);
3062 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3063 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3064 LOGD("Find %s element", element_name);
3068 g_value_reset(&item);
3070 gst_iterator_free(iter);
3078 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3080 gchar *factory_name = NULL;
3081 mmplayer_t *player = (mmplayer_t *)data;
3082 mmplayer_gst_element_t *mainbin = NULL;
3085 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3087 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3088 mainbin = player->pipeline->mainbin;
3090 LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3091 factory_name, GST_ELEMENT_NAME(element));
3093 /* keep the first typefind reference only */
3094 if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+
3095 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3096 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3098 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3099 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3100 LOGD("typefind reference is added");
3104 if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3105 /* update queue2 setting */
3106 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3107 gint64 dur_bytes = 0L;
3108 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3110 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3111 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3113 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3114 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3116 LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3117 /* NOTE : in case of ts streaming, player could not get the correct duration info *
3118 * skip the pull mode(file or ring buffering) setting. */
3119 if (dur_bytes > 0) {
3120 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
3121 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3122 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3128 _mm_player_streaming_set_queue2(player->streamer,
3132 (guint64)dur_bytes); /* no meaning at the moment */
3137 if (g_strrstr(factory_name, "parsebin")) {
3138 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3139 GstElement *ch_element = __mmplayer_gst_find_child_element(child, "multiqueue");
3141 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3142 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3144 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3145 if (MMPLAYER_IS_STREAMING(player)) {
3146 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3148 g_object_set(G_OBJECT(ch_element),
3149 "max-size-time", (guint64)(5 * GST_SECOND),
3150 "use-interleave", FALSE, NULL);
3154 int video_codec_type = 0;
3155 int audio_codec_type = 0;
3157 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3158 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3159 if (player->type_caps &&
3160 !MMPLAYER_IS_HTTP_LIVE_STREAMING(player) &&
3161 !MMPLAYER_IS_DASH_STREAMING(player))
3162 g_object_set(G_OBJECT(element), "sink-caps", player->type_caps, NULL);
3164 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3165 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3167 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3168 and codec default type in ini has to be hw.
3170 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3171 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3172 g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL);
3173 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3174 g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL);
3176 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3177 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3178 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3179 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3181 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3182 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3184 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3185 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3187 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3188 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3191 _mmplayer_gst_element_added((GstElement *)child, element, data);
3197 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3199 LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3204 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3206 GstElement *uridecodebin3 = NULL;
3209 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3211 uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3212 if (!uridecodebin3) {
3213 LOGE("failed to create uridecodebin3");
3218 SECURE_LOGD("uri : %s", player->profile.uri);
3220 /* setting property to streaming source */
3221 g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3222 "message-forward", TRUE,
3223 "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3225 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3226 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3228 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3229 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3231 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3232 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3234 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3235 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3237 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3238 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3240 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3241 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3243 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3244 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3246 _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3247 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3249 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3250 LOGW("[DASH] this is still experimental feature");
3253 return uridecodebin3;
3257 __mmplayer_gst_make_http_src(mmplayer_t *player)
3259 #define MAX_RETRY_COUNT 10
3260 GstElement *element = NULL;
3261 MMHandleType attrs = 0;
3262 gchar *user_agent, *cookies, **cookie_list;
3263 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3265 user_agent = cookies = NULL;
3269 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3271 /* get profile attribute */
3272 attrs = MMPLAYER_GET_ATTRS(player);
3274 LOGE("failed to get content attribute");
3278 LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3280 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3282 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3287 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3288 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3290 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3291 http_timeout = player->ini.http_timeout;
3294 SECURE_LOGD("location : %s", player->profile.uri);
3295 SECURE_LOGD("cookies : %s", cookies);
3296 SECURE_LOGD("user_agent : %s", user_agent);
3297 LOGD("timeout : %d", http_timeout);
3299 /* setting property to streaming source */
3300 g_object_set(G_OBJECT(element), "location", player->profile.uri,
3301 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3302 "retries", MAX_RETRY_COUNT, NULL);
3304 /* parsing cookies */
3305 if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3306 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3307 g_strfreev(cookie_list);
3311 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3313 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3314 LOGW("[DASH] this is still experimental feature");
3321 __mmplayer_gst_make_file_src(mmplayer_t *player)
3323 GstElement *element = NULL;
3326 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3328 LOGD("using filesrc for 'file://' handler");
3329 if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3330 LOGE("failed to get storage info");
3334 element = gst_element_factory_make("filesrc", "source");
3336 LOGE("failed to create filesrc");
3340 g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3347 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3349 mmplayer_t *player = (mmplayer_t *)data;
3351 g_return_val_if_fail(player, FALSE);
3352 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3353 gst_message_ref(msg);
3355 g_mutex_lock(&player->bus_msg_q_lock);
3356 g_queue_push_tail(player->bus_msg_q, msg);
3357 g_mutex_unlock(&player->bus_msg_q_lock);
3359 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3360 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3361 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3365 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3367 mmplayer_t *player = (mmplayer_t *)(data);
3368 GstMessage *msg = NULL;
3371 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3373 player->pipeline->mainbin &&
3374 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3377 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3379 LOGD("[handle: %p] gst bus msg thread will be started.", player);
3380 while (!player->bus_msg_thread_exit) {
3381 g_mutex_lock(&player->bus_msg_q_lock);
3382 msg = g_queue_pop_head(player->bus_msg_q);
3383 g_mutex_unlock(&player->bus_msg_q_lock);
3385 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3388 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3389 /* handle the gst msg */
3390 __mmplayer_gst_bus_msg_callback(msg, player);
3391 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3392 gst_message_unref(msg);
3395 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3402 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3404 gint64 dur_nsec = 0;
3407 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3409 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3410 return MM_ERROR_NONE;
3412 /* NOTE : duration cannot be zero except live streaming.
3413 * Since some element could have some timing problem with querying duration, try again.
3415 if (player->duration == 0) {
3416 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3417 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3418 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3419 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3420 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3421 player->pending_seek.is_pending = true;
3422 player->pending_seek.pos = position;
3423 player->seek_state = MMPLAYER_SEEK_NONE;
3424 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3425 return MM_ERROR_PLAYER_NO_OP;
3427 player->seek_state = MMPLAYER_SEEK_NONE;
3428 return MM_ERROR_PLAYER_SEEK;
3431 player->duration = dur_nsec;
3434 if (player->duration > 0 && player->duration < position) {
3435 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3436 return MM_ERROR_INVALID_ARGUMENT;
3440 return MM_ERROR_NONE;
3444 __mmplayer_gst_check_seekable(mmplayer_t *player)
3446 GstQuery *query = NULL;
3447 gboolean seekable = FALSE;
3449 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3453 query = gst_query_new_seeking(GST_FORMAT_TIME);
3454 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3455 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3456 gst_query_unref(query);
3459 LOGW("non-seekable content");
3460 player->seek_state = MMPLAYER_SEEK_NONE;
3464 LOGW("failed to get seeking query");
3465 gst_query_unref(query); /* keep seeking operation */
3472 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout)
3474 GstState element_state = GST_STATE_VOID_PENDING;
3475 GstState element_pending_state = GST_STATE_VOID_PENDING;
3476 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3481 MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3483 LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3486 ret = gst_element_set_state(element, state);
3487 if (ret == GST_STATE_CHANGE_FAILURE) {
3488 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3490 /* dump state of all element */
3491 _mmplayer_dump_pipeline_state(player);
3493 return MM_ERROR_PLAYER_INTERNAL;
3496 /* return here so state transition to be done in async mode */
3498 LOGD("async state transition. not waiting for state complete.");
3499 return MM_ERROR_NONE;
3502 /* wait for state transition */
3503 ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3504 if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3505 LOGE("failed to change [%s] element state to [%s] within %d sec",
3506 GST_ELEMENT_NAME(element),
3507 gst_element_state_get_name(state), timeout);
3509 LOGE(" [%s] state : %s pending : %s",
3510 GST_ELEMENT_NAME(element),
3511 gst_element_state_get_name(element_state),
3512 gst_element_state_get_name(element_pending_state));
3514 /* dump state of all element */
3515 _mmplayer_dump_pipeline_state(player);
3517 return MM_ERROR_PLAYER_INTERNAL;
3520 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3524 return MM_ERROR_NONE;
3528 _mmplayer_gst_start(mmplayer_t *player)
3530 int ret = MM_ERROR_NONE;
3531 gboolean async = FALSE;
3535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3537 /* NOTE : if SetPosition was called before Start. do it now
3538 * streaming doesn't support it. so it should be always sync
3539 * !!create one more api to check if there is pending seek rather than checking variables
3541 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3542 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3543 ret = _mmplayer_gst_pause(player, FALSE);
3544 if (ret != MM_ERROR_NONE) {
3545 LOGE("failed to set state to PAUSED for pending seek");
3549 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3550 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3551 LOGW("failed to seek pending position. starting from the begin of content");
3554 LOGD("current state before doing transition");
3555 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3556 MMPLAYER_PRINT_STATE(player);
3558 /* set pipeline state to PLAYING */
3559 ret = _mmplayer_gst_set_state(player,
3560 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3561 if (ret != MM_ERROR_NONE) {
3562 LOGE("failed to set state to PLAYING");
3566 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3568 /* generating debug info before returning error */
3569 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3577 _mmplayer_gst_stop(mmplayer_t *player)
3579 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3580 MMHandleType attrs = 0;
3581 gboolean rewind = FALSE;
3583 int ret = MM_ERROR_NONE;
3587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3588 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3590 LOGD("current state before doing transition");
3591 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3592 MMPLAYER_PRINT_STATE(player);
3594 attrs = MMPLAYER_GET_ATTRS(player);
3596 LOGE("cannot get content attribute");
3597 return MM_ERROR_PLAYER_INTERNAL;
3600 /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3601 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3603 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3604 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3607 if (player->es_player_push_mode)
3608 /* disable the async state transition because there could be no data in the pipeline */
3609 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3612 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3614 if (player->es_player_push_mode) {
3615 /* enable the async state transition as default operation */
3616 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3619 /* return if set_state has failed */
3620 if (ret != MM_ERROR_NONE) {
3621 LOGE("failed to set state.");
3627 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3628 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3629 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3630 LOGW("failed to rewind");
3631 ret = MM_ERROR_PLAYER_SEEK;
3636 player->sent_bos = FALSE;
3638 if (player->es_player_push_mode) //for cloudgame
3641 /* wait for seek to complete */
3642 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3643 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3644 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3646 LOGE("fail to stop player.");
3647 ret = MM_ERROR_PLAYER_INTERNAL;
3648 _mmplayer_dump_pipeline_state(player);
3651 /* generate dot file if enabled */
3652 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3660 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3662 int ret = MM_ERROR_NONE;
3666 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3667 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3669 LOGD("current state before doing transition");
3670 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3671 MMPLAYER_PRINT_STATE(player);
3673 /* set pipeline status to PAUSED */
3674 ret = _mmplayer_gst_set_state(player,
3675 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3680 if (ret != MM_ERROR_NONE) {
3681 GstMessage *msg = NULL;
3682 GTimer *timer = NULL;
3683 gdouble MAX_TIMEOUT_SEC = 3;
3685 LOGE("failed to set state to PAUSED");
3687 if (!player->bus_watcher) {
3688 LOGE("there is no bus msg thread. pipeline is shutting down.");
3692 if (player->msg_posted) {
3693 LOGE("error msg is already posted.");
3697 timer = g_timer_new();
3698 g_timer_start(timer);
3700 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3703 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3705 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3706 GError *error = NULL;
3708 /* parse error code */
3709 gst_message_parse_error(msg, &error, NULL);
3711 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3712 /* Note : the streaming error from the streaming source is handled
3713 * using __mmplayer_handle_streaming_error.
3715 __mmplayer_handle_streaming_error(player, msg);
3718 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3720 if (error->domain == GST_STREAM_ERROR)
3721 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3722 else if (error->domain == GST_RESOURCE_ERROR)
3723 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3724 else if (error->domain == GST_LIBRARY_ERROR)
3725 ret = __mmplayer_gst_handle_library_error(player, error->code);
3726 else if (error->domain == GST_CORE_ERROR)
3727 ret = __mmplayer_gst_handle_core_error(player, error->code);
3729 g_error_free(error);
3731 player->msg_posted = TRUE;
3733 gst_message_unref(msg);
3735 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3737 gst_object_unref(bus);
3738 g_timer_stop(timer);
3739 g_timer_destroy(timer);
3744 if (MMPLAYER_USE_DECODEBIN(player)) {
3745 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3746 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3747 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3750 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3753 /* generate dot file before returning error */
3754 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3762 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3764 int ret = MM_ERROR_NONE;
3769 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3770 MM_ERROR_PLAYER_NOT_INITIALIZED);
3772 LOGD("current state before doing transition");
3773 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3774 MMPLAYER_PRINT_STATE(player);
3777 LOGD("do async state transition to PLAYING");
3779 /* set pipeline state to PLAYING */
3780 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3782 ret = _mmplayer_gst_set_state(player,
3783 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3784 if (ret != MM_ERROR_NONE) {
3785 LOGE("failed to set state to PLAYING");
3790 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3793 /* generate dot file */
3794 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3801 /* sending event to one of sinkelements */
3803 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3805 GstEvent *event2 = NULL;
3806 GList *sinks = NULL;
3807 gboolean res = FALSE;
3810 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3811 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3813 /* While adding subtitles in live feeds seek is getting called.
3814 Adding defensive check in framework layer.*/
3815 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3816 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3817 LOGE("Should not send seek event during live playback");
3822 if (player->play_subtitle)
3823 event2 = gst_event_copy((const GstEvent *)event);
3825 sinks = player->sink_elements;
3827 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3829 if (GST_IS_ELEMENT(sink)) {
3830 /* keep ref to the event */
3831 gst_event_ref(event);
3833 if ((res = gst_element_send_event(sink, event))) {
3834 LOGD("sending event[%s] to sink element [%s] success!",
3835 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3837 /* rtsp case, async_done is not called after seek during pause state */
3838 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3839 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3840 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3841 LOGD("RTSP seek completed, after pause state..");
3842 player->seek_state = MMPLAYER_SEEK_NONE;
3843 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3849 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3850 sinks = g_list_next(sinks);
3857 LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3858 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3861 sinks = g_list_next(sinks);
3864 /* Note : Textbin is not linked to the video or audio bin.
3865 * It needs to send the event to the text sink seperately.
3867 if (player->play_subtitle && player->pipeline) {
3868 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3870 if (GST_IS_ELEMENT(text_sink)) {
3871 /* keep ref to the event */
3872 gst_event_ref(event2);
3874 if ((res = gst_element_send_event(text_sink, event2)))
3875 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3876 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3878 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3879 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3881 gst_event_unref(event2);
3885 gst_event_unref(event);
3893 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3894 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3895 gint64 cur, GstSeekType stop_type, gint64 stop)
3897 GstEvent *event = NULL;
3898 gboolean result = FALSE;
3902 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3904 if (player->pipeline && player->pipeline->textbin)
3905 __mmplayer_drop_subtitle(player, FALSE);
3907 event = gst_event_new_seek(rate, format, flags, cur_type,
3908 cur, stop_type, stop);
3910 result = _mmplayer_gst_send_event_to_sink(player, event);
3918 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3920 int ret = MM_ERROR_NONE;
3921 gint64 pos_nsec = 0;
3922 gboolean accurate = FALSE;
3923 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3926 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3927 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3929 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3930 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3933 ret = __mmplayer_gst_check_duration(player, position);
3934 if (ret != MM_ERROR_NONE) {
3935 LOGE("failed to check duration 0x%X", ret);
3936 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3939 if (!__mmplayer_gst_check_seekable(player))
3940 return MM_ERROR_PLAYER_NO_OP;
3942 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3943 position, player->playback_rate, player->duration);
3945 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3946 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3947 This causes problem is position calculation during normal pause resume scenarios also.
3948 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3949 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3950 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3951 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3952 LOGW("getting current position failed in seek");
3954 player->last_position = pos_nsec;
3955 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3958 if (player->seek_state != MMPLAYER_SEEK_NONE) {
3959 LOGD("not completed seek");
3960 return MM_ERROR_PLAYER_DOING_SEEK;
3963 if (!internal_called)
3964 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3966 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3967 that's why set position through property. */
3968 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3969 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3970 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3971 (!player->videodec_linked) && (!player->audiodec_linked)) {
3973 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3974 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3976 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3977 player->seek_state = MMPLAYER_SEEK_NONE;
3978 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3980 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3982 seek_flags |= GST_SEEK_FLAG_ACCURATE;
3984 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3986 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3987 GST_FORMAT_TIME, seek_flags,
3988 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3989 LOGE("failed to set position");
3994 /* NOTE : store last seeking point to overcome some bad operation
3995 * (returning zero when getting current position) of some elements
3997 player->last_position = position;
3999 /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4000 if (player->playback_rate > 1.0)
4001 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4003 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4004 LOGD("buffering should be reset after seeking");
4005 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4006 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4010 return MM_ERROR_NONE;
4013 player->pending_seek.is_pending = true;
4014 player->pending_seek.pos = position;
4016 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4017 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4018 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4019 player->pending_seek.pos);
4021 return MM_ERROR_NONE;
4024 player->seek_state = MMPLAYER_SEEK_NONE;
4025 return MM_ERROR_PLAYER_SEEK;
4029 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4031 #define TRICKPLAY_OFFSET GST_MSECOND
4033 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4034 gint64 pos_nsec = 0;
4035 gboolean ret = TRUE;
4037 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4038 MM_ERROR_PLAYER_NOT_INITIALIZED);
4040 current_state = MMPLAYER_CURRENT_STATE(player);
4042 /* NOTE : query position except paused state to overcome some bad operation
4043 * please refer to below comments in details
4045 if (current_state != MM_PLAYER_STATE_PAUSED)
4046 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4048 /* NOTE : get last point to overcome some bad operation of some elements
4049 *(returning zero when getting current position in paused state
4050 * and when failed to get position during seeking
4052 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4053 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4055 if (player->playback_rate < 0.0)
4056 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4058 pos_nsec = player->last_position;
4061 pos_nsec = player->last_position;
4063 player->last_position = pos_nsec;
4065 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4068 if (player->duration > 0 && pos_nsec > player->duration)
4069 pos_nsec = player->duration;
4071 player->last_position = pos_nsec;
4074 *position = pos_nsec;
4076 return MM_ERROR_NONE;
4080 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4082 #define STREAMING_IS_FINISHED 0
4083 #define BUFFERING_MAX_PER 100
4084 #define DEFAULT_PER_VALUE -1
4085 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4087 mmplayer_gst_element_t *mainbin = NULL;
4088 gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4089 gint64 buffered_total = 0;
4090 gint64 position = 0;
4091 gint buffered_sec = -1;
4092 GstBufferingMode mode = GST_BUFFERING_STREAM;
4093 gint64 content_size_time = player->duration;
4094 guint64 content_size_bytes = player->http_content_size;
4096 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4098 player->pipeline->mainbin,
4099 MM_ERROR_PLAYER_NOT_INITIALIZED);
4101 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4106 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4107 /* and rtsp is not ready yet. */
4108 LOGW("it's only used for http streaming case");
4109 return MM_ERROR_PLAYER_NO_OP;
4112 if (content_size_time <= 0 || content_size_bytes <= 0) {
4113 LOGW("there is no content size");
4114 return MM_ERROR_NONE;
4117 if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4118 LOGW("fail to get current position");
4119 return MM_ERROR_NONE;
4122 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4123 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4125 mainbin = player->pipeline->mainbin;
4126 start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4128 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4129 GstQuery *query = NULL;
4130 gint byte_in_rate = 0, byte_out_rate = 0;
4131 gint64 estimated_total = 0;
4133 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4134 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4135 LOGW("fail to get buffering query from queue2");
4137 gst_query_unref(query);
4138 return MM_ERROR_NONE;
4141 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4142 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4144 if (mode == GST_BUFFERING_STREAM) {
4145 /* using only queue in case of push mode(ts / mp3) */
4146 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4147 GST_FORMAT_BYTES, &buffered_total)) {
4148 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4149 end_per = 100 * buffered_total / content_size_bytes;
4152 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4154 guint num_of_ranges = 0;
4155 gint64 start_byte = 0, stop_byte = 0;
4157 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4158 if (estimated_total != STREAMING_IS_FINISHED) {
4159 /* buffered size info from queue2 */
4160 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4161 for (idx = 0; idx < num_of_ranges; idx++) {
4162 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4163 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4165 buffered_total += (stop_byte - start_byte);
4168 end_per = BUFFERING_MAX_PER;
4171 gst_query_unref(query);
4174 if (end_per == DEFAULT_PER_VALUE) {
4175 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4177 guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4179 /* buffered size info from multiqueue */
4180 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4181 guint curr_size_bytes = 0;
4182 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4183 "curr-size-bytes", &curr_size_bytes, NULL);
4184 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4185 buffered_total += curr_size_bytes;
4188 if (avg_byterate > 0)
4189 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4190 else if (player->total_maximum_bitrate > 0)
4191 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4192 else if (player->total_bitrate > 0)
4193 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4195 if (buffered_sec >= 0)
4196 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4200 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4201 *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4203 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4204 buffered_total, buffered_sec, *start_pos, *end_pos);
4206 return MM_ERROR_NONE;
4210 _mmplayer_gst_create_source(mmplayer_t *player)
4212 GstElement *element = NULL;
4215 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4216 player->pipeline->mainbin, NULL);
4218 /* setup source for gapless play */
4219 switch (player->profile.uri_type) {
4221 case MM_PLAYER_URI_TYPE_FILE:
4222 element = __mmplayer_gst_make_file_src(player);
4224 case MM_PLAYER_URI_TYPE_URL_HTTP:
4225 element = __mmplayer_gst_make_http_src(player);
4228 LOGE("not support uri type %d", player->profile.uri_type);
4233 LOGE("failed to create source element");
4242 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4245 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4246 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4248 SECURE_LOGD("uri : %s", player->profile.uri);
4250 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4252 if ((player->v_stream_caps) &&
4253 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4254 return MM_ERROR_PLAYER_INTERNAL;
4256 if ((player->a_stream_caps) &&
4257 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4258 return MM_ERROR_PLAYER_INTERNAL;
4260 if ((player->s_stream_caps) &&
4261 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4262 return MM_ERROR_PLAYER_INTERNAL;
4265 return MM_ERROR_NONE;
4269 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4271 mmplayer_gst_element_t *mainbin = NULL;
4272 GstElement *autoplug_elem = NULL;
4275 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4276 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4278 mainbin = player->pipeline->mainbin;
4280 LOGD("uri type %d", player->profile.uri_type);
4282 if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4283 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4284 return MM_ERROR_PLAYER_INTERNAL;
4287 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4288 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4291 autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4292 if (!autoplug_elem) {
4293 LOGE("failed to create uridecodebin3 element");
4297 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4298 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4299 mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4301 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4302 LOGE("failed to add uridecodebin to pipeline");
4306 /* FIXME: required ?*/
4307 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4308 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4309 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4311 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4312 LOGE("failed to create fakesink");
4315 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4317 /* take ownership of fakesink. we are reusing it */
4318 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4320 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4321 LOGE("failed to add fakesink to bin");
4322 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4327 return MM_ERROR_NONE;
4331 if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4332 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4334 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4335 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4337 mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4338 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4340 return MM_ERROR_PLAYER_INTERNAL;
4344 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4346 mmplayer_gst_element_t *mainbin = NULL;
4347 GstElement *src_elem = NULL;
4348 GstElement *autoplug_elem = NULL;
4349 GList *element_bucket = NULL;
4350 main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4353 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4354 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4356 LOGD("uri type %d", player->profile.uri_type);
4358 /* create source element */
4359 switch (player->profile.uri_type) {
4360 case MM_PLAYER_URI_TYPE_URL_RTSP:
4361 src_elem = __mmplayer_gst_make_rtsp_src(player);
4363 case MM_PLAYER_URI_TYPE_URL_HTTP:
4364 src_elem = __mmplayer_gst_make_http_src(player);
4366 case MM_PLAYER_URI_TYPE_FILE:
4367 src_elem = __mmplayer_gst_make_file_src(player);
4369 case MM_PLAYER_URI_TYPE_SS:
4371 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4372 src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4374 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4378 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4379 LOGD("get timeout from ini");
4380 http_timeout = player->ini.http_timeout;
4383 /* setting property to streaming source */
4384 g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4387 case MM_PLAYER_URI_TYPE_MEM:
4389 GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4391 src_elem = gst_element_factory_make("appsrc", "mem-source");
4393 LOGE("failed to create appsrc element");
4397 g_object_set(src_elem, "stream-type", stream_type,
4398 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4400 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4401 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4402 _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4403 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4407 LOGE("not support uri type");
4412 LOGE("failed to create source element");
4413 return MM_ERROR_PLAYER_INTERNAL;
4416 mainbin = player->pipeline->mainbin;
4418 /* take source element */
4419 LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4421 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4422 mainbin[MMPLAYER_M_SRC].gst = src_elem;
4423 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4425 /* create next element for auto-plugging */
4426 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4427 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4428 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4429 if (!autoplug_elem) {
4430 LOGE("failed to create typefind element");
4434 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4435 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4436 } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4437 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4438 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4439 if (!autoplug_elem) {
4440 LOGE("failed to create decodebin");
4444 /* default size of mq in decodebin is 2M
4445 * but it can cause blocking issue during seeking depends on content. */
4446 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4449 if (autoplug_elem) {
4450 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4451 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4452 mainbin[autoplug_elem_id].gst = autoplug_elem;
4454 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4457 /* add elements to pipeline */
4458 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4459 LOGE("failed to add elements to pipeline");
4463 /* linking elements in the bucket by added order. */
4464 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4465 LOGE("failed to link some elements");
4469 /* FIXME: need to check whether this is required or not. */
4470 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4471 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4472 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4473 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4474 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4476 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4477 LOGE("failed to create fakesink");
4480 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4482 /* take ownership of fakesink. we are reusing it */
4483 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4485 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4486 LOGE("failed to add fakesink to bin");
4487 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4492 g_list_free(element_bucket);
4495 return MM_ERROR_NONE;
4498 g_list_free(element_bucket);
4500 if (mainbin[MMPLAYER_M_SRC].gst)
4501 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4503 if (mainbin[autoplug_elem_id].gst)
4504 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4506 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4507 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4509 mainbin[MMPLAYER_M_SRC].gst = NULL;
4510 mainbin[autoplug_elem_id].gst = NULL;
4511 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4513 return MM_ERROR_PLAYER_INTERNAL;
4517 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4520 mmplayer_gst_element_t *mainbin = NULL;
4523 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4524 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4526 mainbin = player->pipeline->mainbin;
4528 /* connect bus callback */
4529 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4531 LOGE("cannot get bus from pipeline");
4532 return MM_ERROR_PLAYER_INTERNAL;
4535 player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4536 (GstBusFunc)__mmplayer_gst_msg_push, player,
4537 (GDestroyNotify)_mmplayer_watcher_removed_notify);
4538 if (player->bus_watcher == 0) {
4539 LOGE("failed to add bus watch");
4540 return MM_ERROR_PLAYER_INTERNAL;
4543 g_mutex_init(&player->bus_watcher_mutex);
4544 g_cond_init(&player->bus_watcher_cond);
4546 player->context.thread_default = g_main_context_get_thread_default();
4547 if (player->context.thread_default == NULL) {
4548 player->context.thread_default = g_main_context_default();
4549 LOGD("thread-default context is the global default context");
4551 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4553 /* set sync handler to get tag synchronously */
4554 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4555 gst_object_unref(GST_OBJECT(bus));
4557 /* create gst bus_msb_cb thread */
4558 g_mutex_init(&player->bus_msg_thread_mutex);
4559 g_cond_init(&player->bus_msg_thread_cond);
4560 player->bus_msg_thread_exit = FALSE;
4561 player->bus_msg_thread =
4562 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4563 if (!player->bus_msg_thread) {
4564 LOGE("failed to create gst BUS msg thread");
4565 g_mutex_clear(&player->bus_msg_thread_mutex);
4566 g_cond_clear(&player->bus_msg_thread_cond);
4567 return MM_ERROR_PLAYER_INTERNAL;
4571 return MM_ERROR_NONE;
4575 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4577 int ret = MM_ERROR_NONE;
4578 mmplayer_gst_element_t *mainbin = NULL;
4579 MMMessageParamType msg_param = {0,};
4580 GstElement *element = NULL;
4581 MMHandleType attrs = 0;
4583 main_element_id_e elem_idx = MMPLAYER_M_NUM;
4587 if (!player || !player->pipeline || !player->pipeline->mainbin) {
4588 LOGE("player is not initialized");
4592 mainbin = player->pipeline->mainbin;
4593 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4595 attrs = MMPLAYER_GET_ATTRS(player);
4597 LOGE("fail to get attributes");
4601 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4603 if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4604 LOGE("failed to parse profile");
4605 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4609 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4610 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4611 LOGE("dash or hls is not supportable");
4612 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4616 if (!MMPLAYER_USE_DECODEBIN(player)) {
4617 ret = _mmplayer_gst_build_pipeline_with_src(player);
4618 if (ret != MM_ERROR_NONE)
4621 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4622 LOGE("Failed to change state of uridecodebin3 element");
4628 element = _mmplayer_gst_create_source(player);
4630 LOGE("no source element was created");
4634 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4635 LOGE("failed to add source element to pipeline");
4636 gst_object_unref(GST_OBJECT(element));
4641 /* take source element */
4642 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4643 mainbin[MMPLAYER_M_SRC].gst = element;
4647 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4648 if (player->streamer == NULL) {
4649 player->streamer = _mm_player_streaming_create();
4650 _mm_player_streaming_initialize(player->streamer, TRUE);
4653 elem_idx = MMPLAYER_M_TYPEFIND;
4654 element = gst_element_factory_make("typefind", "typefinder");
4655 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4656 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4658 elem_idx = MMPLAYER_M_AUTOPLUG;
4659 element = _mmplayer_gst_make_decodebin(player);
4662 /* check autoplug element is OK */
4664 LOGE("can not create element(%d)", elem_idx);
4668 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4669 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4670 gst_object_unref(GST_OBJECT(element));
4675 mainbin[elem_idx].id = elem_idx;
4676 mainbin[elem_idx].gst = element;
4678 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4679 LOGE("Failed to link src - autoplug(or typefind)");
4683 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4684 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ????
4685 LOGE("Failed to change state of src element");
4689 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4690 LOGE("Failed to change state of decodebin");
4695 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4696 LOGE("Failed to change state of src element");
4701 player->gapless.stream_changed = TRUE;
4702 player->gapless.running = TRUE;
4708 _mmplayer_set_reconfigure_state(player, FALSE);
4709 if (!player->msg_posted) {
4710 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4711 player->msg_posted = TRUE;