[0.6.272] fix crash when player destroy during prepare_async
[platform/core/multimedia/libmm-player.git] / src / mm_player_gst.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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>
8  *
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
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <dlog.h>
29 #include <mm_error.h>
30 #include <gst/app/gstappsrc.h>
31
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"
37
38 /*===========================================================================================
39 |                                                                                                                                                                                       |
40 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
41 |                                                                                                                                                                                       |
42 ========================================================================================== */
43
44 /*---------------------------------------------------------------------------
45 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
46 ---------------------------------------------------------------------------*/
47 #define MMPLAYER_TAG_INDENT 3
48
49 /*===========================================================================================
50 |                                                                                                                                                                                       |
51 |  FUNCTION DEFINITIONS                                                                                                                                         |
52 |                                                                                                                                                                                       |
53 ========================================================================================== */
54 #ifdef __DEBUG__
55 static void
56 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
57 {
58         gint i, count;
59
60         count = gst_tag_list_get_tag_size(list, tag);
61
62         LOGD("count = %d", count);
63
64         for (i = 0; i < count; i++) {
65                 gchar *str;
66
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();
70                 } else {
71                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
72                 }
73
74                 if (i == 0)
75                         g_print("  %15s: %s", gst_tag_get_nick(tag), str);
76                 else
77                         g_print("                 : %s", str);
78
79                 g_free(str);
80         }
81 }
82 #endif
83
84 static gboolean
85 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
86 {
87         /* check whether the error is posted from not-activated track or not */
88         int msg_src_pos = 0;
89         gint active_index = 0;
90
91         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
92
93         active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index;
94         LOGD("current  active pad index  -%d", active_index);
95
96         if  (src_element_name) {
97                 int idx = 0;
98
99                 if (player->audio_decoders) {
100                         GList *adec = player->audio_decoders;
101                         for (; adec ; adec = g_list_next(adec)) {
102                                 gchar *name = adec->data;
103
104                                 LOGD("found audio decoder name  = %s", name);
105                                 if (g_strrstr(name, src_element_name)) {
106                                         msg_src_pos = idx;
107                                         break;
108                                 }
109                                 idx++;
110                         }
111                 }
112                 LOGD("active pad = %d, error src index = %d", active_index,  msg_src_pos);
113         }
114
115         if (active_index != msg_src_pos) {
116                 LOGD("skip error because error is posted from no activated track");
117                 return FALSE;
118         }
119
120         return TRUE;
121 }
122
123 static int
124 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
125 {
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.
129          */
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;
135                 } else {
136                         if (player->pipeline->audiobin) { // PCM
137                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
138                         } else {
139                                 LOGD("not found any available codec. Player should be destroyed.");
140                                 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
141                         }
142                 }
143         }
144
145         return MM_ERROR_PLAYER_INVALID_STREAM;
146 }
147
148 static int
149 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
150 {
151         if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
152                 LOGE("Not supported subtitle.");
153                 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
154         }
155         return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
156 }
157
158 static int
159 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
160 {
161         /* Decoder Custom Message */
162         if (!strstr(error->message, "ongoing"))
163                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
164
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;
169                 }
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;
174                 }
175         }
176
177         LOGD("not found any available codec. Player should be destroyed.");
178         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
179 }
180
181 static int
182 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
183 {
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;
192
193         return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
194 }
195
196 /* NOTE : decide gstreamer state whether there is some playable track or not. */
197 static gint
198 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
199 {
200         gchar *src_element_name = NULL;
201         GstElement *src_element = NULL;
202         GstElementFactory *factory = NULL;
203         const gchar *klass = NULL;
204
205         MMPLAYER_FENTER();
206
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 &&
211                                                                 player->pipeline &&
212                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
213
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;
218
219         factory = gst_element_get_factory(src_element);
220         if (!factory)
221                 return MM_ERROR_PLAYER_INTERNAL;
222
223         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
224         if (!klass)
225                 return MM_ERROR_PLAYER_INTERNAL;
226
227         LOGD("error code=%d, msg=%s, src element=%s, class=%s",
228                         error->code, error->message, src_element_name, klass);
229
230         if (MMPLAYER_USE_DECODEBIN(player) &&
231                 !__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
232                 return MM_ERROR_NONE;
233
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);
247         default:
248                 break;
249         }
250
251         MMPLAYER_FLEAVE();
252
253         return MM_ERROR_PLAYER_INVALID_STREAM;
254 }
255
256 gint
257 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
258 {
259         gint trans_err = MM_ERROR_NONE;
260
261         MMPLAYER_FENTER();
262
263         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
264
265         switch (code) {
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:
281         default:
282                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
283                 break;
284         }
285
286         MMPLAYER_FLEAVE();
287
288         return trans_err;
289 }
290
291 gint
292 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
293 {
294         gint trans_err = MM_ERROR_NONE;
295
296         MMPLAYER_FENTER();
297
298         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
299
300         switch (code) {
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:
307         default:
308                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
309                 break;
310         }
311
312         MMPLAYER_FLEAVE();
313
314         return trans_err;
315 }
316
317 gint
318 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
319 {
320         gint trans_err = MM_ERROR_NONE;
321
322         MMPLAYER_FENTER();
323
324         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
325
326         switch (code) {
327         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
328                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
329                 break;
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;
335                         break;
336                 }
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;
341                         break;
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;
345
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;
350
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);
356                         }
357                 } /* fall through */
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:
368         default:
369                 trans_err = MM_ERROR_PLAYER_INTERNAL;
370         break;
371         }
372
373         MMPLAYER_FLEAVE();
374
375         return trans_err;
376 }
377
378 gint
379 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
380 {
381         gint trans_err = MM_ERROR_NONE;
382
383         MMPLAYER_FENTER();
384
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);
388
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);
398                 break;
399
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:
406         default:
407                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
408                 break;
409         }
410
411         MMPLAYER_FLEAVE();
412
413         return trans_err;
414 }
415
416 gboolean
417 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
418 {
419         MMMessageParamType msg_param;
420         gchar *msg_src_element;
421
422         MMPLAYER_FENTER();
423
424         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
425         MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
426
427         /* NOTE : do something necessary inside of __gst_handle_XXX_error. not here */
428
429         memset(&msg_param, 0, sizeof(MMMessageParamType));
430
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);
439         } else {
440                 LOGW("This error domain is not defined.");
441
442                 /* we treat system error as an internal error */
443                 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
444         }
445
446         if (message->src) {
447                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
448
449                 msg_param.data = (void *)error->message;
450
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);
453         }
454
455         /* no error */
456         if (msg_param.code == MM_ERROR_NONE)
457                 return TRUE;
458
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))) {
464
465                 /* The error will be handled by mused.
466                  * @ref _mmplayer_manage_external_storage_state() */
467
468                 LOGW("storage is removed, skip error post");
469                 return TRUE;
470         }
471
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;
477         } else {
478                 LOGD("skip error post because it's sent already.");
479         }
480
481         MMPLAYER_FLEAVE();
482
483         return TRUE;
484 }
485
486 static gboolean
487 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
488 {
489         LOGD("\n");
490         MMMessageParamType msg_param = {0, };
491         gchar *msg_src_element = NULL;
492         GstStructure *s = NULL;
493         guint error_id = 0;
494         gchar *error_string = NULL;
495
496         MMPLAYER_FENTER();
497
498         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
499         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
500
501         s = gst_structure_copy(gst_message_get_structure(message));
502
503
504         if (!gst_structure_get_uint(s, "error_id", &error_id))
505                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
506
507         switch (error_id) {
508         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
509                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
510                 break;
511         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
512                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
513                 break;
514         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
515                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
516                 break;
517         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
518                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
519                 break;
520         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
521                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
522                 break;
523         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
524                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
525                 break;
526         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
527                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
528                 break;
529         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
530                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
531                 break;
532         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
533                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
534                 break;
535         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
536                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
537                 break;
538         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
539                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
540                 break;
541         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
542                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
543                 break;
544         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
545                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
546                 break;
547         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
548                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
549                 break;
550         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
551                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
552                 break;
553         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
554                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
555                 break;
556         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
557                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
558                 break;
559         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
560                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
561                 break;
562         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
563                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
564                 break;
565         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
566                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
567                 break;
568         case MMPLAYER_STREAMING_ERROR_GONE:
569                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
570                 break;
571         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
572                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
573                 break;
574         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
575                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
576                 break;
577         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
578                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
579                 break;
580         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
581                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
582                 break;
583         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
584                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
585                 break;
586         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
587                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
588                 break;
589         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
590                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
591                 break;
592         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
593                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
594                 break;
595         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
596                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
597                 break;
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;
600                 break;
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;
603                 break;
604         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
605                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
606                 break;
607         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
608                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
609                 break;
610         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
611                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
612                 break;
613         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
614                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
615                 break;
616         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
617                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
618                 break;
619         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
620                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
621                 break;
622         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
623                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
624                 break;
625         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
626                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
627                 break;
628         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
629                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
630                 break;
631         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
632                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
633                 break;
634         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
635                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
636                 break;
637         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
638                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
639                 break;
640         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
641                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
642                 break;
643         default:
644                 {
645                         gst_structure_free(s);
646                         return MM_ERROR_PLAYER_STREAMING_FAIL;
647                 }
648         }
649
650         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
651         if (error_string)
652                 msg_param.data = (void *)error_string;
653
654         if (message->src) {
655                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
656
657                 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
658                         msg_src_element, msg_param.code, (char *)msg_param.data);
659         }
660
661         /* post error to application */
662         if (!player->msg_posted) {
663                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
664
665                 /* don't post more if one was sent already */
666                 player->msg_posted = TRUE;
667         } else {
668                 LOGD("skip error post because it's sent already.");
669         }
670
671         gst_structure_free(s);
672         MMPLAYER_FREEIF(error_string);
673
674         MMPLAYER_FLEAVE();
675         return TRUE;
676
677 }
678
679 static void
680 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
681 {
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);
709 }
710
711 static gboolean
712 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
713 {
714
715 /* macro for better code readability */
716 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
717         do { \
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); \
728                                 } else { \
729                                         mm_player_set_attribute((MMHandleType)player, NULL,\
730                                                         playertag, string, strlen(string), NULL); \
731                                 } \
732                                 MMPLAYER_FREEIF(string); \
733                         } \
734                 } \
735         } while (0)
736
737 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
738         do {    \
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);\
746                                 break;\
747                         } \
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);\
760                                 } \
761                         } \
762                         gst_buffer_unmap(buffer, &info);\
763                         gst_sample_unref(sample);\
764                 }       \
765         } while (0)
766
767 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
768         do {    \
769                 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
770                         if (v_uint) { \
771                                 int i = 0; \
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; \
777                                 else \
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);\
798                                 } else { \
799                                         mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
800                                 } \
801                                 v_uint = 0;\
802                         } \
803                 } \
804         } while (0)
805
806 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
807         do { \
808                 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
809                         if (date != NULL) {\
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);\
815                                 g_date_free(date);\
816                         } \
817                 } \
818         } while (0)
819
820 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
821         do { \
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);\
830                         } \
831                 } \
832         } while (0)
833
834         /* function start */
835         GstTagList *tag_list = NULL;
836
837         char *string = NULL;
838         guint v_uint = 0;
839         GDate *date = NULL;
840         GstDateTime *datetime = NULL;
841         /* album cover */
842         GstBuffer *buffer = NULL;
843         gint index = 0;
844         MMMessageParamType msg_param = {0, };
845
846         /* currently not used. but those are needed for above macro */
847         //guint64 v_uint64 = 0;
848         //gdouble v_double = 0;
849
850         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
851
852         /* get tag list from gst message */
853         gst_message_parse_tag(msg, &tag_list);
854
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");
874
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;
883                         } else {
884                                 LOGD("This is not spherical content");
885                                 player->is_content_spherical = FALSE;
886                         }
887
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;
891                                 } else {
892                                         LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
893                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
894                                 }
895                         }
896
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;
904                                 } else {
905                                         LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
906                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
907                                 }
908                         }
909                 }
910         }
911
912         gst_tag_list_unref(tag_list);
913
914         return TRUE;
915 }
916
917 /* if retval is FALSE, it will be dropped for performance. */
918 static gboolean
919 __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message)
920 {
921         gboolean retval = FALSE;
922
923         if (!(player->pipeline && player->pipeline->mainbin)) {
924                 LOGE("player pipeline handle is null");
925                 return TRUE;
926         }
927
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:
939                 retval = TRUE;
940                 break;
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))
945                         retval = TRUE;
946                 else
947                         retval = FALSE;
948                 break;
949         case GST_MESSAGE_BUFFERING:
950         {
951                 gint buffer_percent = 0;
952
953                 retval = TRUE;
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);
957                         break;
958                 }
959
960                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
961                         LOGW("can't get cmd lock, send msg to bus");
962                         break;
963                 }
964
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;
968                 }
969
970                 MMPLAYER_CMD_UNLOCK(player);
971
972                 break;
973         }
974         case GST_MESSAGE_STREAMS_SELECTED:
975         {
976                 if (MMPLAYER_USE_DECODEBIN(player))
977                         break; /* drop msg */
978
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)) {
982
983                         gint64 dur_bytes = 0L;
984
985                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
986                                 LOGE("fail to get duration.");
987
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));
995                 }
996
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);
1001                 retval = TRUE;
1002                 break;
1003         }
1004         default:
1005                 retval = FALSE;
1006                 break;
1007         }
1008
1009         return retval;
1010 }
1011
1012 static void
1013 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1014 {
1015         guint64 data_size = 0;
1016         gint64 pos_nsec = 0;
1017
1018         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1019
1020         _mmplayer_gst_get_position(player, &pos_nsec);  /* to update player->last_position */
1021
1022         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1023                 data_size = player->http_content_size;
1024         }
1025
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);
1028
1029         return;
1030 }
1031
1032 static int
1033 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1034 {
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;
1040
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;
1044                 goto exit;
1045         }
1046
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);
1051
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);
1058
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:
1063                         {
1064                                 switch (pending_state) {
1065                                 case MM_PLAYER_STATE_PLAYING:
1066                                         _mmplayer_gst_pause(player, TRUE);
1067                                         break;
1068
1069                                 case MM_PLAYER_STATE_PAUSED:
1070                                         LOGD("player is already going to paused state, there is nothing to do.");
1071                                         break;
1072
1073                                 case MM_PLAYER_STATE_NONE:
1074                                 case MM_PLAYER_STATE_NULL:
1075                                 case MM_PLAYER_STATE_READY:
1076                                 default:
1077                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1078                                         break;
1079                                 }
1080                         }
1081                         break;
1082
1083                 case MM_PLAYER_STATE_PLAYING:
1084                         {
1085                                 switch (pending_state) {
1086                                 case MM_PLAYER_STATE_NONE:
1087                                         {
1088                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1089                                                         _mmplayer_gst_resume(player, TRUE);
1090                                         }
1091                                         break;
1092
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.
1096                                          */
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.
1100                                                  */
1101                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1102                                         }
1103                                         _mmplayer_gst_resume(player, TRUE);
1104                                         break;
1105
1106                                 case MM_PLAYER_STATE_PLAYING:
1107                                         LOGD("player is already going to playing state, there is nothing to do.");
1108                                         break;
1109
1110                                 case MM_PLAYER_STATE_NULL:
1111                                 case MM_PLAYER_STATE_READY:
1112                                 default:
1113                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1114                                         break;
1115                                 }
1116                         }
1117                         break;
1118
1119                 case MM_PLAYER_STATE_NULL:
1120                 case MM_PLAYER_STATE_READY:
1121                 case MM_PLAYER_STATE_NONE:
1122                 default:
1123                         LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1124                         break;
1125                 }
1126         } else {
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.
1129                  */
1130                 switch (pending_state) {
1131                 case MM_PLAYER_STATE_NONE:
1132                         {
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);
1138                                         }
1139                                 }
1140                         }
1141                         break;
1142
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);
1147                         break;
1148
1149                 case MM_PLAYER_STATE_PAUSED:
1150                         break;
1151
1152                 case MM_PLAYER_STATE_NULL:
1153                 case MM_PLAYER_STATE_READY:
1154                 default:
1155                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1156                         break;
1157                 }
1158         }
1159
1160 exit:
1161         return ret;
1162 }
1163
1164 static stream_variant_t *
1165 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1166 {
1167         stream_variant_t *var_info = NULL;
1168         g_return_val_if_fail(self != NULL, NULL);
1169
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;
1175         return var_info;
1176 }
1177
1178 static gboolean
1179 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1180 {
1181         gint64 bytes = 0;
1182
1183         MMPLAYER_FENTER();
1184
1185         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1186         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1187
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)));
1191
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;
1195                 }
1196         } else {
1197                 /* handling audio clip which has vbr. means duration is keep changing */
1198                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1199         }
1200
1201         MMPLAYER_FLEAVE();
1202
1203         return TRUE;
1204 }
1205
1206 static gboolean
1207 __mmplayer_eos_timer_cb(gpointer u_data)
1208 {
1209         mmplayer_t *player = NULL;
1210         MMHandleType attrs = 0;
1211         int count = 0;
1212
1213         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1214
1215         player = (mmplayer_t *)u_data;
1216         attrs = MMPLAYER_GET_ATTRS(player);
1217
1218         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1219
1220         if (count == -1) {
1221                 gint ret_value = 0;
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");
1225         } else {
1226                 /* posting eos */
1227                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1228         }
1229
1230         /* we are returning FALSE as we need only one posting */
1231         return FALSE;
1232 }
1233
1234 static void
1235 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1236 {
1237         MMPLAYER_RETURN_IF_FAIL(player);
1238
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);
1243
1244                 if (player->audio_decoded_cb)
1245                         _mmplayer_cancel_eos_timer(player);
1246
1247                 return;
1248         }
1249
1250         /* cancel if existing */
1251         _mmplayer_cancel_eos_timer(player);
1252
1253         /* init new timeout */
1254         /* NOTE : consider give high priority to this timer */
1255         LOGD("posting EOS message after [%d] msec", delay_in_ms);
1256
1257         player->eos_timer = g_timeout_add(delay_in_ms,
1258                 __mmplayer_eos_timer_cb, player);
1259
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);
1262
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);
1267         }
1268 }
1269
1270 static int
1271 __mmplayer_gst_pending_seek(mmplayer_t *player)
1272 {
1273         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1274         int ret = MM_ERROR_NONE;
1275
1276         MMPLAYER_FENTER();
1277
1278         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1279
1280         if (!player->pending_seek.is_pending) {
1281                 LOGD("pending seek is not reserved. nothing to do.");
1282                 return ret;
1283         }
1284
1285         /* check player state if player could pending seek or not. */
1286         current_state = MMPLAYER_CURRENT_STATE(player);
1287
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));
1291                 return ret;
1292         }
1293
1294         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1295
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.");
1299
1300         player->pending_seek.is_pending = false;
1301
1302         MMPLAYER_FLEAVE();
1303
1304         return ret;
1305 }
1306
1307 static void
1308 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type  type)
1309 {
1310         mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1311
1312         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1313
1314         audiobin = player->pipeline->audiobin; /* can be null */
1315         videobin = player->pipeline->videobin; /* can be null */
1316         textbin = player->pipeline->textbin;   /* can be null */
1317
1318         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1319
1320         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1321                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1322
1323         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1324                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1325
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);
1328
1329         return;
1330 }
1331
1332 static void
1333 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1334 {
1335         mmplayer_gst_element_t *textbin;
1336         MMPLAYER_FENTER();
1337
1338         MMPLAYER_RETURN_IF_FAIL(player &&
1339                                         player->pipeline &&
1340                                         player->pipeline->textbin);
1341
1342         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1343
1344         textbin = player->pipeline->textbin;
1345
1346         if (is_drop) {
1347                 LOGD("Drop subtitle text after getting EOS");
1348
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);
1351
1352                 player->is_subtitle_force_drop = TRUE;
1353         } else {
1354                 if (player->is_subtitle_force_drop == TRUE) {
1355                         LOGD("Enable subtitle data path without drop");
1356
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);
1359
1360                         LOGD("non-connected with external display");
1361
1362                         player->is_subtitle_force_drop = FALSE;
1363                 }
1364         }
1365 }
1366
1367 static void
1368 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1369 {
1370         MMHandleType attrs = 0;
1371         gint count = 0;
1372
1373         MMPLAYER_FENTER();
1374
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");
1379                 return;
1380         }
1381
1382         if (player->pipeline && player->pipeline->textbin)
1383                 __mmplayer_drop_subtitle(player, TRUE);
1384
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);
1387
1388         /* rewind if repeat count is greater then zero */
1389         /* get play count */
1390         attrs = MMPLAYER_GET_ATTRS(player);
1391         if (attrs) {
1392                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1393
1394                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1395
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);
1401                         }
1402
1403                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1404
1405                         /* initialize */
1406                         player->sent_bos = FALSE;
1407
1408                         LOGD("do not post eos msg for repeating");
1409                         return;
1410                 }
1411         }
1412
1413         if (player->pipeline)
1414                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1415
1416         /* post eos message to application */
1417         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1418
1419         /* reset last position */
1420         player->last_position = 0;
1421
1422         MMPLAYER_FLEAVE();
1423         return;
1424 }
1425
1426 static void
1427 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1428 {
1429         GError *error = NULL;
1430         gchar *debug = NULL;
1431
1432         MMPLAYER_FENTER();
1433
1434         /* generating debug info before returning error */
1435         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1436
1437         /* get error code */
1438         gst_message_parse_error(msg, &error, &debug);
1439
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.
1443                  */
1444                 __mmplayer_handle_streaming_error(player, msg);
1445
1446                 /* dump state of all element */
1447                 _mmplayer_dump_pipeline_state(player);
1448         } else {
1449                 /* translate gst error code to msl error code. then post it
1450                  * to application if needed
1451                  */
1452                 __mmplayer_handle_gst_error(player, msg, error);
1453
1454                 if (debug)
1455                         LOGE("error debug : %s", debug);
1456         }
1457
1458         MMPLAYER_FREEIF(debug);
1459         g_error_free(error);
1460
1461         MMPLAYER_FLEAVE();
1462         return;
1463 }
1464
1465 static void
1466 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1467 {
1468         MMMessageParamType msg_param = {0, };
1469         int bRet = MM_ERROR_NONE;
1470
1471         MMPLAYER_FENTER();
1472         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1473
1474         if (!MMPLAYER_IS_STREAMING(player)) {
1475                 LOGW("this is not streaming playback.");
1476                 return;
1477         }
1478
1479         MMPLAYER_CMD_LOCK(player);
1480
1481         if (!player->streamer) {
1482                 LOGW("Pipeline is shutting down");
1483                 MMPLAYER_CMD_UNLOCK(player);
1484                 return;
1485         }
1486
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;
1490
1491                 gst_message_parse_buffering(msg, &buffer_percent);
1492
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;
1497                 }
1498                 MMPLAYER_CMD_UNLOCK(player);
1499                 return;
1500         }
1501
1502         /* ignore the remained buffering message */
1503         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1504                 gint buffer_percent = 0;
1505
1506                 gst_message_parse_buffering(msg, &buffer_percent);
1507
1508                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1509                                         player->streamer->buffering_percent, buffer_percent);
1510
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;
1514
1515                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1516                 } else {
1517                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1518                         MMPLAYER_CMD_UNLOCK(player);
1519                         return;
1520                 }
1521         }
1522
1523         __mmplayer_update_buffer_setting(player, msg);
1524
1525         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1526
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);
1530
1531                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1532                         player->pending_resume &&
1533                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1534
1535                         player->is_external_subtitle_added_now = FALSE;
1536                         player->pending_resume = FALSE;
1537                         _mmplayer_resume((MMHandleType)player);
1538                 }
1539
1540                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1541                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1542
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;
1551                                 }
1552                         }
1553                 }
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);
1558                         return;
1559                 }
1560
1561                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1562
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);
1565
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);
1569                         } else {
1570                                 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1571                         }
1572                 } else {
1573                         msg_param.connection.buffering = player->streamer->buffering_percent;
1574                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1575                 }
1576         }
1577         MMPLAYER_CMD_UNLOCK(player);
1578
1579         MMPLAYER_FLEAVE();
1580         return;
1581
1582 }
1583
1584 static void
1585 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1586 {
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;
1592
1593         MMPLAYER_FENTER();
1594         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1595
1596         mainbin = player->pipeline->mainbin;
1597
1598         /* we only handle messages from pipeline */
1599         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1600                 return;
1601
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");
1606
1607         if (!voldstate || !vnewstate) {
1608                 LOGE("received msg has wrong format.");
1609                 return;
1610         }
1611
1612         oldstate = (GstState)voldstate->data[0].v_int;
1613         newstate = (GstState)vnewstate->data[0].v_int;
1614         if (vpending)
1615                 pending = (GstState)vpending->data[0].v_int;
1616
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));
1622
1623         if (newstate == GST_STATE_PLAYING) {
1624                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1625
1626                         int retVal = MM_ERROR_NONE;
1627                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1628
1629                         retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1630
1631                         if (MM_ERROR_NONE != retVal)
1632                                 LOGE("failed to seek pending position. just keep staying current position.");
1633
1634                         player->pending_seek.is_pending = false;
1635                 }
1636         }
1637
1638         if (oldstate == newstate) {
1639                 LOGD("pipeline reports state transition to old state");
1640                 return;
1641         }
1642
1643         switch (newstate) {
1644         case GST_STATE_PAUSED:
1645                 {
1646                         gboolean prepare_async = FALSE;
1647
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);
1652                         }
1653
1654                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1655                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1656
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);
1660
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);
1666                                 }
1667                         }
1668                 }
1669                 break;
1670
1671         case GST_STATE_PLAYING:
1672                 {
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);
1679
1680                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1681
1682                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1683                                         if (player->streamer->buffering_percent < 100) {
1684
1685                                                 MMMessageParamType msg_param = {0, };
1686                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1687
1688                                                 msg_param.connection.buffering = 100;
1689                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1690                                         }
1691                                 }
1692                         }
1693
1694                         if (player->gapless.stream_changed) {
1695                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1696                                 player->gapless.stream_changed = FALSE;
1697                         }
1698
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);
1702                         }
1703                 }
1704                 break;
1705         case GST_STATE_VOID_PENDING:
1706         case GST_STATE_NULL:
1707         case GST_STATE_READY:
1708         default:
1709                 break;
1710         }
1711
1712         MMPLAYER_FLEAVE();
1713         return;
1714 }
1715
1716 static void
1717 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1718 {
1719         const gchar *structure_name;
1720         gint count = 0, idx = 0;
1721
1722         MMPLAYER_FENTER();
1723         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1724
1725         if (gst_message_get_structure(msg) == NULL)
1726                 return;
1727
1728         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1729         if (!structure_name)
1730                 return;
1731
1732         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1733
1734         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1735                 const GValue *var_info = NULL;
1736
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);
1741
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);
1745
1746                         count = g_list_length(player->adaptive_info.var_list);
1747                         if (count > 0) {
1748                                 stream_variant_t *temp = NULL;
1749
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);
1754                                         if (temp)
1755                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1756                                 }
1757                         }
1758                 }
1759         }
1760
1761         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1762                 gint num_buffers = 0;
1763                 gint extra_num_buffers = 0;
1764
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);
1769                 }
1770
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);
1775                 }
1776                 return;
1777         }
1778
1779         if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1780                 _mmplayer_track_update_text_attr_info(player, msg);
1781
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);
1787         }
1788
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;
1797
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);
1802
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);
1806                 if (audio_codec)
1807                         mm_player_set_attribute((MMHandleType)player, NULL,
1808                                         "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1809
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);
1813                 if (video_codec)
1814                         mm_player_set_attribute((MMHandleType)player, NULL,
1815                                         "content_video_codec", video_codec, strlen(video_codec), NULL);
1816
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]),
1825                                 NULL);
1826                         g_strfreev(res_str);
1827                 }
1828         }
1829
1830         MMPLAYER_FLEAVE();
1831         return;
1832 }
1833
1834 static void
1835 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1836 {
1837         mmplayer_gst_element_t *mainbin;
1838
1839         MMPLAYER_FENTER();
1840         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1841
1842         mainbin = player->pipeline->mainbin;
1843
1844         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1845
1846         /* we only handle messages from pipeline */
1847         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1848                 return;
1849
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)));
1860
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);
1866                         }
1867
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;
1874                                 gint percent = 0;
1875
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);
1881
1882                                         LOGD("buffered percent(%s): %d",
1883                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1884                                 }
1885
1886                                 if (percent >= 100)
1887                                         __mmplayer_handle_buffering_playback(player);
1888                         }
1889
1890                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1891                 }
1892         }
1893
1894         MMPLAYER_FLEAVE();
1895         return;
1896 }
1897
1898 static void
1899 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1900 {
1901         GValue val = { 0, };
1902         gchar *str = NULL;
1903         guint indent = GPOINTER_TO_UINT(user_data);
1904
1905         if (!gst_tag_list_copy_value(&val, tags, tag))
1906                 return;
1907
1908         if (G_VALUE_HOLDS_STRING(&val))
1909                 str = g_value_dup_string(&val);
1910         else
1911                 str = gst_value_serialize(&val);
1912
1913         LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1914         g_free(str);
1915         g_value_unset(&val);
1916 }
1917
1918 static void
1919 __mmplayer_dump_collection(GstStreamCollection * collection)
1920 {
1921         guint i = 0;
1922         GstTagList *tags = NULL;
1923         GstCaps *caps = NULL;
1924
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));
1931
1932                 caps = gst_stream_get_caps(stream);
1933                 if (caps) {
1934                         gchar *caps_str = gst_caps_to_string(caps);
1935                         LOGD ("  caps: %s\n", caps_str);
1936                         g_free(caps_str);
1937                         gst_caps_unref(caps);
1938                 }
1939
1940                 tags = gst_stream_get_tags(stream);
1941                 if (tags) {
1942                         LOGD ("  tags:\n");
1943                         gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1944                         gst_tag_list_unref(tags);
1945                 }
1946         }
1947 }
1948
1949 static void
1950 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1951                         GstStream *stream, GParamSpec *pspec, gpointer data)
1952 {
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);
1959                 g_free(caps_str);
1960                 gst_caps_unref(caps);
1961         }
1962
1963         if (g_str_equal (pspec->name, "tags")) {
1964                 GstTagList *tags = gst_stream_get_tags(stream);
1965                 if (tags) {
1966                         LOGD ("  tags:\n");
1967                         gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1968                         gst_tag_list_unref(tags);
1969                 }
1970         }
1971 }
1972
1973 static void
1974 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1975 {
1976         mmplayer_t *player = (mmplayer_t *)(data);
1977
1978         MMPLAYER_RETURN_IF_FAIL(player);
1979         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1980
1981         switch (GST_MESSAGE_TYPE(msg)) {
1982         case GST_MESSAGE_UNKNOWN:
1983                 LOGD("unknown message received");
1984                 break;
1985
1986         case GST_MESSAGE_EOS:
1987                 LOGD("GST_MESSAGE_EOS received");
1988                 __mmplayer_gst_handle_eos_message(player, msg);
1989                 break;
1990
1991         case GST_MESSAGE_ERROR:
1992                 _mmplayer_set_reconfigure_state(player, FALSE);
1993                 __mmplayer_gst_handle_error_message(player, msg);
1994                 break;
1995
1996         case GST_MESSAGE_WARNING:
1997                 {
1998                         char *debug = NULL;
1999                         GError *error = NULL;
2000
2001                         gst_message_parse_warning(msg, &error, &debug);
2002
2003                         LOGD("warning : %s", error->message);
2004                         LOGD("debug : %s", debug);
2005
2006                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2007
2008                         MMPLAYER_FREEIF(debug);
2009                         g_error_free(error);
2010                 }
2011                 break;
2012
2013         case GST_MESSAGE_TAG:
2014                 {
2015                         LOGD("GST_MESSAGE_TAG");
2016                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2017                                 LOGW("failed to extract tags from gstmessage");
2018                 }
2019                 break;
2020
2021         case GST_MESSAGE_BUFFERING:
2022                 __mmplayer_gst_handle_buffering_message(player, msg);
2023                 break;
2024
2025         case GST_MESSAGE_STATE_CHANGED:
2026                 __mmplayer_gst_handle_state_message(player, msg);
2027                 break;
2028
2029         case GST_MESSAGE_CLOCK_LOST:
2030                         {
2031                                 GstClock *clock = NULL;
2032                                 gboolean need_new_clock = FALSE;
2033
2034                                 gst_message_parse_clock_lost(msg, &clock);
2035                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2036
2037                                 if (!player->videodec_linked)
2038                                         need_new_clock = TRUE;
2039                                 else if (!player->ini.use_system_clock)
2040                                         need_new_clock = TRUE;
2041
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);
2046                                 }
2047                         }
2048                         break;
2049
2050         case GST_MESSAGE_NEW_CLOCK:
2051                         {
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"));
2055                         }
2056                         break;
2057
2058         case GST_MESSAGE_ELEMENT:
2059                 __mmplayer_gst_handle_element_message(player, msg);
2060                         break;
2061
2062         case GST_MESSAGE_DURATION_CHANGED:
2063                 {
2064                         LOGD("GST_MESSAGE_DURATION_CHANGED");
2065                         if (!__mmplayer_gst_handle_duration(player, msg))
2066                                 LOGW("failed to update duration");
2067                 }
2068                 break;
2069
2070         case GST_MESSAGE_ASYNC_START:
2071                         LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2072                 break;
2073
2074         case GST_MESSAGE_ASYNC_DONE:
2075                 __mmplayer_gst_handle_async_done_message(player, msg);
2076                 break;
2077         case GST_MESSAGE_STREAM_COLLECTION:
2078         {
2079                 GstStreamCollection *collection = NULL;
2080                 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2081
2082                 gst_message_parse_stream_collection(msg, &collection);
2083                 if (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;
2088                         }
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);
2093                         }
2094                         gst_object_unref(collection);
2095                 }
2096         } break;
2097         case GST_MESSAGE_STREAMS_SELECTED:
2098         {
2099                 GstStreamCollection *collection = NULL;
2100                 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2101
2102                 gst_message_parse_streams_selected(msg, &collection);
2103                 if (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);
2110                         }
2111                         gst_object_unref (collection);
2112                 }
2113         } break;
2114
2115 #ifdef __DEBUG__
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;
2131 #endif
2132
2133         default:
2134                 break;
2135         }
2136
2137         /* should not call 'gst_message_unref(msg)' */
2138         return;
2139 }
2140
2141 static GstBusSyncReply
2142 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2143 {
2144         mmplayer_t *player = (mmplayer_t *)data;
2145         GstBusSyncReply reply = GST_BUS_DROP;
2146
2147         if (!(player->pipeline && player->pipeline->mainbin)) {
2148                 LOGE("player pipeline handle is null");
2149                 return GST_BUS_PASS;
2150         }
2151
2152         if (!__mmplayer_gst_check_useful_message(player, message)) {
2153                 gst_message_unref(message);
2154                 return GST_BUS_DROP;
2155         }
2156
2157         switch (GST_MESSAGE_TYPE(message)) {
2158         case GST_MESSAGE_TAG:
2159                 __mmplayer_gst_extract_tag_from_msg(player, message);
2160
2161 #ifdef __DEBUG__
2162                 {
2163                         GstTagList *tags = NULL;
2164
2165                         gst_message_parse_tag(message, &tags);
2166                         if (tags) {
2167                                 LOGE("TAGS received from element \"%s\".",
2168                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2169
2170                                 gst_tag_list_foreach(tags, print_tag, NULL);
2171                                 gst_tag_list_unref(tags);
2172                                 tags = NULL;
2173                         }
2174                         break;
2175                 }
2176 #endif
2177                 break;
2178
2179         case GST_MESSAGE_DURATION_CHANGED:
2180                 __mmplayer_gst_handle_duration(player, message);
2181                 break;
2182         case GST_MESSAGE_ELEMENT:
2183                 {
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;
2189                                 break;
2190                         }
2191                         __mmplayer_gst_handle_element_message(player, message);
2192                 }
2193                 break;
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.
2197                  */
2198         default:
2199                 reply = GST_BUS_PASS;
2200                 break;
2201         }
2202
2203         if (reply == GST_BUS_DROP)
2204                 gst_message_unref(message);
2205
2206         return reply;
2207 }
2208
2209 static void
2210 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2211 {
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;
2216         gint len = size;
2217
2218         MMPLAYER_RETURN_IF_FAIL(element);
2219         MMPLAYER_RETURN_IF_FAIL(buf);
2220
2221         buffer = gst_buffer_new();
2222
2223         if (buf->offset < 0 || buf->len < 0) {
2224                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2225                 return;
2226         }
2227
2228         if (buf->offset >= buf->len) {
2229                 LOGD("call eos appsrc");
2230                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2231                 return;
2232         }
2233
2234         if (buf->len - buf->offset < size)
2235                 len = buf->len - buf->offset;
2236
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);
2240
2241 #ifdef __DEBUG__
2242         LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2243 #endif
2244         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2245
2246         buf->offset += len;
2247 }
2248
2249 static gboolean
2250 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2251 {
2252         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2253
2254         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2255
2256         buf->offset  = (int)size;
2257
2258         return TRUE;
2259 }
2260
2261 void
2262 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2263 {
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;
2268
2269         MMPLAYER_RETURN_IF_FAIL(player);
2270
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;
2275         } else {
2276                 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2277                 return;
2278         }
2279
2280         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2281
2282         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2283
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;
2288
2289         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2290 }
2291
2292 void
2293 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2294 {
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;
2299
2300         MMPLAYER_RETURN_IF_FAIL(player);
2301
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;
2306         } else {
2307                 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2308                 return;
2309         }
2310
2311         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2312
2313         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2314
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;
2319
2320         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2321 }
2322
2323 gboolean
2324 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2325 {
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,};
2329
2330         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2331
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;
2336         } else {
2337                 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2338                 return TRUE;
2339         }
2340
2341         LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2342
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;
2346
2347         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2348
2349         return TRUE;
2350 }
2351
2352 static gboolean
2353 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2354 {
2355 #define MAX_LEN_NAME 20
2356
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;
2362
2363         mmplayer_gst_element_t *mainbin = NULL;
2364         GstElement *decodebin = NULL;
2365         GstCaps *dec_caps = NULL;
2366
2367         MMPLAYER_FENTER();
2368
2369         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2370                                                 player->pipeline &&
2371                                                 player->pipeline->mainbin, FALSE);
2372         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2373
2374         mainbin = player->pipeline->mainbin;
2375         switch (type) {
2376         case MM_PLAYER_STREAM_TYPE_AUDIO:
2377                 prefix = "audio";
2378                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2379         break;
2380         case MM_PLAYER_STREAM_TYPE_VIDEO:
2381                 prefix = "video";
2382                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2383         break;
2384         default:
2385                 LOGE("invalid type %d", type);
2386                 return FALSE;
2387         }
2388
2389         if (mainbin[elem_id].gst) {
2390                 LOGE("elem(%d) is already created", elem_id);
2391                 return FALSE;
2392         }
2393
2394         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2395
2396         /* create decodebin */
2397         decodebin = gst_element_factory_make("decodebin", dec_name);
2398         if (!decodebin) {
2399                 LOGE("failed to create %s", dec_name);
2400                 return FALSE;
2401         }
2402
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);
2406
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);
2411
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);
2415
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);
2419
2420         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2421                 LOGE("failed to add new decodebin");
2422                 return FALSE;
2423         }
2424
2425         dec_caps = gst_pad_query_caps(srcpad, NULL);
2426         if (dec_caps) {
2427 #ifdef __DEBUG__
2428                 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2429 #endif
2430                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2431                 gst_caps_unref(dec_caps);
2432         }
2433
2434         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2435
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));
2438                 goto ERROR;
2439         }
2440         gst_object_unref(GST_OBJECT(sinkpad));
2441
2442         gst_element_sync_state_with_parent(decodebin);
2443
2444         mainbin[elem_id].id = elem_id;
2445         mainbin[elem_id].gst = decodebin;
2446
2447         MMPLAYER_FLEAVE();
2448         return TRUE;
2449
2450 ERROR:
2451         if (sinkpad)
2452                 gst_object_unref(GST_OBJECT(sinkpad));
2453
2454         if (decodebin) {
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);
2458         }
2459
2460         MMPLAYER_FLEAVE();
2461         return ret;
2462 }
2463
2464 static gboolean
2465 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2466 {
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;
2471
2472         gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2473         GstElement *src = NULL, *queue = NULL;
2474         GstPad *srcpad = NULL;
2475
2476         MMPLAYER_FENTER();
2477         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2478                                 player->pipeline->mainbin, FALSE);
2479
2480         mainbin = player->pipeline->mainbin;
2481
2482         LOGD("type(%d) path is creating", type);
2483         switch (type) {
2484         case MM_PLAYER_STREAM_TYPE_AUDIO:
2485                 prefix = "audio";
2486                 if (mainbin[MMPLAYER_M_SRC].gst)
2487                         src_id = MMPLAYER_M_2ND_SRC;
2488                 else
2489                         src_id = MMPLAYER_M_SRC;
2490                 queue_id = MMPLAYER_M_A_BUFFER;
2491         break;
2492         case MM_PLAYER_STREAM_TYPE_VIDEO:
2493                 prefix = "video";
2494                 src_id = MMPLAYER_M_SRC;
2495                 queue_id = MMPLAYER_M_V_BUFFER;
2496         break;
2497         case MM_PLAYER_STREAM_TYPE_TEXT:
2498                 prefix = "subtitle";
2499                 src_id = MMPLAYER_M_SUBSRC;
2500                 queue_id = MMPLAYER_M_S_BUFFER;
2501         break;
2502         default:
2503                 LOGE("invalid type %d", type);
2504                 return FALSE;
2505         }
2506
2507         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2508         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2509
2510         /* create source */
2511         src = gst_element_factory_make("appsrc", src_name);
2512         if (!src) {
2513                 LOGF("failed to create %s", src_name);
2514                 goto ERROR;
2515         }
2516
2517         mainbin[src_id].id = src_id;
2518         mainbin[src_id].gst = src;
2519
2520         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2521                                                                 "caps", caps, NULL);
2522
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);
2526
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);
2529
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);
2532
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);
2535
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);
2542
2543         /* create queue */
2544         queue = gst_element_factory_make("queue2", queue_name);
2545         if (!queue) {
2546                 LOGE("failed to create %s", queue_name);
2547                 goto ERROR;
2548         }
2549         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2550
2551         mainbin[queue_id].id = queue_id;
2552         mainbin[queue_id].gst = queue;
2553
2554         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2555                 LOGE("failed to add src");
2556                 goto ERROR;
2557         }
2558
2559         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2560                 LOGE("failed to add queue");
2561                 goto ERROR;
2562         }
2563
2564         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2565                 LOGE("failed to link src and queue");
2566                 goto ERROR;
2567         }
2568
2569         /* create decoder */
2570         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2571         if (!srcpad) {
2572                 LOGE("failed to get srcpad of queue");
2573                 goto ERROR;
2574         }
2575
2576         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2577                 _mmplayer_gst_create_decoder(player, srcpad, caps);
2578         } else {
2579                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2580                         LOGE("failed to create decoder");
2581                         gst_object_unref(GST_OBJECT(srcpad));
2582                         goto ERROR;
2583                 }
2584         }
2585         gst_object_unref(GST_OBJECT(srcpad));
2586         return TRUE;
2587
2588 ERROR:
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;
2594         }
2595
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;
2601         }
2602
2603         return FALSE;
2604 }
2605
2606 static void
2607 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2608 {
2609         GstPad *sinkpad = NULL;
2610         GstCaps *caps = NULL;
2611         GstElement *new_element = NULL;
2612         GstStructure *str = NULL;
2613         const gchar *name = NULL;
2614
2615         mmplayer_t *player = (mmplayer_t *)data;
2616
2617         MMPLAYER_FENTER();
2618
2619         MMPLAYER_RETURN_IF_FAIL(element && pad);
2620         MMPLAYER_RETURN_IF_FAIL(player &&
2621                                         player->pipeline &&
2622                                         player->pipeline->mainbin);
2623
2624         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2625          * num_dynamic_pad will decreased after creating a sinkbin.
2626          */
2627         player->num_dynamic_pad++;
2628         LOGD("stream count inc : %d", player->num_dynamic_pad);
2629
2630         caps = gst_pad_query_caps(pad, NULL);
2631         MMPLAYER_CHECK_NULL(caps);
2632
2633         str = gst_caps_get_structure(caps, 0);
2634         name = gst_structure_get_string(str, "media");
2635         if (!name) {
2636                 LOGE("cannot get mimetype from structure.");
2637                 goto ERROR;
2638         }
2639
2640         if (strstr(name, "video")) {
2641                 gint stype = 0;
2642                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2643
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;
2648                         }
2649
2650                         new_element = gst_element_factory_make("fakesink", NULL);
2651                         player->num_dynamic_pad--;
2652                         goto NEW_ELEMENT;
2653                 }
2654         }
2655
2656         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2657                 LOGE("failed to autoplug for caps");
2658                 goto ERROR;
2659         }
2660
2661         gst_caps_unref(caps);
2662         caps = NULL;
2663
2664 NEW_ELEMENT:
2665
2666         /* execute new_element if created*/
2667         if (new_element) {
2668                 LOGD("adding new element to pipeline");
2669
2670                 /* set state to READY before add to bin */
2671                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2672
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");
2676                         goto ERROR;
2677                 }
2678
2679                 /* get pad from element */
2680                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2681                 if (!sinkpad) {
2682                         LOGE("failed to get sinkpad from autoplug element");
2683                         goto ERROR;
2684                 }
2685
2686                 /* link it */
2687                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2688                         LOGE("failed to link autoplug element");
2689                         goto ERROR;
2690                 }
2691
2692                 gst_object_unref(sinkpad);
2693                 sinkpad = NULL;
2694
2695                 /* run. setting PLAYING here since streaming source is live source */
2696                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2697         }
2698
2699         if (caps)
2700                 gst_caps_unref(caps);
2701
2702         MMPLAYER_FLEAVE();
2703
2704         return;
2705
2706 STATE_CHANGE_FAILED:
2707 ERROR:
2708         /* FIXIT : take care if new_element has already added to pipeline */
2709         if (new_element)
2710                 gst_object_unref(GST_OBJECT(new_element));
2711
2712         if (sinkpad)
2713                 gst_object_unref(GST_OBJECT(sinkpad));
2714
2715         if (caps)
2716                 gst_caps_unref(caps);
2717
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
2721          */
2722 }
2723
2724 static void
2725 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2726 {
2727         mmplayer_t *player = (mmplayer_t *)data;
2728
2729         MMPLAYER_FENTER();
2730
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
2735
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.
2740          */
2741         if (player->num_dynamic_pad == 0) {
2742                 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2743
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.
2750                          */
2751                         return;
2752         }
2753
2754         /* create dot before error-return. for debugging */
2755         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2756
2757         player->no_more_pad = TRUE;
2758
2759         MMPLAYER_FLEAVE();
2760 }
2761
2762 static GstElement *
2763 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2764 {
2765         GstElement *element = NULL;
2766         gchar *user_agent = NULL;
2767         MMHandleType attrs = 0;
2768
2769         MMPLAYER_FENTER();
2770         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2771
2772         /* get profile attribute */
2773         attrs = MMPLAYER_GET_ATTRS(player);
2774         if (!attrs) {
2775                 LOGE("failed to get content attribute");
2776                 return NULL;
2777         }
2778
2779         element = gst_element_factory_make("rtspsrc", "rtsp source");
2780         if (!element) {
2781                 LOGE("failed to create rtspsrc element");
2782                 return NULL;
2783         }
2784
2785         /* get attribute */
2786         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2787
2788         SECURE_LOGD("user_agent : %s", user_agent);
2789
2790         /* setting property to streaming source */
2791         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2792         if (user_agent)
2793                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2794
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);
2799
2800         MMPLAYER_FLEAVE();
2801         return element;
2802 }
2803
2804 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2805 {
2806 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2807
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;
2813         cookie_list = NULL;
2814
2815         MMPLAYER_FENTER();
2816         MMPLAYER_RETURN_IF_FAIL(player);
2817
2818         LOGD("source element %s", GST_ELEMENT_NAME(source));
2819
2820         attrs = MMPLAYER_GET_ATTRS(player);
2821         if (!attrs) {
2822                 LOGE("failed to get content attribute");
2823                 return;
2824         }
2825
2826         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2827         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2828
2829         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2830                 http_timeout = player->ini.http_timeout;
2831
2832         SECURE_LOGD("cookies : %s", cookies);
2833         SECURE_LOGD("user_agent :  %s", user_agent);
2834         LOGD("timeout : %d", http_timeout);
2835
2836         g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2837
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);
2841         }
2842
2843         if (user_agent)
2844                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2845
2846         MMPLAYER_FLEAVE();
2847         return;
2848 }
2849
2850 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2851 {
2852         mmplayer_t *player = (mmplayer_t *)data;
2853         gchar *user_agent = NULL;
2854         MMHandleType attrs = 0;
2855
2856         MMPLAYER_FENTER();
2857         MMPLAYER_RETURN_IF_FAIL(player);
2858
2859         attrs = MMPLAYER_GET_ATTRS(player);
2860         if (!attrs) {
2861                 LOGE("failed to get content attribute");
2862                 return;
2863         }
2864
2865         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2866
2867         SECURE_LOGD("user_agent : %s", user_agent);
2868
2869         if (user_agent)
2870                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2871
2872         MMPLAYER_FLEAVE();
2873 }
2874
2875 static void
2876 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2877 {
2878         mmplayer_t *player = (mmplayer_t *)data;
2879         GstElement *source = NULL;
2880
2881         MMPLAYER_FENTER();
2882         LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2883
2884         g_object_get(orig, pspec->name, &source, NULL);
2885
2886         player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2887         player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2888
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);
2898
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);
2903         }
2904         gst_object_unref (source);
2905
2906         MMPLAYER_FLEAVE();
2907 }
2908
2909 static gint
2910 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2911     GstStream * stream, gpointer data)
2912 {
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         GstStructure *caps_structure = NULL;
2919         gchar *caps_str = NULL;
2920
2921         LOGD("Stream type %s flags 0x%x",
2922                         gst_stream_type_get_name(stype),
2923                         gst_stream_get_stream_flags(stream));
2924         LOGD("  ID: %s", gst_stream_get_stream_id(stream));
2925
2926         if (caps) {
2927                 caps_str = gst_caps_to_string(caps);
2928                 caps_structure = gst_caps_get_structure(caps, 0);
2929                 const gchar *mime = gst_structure_get_name(caps_structure);
2930
2931                 LOGD("  caps: %s", caps_str);
2932
2933                 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2934                         if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2935                                 LOGW("skip [%s] by unsupported codec keyword [%s]",
2936                                                 mime, player->ini.unsupported_codec_keyword[idx]);
2937
2938                                 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2939                                 ret = 0;
2940                                 goto EXIT;
2941                         }
2942                 }
2943         }
2944
2945         switch (stype) {
2946         case GST_STREAM_TYPE_AUDIO:
2947         {
2948                 gint samplerate = 0;
2949                 gint channels = 0;
2950
2951                 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2952
2953                 if (caps_structure) {
2954                         gst_structure_get_int(caps_structure, "rate", &samplerate);
2955                         gst_structure_get_int(caps_structure, "channels", &channels);
2956
2957                         if (channels > 0 && samplerate == 0) {
2958                                 LOGW("Skip corrupted audio stream");
2959                                 goto EXIT;
2960                         }
2961
2962                         if (g_strrstr(caps_str, "mobile-xmf"))
2963                                 mm_player_set_attribute((MMHandleType)player, NULL,
2964                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2965                 }
2966                 break;
2967         }
2968         case GST_STREAM_TYPE_VIDEO:
2969         {
2970                 gint stype = 0;
2971                 gint width = 0;
2972
2973                 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2974
2975                 /* do not support multi track video */
2976                 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2977                         goto EXIT;
2978
2979                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2980
2981                 /* don't make video because of not required */
2982                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2983                         (!player->set_mode.video_export)) {
2984                         LOGD("no need video decoding, skip video stream");
2985                         goto EXIT;
2986                 }
2987
2988                 if (caps_structure) {
2989                         gst_structure_get_int(caps_structure, "width", &width);
2990
2991                         if (width != 0) {
2992                                 if (player->v_stream_caps) {
2993                                         gst_caps_unref(player->v_stream_caps);
2994                                         player->v_stream_caps = NULL;
2995                                 }
2996
2997                                 player->v_stream_caps = gst_caps_copy(caps);
2998                                 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
2999                         }
3000                 }
3001                 break;
3002         }
3003         case GST_STREAM_TYPE_TEXT:
3004                 type = MM_PLAYER_TRACK_TYPE_TEXT;
3005                 break;
3006         default:
3007                 LOGW("Skip not supported stream type");
3008                 goto EXIT;
3009         }
3010
3011         _mmplayer_track_update_stream(player, type, stream);
3012
3013         if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3014                 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3015                 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3016                         _mmplayer_set_audio_attrs(player, caps);
3017                 ret = 1;
3018         }
3019
3020 EXIT:
3021         g_free(caps_str);
3022         if (caps)
3023                 gst_caps_unref(caps);
3024
3025         LOGD("ret %d", ret);
3026         return ret;
3027 }
3028
3029 static gboolean
3030 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3031     GstStream * stream, gpointer data)
3032 {
3033         mmplayer_t *player = (mmplayer_t *)data;
3034         GstStreamType stype = gst_stream_get_stream_type(stream);
3035
3036         MMPLAYER_FENTER();
3037         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3038
3039         LOGD("stream type %s", gst_stream_type_get_name(stype));
3040
3041         /* public does not support audio hw decoder at the moment */
3042
3043         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3044                 LOGW("video decoder resource is already acquired, skip it.");
3045                 return TRUE;
3046         }
3047
3048         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3049                 LOGE("failed to acquire video decoder resource");
3050                 return FALSE;
3051         }
3052         player->interrupted_by_resource = FALSE;
3053         MMPLAYER_FLEAVE();
3054         return TRUE;
3055 }
3056
3057 static GstElement *
3058 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3059 {
3060         GstIterator *iter = NULL;
3061         GValue item = {0, };
3062         GstElement *ch_element = NULL;
3063         GstElementFactory *ch_factory = NULL;
3064
3065         MMPLAYER_FENTER();
3066         MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3067
3068         iter = gst_bin_iterate_recurse(bin);
3069         MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3070
3071         while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3072                 ch_element = g_value_get_object(&item);
3073                 ch_factory = gst_element_get_factory(ch_element);
3074                 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3075                 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3076                         LOGD("Find %s element", element_name);
3077                         break;
3078                 }
3079                 ch_element = NULL;
3080                 g_value_reset(&item);
3081         }
3082         gst_iterator_free(iter);
3083
3084         MMPLAYER_FLEAVE();
3085         return ch_element;
3086 }
3087
3088 static void
3089 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3090 {
3091         gchar *factory_name = NULL;
3092         mmplayer_t *player = (mmplayer_t *)data;
3093         mmplayer_gst_element_t *mainbin = NULL;
3094
3095         MMPLAYER_FENTER();
3096         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3097
3098         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3099         mainbin = player->pipeline->mainbin;
3100
3101         LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3102                 factory_name, GST_ELEMENT_NAME(element));
3103
3104         /* keep the first typefind reference only */
3105         if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {  // FIXME : not required for local playback+
3106                 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3107                 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3108
3109                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3110                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3111                 LOGD("typefind reference is added");
3112                 return;
3113         }
3114
3115         if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3116                 /* update queue2 setting */
3117                 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3118                         gint64 dur_bytes = 0L;
3119                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3120
3121                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3122                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3123
3124                         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3125                                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3126
3127                         LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3128                         /* NOTE : in case of ts streaming, player could not get the correct duration info *
3129                          *                skip the pull mode(file or ring buffering) setting. */
3130                         if (dur_bytes > 0) {
3131                                 if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) {
3132                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3133                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3134                                 }
3135                         } else {
3136                                 dur_bytes = 0;
3137                         }
3138
3139                         _mm_player_streaming_set_queue2(player->streamer,
3140                                                                                         element,
3141                                                                                         FALSE,
3142                                                                                         type,
3143                                                                                         (guint64)dur_bytes); /* no meaning at the moment */
3144                         return;
3145                 }
3146         }
3147
3148         if (g_strrstr(factory_name, "parsebin")) {
3149                 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3150                         GstElement *ch_element = __mmplayer_gst_find_child_element(child, "multiqueue");
3151                         if (ch_element) {
3152                                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3153                                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3154
3155                                 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3156                                 if (MMPLAYER_IS_STREAMING(player)) {
3157                                         _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3158                                 } else {
3159                                         g_object_set(G_OBJECT(ch_element),
3160                                                                                         "max-size-time", (guint64)(5 * GST_SECOND),
3161                                                                                         "use-interleave", FALSE, NULL);
3162                                 }
3163                         }
3164                 }
3165                 int video_codec_type = 0;
3166                 int audio_codec_type = 0;
3167
3168                 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3169                 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3170                 if (player->type_caps &&
3171                         !MMPLAYER_IS_HTTP_LIVE_STREAMING(player) &&
3172                         !MMPLAYER_IS_DASH_STREAMING(player))
3173                         g_object_set(G_OBJECT(element), "sink-caps", player->type_caps, NULL);
3174
3175                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3176                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3177
3178                 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3179                    and codec default type in ini has to be hw.
3180                  */
3181                 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3182                 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3183                         g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL);
3184                 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3185                         g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL);
3186
3187                 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3188                 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3189                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3190                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3191
3192                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3193                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3194
3195                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3196                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3197
3198                 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3199                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3200
3201         } else {
3202                 _mmplayer_gst_element_added((GstElement *)child, element, data);
3203         }
3204         return;
3205 }
3206
3207 static void
3208 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3209 {
3210         MMPLAYER_FENTER();
3211
3212         MMPLAYER_RETURN_IF_FAIL(player);
3213         MMPLAYER_RETURN_IF_FAIL(removed_element);
3214
3215         LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3216
3217         for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3218                 GList *node = player->signals[type];
3219                 while (node) {
3220                         GList *next_node = node->next;
3221                         mmplayer_signal_item_t *item = node->data;
3222                         if (item && item->obj == G_OBJECT(removed_element)) {
3223                                 player->signals[type] = g_list_delete_link(player->signals[type], node);
3224                                 MMPLAYER_FREEIF(item);
3225                         }
3226                         node = next_node;
3227                 }
3228         }
3229
3230         MMPLAYER_FLEAVE();
3231 }
3232
3233 void
3234 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3235 {
3236         mmplayer_t *player = (mmplayer_t *)data;
3237
3238         MMPLAYER_FENTER();
3239
3240         MMPLAYER_RETURN_IF_FAIL(player);
3241
3242         LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3243
3244         __mmplayer_delete_signal_connection(player, element);
3245
3246         MMPLAYER_FLEAVE();
3247 }
3248
3249 static GstElement *
3250 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3251 {
3252         GstElement *uridecodebin3 = NULL;
3253
3254         MMPLAYER_FENTER();
3255         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3256
3257         uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3258         if (!uridecodebin3) {
3259                 LOGE("failed to create uridecodebin3");
3260                 return NULL;
3261         }
3262
3263         /* get attribute */
3264         SECURE_LOGD("uri : %s", player->profile.uri);
3265
3266         /* setting property to streaming source */
3267         g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3268                         "message-forward", TRUE,
3269                         "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3270
3271         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3272                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3273
3274         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3275                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3276
3277         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3278                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3279
3280         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3281                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3282
3283         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3284                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3285
3286         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3287                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3288
3289         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3290                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3291
3292         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3293                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3294
3295         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3296                 LOGW("[DASH] this is still experimental feature");
3297
3298         MMPLAYER_FLEAVE();
3299         return uridecodebin3;
3300 }
3301
3302 static GstElement *
3303 __mmplayer_gst_make_http_src(mmplayer_t *player)
3304 {
3305 #define MAX_RETRY_COUNT 10
3306         GstElement *element = NULL;
3307         MMHandleType attrs = 0;
3308         gchar *user_agent, *cookies, **cookie_list;
3309         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3310
3311         user_agent = cookies = NULL;
3312         cookie_list = NULL;
3313
3314         MMPLAYER_FENTER();
3315         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3316
3317         /* get profile attribute */
3318         attrs = MMPLAYER_GET_ATTRS(player);
3319         if (!attrs) {
3320                 LOGE("failed to get content attribute");
3321                 return NULL;
3322         }
3323
3324         LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3325
3326         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3327         if (!element) {
3328                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3329                 return NULL;
3330         }
3331
3332         /* get attribute */
3333         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3334         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3335
3336         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3337                 http_timeout = player->ini.http_timeout;
3338
3339         /* get attribute */
3340         SECURE_LOGD("location : %s", player->profile.uri);
3341         SECURE_LOGD("cookies : %s", cookies);
3342         SECURE_LOGD("user_agent :  %s", user_agent);
3343         LOGD("timeout : %d", http_timeout);
3344
3345         /* setting property to streaming source */
3346         g_object_set(G_OBJECT(element), "location", player->profile.uri,
3347                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3348                                 "retries", MAX_RETRY_COUNT, NULL);
3349
3350         /* parsing cookies */
3351         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3352                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3353                 g_strfreev(cookie_list);
3354         }
3355
3356         if (user_agent)
3357                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3358
3359         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3360                 LOGW("[DASH] this is still experimental feature");
3361
3362         MMPLAYER_FLEAVE();
3363         return element;
3364 }
3365
3366 static GstElement *
3367 __mmplayer_gst_make_file_src(mmplayer_t *player)
3368 {
3369         GstElement *element = NULL;
3370
3371         MMPLAYER_FENTER();
3372         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3373
3374         LOGD("using filesrc for 'file://' handler");
3375         if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3376                 LOGE("failed to get storage info");
3377                 return NULL;
3378         }
3379
3380         element = gst_element_factory_make("filesrc", "source");
3381         if (!element) {
3382                 LOGE("failed to create filesrc");
3383                 return NULL;
3384         }
3385
3386         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3387
3388         MMPLAYER_FLEAVE();
3389         return element;
3390 }
3391
3392 static gboolean
3393 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3394 {
3395         mmplayer_t *player = (mmplayer_t *)data;
3396
3397         g_return_val_if_fail(player, FALSE);
3398         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3399         gst_message_ref(msg);
3400
3401         g_mutex_lock(&player->bus_msg_q_lock);
3402         g_queue_push_tail(player->bus_msg_q, msg);
3403         g_mutex_unlock(&player->bus_msg_q_lock);
3404
3405         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3406         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3407         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3408         return TRUE;
3409 }
3410
3411 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3412 {
3413         mmplayer_t *player = (mmplayer_t *)(data);
3414         GstMessage *msg = NULL;
3415
3416         MMPLAYER_FENTER();
3417         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3418                                                 player->pipeline &&
3419                                                 player->pipeline->mainbin &&
3420                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3421                                                 NULL);
3422
3423         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3424
3425         LOGD("[handle: %p] gst bus msg thread will be started.", player);
3426         while (!player->bus_msg_thread_exit) {
3427                 g_mutex_lock(&player->bus_msg_q_lock);
3428                 msg = g_queue_pop_head(player->bus_msg_q);
3429                 g_mutex_unlock(&player->bus_msg_q_lock);
3430                 if (msg == NULL) {
3431                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3432                         continue;
3433                 }
3434                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3435                 /* handle the gst msg */
3436                 __mmplayer_gst_bus_msg_callback(msg, player);
3437                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3438                 gst_message_unref(msg);
3439         }
3440
3441         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3442         MMPLAYER_FLEAVE();
3443
3444         return NULL;
3445 }
3446
3447 static int
3448 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3449 {
3450         gint64 dur_nsec = 0;
3451         gint64 pos_nsec = 0;
3452
3453         MMPLAYER_FENTER();
3454         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3455
3456         if (MMPLAYER_IS_MS_BUFF_SRC(player))
3457                 return MM_ERROR_NONE;
3458
3459         /* NOTE : duration cannot be zero except live streaming.
3460          *              Since some element could have some timing problem with querying duration, try again.
3461          */
3462         if (player->duration == 0) {
3463                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3464                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3465                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3466                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3467                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3468                                 player->pending_seek.is_pending = true;
3469                                 player->pending_seek.pos = position;
3470                                 player->seek_state = MMPLAYER_SEEK_NONE;
3471                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3472                                 return MM_ERROR_PLAYER_NO_OP;
3473                         } else {
3474                                 player->seek_state = MMPLAYER_SEEK_NONE;
3475                                 return MM_ERROR_PLAYER_SEEK;
3476                         }
3477                 }
3478                 player->duration = dur_nsec;
3479         }
3480
3481         if (player->duration > 0 && player->duration < position) {
3482                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3483                 return MM_ERROR_INVALID_ARGUMENT;
3484         }
3485
3486         if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3487                 if ((pos_nsec == player->duration) && /* current pos is end of stream  */
3488                         ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3489                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3490                         player->seek_state = MMPLAYER_SEEK_NONE;
3491                         return MM_ERROR_PLAYER_NO_OP;
3492                 }
3493         }
3494
3495         MMPLAYER_FLEAVE();
3496         return MM_ERROR_NONE;
3497 }
3498
3499 static gboolean
3500 __mmplayer_gst_check_seekable(mmplayer_t *player)
3501 {
3502         GstQuery *query = NULL;
3503         gboolean seekable = FALSE;
3504
3505         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3506                 return TRUE;
3507         }
3508
3509         query = gst_query_new_seeking(GST_FORMAT_TIME);
3510         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3511                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3512                 gst_query_unref(query);
3513
3514                 if (!seekable) {
3515                         LOGW("non-seekable content");
3516                         player->seek_state = MMPLAYER_SEEK_NONE;
3517                         return FALSE;
3518                 }
3519         } else {
3520                 LOGW("failed to get seeking query");
3521                 gst_query_unref(query); /* keep seeking operation */
3522         }
3523
3524         return TRUE;
3525 }
3526
3527 int
3528 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
3529 {
3530         GstState element_state = GST_STATE_VOID_PENDING;
3531         GstState element_pending_state = GST_STATE_VOID_PENDING;
3532         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3533
3534         MMPLAYER_FENTER();
3535
3536         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3537         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3538
3539         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3540
3541         /* set state */
3542         ret = gst_element_set_state(element, state);
3543         if (ret == GST_STATE_CHANGE_FAILURE) {
3544                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3545
3546                 /* dump state of all element */
3547                 _mmplayer_dump_pipeline_state(player);
3548
3549                 return MM_ERROR_PLAYER_INTERNAL;
3550         }
3551
3552         /* return here so state transition to be done in async mode */
3553         if (async) {
3554                 LOGD("async state transition. not waiting for state complete.");
3555                 return MM_ERROR_NONE;
3556         }
3557
3558         /* wait for state transition */
3559         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3560         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3561                 LOGE("failed to change [%s] element state to [%s] within %d sec",
3562                         GST_ELEMENT_NAME(element),
3563                         gst_element_state_get_name(state), timeout);
3564
3565                 LOGE(" [%s] state : %s   pending : %s",
3566                         GST_ELEMENT_NAME(element),
3567                         gst_element_state_get_name(element_state),
3568                         gst_element_state_get_name(element_pending_state));
3569
3570                 /* dump state of all element */
3571                 _mmplayer_dump_pipeline_state(player);
3572
3573                 return MM_ERROR_PLAYER_INTERNAL;
3574         }
3575
3576         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3577
3578         MMPLAYER_FLEAVE();
3579
3580         return MM_ERROR_NONE;
3581 }
3582
3583 int
3584 _mmplayer_gst_start(mmplayer_t *player)
3585 {
3586         int ret = MM_ERROR_NONE;
3587         gboolean async = FALSE;
3588
3589         MMPLAYER_FENTER();
3590
3591         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3592
3593         /* NOTE : if SetPosition was called before Start. do it now
3594          * streaming doesn't support it. so it should be always sync
3595          * !!create one more api to check if there is pending seek rather than checking variables
3596          */
3597         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3598                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3599                 ret = _mmplayer_gst_pause(player, FALSE);
3600                 if (ret != MM_ERROR_NONE) {
3601                         LOGE("failed to set state to PAUSED for pending seek");
3602                         return ret;
3603                 }
3604
3605                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3606                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3607                                 LOGW("failed to seek pending position. starting from the begin of content");
3608         }
3609
3610         LOGD("current state before doing transition");
3611         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3612         MMPLAYER_PRINT_STATE(player);
3613
3614         /* set pipeline state to PLAYING  */
3615         ret = _mmplayer_gst_set_state(player,
3616                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3617         if (ret != MM_ERROR_NONE) {
3618                 LOGE("failed to set state to PLAYING");
3619                 return ret;
3620         }
3621
3622         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3623
3624         /* generating debug info before returning error */
3625         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3626
3627         MMPLAYER_FLEAVE();
3628
3629         return ret;
3630 }
3631
3632 int
3633 _mmplayer_gst_stop(mmplayer_t *player)
3634 {
3635         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3636         MMHandleType attrs = 0;
3637         gboolean rewind = FALSE;
3638         gint timeout = 0;
3639         int ret = MM_ERROR_NONE;
3640
3641         MMPLAYER_FENTER();
3642
3643         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3644         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3645
3646         LOGD("current state before doing transition");
3647         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3648         MMPLAYER_PRINT_STATE(player);
3649
3650         attrs = MMPLAYER_GET_ATTRS(player);
3651         if (!attrs) {
3652                 LOGE("cannot get content attribute");
3653                 return MM_ERROR_PLAYER_INTERNAL;
3654         }
3655
3656         /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3657         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3658
3659         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3660                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3661                 rewind = TRUE;
3662
3663         if (player->es_player_push_mode)
3664                 /* disable the async state transition because there could be no data in the pipeline */
3665                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3666
3667         /* set gst state */
3668         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3669
3670         if (player->es_player_push_mode) {
3671                 /* enable the async state transition as default operation */
3672                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3673         }
3674
3675         /* return if set_state has failed */
3676         if (ret != MM_ERROR_NONE) {
3677                 LOGE("failed to set state.");
3678                 return ret;
3679         }
3680
3681         /* rewind */
3682         if (rewind) {
3683                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3684                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3685                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3686                         LOGW("failed to rewind");
3687                         ret = MM_ERROR_PLAYER_SEEK;
3688                 }
3689         }
3690
3691         /* initialize */
3692         player->sent_bos = FALSE;
3693
3694         if (player->es_player_push_mode) //for cloudgame
3695                 timeout = 0;
3696
3697         /* wait for seek to complete */
3698         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3699         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3700                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3701         } else {
3702                 LOGE("fail to stop player.");
3703                 ret = MM_ERROR_PLAYER_INTERNAL;
3704                 _mmplayer_dump_pipeline_state(player);
3705         }
3706
3707         /* generate dot file if enabled */
3708         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3709
3710         MMPLAYER_FLEAVE();
3711
3712         return ret;
3713 }
3714
3715 int
3716 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3717 {
3718         int ret = MM_ERROR_NONE;
3719
3720         MMPLAYER_FENTER();
3721
3722         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3723         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3724
3725         LOGD("current state before doing transition");
3726         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3727         MMPLAYER_PRINT_STATE(player);
3728
3729         /* set pipeline status to PAUSED */
3730         ret = _mmplayer_gst_set_state(player,
3731                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3732
3733         if (async)
3734                 goto EXIT;
3735
3736         if (ret != MM_ERROR_NONE) {
3737                 GstMessage *msg = NULL;
3738                 GTimer *timer = NULL;
3739                 gdouble MAX_TIMEOUT_SEC = 3;
3740
3741                 LOGE("failed to set state to PAUSED");
3742
3743                 if (!player->bus_watcher) {
3744                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3745                         return ret;
3746                 }
3747
3748                 if (player->msg_posted) {
3749                         LOGE("error msg is already posted.");
3750                         return ret;
3751                 }
3752
3753                 timer = g_timer_new();
3754                 g_timer_start(timer);
3755
3756                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3757
3758                 do {
3759                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3760                         if (msg) {
3761                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3762                                         GError *error = NULL;
3763
3764                                         /* parse error code */
3765                                         gst_message_parse_error(msg, &error, NULL);
3766
3767                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3768                                                 /* Note : the streaming error from the streaming source is handled
3769                                                         *   using __mmplayer_handle_streaming_error.
3770                                                         */
3771                                                 __mmplayer_handle_streaming_error(player, msg);
3772
3773                                         } else if (error) {
3774                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3775
3776                                                 if (error->domain == GST_STREAM_ERROR)
3777                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3778                                                 else if (error->domain == GST_RESOURCE_ERROR)
3779                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3780                                                 else if (error->domain == GST_LIBRARY_ERROR)
3781                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3782                                                 else if (error->domain == GST_CORE_ERROR)
3783                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3784
3785                                                 g_error_free(error);
3786                                         }
3787                                         player->msg_posted = TRUE;
3788                                 }
3789                                 gst_message_unref(msg);
3790                         }
3791                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3792                 /* clean */
3793                 gst_object_unref(bus);
3794                 g_timer_stop(timer);
3795                 g_timer_destroy(timer);
3796
3797                 return ret;
3798         }
3799
3800         if (MMPLAYER_USE_DECODEBIN(player)) {
3801                 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3802                         (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3803                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3804         }
3805
3806         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3807
3808 EXIT:
3809         /* generate dot file before returning error */
3810         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3811
3812         MMPLAYER_FLEAVE();
3813
3814         return ret;
3815 }
3816
3817 int
3818 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3819 {
3820         int ret = MM_ERROR_NONE;
3821         gint timeout = 0;
3822
3823         MMPLAYER_FENTER();
3824
3825         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3826                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3827
3828         LOGD("current state before doing transition");
3829         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3830         MMPLAYER_PRINT_STATE(player);
3831
3832         if (async)
3833                 LOGD("do async state transition to PLAYING");
3834
3835         /* set pipeline state to PLAYING */
3836         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3837
3838         ret = _mmplayer_gst_set_state(player,
3839                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3840         if (ret != MM_ERROR_NONE) {
3841                 LOGE("failed to set state to PLAYING");
3842                 goto EXIT;
3843         }
3844
3845         if (!async)
3846                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3847
3848 EXIT:
3849         /* generate dot file */
3850         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3851
3852         MMPLAYER_FLEAVE();
3853
3854         return ret;
3855 }
3856
3857 /* sending event to one of sinkelements */
3858 gboolean
3859 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3860 {
3861         GstEvent *event2 = NULL;
3862         GList *sinks = NULL;
3863         gboolean res = FALSE;
3864         MMPLAYER_FENTER();
3865
3866         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3867         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3868
3869         /* While adding subtitles in live feeds seek is getting called.
3870            Adding defensive check in framework layer.*/
3871         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3872                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3873                         LOGE("Should not send seek event during live playback");
3874                         return TRUE;
3875                 }
3876         }
3877
3878         if (player->play_subtitle)
3879                 event2 = gst_event_copy((const GstEvent *)event);
3880
3881         sinks = player->sink_elements;
3882         while (sinks) {
3883                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3884
3885                 if (GST_IS_ELEMENT(sink)) {
3886                         /* keep ref to the event */
3887                         gst_event_ref(event);
3888
3889                         if ((res = gst_element_send_event(sink, event))) {
3890                                 LOGD("sending event[%s] to sink element [%s] success!",
3891                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3892
3893                                 /* rtsp case, async_done is not called after seek during pause state */
3894                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3895                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3896                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3897                                                         LOGD("RTSP seek completed, after pause state..");
3898                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3899                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3900                                                 }
3901
3902                                         }
3903                                 }
3904
3905                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3906                                         sinks = g_list_next(sinks);
3907                                         continue;
3908                                 } else {
3909                                         break;
3910                                 }
3911                         }
3912
3913                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3914                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3915                 }
3916
3917                 sinks = g_list_next(sinks);
3918         }
3919
3920         /* Note : Textbin is not linked to the video or audio bin.
3921          * It needs to send the event to the text sink seperately.
3922          */
3923         if (player->play_subtitle && player->pipeline) {
3924                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3925
3926                 if (GST_IS_ELEMENT(text_sink)) {
3927                         /* keep ref to the event */
3928                         gst_event_ref(event2);
3929
3930                         if ((res = gst_element_send_event(text_sink, event2)))
3931                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3932                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3933                         else
3934                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3935                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3936
3937                         gst_event_unref(event2);
3938                 }
3939         }
3940
3941         gst_event_unref(event);
3942
3943         MMPLAYER_FLEAVE();
3944
3945         return res;
3946 }
3947
3948 gboolean
3949 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3950                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3951                         gint64 cur, GstSeekType stop_type, gint64 stop)
3952 {
3953         GstEvent *event = NULL;
3954         gboolean result = FALSE;
3955
3956         MMPLAYER_FENTER();
3957
3958         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3959
3960         if (player->pipeline && player->pipeline->textbin)
3961                 __mmplayer_drop_subtitle(player, FALSE);
3962
3963         event = gst_event_new_seek(rate, format, flags, cur_type,
3964                 cur, stop_type, stop);
3965
3966         result = _mmplayer_gst_send_event_to_sink(player, event);
3967
3968         MMPLAYER_FLEAVE();
3969
3970         return result;
3971 }
3972
3973 int
3974 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3975 {
3976         int ret = MM_ERROR_NONE;
3977         gint64 pos_nsec = 0;
3978         gboolean accurate = FALSE;
3979         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3980
3981         MMPLAYER_FENTER();
3982         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3983         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3984
3985         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3986                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3987                 goto PENDING;
3988
3989         ret = __mmplayer_gst_check_position(player, position);
3990         if (ret != MM_ERROR_NONE) {
3991                 LOGW("result of check position info 0x%X", ret);
3992                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3993         }
3994
3995         if (!__mmplayer_gst_check_seekable(player))
3996                 return MM_ERROR_PLAYER_NO_OP;
3997
3998         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3999                                 position, player->playback_rate, player->duration);
4000
4001         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
4002            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
4003            This causes problem is position calculation during normal pause resume scenarios also.
4004            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
4005         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
4006                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
4007                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
4008                         LOGW("getting current position failed in seek");
4009
4010                 player->last_position = pos_nsec;
4011                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
4012         }
4013
4014         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4015                 LOGD("not completed seek");
4016                 return MM_ERROR_PLAYER_DOING_SEEK;
4017         }
4018
4019         if (!internal_called)
4020                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
4021
4022         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
4023                 that's why set position through property. */
4024         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
4025                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
4026                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
4027                 (!player->videodec_linked) && (!player->audiodec_linked)) {
4028
4029                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
4030                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
4031
4032                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
4033                 player->seek_state = MMPLAYER_SEEK_NONE;
4034                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
4035         } else {
4036                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
4037                 if (accurate)
4038                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
4039                 else
4040                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
4041
4042                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
4043                                                 GST_FORMAT_TIME, seek_flags,
4044                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4045                         LOGE("failed to set position");
4046                         goto SEEK_ERROR;
4047                 }
4048         }
4049
4050         /* NOTE : store last seeking point to overcome some bad operation
4051          *     (returning zero when getting current position) of some elements
4052          */
4053         player->last_position = position;
4054
4055         /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4056         if (player->playback_rate > 1.0)
4057                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4058
4059         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4060                 LOGD("buffering should be reset after seeking");
4061                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4062                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4063         }
4064
4065         MMPLAYER_FLEAVE();
4066         return MM_ERROR_NONE;
4067
4068 PENDING:
4069         player->pending_seek.is_pending = true;
4070         player->pending_seek.pos = position;
4071
4072         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4073                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4074                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4075                 player->pending_seek.pos);
4076
4077         return MM_ERROR_NONE;
4078
4079 SEEK_ERROR:
4080         player->seek_state = MMPLAYER_SEEK_NONE;
4081         return MM_ERROR_PLAYER_SEEK;
4082 }
4083
4084 int
4085 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4086 {
4087 #define TRICKPLAY_OFFSET GST_MSECOND
4088
4089         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4090         gint64 pos_nsec = 0;
4091         gboolean ret = TRUE;
4092
4093         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4094                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4095
4096         current_state = MMPLAYER_CURRENT_STATE(player);
4097
4098         /* NOTE : query position except paused state to overcome some bad operation
4099          * please refer to below comments in details
4100          */
4101         if (current_state != MM_PLAYER_STATE_PAUSED)
4102                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4103
4104         /* NOTE : get last point to overcome some bad operation of some elements
4105          *(returning zero when getting current position in paused state
4106          * and when failed to get position during seeking
4107          */
4108         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4109                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4110
4111                 if (player->playback_rate < 0.0)
4112                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4113                 else
4114                         pos_nsec = player->last_position;
4115
4116                 if (!ret)
4117                         pos_nsec = player->last_position;
4118                 else
4119                         player->last_position = pos_nsec;
4120
4121                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4122
4123         } else {
4124                 if (player->duration > 0 && pos_nsec > player->duration)
4125                         pos_nsec = player->duration;
4126
4127                 player->last_position = pos_nsec;
4128         }
4129
4130         *position = pos_nsec;
4131
4132         return MM_ERROR_NONE;
4133 }
4134
4135 int
4136 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4137 {
4138 #define STREAMING_IS_FINISHED   0
4139 #define BUFFERING_MAX_PER       100
4140 #define DEFAULT_PER_VALUE       -1
4141 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4142
4143         mmplayer_gst_element_t *mainbin = NULL;
4144         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4145         gint64 buffered_total = 0;
4146         gint64 position = 0;
4147         gint buffered_sec = -1;
4148         GstBufferingMode mode = GST_BUFFERING_STREAM;
4149         gint64 content_size_time = player->duration;
4150         guint64 content_size_bytes = player->http_content_size;
4151
4152         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4153                                                 player->pipeline &&
4154                                                 player->pipeline->mainbin,
4155                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4156
4157         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4158
4159         *start_pos = 0;
4160         *end_pos = 0;
4161
4162         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4163                 /* and rtsp is not ready yet. */
4164                 LOGW("it's only used for http streaming case");
4165                 return MM_ERROR_PLAYER_NO_OP;
4166         }
4167
4168         if (content_size_time <= 0 || content_size_bytes <= 0) {
4169                 LOGW("there is no content size");
4170                 return MM_ERROR_NONE;
4171         }
4172
4173         if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4174                 LOGW("fail to get current position");
4175                 return MM_ERROR_NONE;
4176         }
4177
4178         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4179                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4180
4181         mainbin = player->pipeline->mainbin;
4182         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4183
4184         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4185                 GstQuery *query = NULL;
4186                 gint byte_in_rate = 0, byte_out_rate = 0;
4187                 gint64 estimated_total = 0;
4188
4189                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4190                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4191                         LOGW("fail to get buffering query from queue2");
4192                         if (query)
4193                                 gst_query_unref(query);
4194                         return MM_ERROR_NONE;
4195                 }
4196
4197                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4198                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4199
4200                 if (mode == GST_BUFFERING_STREAM) {
4201                         /* using only queue in case of push mode(ts / mp3) */
4202                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4203                                 GST_FORMAT_BYTES, &buffered_total)) {
4204                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4205                                 end_per = 100 * buffered_total / content_size_bytes;
4206                         }
4207                 } else {
4208                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4209                         guint idx = 0;
4210                         guint num_of_ranges = 0;
4211                         gint64 start_byte = 0, stop_byte = 0;
4212
4213                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4214                         if (estimated_total != STREAMING_IS_FINISHED) {
4215                                 /* buffered size info from queue2 */
4216                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4217                                 for (idx = 0; idx < num_of_ranges; idx++) {
4218                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4219                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4220
4221                                         buffered_total += (stop_byte - start_byte);
4222                                 }
4223                         } else {
4224                                 end_per = BUFFERING_MAX_PER;
4225                         }
4226                 }
4227                 gst_query_unref(query);
4228         }
4229
4230         if (end_per == DEFAULT_PER_VALUE) {
4231                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4232                 if (dur_sec > 0) {
4233                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4234
4235                         /* buffered size info from multiqueue */
4236                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4237                                 guint curr_size_bytes = 0;
4238                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4239                                         "curr-size-bytes", &curr_size_bytes, NULL);
4240                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4241                                 buffered_total += curr_size_bytes;
4242                         }
4243
4244                         if (avg_byterate > 0)
4245                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4246                         else if (player->total_maximum_bitrate > 0)
4247                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4248                         else if (player->total_bitrate > 0)
4249                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4250
4251                         if (buffered_sec >= 0)
4252                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4253                 }
4254         }
4255
4256         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4257         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4258
4259         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4260                 buffered_total, buffered_sec, *start_pos, *end_pos);
4261
4262         return MM_ERROR_NONE;
4263 }
4264
4265 GstElement *
4266 _mmplayer_gst_create_source(mmplayer_t *player)
4267 {
4268         GstElement *element = NULL;
4269
4270         MMPLAYER_FENTER();
4271         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4272                                 player->pipeline->mainbin, NULL);
4273
4274         /* setup source for gapless play */
4275         switch (player->profile.uri_type) {
4276         /* file source */
4277         case MM_PLAYER_URI_TYPE_FILE:
4278                 element = __mmplayer_gst_make_file_src(player);
4279                 break;
4280         case MM_PLAYER_URI_TYPE_URL_HTTP:
4281                 element = __mmplayer_gst_make_http_src(player);
4282                 break;
4283         default:
4284                 LOGE("not support uri type %d", player->profile.uri_type);
4285                 break;
4286         }
4287
4288         if (!element) {
4289                 LOGE("failed to create source element");
4290                 return NULL;
4291         }
4292
4293         MMPLAYER_FLEAVE();
4294         return element;
4295 }
4296
4297 int
4298 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4299 {
4300         MMPLAYER_FENTER();
4301         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4302                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4303
4304         SECURE_LOGD("uri : %s", player->profile.uri);
4305
4306         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4307
4308         if ((player->v_stream_caps) &&
4309                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4310                 return MM_ERROR_PLAYER_INTERNAL;
4311
4312         if ((player->a_stream_caps) &&
4313                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4314                 return MM_ERROR_PLAYER_INTERNAL;
4315
4316         if ((player->s_stream_caps) &&
4317                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4318                 return MM_ERROR_PLAYER_INTERNAL;
4319
4320         MMPLAYER_FLEAVE();
4321         return MM_ERROR_NONE;
4322 }
4323
4324 int
4325 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4326 {
4327         mmplayer_gst_element_t *mainbin = NULL;
4328         GstElement *autoplug_elem = NULL;
4329
4330         MMPLAYER_FENTER();
4331         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4332                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4333
4334         mainbin = player->pipeline->mainbin;
4335
4336         LOGD("uri type %d", player->profile.uri_type);
4337
4338         if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4339                 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4340                 return MM_ERROR_PLAYER_INTERNAL;
4341         }
4342
4343         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4344                 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4345         }
4346
4347         autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4348         if (!autoplug_elem) {
4349                 LOGE("failed to create uridecodebin3 element");
4350                 goto ERROR;
4351         }
4352
4353         LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4354         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4355         mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4356
4357         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4358                 LOGE("failed to add uridecodebin to pipeline");
4359                 goto ERROR;
4360         }
4361
4362         /* FIXME: required ?*/
4363         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4364         mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4365         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4366
4367         if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4368                 LOGE("failed to create fakesink");
4369                 goto ERROR;
4370         }
4371         GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4372
4373         /* take ownership of fakesink. we are reusing it */
4374         gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4375
4376         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4377                 LOGE("failed to add fakesink to bin");
4378                 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4379                 goto ERROR;
4380         }
4381
4382         MMPLAYER_FLEAVE();
4383         return MM_ERROR_NONE;
4384
4385 ERROR:
4386
4387         if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4388                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4389
4390         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4391                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4392
4393         mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4394         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4395
4396         return MM_ERROR_PLAYER_INTERNAL;
4397 }
4398
4399 int
4400 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4401 {
4402         mmplayer_gst_element_t *mainbin = NULL;
4403         GstElement *src_elem = NULL;
4404         GstElement *autoplug_elem = NULL;
4405         GList *element_bucket = NULL;
4406         main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4407
4408         MMPLAYER_FENTER();
4409         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4410                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4411
4412         LOGD("uri type %d", player->profile.uri_type);
4413
4414         /* create source element */
4415         switch (player->profile.uri_type) {
4416         case MM_PLAYER_URI_TYPE_URL_RTSP:
4417                 src_elem = __mmplayer_gst_make_rtsp_src(player);
4418                 break;
4419         case MM_PLAYER_URI_TYPE_URL_HTTP:
4420                 src_elem = __mmplayer_gst_make_http_src(player);
4421                 break;
4422         case MM_PLAYER_URI_TYPE_FILE:
4423                 src_elem = __mmplayer_gst_make_file_src(player);
4424                 break;
4425         case MM_PLAYER_URI_TYPE_SS:
4426                 {
4427                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4428                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4429                         if (!src_elem) {
4430                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4431                                 break;
4432                         }
4433
4434                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4435                                 LOGD("get timeout from ini");
4436                                 http_timeout = player->ini.http_timeout;
4437                         }
4438
4439                         /* setting property to streaming source */
4440                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4441                 }
4442                 break;
4443         case MM_PLAYER_URI_TYPE_MEM:
4444                 {
4445                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4446
4447                         src_elem = gst_element_factory_make("appsrc", "mem-source");
4448                         if (!src_elem) {
4449                                 LOGE("failed to create appsrc element");
4450                                 break;
4451                         }
4452
4453                         g_object_set(src_elem, "stream-type", stream_type,
4454                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4455
4456                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4457                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4458                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4459                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4460                 }
4461                 break;
4462         default:
4463                 LOGE("not support uri type");
4464                 break;
4465         }
4466
4467         if (!src_elem) {
4468                 LOGE("failed to create source element");
4469                 return MM_ERROR_PLAYER_INTERNAL;
4470         }
4471
4472         mainbin = player->pipeline->mainbin;
4473
4474         /* take source element */
4475         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4476
4477         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4478         mainbin[MMPLAYER_M_SRC].gst = src_elem;
4479         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4480
4481         /* create next element for auto-plugging */
4482         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4483                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4484                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4485                 if (!autoplug_elem) {
4486                         LOGE("failed to create typefind element");
4487                         goto ERROR;
4488                 }
4489
4490                 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4491                                                                         G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4492         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4493                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4494                 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4495                 if (!autoplug_elem) {
4496                         LOGE("failed to create decodebin");
4497                         goto ERROR;
4498                 }
4499
4500                 /* default size of mq in decodebin is 2M
4501                  * but it can cause blocking issue during seeking depends on content. */
4502                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4503         }
4504
4505         if (autoplug_elem) {
4506                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4507                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4508                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4509
4510                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4511         }
4512
4513         /* add elements to pipeline */
4514         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4515                 LOGE("failed to add elements to pipeline");
4516                 goto ERROR;
4517         }
4518
4519         /* linking elements in the bucket by added order. */
4520         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4521                 LOGE("failed to link some elements");
4522                 goto ERROR;
4523         }
4524
4525         /* FIXME: need to check whether this is required or not. */
4526         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4527                 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4528                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4529                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4530                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4531
4532                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4533                         LOGE("failed to create fakesink");
4534                         goto ERROR;
4535                 }
4536                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4537
4538                 /* take ownership of fakesink. we are reusing it */
4539                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4540
4541                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4542                         LOGE("failed to add fakesink to bin");
4543                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4544                         goto ERROR;
4545                 }
4546         }
4547
4548         g_list_free(element_bucket);
4549
4550         MMPLAYER_FLEAVE();
4551         return MM_ERROR_NONE;
4552
4553 ERROR:
4554         g_list_free(element_bucket);
4555
4556         if (mainbin[MMPLAYER_M_SRC].gst)
4557                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4558
4559         if (mainbin[autoplug_elem_id].gst)
4560                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4561
4562         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4563                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4564
4565         mainbin[MMPLAYER_M_SRC].gst = NULL;
4566         mainbin[autoplug_elem_id].gst = NULL;
4567         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4568
4569         return MM_ERROR_PLAYER_INTERNAL;
4570 }
4571
4572 int
4573 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4574 {
4575         GstBus  *bus = NULL;
4576         mmplayer_gst_element_t *mainbin = NULL;
4577
4578         MMPLAYER_FENTER();
4579         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4580                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4581
4582         mainbin = player->pipeline->mainbin;
4583
4584         /* connect bus callback */
4585         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4586         if (!bus) {
4587                 LOGE("cannot get bus from pipeline");
4588                 return MM_ERROR_PLAYER_INTERNAL;
4589         }
4590
4591         player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4592                                                         (GstBusFunc)__mmplayer_gst_msg_push, player,
4593                                                         (GDestroyNotify)_mmplayer_watcher_removed_notify);
4594         if (player->bus_watcher == 0) {
4595                 LOGE("failed to add bus watch");
4596                 return MM_ERROR_PLAYER_INTERNAL;
4597         }
4598
4599         g_mutex_init(&player->bus_watcher_mutex);
4600         g_cond_init(&player->bus_watcher_cond);
4601
4602         player->context.thread_default = g_main_context_get_thread_default();
4603         if (player->context.thread_default == NULL) {
4604                 player->context.thread_default = g_main_context_default();
4605                 LOGD("thread-default context is the global default context");
4606         }
4607         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4608
4609         /* set sync handler to get tag synchronously */
4610         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4611         gst_object_unref(GST_OBJECT(bus));
4612
4613         /* create gst bus_msb_cb thread */
4614         g_mutex_init(&player->bus_msg_thread_mutex);
4615         g_cond_init(&player->bus_msg_thread_cond);
4616         player->bus_msg_thread_exit = FALSE;
4617         player->bus_msg_thread =
4618                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4619         if (!player->bus_msg_thread) {
4620                 LOGE("failed to create gst BUS msg thread");
4621                 g_mutex_clear(&player->bus_msg_thread_mutex);
4622                 g_cond_clear(&player->bus_msg_thread_cond);
4623                 return MM_ERROR_PLAYER_INTERNAL;
4624         }
4625
4626         MMPLAYER_FLEAVE();
4627         return MM_ERROR_NONE;
4628 }
4629
4630 void
4631 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4632 {
4633         int ret = MM_ERROR_NONE;
4634         mmplayer_gst_element_t *mainbin = NULL;
4635         MMMessageParamType msg_param = {0,};
4636         GstElement *element = NULL;
4637         MMHandleType attrs = 0;
4638         char *uri = NULL;
4639         main_element_id_e elem_idx = MMPLAYER_M_NUM;
4640
4641         MMPLAYER_FENTER();
4642
4643         if (!player || !player->pipeline || !player->pipeline->mainbin) {
4644                 LOGE("player is not initialized");
4645                 goto ERROR;
4646         }
4647
4648         mainbin = player->pipeline->mainbin;
4649         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4650
4651         attrs = MMPLAYER_GET_ATTRS(player);
4652         if (!attrs) {
4653                 LOGE("fail to get attributes");
4654                 goto ERROR;
4655         }
4656
4657         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4658
4659         if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4660                 LOGE("failed to parse profile");
4661                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4662                 goto ERROR;
4663         }
4664
4665         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4666                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4667                 LOGE("dash or hls is not supportable");
4668                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4669                 goto ERROR;
4670         }
4671
4672         if (!MMPLAYER_USE_DECODEBIN(player)) {
4673                 ret = _mmplayer_gst_build_pipeline_with_src(player);
4674                 if (ret != MM_ERROR_NONE)
4675                         goto ERROR;
4676
4677                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4678                         LOGE("Failed to change state of uridecodebin3 element");
4679                         goto ERROR;
4680                 }
4681                 goto DONE;
4682         }
4683
4684         element = _mmplayer_gst_create_source(player);
4685         if (!element) {
4686                 LOGE("no source element was created");
4687                 goto ERROR;
4688         }
4689
4690         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4691                 LOGE("failed to add source element to pipeline");
4692                 gst_object_unref(GST_OBJECT(element));
4693                 element = NULL;
4694                 goto ERROR;
4695         }
4696
4697         /* take source element */
4698         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4699         mainbin[MMPLAYER_M_SRC].gst = element;
4700
4701         element = NULL;
4702
4703         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4704                 if (player->streamer == NULL) {
4705                         player->streamer = _mm_player_streaming_create();
4706                         _mm_player_streaming_initialize(player->streamer, TRUE);
4707                 }
4708
4709                 elem_idx = MMPLAYER_M_TYPEFIND;
4710                 element = gst_element_factory_make("typefind", "typefinder");
4711                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4712                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4713         } else {
4714                 elem_idx = MMPLAYER_M_AUTOPLUG;
4715                 element = _mmplayer_gst_make_decodebin(player);
4716         }
4717
4718         /* check autoplug element is OK */
4719         if (!element) {
4720                 LOGE("can not create element(%d)", elem_idx);
4721                 goto ERROR;
4722         }
4723
4724         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4725                 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4726                 gst_object_unref(GST_OBJECT(element));
4727                 element = NULL;
4728                 goto ERROR;
4729         }
4730
4731         mainbin[elem_idx].id = elem_idx;
4732         mainbin[elem_idx].gst = element;
4733
4734         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4735                 LOGE("Failed to link src - autoplug(or typefind)");
4736                 goto ERROR;
4737         }
4738
4739         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4740                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {  // ????
4741                         LOGE("Failed to change state of src element");
4742                         goto ERROR;
4743                 }
4744         } else {
4745                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4746                         LOGE("Failed to change state of decodebin");
4747                         goto ERROR;
4748                 }
4749         }
4750
4751         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4752                 LOGE("Failed to change state of src element");
4753                 goto ERROR;
4754         }
4755
4756 DONE:
4757         player->gapless.stream_changed = TRUE;
4758         player->gapless.running = TRUE;
4759         MMPLAYER_FLEAVE();
4760         return;
4761
4762 ERROR:
4763         if (player) {
4764                 _mmplayer_set_reconfigure_state(player, FALSE);
4765                 if (!player->msg_posted) {
4766                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4767                         player->msg_posted = TRUE;
4768                 }
4769         }
4770         return;
4771 }