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