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