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