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