89d50f302864d17c5ca172ac0a61dc302dcde76b
[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 = {0, };
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                                 break;\
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 static 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         attrs = MMPLAYER_GET_ATTRS(player);
2843         if (!attrs) {
2844                 LOGE("failed to get content attribute");
2845                 return;
2846         }
2847
2848         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2849         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2850
2851         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2852                 http_timeout = player->ini.http_timeout;
2853
2854         SECURE_LOGD("cookies : %s", cookies);
2855         SECURE_LOGD("user_agent :  %s", user_agent);
2856         LOGD("timeout : %d", http_timeout);
2857
2858         g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2859
2860         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2861                 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2862                 g_strfreev(cookie_list);
2863         }
2864
2865         if (user_agent)
2866                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2867
2868         MMPLAYER_FLEAVE();
2869         return;
2870 }
2871
2872 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2873 {
2874         mmplayer_t *player = (mmplayer_t *)data;
2875         gchar *user_agent = NULL;
2876         MMHandleType attrs = 0;
2877
2878         MMPLAYER_FENTER();
2879         MMPLAYER_RETURN_IF_FAIL(player);
2880
2881         attrs = MMPLAYER_GET_ATTRS(player);
2882         if (!attrs) {
2883                 LOGE("failed to get content attribute");
2884                 return;
2885         }
2886
2887         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2888
2889         SECURE_LOGD("user_agent : %s", user_agent);
2890
2891         if (user_agent)
2892                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2893
2894         MMPLAYER_FLEAVE();
2895 }
2896
2897 static void
2898 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2899 {
2900         mmplayer_t *player = (mmplayer_t *)data;
2901         GstElement *source = NULL;
2902
2903         MMPLAYER_FENTER();
2904         LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2905
2906         g_object_get(orig, pspec->name, &source, NULL);
2907
2908         player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2909         player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2910
2911         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2912                 __mmplayer_http_src_setup(source, data);
2913         } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2914                 __mmplayer_rtsp_src_setup(source, data);
2915         } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2916                 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2917         } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2918                 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2919                         "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2920
2921                 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2922                                                 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2923                 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2924                                                 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2925         }
2926         gst_object_unref (source);
2927
2928         MMPLAYER_FLEAVE();
2929 }
2930
2931 static gint
2932 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2933     GstStream * stream, gpointer data)
2934 {
2935         gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2936         GstStreamType stype = gst_stream_get_stream_type(stream);
2937         mmplayer_t *player = (mmplayer_t *)data;
2938         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2939         GstCaps *caps = gst_stream_get_caps(stream);
2940         gchar *caps_str = NULL;
2941
2942         LOGD("Stream type %s flags 0x%x",
2943                         gst_stream_type_get_name(stype),
2944                         gst_stream_get_stream_flags(stream));
2945         LOGD("  ID: %s", gst_stream_get_stream_id(stream));
2946
2947         if (caps) {
2948                 caps_str = gst_caps_to_string(caps);
2949                 LOGD("  caps: %s", caps_str);
2950         }
2951
2952         switch (stype) {
2953         case GST_STREAM_TYPE_AUDIO:
2954         {
2955                 GstStructure *caps_structure = NULL;
2956                 gint samplerate = 0;
2957                 gint channels = 0;
2958
2959                 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2960
2961                 if (caps) {
2962                         caps_structure = gst_caps_get_structure(caps, 0);
2963                         gst_structure_get_int(caps_structure, "rate", &samplerate);
2964                         gst_structure_get_int(caps_structure, "channels", &channels);
2965
2966                         if (channels > 0 && samplerate == 0) {
2967                                 LOGW("Skip corrupted audio stream");
2968                                 goto EXIT;
2969                         }
2970
2971                         if (g_strrstr(caps_str, "mobile-xmf"))
2972                                 mm_player_set_attribute((MMHandleType)player, NULL,
2973                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2974                 }
2975                 break;
2976         }
2977         case GST_STREAM_TYPE_VIDEO:
2978         {
2979                 GstStructure *caps_structure = NULL;
2980                 gint stype = 0;
2981                 gint width = 0;
2982
2983                 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2984
2985                 /* do not support multi track video */
2986                 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2987                         goto EXIT;
2988
2989                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2990
2991                 /* don't make video because of not required */
2992                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2993                         (!player->set_mode.video_export)) {
2994                         LOGD("no need video decoding, skip video stream");
2995                         goto EXIT;
2996                 }
2997
2998                 if (caps) {
2999                         caps_structure = gst_caps_get_structure(caps, 0);
3000                         gst_structure_get_int(caps_structure, "width", &width);
3001
3002                         if (width != 0) {
3003                                 if (player->v_stream_caps) {
3004                                         gst_caps_unref(player->v_stream_caps);
3005                                         player->v_stream_caps = NULL;
3006                                 }
3007
3008                                 player->v_stream_caps = gst_caps_copy(caps);
3009                                 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3010                         }
3011                 }
3012                 break;
3013         }
3014         case GST_STREAM_TYPE_TEXT:
3015                 type = MM_PLAYER_TRACK_TYPE_TEXT;
3016                 break;
3017         default:
3018                 LOGW("Skip not supported stream type");
3019                 goto EXIT;
3020         }
3021
3022         _mmplayer_track_update_stream(player, type, stream);
3023
3024         if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3025                 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3026                 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3027                         _mmplayer_set_audio_attrs(player, caps);
3028                 ret = 1;
3029         }
3030
3031 EXIT:
3032         g_free(caps_str);
3033         if (caps)
3034                 gst_caps_unref(caps);
3035
3036         LOGD("ret %d", ret);
3037         return ret;
3038 }
3039
3040 static gboolean
3041 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3042     GstStream * stream, gpointer data)
3043 {
3044         mmplayer_t *player = (mmplayer_t *)data;
3045         GstStreamType stype = gst_stream_get_stream_type(stream);
3046
3047         MMPLAYER_FENTER();
3048         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3049
3050         LOGD("stream type %s", gst_stream_type_get_name(stype));
3051
3052         /* public does not support audio hw decoder at the moment */
3053
3054         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3055                 LOGW("video decoder resource is already acquired, skip it.");
3056                 return TRUE;
3057         }
3058
3059         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3060                 LOGE("failed to acquire video decoder resource");
3061                 return FALSE;
3062         }
3063         player->interrupted_by_resource = FALSE;
3064         MMPLAYER_FLEAVE();
3065         return TRUE;
3066 }
3067
3068 static void
3069 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3070 {
3071         gchar *factory_name = NULL;
3072         mmplayer_t *player = (mmplayer_t *)data;
3073         mmplayer_gst_element_t *mainbin = NULL;
3074
3075         MMPLAYER_FENTER();
3076         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3077
3078         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3079         mainbin = player->pipeline->mainbin;
3080
3081         LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
3082                 factory_name, GST_ELEMENT_NAME(element));
3083
3084         /* keep the first typefind reference only */
3085         if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {  // FIXME : not required for local playback+
3086                 mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
3087                 mainbin[MMPLAYER_M_TYPEFIND].gst = element;
3088
3089                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3090                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3091                 LOGD("typefind reference is added");
3092                 return;
3093         }
3094
3095         if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) {
3096                 /* update queue2 setting */
3097                 if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3098                         gint64 dur_bytes = 0L;
3099                         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
3100
3101                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
3102                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
3103
3104                         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3105                                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
3106
3107                         LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes);
3108                         /* NOTE : in case of ts streaming, player could not get the correct duration info *
3109                          *                skip the pull mode(file or ring buffering) setting. */
3110                         if (dur_bytes > 0) {
3111                                 if (!(__mmplayer_is_mpegts_type(player->type) || __mmplayer_is_hls_type(player->type)
3112                                         || __mmplayer_is_mp3_type(player->type))) {
3113                                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
3114                                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
3115                                 }
3116                         } else {
3117                                 dur_bytes = 0;
3118                         }
3119
3120                         _mm_player_streaming_set_queue2(player->streamer,
3121                                                                                         element,
3122                                                                                         FALSE,
3123                                                                                         type,
3124                                                                                         (guint64)dur_bytes); /* no meaning at the moment */
3125                         return;
3126                 }
3127
3128                 /* update mq setting */
3129                 if (g_strrstr(factory_name, "parsebin") && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) {
3130                         GstIterator *iter = NULL;
3131                         GValue item = {0, };
3132                         GstElement *ch_element = NULL;
3133                         GstElementFactory *ch_factory = NULL;
3134
3135                         iter = gst_bin_iterate_recurse(child);
3136                         if (iter != NULL) {
3137                                 while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3138                                         ch_element = g_value_get_object(&item);
3139                                         ch_factory = gst_element_get_factory(ch_element);
3140                                         LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3141                                         if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) {
3142                                                 LOGD("get multiqueue");
3143                                                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
3144                                                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element;
3145
3146                                                 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
3147                                                 _mm_player_streaming_set_multiqueue(player->streamer, ch_element);
3148                                                 g_value_reset(&item);
3149                                                 break;
3150                                         }
3151                                         g_value_reset(&item);
3152                                 }
3153                                 gst_iterator_free(iter);
3154                         }
3155                 }
3156         }
3157
3158         if (g_strrstr(factory_name, "parsebin")) {
3159                 int video_codec_type = 0;
3160                 int audio_codec_type = 0;
3161
3162                 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL);
3163                 g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL);
3164                 if (player->type_caps &&
3165                         !MMPLAYER_IS_HTTP_LIVE_STREAMING(player) &&
3166                         !MMPLAYER_IS_DASH_STREAMING(player))
3167                         g_object_set(G_OBJECT(element), "sink-caps", player->type_caps, NULL);
3168
3169                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3170                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3171
3172                 /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder
3173                    and codec default type in ini has to be hw.
3174                  */
3175                 LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3176                 if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3177                         g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL);
3178                 if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3179                         g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL);
3180
3181                 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
3182                 mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
3183                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3184                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3185
3186                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3187                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
3188
3189                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
3190                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3191
3192                 _mmplayer_add_signal_connection(player, G_OBJECT(child),
3193                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3194
3195         } else {
3196                 _mmplayer_gst_element_added((GstElement *)child, element, data);
3197         }
3198         return;
3199 }
3200
3201 void
3202 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3203 {
3204         LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3205         return;
3206 }
3207
3208 static GstElement *
3209 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3210 {
3211         GstElement *uridecodebin3 = NULL;
3212
3213         MMPLAYER_FENTER();
3214         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3215
3216         uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3217         if (!uridecodebin3) {
3218                 LOGE("failed to create uridecodebin3");
3219                 return NULL;
3220         }
3221
3222         /* get attribute */
3223         SECURE_LOGD("uri : %s", player->profile.uri);
3224
3225         /* setting property to streaming source */
3226         g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3227                         "message-forward", TRUE,
3228                         "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL);
3229
3230         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3231                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3232
3233         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3234                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3235
3236         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3237                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3238
3239         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3240                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3241
3242         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3244
3245         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3247
3248         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3250
3251         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3252                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3253
3254         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3255                 LOGW("[DASH] this is still experimental feature");
3256
3257         MMPLAYER_FLEAVE();
3258         return uridecodebin3;
3259 }
3260
3261 static GstElement *
3262 __mmplayer_gst_make_http_src(mmplayer_t *player)
3263 {
3264 #define MAX_RETRY_COUNT 10
3265         GstElement *element = NULL;
3266         MMHandleType attrs = 0;
3267         gchar *user_agent, *cookies, **cookie_list;
3268         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3269
3270         user_agent = cookies = NULL;
3271         cookie_list = NULL;
3272
3273         MMPLAYER_FENTER();
3274         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3275
3276         /* get profile attribute */
3277         attrs = MMPLAYER_GET_ATTRS(player);
3278         if (!attrs) {
3279                 LOGE("failed to get content attribute");
3280                 return NULL;
3281         }
3282
3283         LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3284
3285         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3286         if (!element) {
3287                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3288                 return NULL;
3289         }
3290
3291         /* get attribute */
3292         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3293         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3294
3295         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3296                 http_timeout = player->ini.http_timeout;
3297
3298         /* get attribute */
3299         SECURE_LOGD("location : %s", player->profile.uri);
3300         SECURE_LOGD("cookies : %s", cookies);
3301         SECURE_LOGD("user_agent :  %s", user_agent);
3302         LOGD("timeout : %d", http_timeout);
3303
3304         /* setting property to streaming source */
3305         g_object_set(G_OBJECT(element), "location", player->profile.uri,
3306                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3307                                 "retries", MAX_RETRY_COUNT, NULL);
3308
3309         /* parsing cookies */
3310         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3311                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3312                 g_strfreev(cookie_list);
3313         }
3314
3315         if (user_agent)
3316                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3317
3318         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3319                 LOGW("[DASH] this is still experimental feature");
3320
3321         MMPLAYER_FLEAVE();
3322         return element;
3323 }
3324
3325 static GstElement *
3326 __mmplayer_gst_make_file_src(mmplayer_t *player)
3327 {
3328         GstElement *element = NULL;
3329
3330         MMPLAYER_FENTER();
3331         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3332
3333         LOGD("using filesrc for 'file://' handler");
3334         if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3335                 LOGE("failed to get storage info");
3336                 return NULL;
3337         }
3338
3339         element = gst_element_factory_make("filesrc", "source");
3340         if (!element) {
3341                 LOGE("failed to create filesrc");
3342                 return NULL;
3343         }
3344
3345         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3346
3347         MMPLAYER_FLEAVE();
3348         return element;
3349 }
3350
3351 static gboolean
3352 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3353 {
3354         mmplayer_t *player = (mmplayer_t *)data;
3355
3356         g_return_val_if_fail(player, FALSE);
3357         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3358         gst_message_ref(msg);
3359
3360         g_mutex_lock(&player->bus_msg_q_lock);
3361         g_queue_push_tail(player->bus_msg_q, msg);
3362         g_mutex_unlock(&player->bus_msg_q_lock);
3363
3364         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3365         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3366         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3367         return TRUE;
3368 }
3369
3370 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3371 {
3372         mmplayer_t *player = (mmplayer_t *)(data);
3373         GstMessage *msg = NULL;
3374
3375         MMPLAYER_FENTER();
3376         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3377                                                 player->pipeline &&
3378                                                 player->pipeline->mainbin &&
3379                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3380                                                 NULL);
3381
3382         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3383
3384         LOGD("[handle: %p] gst bus msg thread will be started.", player);
3385         while (!player->bus_msg_thread_exit) {
3386                 g_mutex_lock(&player->bus_msg_q_lock);
3387                 msg = g_queue_pop_head(player->bus_msg_q);
3388                 g_mutex_unlock(&player->bus_msg_q_lock);
3389                 if (msg == NULL) {
3390                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3391                         continue;
3392                 }
3393                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3394                 /* handle the gst msg */
3395                 __mmplayer_gst_bus_msg_callback(msg, player);
3396                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3397                 gst_message_unref(msg);
3398         }
3399
3400         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3401         MMPLAYER_FLEAVE();
3402
3403         return NULL;
3404 }
3405
3406 static int
3407 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3408 {
3409         gint64 dur_nsec = 0;
3410
3411         MMPLAYER_FENTER();
3412         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3413
3414         if (MMPLAYER_IS_MS_BUFF_SRC(player))
3415                 return MM_ERROR_NONE;
3416
3417         /* NOTE : duration cannot be zero except live streaming.
3418          *              Since some element could have some timing problem with querying duration, try again.
3419          */
3420         if (player->duration == 0) {
3421                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3422                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3423                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3424                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3425                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3426                                 player->pending_seek.is_pending = true;
3427                                 player->pending_seek.pos = position;
3428                                 player->seek_state = MMPLAYER_SEEK_NONE;
3429                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3430                                 return MM_ERROR_PLAYER_NO_OP;
3431                         } else {
3432                                 player->seek_state = MMPLAYER_SEEK_NONE;
3433                                 return MM_ERROR_PLAYER_SEEK;
3434                         }
3435                 }
3436                 player->duration = dur_nsec;
3437         }
3438
3439         if (player->duration > 0 && player->duration < position) {
3440                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3441                 return MM_ERROR_INVALID_ARGUMENT;
3442         }
3443
3444         MMPLAYER_FLEAVE();
3445         return MM_ERROR_NONE;
3446 }
3447
3448 static gboolean
3449 __mmplayer_gst_check_seekable(mmplayer_t *player)
3450 {
3451         GstQuery *query = NULL;
3452         gboolean seekable = FALSE;
3453
3454         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3455                 return TRUE;
3456         }
3457
3458         query = gst_query_new_seeking(GST_FORMAT_TIME);
3459         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3460                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3461                 gst_query_unref(query);
3462
3463                 if (!seekable) {
3464                         LOGW("non-seekable content");
3465                         player->seek_state = MMPLAYER_SEEK_NONE;
3466                         return FALSE;
3467                 }
3468         } else {
3469                 LOGW("failed to get seeking query");
3470                 gst_query_unref(query); /* keep seeking operation */
3471         }
3472
3473         return TRUE;
3474 }
3475
3476 int
3477 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
3478 {
3479         GstState element_state = GST_STATE_VOID_PENDING;
3480         GstState element_pending_state = GST_STATE_VOID_PENDING;
3481         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3482
3483         MMPLAYER_FENTER();
3484
3485         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3486         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3487
3488         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3489
3490         /* set state */
3491         ret = gst_element_set_state(element, state);
3492         if (ret == GST_STATE_CHANGE_FAILURE) {
3493                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3494
3495                 /* dump state of all element */
3496                 _mmplayer_dump_pipeline_state(player);
3497
3498                 return MM_ERROR_PLAYER_INTERNAL;
3499         }
3500
3501         /* return here so state transition to be done in async mode */
3502         if (async) {
3503                 LOGD("async state transition. not waiting for state complete.");
3504                 return MM_ERROR_NONE;
3505         }
3506
3507         /* wait for state transition */
3508         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3509         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3510                 LOGE("failed to change [%s] element state to [%s] within %d sec",
3511                         GST_ELEMENT_NAME(element),
3512                         gst_element_state_get_name(state), timeout);
3513
3514                 LOGE(" [%s] state : %s   pending : %s",
3515                         GST_ELEMENT_NAME(element),
3516                         gst_element_state_get_name(element_state),
3517                         gst_element_state_get_name(element_pending_state));
3518
3519                 /* dump state of all element */
3520                 _mmplayer_dump_pipeline_state(player);
3521
3522                 return MM_ERROR_PLAYER_INTERNAL;
3523         }
3524
3525         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3526
3527         MMPLAYER_FLEAVE();
3528
3529         return MM_ERROR_NONE;
3530 }
3531
3532 int
3533 _mmplayer_gst_start(mmplayer_t *player)
3534 {
3535         int ret = MM_ERROR_NONE;
3536         gboolean async = FALSE;
3537
3538         MMPLAYER_FENTER();
3539
3540         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3541
3542         /* NOTE : if SetPosition was called before Start. do it now
3543          * streaming doesn't support it. so it should be always sync
3544          * !!create one more api to check if there is pending seek rather than checking variables
3545          */
3546         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3547                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3548                 ret = _mmplayer_gst_pause(player, FALSE);
3549                 if (ret != MM_ERROR_NONE) {
3550                         LOGE("failed to set state to PAUSED for pending seek");
3551                         return ret;
3552                 }
3553
3554                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3555                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3556                                 LOGW("failed to seek pending position. starting from the begin of content");
3557         }
3558
3559         LOGD("current state before doing transition");
3560         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3561         MMPLAYER_PRINT_STATE(player);
3562
3563         /* set pipeline state to PLAYING  */
3564         ret = _mmplayer_gst_set_state(player,
3565                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3566         if (ret != MM_ERROR_NONE) {
3567                 LOGE("failed to set state to PLAYING");
3568                 return ret;
3569         }
3570
3571         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3572
3573         /* generating debug info before returning error */
3574         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3575
3576         MMPLAYER_FLEAVE();
3577
3578         return ret;
3579 }
3580
3581 int
3582 _mmplayer_gst_stop(mmplayer_t *player)
3583 {
3584         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3585         MMHandleType attrs = 0;
3586         gboolean rewind = FALSE;
3587         gint timeout = 0;
3588         int ret = MM_ERROR_NONE;
3589
3590         MMPLAYER_FENTER();
3591
3592         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3593         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3594
3595         LOGD("current state before doing transition");
3596         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3597         MMPLAYER_PRINT_STATE(player);
3598
3599         attrs = MMPLAYER_GET_ATTRS(player);
3600         if (!attrs) {
3601                 LOGE("cannot get content attribute");
3602                 return MM_ERROR_PLAYER_INTERNAL;
3603         }
3604
3605         /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3606         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3607
3608         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3609                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3610                 rewind = TRUE;
3611
3612         if (player->es_player_push_mode)
3613                 /* disable the async state transition because there could be no data in the pipeline */
3614                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3615
3616         /* set gst state */
3617         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3618
3619         if (player->es_player_push_mode) {
3620                 /* enable the async state transition as default operation */
3621                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3622         }
3623
3624         /* return if set_state has failed */
3625         if (ret != MM_ERROR_NONE) {
3626                 LOGE("failed to set state.");
3627                 return ret;
3628         }
3629
3630         /* rewind */
3631         if (rewind) {
3632                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3633                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3634                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3635                         LOGW("failed to rewind");
3636                         ret = MM_ERROR_PLAYER_SEEK;
3637                 }
3638         }
3639
3640         /* initialize */
3641         player->sent_bos = FALSE;
3642
3643         if (player->es_player_push_mode) //for cloudgame
3644                 timeout = 0;
3645
3646         /* wait for seek to complete */
3647         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3648         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3649                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3650         } else {
3651                 LOGE("fail to stop player.");
3652                 ret = MM_ERROR_PLAYER_INTERNAL;
3653                 _mmplayer_dump_pipeline_state(player);
3654         }
3655
3656         /* generate dot file if enabled */
3657         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3658
3659         MMPLAYER_FLEAVE();
3660
3661         return ret;
3662 }
3663
3664 int
3665 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3666 {
3667         int ret = MM_ERROR_NONE;
3668
3669         MMPLAYER_FENTER();
3670
3671         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3672         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3673
3674         LOGD("current state before doing transition");
3675         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3676         MMPLAYER_PRINT_STATE(player);
3677
3678         /* set pipeline status to PAUSED */
3679         ret = _mmplayer_gst_set_state(player,
3680                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3681
3682         if (async)
3683                 goto EXIT;
3684
3685         if (ret != MM_ERROR_NONE) {
3686                 GstMessage *msg = NULL;
3687                 GTimer *timer = NULL;
3688                 gdouble MAX_TIMEOUT_SEC = 3;
3689
3690                 LOGE("failed to set state to PAUSED");
3691
3692                 if (!player->bus_watcher) {
3693                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3694                         return ret;
3695                 }
3696
3697                 if (player->msg_posted) {
3698                         LOGE("error msg is already posted.");
3699                         return ret;
3700                 }
3701
3702                 timer = g_timer_new();
3703                 g_timer_start(timer);
3704
3705                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3706
3707                 do {
3708                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3709                         if (msg) {
3710                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3711                                         GError *error = NULL;
3712
3713                                         /* parse error code */
3714                                         gst_message_parse_error(msg, &error, NULL);
3715
3716                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3717                                                 /* Note : the streaming error from the streaming source is handled
3718                                                         *   using __mmplayer_handle_streaming_error.
3719                                                         */
3720                                                 __mmplayer_handle_streaming_error(player, msg);
3721
3722                                         } else if (error) {
3723                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3724
3725                                                 if (error->domain == GST_STREAM_ERROR)
3726                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3727                                                 else if (error->domain == GST_RESOURCE_ERROR)
3728                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3729                                                 else if (error->domain == GST_LIBRARY_ERROR)
3730                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3731                                                 else if (error->domain == GST_CORE_ERROR)
3732                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3733
3734                                                 g_error_free(error);
3735                                         }
3736                                         player->msg_posted = TRUE;
3737                                 }
3738                                 gst_message_unref(msg);
3739                         }
3740                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3741                 /* clean */
3742                 gst_object_unref(bus);
3743                 g_timer_stop(timer);
3744                 g_timer_destroy(timer);
3745
3746                 return ret;
3747         }
3748
3749         if (MMPLAYER_USE_DECODEBIN(player)) {
3750                 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3751                         (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3752                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3753         }
3754
3755         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3756
3757 EXIT:
3758         /* generate dot file before returning error */
3759         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3760
3761         MMPLAYER_FLEAVE();
3762
3763         return ret;
3764 }
3765
3766 int
3767 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3768 {
3769         int ret = MM_ERROR_NONE;
3770         gint timeout = 0;
3771
3772         MMPLAYER_FENTER();
3773
3774         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3775                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3776
3777         LOGD("current state before doing transition");
3778         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3779         MMPLAYER_PRINT_STATE(player);
3780
3781         if (async)
3782                 LOGD("do async state transition to PLAYING");
3783
3784         /* set pipeline state to PLAYING */
3785         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3786
3787         ret = _mmplayer_gst_set_state(player,
3788                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3789         if (ret != MM_ERROR_NONE) {
3790                 LOGE("failed to set state to PLAYING");
3791                 goto EXIT;
3792         }
3793
3794         if (!async)
3795                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3796
3797 EXIT:
3798         /* generate dot file */
3799         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3800
3801         MMPLAYER_FLEAVE();
3802
3803         return ret;
3804 }
3805
3806 /* sending event to one of sinkelements */
3807 gboolean
3808 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3809 {
3810         GstEvent *event2 = NULL;
3811         GList *sinks = NULL;
3812         gboolean res = FALSE;
3813         MMPLAYER_FENTER();
3814
3815         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3816         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3817
3818         /* While adding subtitles in live feeds seek is getting called.
3819            Adding defensive check in framework layer.*/
3820         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3821                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3822                         LOGE("Should not send seek event during live playback");
3823                         return TRUE;
3824                 }
3825         }
3826
3827         if (player->play_subtitle)
3828                 event2 = gst_event_copy((const GstEvent *)event);
3829
3830         sinks = player->sink_elements;
3831         while (sinks) {
3832                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3833
3834                 if (GST_IS_ELEMENT(sink)) {
3835                         /* keep ref to the event */
3836                         gst_event_ref(event);
3837
3838                         if ((res = gst_element_send_event(sink, event))) {
3839                                 LOGD("sending event[%s] to sink element [%s] success!",
3840                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3841
3842                                 /* rtsp case, async_done is not called after seek during pause state */
3843                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3844                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3845                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3846                                                         LOGD("RTSP seek completed, after pause state..");
3847                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3848                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3849                                                 }
3850
3851                                         }
3852                                 }
3853
3854                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3855                                         sinks = g_list_next(sinks);
3856                                         continue;
3857                                 } else {
3858                                         break;
3859                                 }
3860                         }
3861
3862                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3863                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3864                 }
3865
3866                 sinks = g_list_next(sinks);
3867         }
3868
3869         /* Note : Textbin is not linked to the video or audio bin.
3870          * It needs to send the event to the text sink seperately.
3871          */
3872         if (player->play_subtitle && player->pipeline) {
3873                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3874
3875                 if (GST_IS_ELEMENT(text_sink)) {
3876                         /* keep ref to the event */
3877                         gst_event_ref(event2);
3878
3879                         if ((res = gst_element_send_event(text_sink, event2)))
3880                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3881                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3882                         else
3883                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3884                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3885
3886                         gst_event_unref(event2);
3887                 }
3888         }
3889
3890         gst_event_unref(event);
3891
3892         MMPLAYER_FLEAVE();
3893
3894         return res;
3895 }
3896
3897 gboolean
3898 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3899                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3900                         gint64 cur, GstSeekType stop_type, gint64 stop)
3901 {
3902         GstEvent *event = NULL;
3903         gboolean result = FALSE;
3904
3905         MMPLAYER_FENTER();
3906
3907         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3908
3909         if (player->pipeline && player->pipeline->textbin)
3910                 __mmplayer_drop_subtitle(player, FALSE);
3911
3912         event = gst_event_new_seek(rate, format, flags, cur_type,
3913                 cur, stop_type, stop);
3914
3915         result = _mmplayer_gst_send_event_to_sink(player, event);
3916
3917         MMPLAYER_FLEAVE();
3918
3919         return result;
3920 }
3921
3922 int
3923 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3924 {
3925         int ret = MM_ERROR_NONE;
3926         gint64 pos_nsec = 0;
3927         gboolean accurate = FALSE;
3928         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3929
3930         MMPLAYER_FENTER();
3931         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3932         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3933
3934         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3935                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3936                 goto PENDING;
3937
3938         ret = __mmplayer_gst_check_duration(player, position);
3939         if (ret != MM_ERROR_NONE) {
3940                 LOGE("failed to check duration 0x%X", ret);
3941                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3942         }
3943
3944         if (!__mmplayer_gst_check_seekable(player))
3945                 return MM_ERROR_PLAYER_NO_OP;
3946
3947         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3948                                 position, player->playback_rate, player->duration);
3949
3950         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3951            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3952            This causes problem is position calculation during normal pause resume scenarios also.
3953            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3954         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3955                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3956                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3957                         LOGW("getting current position failed in seek");
3958
3959                 player->last_position = pos_nsec;
3960                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3961         }
3962
3963         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3964                 LOGD("not completed seek");
3965                 return MM_ERROR_PLAYER_DOING_SEEK;
3966         }
3967
3968         if (!internal_called)
3969                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3970
3971         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3972                 that's why set position through property. */
3973         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3974                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3975                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3976                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3977
3978                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3979                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3980
3981                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3982                 player->seek_state = MMPLAYER_SEEK_NONE;
3983                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3984         } else {
3985                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3986                 if (accurate)
3987                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3988                 else
3989                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3990
3991                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3992                                                 GST_FORMAT_TIME, seek_flags,
3993                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3994                         LOGE("failed to set position");
3995                         goto SEEK_ERROR;
3996                 }
3997         }
3998
3999         /* NOTE : store last seeking point to overcome some bad operation
4000          *     (returning zero when getting current position) of some elements
4001          */
4002         player->last_position = position;
4003
4004         /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4005         if (player->playback_rate > 1.0)
4006                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4007
4008         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4009                 LOGD("buffering should be reset after seeking");
4010                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4011                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4012         }
4013
4014         MMPLAYER_FLEAVE();
4015         return MM_ERROR_NONE;
4016
4017 PENDING:
4018         player->pending_seek.is_pending = true;
4019         player->pending_seek.pos = position;
4020
4021         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4022                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4023                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4024                 player->pending_seek.pos);
4025
4026         return MM_ERROR_NONE;
4027
4028 SEEK_ERROR:
4029         player->seek_state = MMPLAYER_SEEK_NONE;
4030         return MM_ERROR_PLAYER_SEEK;
4031 }
4032
4033 int
4034 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4035 {
4036 #define TRICKPLAY_OFFSET GST_MSECOND
4037
4038         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4039         gint64 pos_nsec = 0;
4040         gboolean ret = TRUE;
4041
4042         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4043                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4044
4045         current_state = MMPLAYER_CURRENT_STATE(player);
4046
4047         /* NOTE : query position except paused state to overcome some bad operation
4048          * please refer to below comments in details
4049          */
4050         if (current_state != MM_PLAYER_STATE_PAUSED)
4051                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4052
4053         /* NOTE : get last point to overcome some bad operation of some elements
4054          *(returning zero when getting current position in paused state
4055          * and when failed to get position during seeking
4056          */
4057         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4058                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4059
4060                 if (player->playback_rate < 0.0)
4061                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4062                 else
4063                         pos_nsec = player->last_position;
4064
4065                 if (!ret)
4066                         pos_nsec = player->last_position;
4067                 else
4068                         player->last_position = pos_nsec;
4069
4070                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4071
4072         } else {
4073                 if (player->duration > 0 && pos_nsec > player->duration)
4074                         pos_nsec = player->duration;
4075
4076                 player->last_position = pos_nsec;
4077         }
4078
4079         *position = pos_nsec;
4080
4081         return MM_ERROR_NONE;
4082 }
4083
4084 int
4085 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4086 {
4087 #define STREAMING_IS_FINISHED   0
4088 #define BUFFERING_MAX_PER       100
4089 #define DEFAULT_PER_VALUE       -1
4090 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4091
4092         mmplayer_gst_element_t *mainbin = NULL;
4093         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4094         gint64 buffered_total = 0;
4095         gint64 position = 0;
4096         gint buffered_sec = -1;
4097         GstBufferingMode mode = GST_BUFFERING_STREAM;
4098         gint64 content_size_time = player->duration;
4099         guint64 content_size_bytes = player->http_content_size;
4100
4101         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4102                                                 player->pipeline &&
4103                                                 player->pipeline->mainbin,
4104                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4105
4106         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4107
4108         *start_pos = 0;
4109         *end_pos = 0;
4110
4111         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4112                 /* and rtsp is not ready yet. */
4113                 LOGW("it's only used for http streaming case");
4114                 return MM_ERROR_PLAYER_NO_OP;
4115         }
4116
4117         if (content_size_time <= 0 || content_size_bytes <= 0) {
4118                 LOGW("there is no content size");
4119                 return MM_ERROR_NONE;
4120         }
4121
4122         if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4123                 LOGW("fail to get current position");
4124                 return MM_ERROR_NONE;
4125         }
4126
4127         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4128                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4129
4130         mainbin = player->pipeline->mainbin;
4131         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4132
4133         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4134                 GstQuery *query = NULL;
4135                 gint byte_in_rate = 0, byte_out_rate = 0;
4136                 gint64 estimated_total = 0;
4137
4138                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4139                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4140                         LOGW("fail to get buffering query from queue2");
4141                         if (query)
4142                                 gst_query_unref(query);
4143                         return MM_ERROR_NONE;
4144                 }
4145
4146                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4147                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4148
4149                 if (mode == GST_BUFFERING_STREAM) {
4150                         /* using only queue in case of push mode(ts / mp3) */
4151                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4152                                 GST_FORMAT_BYTES, &buffered_total)) {
4153                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4154                                 end_per = 100 * buffered_total / content_size_bytes;
4155                         }
4156                 } else {
4157                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4158                         guint idx = 0;
4159                         guint num_of_ranges = 0;
4160                         gint64 start_byte = 0, stop_byte = 0;
4161
4162                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4163                         if (estimated_total != STREAMING_IS_FINISHED) {
4164                                 /* buffered size info from queue2 */
4165                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4166                                 for (idx = 0; idx < num_of_ranges; idx++) {
4167                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4168                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4169
4170                                         buffered_total += (stop_byte - start_byte);
4171                                 }
4172                         } else {
4173                                 end_per = BUFFERING_MAX_PER;
4174                         }
4175                 }
4176                 gst_query_unref(query);
4177         }
4178
4179         if (end_per == DEFAULT_PER_VALUE) {
4180                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4181                 if (dur_sec > 0) {
4182                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4183
4184                         /* buffered size info from multiqueue */
4185                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4186                                 guint curr_size_bytes = 0;
4187                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4188                                         "curr-size-bytes", &curr_size_bytes, NULL);
4189                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4190                                 buffered_total += curr_size_bytes;
4191                         }
4192
4193                         if (avg_byterate > 0)
4194                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4195                         else if (player->total_maximum_bitrate > 0)
4196                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4197                         else if (player->total_bitrate > 0)
4198                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4199
4200                         if (buffered_sec >= 0)
4201                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4202                 }
4203         }
4204
4205         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4206         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4207
4208         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4209                 buffered_total, buffered_sec, *start_pos, *end_pos);
4210
4211         return MM_ERROR_NONE;
4212 }
4213
4214 GstElement *
4215 _mmplayer_gst_create_source(mmplayer_t *player)
4216 {
4217         GstElement *element = NULL;
4218
4219         MMPLAYER_FENTER();
4220         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4221                                 player->pipeline->mainbin, NULL);
4222
4223         /* setup source for gapless play */
4224         switch (player->profile.uri_type) {
4225         /* file source */
4226         case MM_PLAYER_URI_TYPE_FILE:
4227                 element = __mmplayer_gst_make_file_src(player);
4228                 break;
4229         case MM_PLAYER_URI_TYPE_URL_HTTP:
4230                 element = __mmplayer_gst_make_http_src(player);
4231                 break;
4232         default:
4233                 LOGE("not support uri type %d", player->profile.uri_type);
4234                 break;
4235         }
4236
4237         if (!element) {
4238                 LOGE("failed to create source element");
4239                 return NULL;
4240         }
4241
4242         MMPLAYER_FLEAVE();
4243         return element;
4244 }
4245
4246 int
4247 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4248 {
4249         MMPLAYER_FENTER();
4250         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4251                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4252
4253         SECURE_LOGD("uri : %s", player->profile.uri);
4254
4255         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4256
4257         if ((player->v_stream_caps) &&
4258                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4259                 return MM_ERROR_PLAYER_INTERNAL;
4260
4261         if ((player->a_stream_caps) &&
4262                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4263                 return MM_ERROR_PLAYER_INTERNAL;
4264
4265         if ((player->s_stream_caps) &&
4266                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4267                 return MM_ERROR_PLAYER_INTERNAL;
4268
4269         MMPLAYER_FLEAVE();
4270         return MM_ERROR_NONE;
4271 }
4272
4273 int
4274 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4275 {
4276         mmplayer_gst_element_t *mainbin = NULL;
4277         GstElement *autoplug_elem = NULL;
4278
4279         MMPLAYER_FENTER();
4280         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4281                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4282
4283         mainbin = player->pipeline->mainbin;
4284
4285         LOGD("uri type %d", player->profile.uri_type);
4286
4287         if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4288                 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4289                 return MM_ERROR_PLAYER_INTERNAL;
4290         }
4291
4292         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4293                 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4294         }
4295
4296         autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4297         if (!autoplug_elem) {
4298                 LOGE("failed to create uridecodebin3 element");
4299                 goto ERROR;
4300         }
4301
4302         LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4303         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4304         mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4305
4306         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4307                 LOGE("failed to add uridecodebin to pipeline");
4308                 goto ERROR;
4309         }
4310
4311         /* FIXME: required ?*/
4312         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4313         mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4314         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4315
4316         if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4317                 LOGE("failed to create fakesink");
4318                 goto ERROR;
4319         }
4320         GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4321
4322         /* take ownership of fakesink. we are reusing it */
4323         gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4324
4325         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4326                 LOGE("failed to add fakesink to bin");
4327                 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4328                 goto ERROR;
4329         }
4330
4331         MMPLAYER_FLEAVE();
4332         return MM_ERROR_NONE;
4333
4334 ERROR:
4335
4336         if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4337                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4338
4339         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4340                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4341
4342         mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4343         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4344
4345         return MM_ERROR_PLAYER_INTERNAL;
4346 }
4347
4348 int
4349 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4350 {
4351         mmplayer_gst_element_t *mainbin = NULL;
4352         GstElement *src_elem = NULL;
4353         GstElement *autoplug_elem = NULL;
4354         GList *element_bucket = NULL;
4355         main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4356
4357         MMPLAYER_FENTER();
4358         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4359                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4360
4361         LOGD("uri type %d", player->profile.uri_type);
4362
4363         /* create source element */
4364         switch (player->profile.uri_type) {
4365         case MM_PLAYER_URI_TYPE_URL_RTSP:
4366                 src_elem = __mmplayer_gst_make_rtsp_src(player);
4367                 break;
4368         case MM_PLAYER_URI_TYPE_URL_HTTP:
4369                 src_elem = __mmplayer_gst_make_http_src(player);
4370                 break;
4371         case MM_PLAYER_URI_TYPE_FILE:
4372                 src_elem = __mmplayer_gst_make_file_src(player);
4373                 break;
4374         case MM_PLAYER_URI_TYPE_SS:
4375                 {
4376                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4377                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4378                         if (!src_elem) {
4379                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4380                                 break;
4381                         }
4382
4383                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4384                                 LOGD("get timeout from ini");
4385                                 http_timeout = player->ini.http_timeout;
4386                         }
4387
4388                         /* setting property to streaming source */
4389                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4390                 }
4391                 break;
4392         case MM_PLAYER_URI_TYPE_MEM:
4393                 {
4394                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4395
4396                         src_elem = gst_element_factory_make("appsrc", "mem-source");
4397                         if (!src_elem) {
4398                                 LOGE("failed to create appsrc element");
4399                                 break;
4400                         }
4401
4402                         g_object_set(src_elem, "stream-type", stream_type,
4403                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4404
4405                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4406                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4407                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4408                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4409                 }
4410                 break;
4411         default:
4412                 LOGE("not support uri type");
4413                 break;
4414         }
4415
4416         if (!src_elem) {
4417                 LOGE("failed to create source element");
4418                 return MM_ERROR_PLAYER_INTERNAL;
4419         }
4420
4421         mainbin = player->pipeline->mainbin;
4422
4423         /* take source element */
4424         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4425
4426         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4427         mainbin[MMPLAYER_M_SRC].gst = src_elem;
4428         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4429
4430         /* create next element for auto-plugging */
4431         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4432                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4433                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4434                 if (!autoplug_elem) {
4435                         LOGE("failed to create typefind element");
4436                         goto ERROR;
4437                 }
4438
4439                 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4440                                                                         G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4441         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4442                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4443                 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4444                 if (!autoplug_elem) {
4445                         LOGE("failed to create decodebin");
4446                         goto ERROR;
4447                 }
4448
4449                 /* default size of mq in decodebin is 2M
4450                  * but it can cause blocking issue during seeking depends on content. */
4451                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4452         }
4453
4454         if (autoplug_elem) {
4455                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4456                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4457                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4458
4459                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4460         }
4461
4462         /* add elements to pipeline */
4463         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4464                 LOGE("failed to add elements to pipeline");
4465                 goto ERROR;
4466         }
4467
4468         /* linking elements in the bucket by added order. */
4469         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4470                 LOGE("failed to link some elements");
4471                 goto ERROR;
4472         }
4473
4474         /* FIXME: need to check whether this is required or not. */
4475         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4476                 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4477                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4478                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4479                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4480
4481                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4482                         LOGE("failed to create fakesink");
4483                         goto ERROR;
4484                 }
4485                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4486
4487                 /* take ownership of fakesink. we are reusing it */
4488                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4489
4490                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4491                         LOGE("failed to add fakesink to bin");
4492                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4493                         goto ERROR;
4494                 }
4495         }
4496
4497         g_list_free(element_bucket);
4498
4499         MMPLAYER_FLEAVE();
4500         return MM_ERROR_NONE;
4501
4502 ERROR:
4503         g_list_free(element_bucket);
4504
4505         if (mainbin[MMPLAYER_M_SRC].gst)
4506                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4507
4508         if (mainbin[autoplug_elem_id].gst)
4509                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4510
4511         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4512                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4513
4514         mainbin[MMPLAYER_M_SRC].gst = NULL;
4515         mainbin[autoplug_elem_id].gst = NULL;
4516         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4517
4518         return MM_ERROR_PLAYER_INTERNAL;
4519 }
4520
4521 int
4522 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4523 {
4524         GstBus  *bus = NULL;
4525         mmplayer_gst_element_t *mainbin = NULL;
4526
4527         MMPLAYER_FENTER();
4528         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4529                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4530
4531         mainbin = player->pipeline->mainbin;
4532
4533         /* connect bus callback */
4534         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4535         if (!bus) {
4536                 LOGE("cannot get bus from pipeline");
4537                 return MM_ERROR_PLAYER_INTERNAL;
4538         }
4539
4540         player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4541                                                         (GstBusFunc)__mmplayer_gst_msg_push, player,
4542                                                         (GDestroyNotify)_mmplayer_watcher_removed_notify);
4543         if (player->bus_watcher == 0) {
4544                 LOGE("failed to add bus watch");
4545                 return MM_ERROR_PLAYER_INTERNAL;
4546         }
4547
4548         g_mutex_init(&player->bus_watcher_mutex);
4549         g_cond_init(&player->bus_watcher_cond);
4550
4551         player->context.thread_default = g_main_context_get_thread_default();
4552         if (player->context.thread_default == NULL) {
4553                 player->context.thread_default = g_main_context_default();
4554                 LOGD("thread-default context is the global default context");
4555         }
4556         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4557
4558         /* set sync handler to get tag synchronously */
4559         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4560         gst_object_unref(GST_OBJECT(bus));
4561
4562         /* create gst bus_msb_cb thread */
4563         g_mutex_init(&player->bus_msg_thread_mutex);
4564         g_cond_init(&player->bus_msg_thread_cond);
4565         player->bus_msg_thread_exit = FALSE;
4566         player->bus_msg_thread =
4567                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4568         if (!player->bus_msg_thread) {
4569                 LOGE("failed to create gst BUS msg thread");
4570                 g_mutex_clear(&player->bus_msg_thread_mutex);
4571                 g_cond_clear(&player->bus_msg_thread_cond);
4572                 return MM_ERROR_PLAYER_INTERNAL;
4573         }
4574
4575         MMPLAYER_FLEAVE();
4576         return MM_ERROR_NONE;
4577 }
4578
4579 void
4580 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4581 {
4582         int ret = MM_ERROR_NONE;
4583         mmplayer_gst_element_t *mainbin = NULL;
4584         MMMessageParamType msg_param = {0,};
4585         GstElement *element = NULL;
4586         MMHandleType attrs = 0;
4587         char *uri = NULL;
4588         main_element_id_e elem_idx = MMPLAYER_M_NUM;
4589
4590         MMPLAYER_FENTER();
4591
4592         if (!player || !player->pipeline || !player->pipeline->mainbin) {
4593                 LOGE("player is not initialized");
4594                 goto ERROR;
4595         }
4596
4597         mainbin = player->pipeline->mainbin;
4598         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4599
4600         attrs = MMPLAYER_GET_ATTRS(player);
4601         if (!attrs) {
4602                 LOGE("fail to get attributes");
4603                 goto ERROR;
4604         }
4605
4606         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4607
4608         if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4609                 LOGE("failed to parse profile");
4610                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4611                 goto ERROR;
4612         }
4613
4614         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4615                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4616                 LOGE("dash or hls is not supportable");
4617                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4618                 goto ERROR;
4619         }
4620
4621         if (!MMPLAYER_USE_DECODEBIN(player)) {
4622                 ret = _mmplayer_gst_build_pipeline_with_src(player);
4623                 if (ret != MM_ERROR_NONE)
4624                         goto ERROR;
4625
4626                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4627                         LOGE("Failed to change state of uridecodebin3 element");
4628                         goto ERROR;
4629                 }
4630                 goto DONE;
4631         }
4632
4633         element = _mmplayer_gst_create_source(player);
4634         if (!element) {
4635                 LOGE("no source element was created");
4636                 goto ERROR;
4637         }
4638
4639         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4640                 LOGE("failed to add source element to pipeline");
4641                 gst_object_unref(GST_OBJECT(element));
4642                 element = NULL;
4643                 goto ERROR;
4644         }
4645
4646         /* take source element */
4647         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4648         mainbin[MMPLAYER_M_SRC].gst = element;
4649
4650         element = NULL;
4651
4652         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4653                 if (player->streamer == NULL) {
4654                         player->streamer = _mm_player_streaming_create();
4655                         _mm_player_streaming_initialize(player->streamer, TRUE);
4656                 }
4657
4658                 elem_idx = MMPLAYER_M_TYPEFIND;
4659                 element = gst_element_factory_make("typefind", "typefinder");
4660                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4661                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4662         } else {
4663                 elem_idx = MMPLAYER_M_AUTOPLUG;
4664                 element = _mmplayer_gst_make_decodebin(player);
4665         }
4666
4667         /* check autoplug element is OK */
4668         if (!element) {
4669                 LOGE("can not create element(%d)", elem_idx);
4670                 goto ERROR;
4671         }
4672
4673         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4674                 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4675                 gst_object_unref(GST_OBJECT(element));
4676                 element = NULL;
4677                 goto ERROR;
4678         }
4679
4680         mainbin[elem_idx].id = elem_idx;
4681         mainbin[elem_idx].gst = element;
4682
4683         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4684                 LOGE("Failed to link src - autoplug(or typefind)");
4685                 goto ERROR;
4686         }
4687
4688         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4689                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {  // ????
4690                         LOGE("Failed to change state of src element");
4691                         goto ERROR;
4692                 }
4693         } else {
4694                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4695                         LOGE("Failed to change state of decodebin");
4696                         goto ERROR;
4697                 }
4698         }
4699
4700         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4701                 LOGE("Failed to change state of src element");
4702                 goto ERROR;
4703         }
4704
4705 DONE:
4706         player->gapless.stream_changed = TRUE;
4707         player->gapless.running = TRUE;
4708         MMPLAYER_FLEAVE();
4709         return;
4710
4711 ERROR:
4712         if (player) {
4713                 _mmplayer_set_reconfigure_state(player, FALSE);
4714                 if (!player->msg_posted) {
4715                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4716                         player->msg_posted = TRUE;
4717                 }
4718         }
4719         return;
4720 }