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