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