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