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