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