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