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