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