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