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