c3fb4d029f0ee0565c9d04500b7d9815c6e3c366
[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
937                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
938                         (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
939                         (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
940
941                         gint64 dur_bytes = 0L;
942
943                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
944                                 LOGE("fail to get duration.");
945
946                         /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
947                          * use file information was already set on Q2 when it was created. */
948                         _mm_player_streaming_set_queue2(player->streamer,
949                                                         player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
950                                                         TRUE,                                                           /* use_buffering */
951                                                         MUXED_BUFFER_TYPE_MAX,                          /* use previous buffer type setting */
952                                                         ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
953                 }
954
955                 LOGD("GST_MESSAGE_STREAMS_SELECTED");
956                 player->no_more_pad = TRUE;
957                 _mmplayer_set_reconfigure_state(player, FALSE);
958                 _mmplayer_pipeline_complete(NULL, player);
959                 retval = TRUE;
960                 break;
961         }
962         default:
963                 retval = FALSE;
964                 break;
965         }
966
967         return retval;
968 }
969
970 static void
971 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
972 {
973         guint64 data_size = 0;
974         gint64 pos_nsec = 0;
975
976         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
977
978         _mmplayer_gst_get_position(player, &pos_nsec);  /* to update player->last_position */
979
980         if (MMPLAYER_IS_HTTP_STREAMING(player))
981                 data_size = player->http_content_size;
982
983         _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
984         if (!player->streamer->is_adaptive_streaming) {
985                 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
986                 return;
987         }
988
989         /* adaptivedemux2 is used for buffering in uridecodebin3 */
990         if (!player->streamer->buffering_req.is_pre_buffering) {
991                 LOGD("adaptive> set rebuffer time : %d ms", player->streamer->buffering_req.rebuffer_time);
992                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
993                         "low-watermark-time", (guint64)(player->streamer->buffering_req.rebuffer_time * GST_MSECOND),
994                         NULL);
995         }
996 }
997
998 static int
999 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1000 {
1001         int ret = MM_ERROR_NONE;
1002         mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1003         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1004         mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1005         mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1006
1007         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1008                 LOGW("do nothing for buffering msg");
1009                 ret = MM_ERROR_PLAYER_INVALID_STATE;
1010                 goto exit;
1011         }
1012
1013         prev_state = MMPLAYER_PREV_STATE(player);
1014         current_state = MMPLAYER_CURRENT_STATE(player);
1015         target_state = MMPLAYER_TARGET_STATE(player);
1016         pending_state = MMPLAYER_PENDING_STATE(player);
1017
1018         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1019                 MMPLAYER_STATE_GET_NAME(prev_state),
1020                 MMPLAYER_STATE_GET_NAME(current_state),
1021                 MMPLAYER_STATE_GET_NAME(pending_state),
1022                 MMPLAYER_STATE_GET_NAME(target_state),
1023                 player->streamer->buffering_state);
1024
1025         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1026                 /* NOTE : if buffering has done, player has to go to target state. */
1027                 switch (target_state) {
1028                 case MM_PLAYER_STATE_PAUSED:
1029                         {
1030                                 switch (pending_state) {
1031                                 case MM_PLAYER_STATE_PLAYING:
1032                                         _mmplayer_gst_pause(player, TRUE);
1033                                         break;
1034
1035                                 case MM_PLAYER_STATE_PAUSED:
1036                                         LOGD("player is already going to paused state, there is nothing to do.");
1037                                         break;
1038
1039                                 case MM_PLAYER_STATE_NONE:
1040                                 case MM_PLAYER_STATE_NULL:
1041                                 case MM_PLAYER_STATE_READY:
1042                                 default:
1043                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1044                                         break;
1045                                 }
1046                         }
1047                         break;
1048
1049                 case MM_PLAYER_STATE_PLAYING:
1050                         {
1051                                 switch (pending_state) {
1052                                 case MM_PLAYER_STATE_NONE:
1053                                         {
1054                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1055                                                         _mmplayer_gst_resume(player, TRUE);
1056                                         }
1057                                         break;
1058
1059                                 case MM_PLAYER_STATE_PAUSED:
1060                                         /* NOTE: It should be worked as asynchronously.
1061                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1062                                          */
1063                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
1064                                                 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1065                                                  * The current state should be changed to paused purposely to prevent state conflict.
1066                                                  */
1067                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1068                                         }
1069                                         _mmplayer_gst_resume(player, TRUE);
1070                                         break;
1071
1072                                 case MM_PLAYER_STATE_PLAYING:
1073                                         LOGD("player is already going to playing state, there is nothing to do.");
1074                                         break;
1075
1076                                 case MM_PLAYER_STATE_NULL:
1077                                 case MM_PLAYER_STATE_READY:
1078                                 default:
1079                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1080                                         break;
1081                                 }
1082                         }
1083                         break;
1084
1085                 case MM_PLAYER_STATE_NULL:
1086                 case MM_PLAYER_STATE_READY:
1087                 case MM_PLAYER_STATE_NONE:
1088                 default:
1089                         LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1090                         break;
1091                 }
1092         } else {
1093                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1094                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1095                  */
1096                 switch (pending_state) {
1097                 case MM_PLAYER_STATE_NONE:
1098                         {
1099                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1100                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1101                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1102                                                 LOGD("set pause state during buffering");
1103                                                 _mmplayer_gst_pause(player, TRUE);
1104                                         }
1105                                 }
1106                         }
1107                         break;
1108
1109                 case MM_PLAYER_STATE_PLAYING:
1110                         /* rtsp streaming pause makes rtsp server stop sending data. */
1111                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1112                                 _mmplayer_gst_pause(player, TRUE);
1113                         break;
1114
1115                 case MM_PLAYER_STATE_PAUSED:
1116                         break;
1117
1118                 case MM_PLAYER_STATE_NULL:
1119                 case MM_PLAYER_STATE_READY:
1120                 default:
1121                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1122                         break;
1123                 }
1124         }
1125
1126 exit:
1127         return ret;
1128 }
1129
1130 static stream_variant_t *
1131 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1132 {
1133         stream_variant_t *var_info = NULL;
1134         g_return_val_if_fail(self != NULL, NULL);
1135
1136         var_info = g_new0(stream_variant_t, 1);
1137         if (!var_info) return NULL;
1138         var_info->bandwidth = self->bandwidth;
1139         var_info->width = self->width;
1140         var_info->height = self->height;
1141         return var_info;
1142 }
1143
1144 static gboolean
1145 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1146 {
1147         gint64 bytes = 0;
1148
1149         MMPLAYER_FENTER();
1150
1151         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1152         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1153
1154         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1155                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1156                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1157
1158                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1159                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1160                         player->http_content_size = (bytes > 0) ? bytes : 0;
1161                 }
1162         } else {
1163                 /* handling audio clip which has vbr. means duration is keep changing */
1164                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1165         }
1166
1167         MMPLAYER_FLEAVE();
1168
1169         return TRUE;
1170 }
1171
1172 static gboolean
1173 __mmplayer_eos_timer_cb(gpointer u_data)
1174 {
1175         mmplayer_t *player = NULL;
1176         MMHandleType attrs = 0;
1177         int count = 0;
1178
1179         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1180
1181         player = (mmplayer_t *)u_data;
1182         attrs = MMPLAYER_GET_ATTRS(player);
1183
1184         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1185
1186         if (count == -1) {
1187                 gint ret_value = 0;
1188                 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1189                 if (ret_value != MM_ERROR_NONE)
1190                         LOGE("seeking to 0 failed in repeat play");
1191         } else {
1192                 /* posting eos */
1193                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1194         }
1195
1196         /* we are returning FALSE as we need only one posting */
1197         return FALSE;
1198 }
1199
1200 static void
1201 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1202 {
1203         MMPLAYER_RETURN_IF_FAIL(player);
1204
1205         /* post now if delay is zero */
1206         if (delay_in_ms == 0 || player->audio_decoded_cb) {
1207                 LOGD("eos delay is zero. posting EOS now");
1208                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1209
1210                 if (player->audio_decoded_cb)
1211                         _mmplayer_cancel_eos_timer(player);
1212
1213                 return;
1214         }
1215
1216         /* cancel if existing */
1217         _mmplayer_cancel_eos_timer(player);
1218
1219         /* init new timeout */
1220         /* NOTE : consider give high priority to this timer */
1221         LOGD("posting EOS message after [%d] msec", delay_in_ms);
1222
1223         player->eos_timer = g_timeout_add(delay_in_ms,
1224                 __mmplayer_eos_timer_cb, player);
1225
1226         player->context.global_default = g_main_context_default();
1227         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1228
1229         /* check timer is valid. if not, send EOS now */
1230         if (player->eos_timer == 0) {
1231                 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1232                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1233         }
1234 }
1235
1236 static int
1237 __mmplayer_gst_pending_seek(mmplayer_t *player)
1238 {
1239         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1240         int ret = MM_ERROR_NONE;
1241
1242         MMPLAYER_FENTER();
1243
1244         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1245
1246         if (!player->pending_seek.is_pending) {
1247                 LOGD("pending seek is not reserved. nothing to do.");
1248                 return ret;
1249         }
1250
1251         /* check player state if player could pending seek or not. */
1252         current_state = MMPLAYER_CURRENT_STATE(player);
1253
1254         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1255                 LOGW("try to pending seek in %s state, try next time. ",
1256                         MMPLAYER_STATE_GET_NAME(current_state));
1257                 return ret;
1258         }
1259
1260         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1261
1262         ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1263         if (ret != MM_ERROR_NONE)
1264                 LOGE("failed to seek pending position. just keep staying current position.");
1265
1266         player->pending_seek.is_pending = false;
1267
1268         MMPLAYER_FLEAVE();
1269
1270         return ret;
1271 }
1272
1273 static void
1274 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type  type)
1275 {
1276         mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1277
1278         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1279
1280         audiobin = player->pipeline->audiobin; /* can be null */
1281         videobin = player->pipeline->videobin; /* can be null */
1282         textbin = player->pipeline->textbin;   /* can be null */
1283
1284         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1285
1286         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1287                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1288
1289         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1290                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1291
1292         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1293                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1294
1295         return;
1296 }
1297
1298 static void
1299 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1300 {
1301         mmplayer_gst_element_t *textbin;
1302         MMPLAYER_FENTER();
1303
1304         MMPLAYER_RETURN_IF_FAIL(player &&
1305                                         player->pipeline &&
1306                                         player->pipeline->textbin);
1307
1308         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1309
1310         textbin = player->pipeline->textbin;
1311
1312         if (is_drop) {
1313                 LOGD("Drop subtitle text after getting EOS");
1314
1315                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1316                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1317
1318                 player->is_subtitle_force_drop = TRUE;
1319         } else {
1320                 if (player->is_subtitle_force_drop == TRUE) {
1321                         LOGD("Enable subtitle data path without drop");
1322
1323                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1324                         __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1325
1326                         LOGD("non-connected with external display");
1327
1328                         player->is_subtitle_force_drop = FALSE;
1329                 }
1330         }
1331 }
1332
1333 static void
1334 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1335 {
1336         MMHandleType attrs = 0;
1337         gint count = 0;
1338
1339         MMPLAYER_FENTER();
1340
1341         /* NOTE : EOS event is coming multiple time. watch out it */
1342         /* check state. we only process EOS when pipeline state goes to PLAYING */
1343         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1344                 LOGD("EOS received on non-playing state. ignoring it");
1345                 return;
1346         }
1347
1348         if (player->pipeline && player->pipeline->textbin)
1349                 __mmplayer_drop_subtitle(player, TRUE);
1350
1351         if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1352                 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1353
1354         /* rewind if repeat count is greater then zero */
1355         /* get play count */
1356         attrs = MMPLAYER_GET_ATTRS(player);
1357         if (attrs) {
1358                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1359
1360                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1361
1362                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1363                         if (player->playback_rate < 0.0) {
1364                                 player->resumed_by_rewind = TRUE;
1365                                 _mmplayer_set_mute((MMHandleType)player, false);
1366                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1367                         }
1368
1369                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1370
1371                         /* initialize */
1372                         player->sent_bos = FALSE;
1373
1374                         LOGD("do not post eos msg for repeating");
1375                         return;
1376                 }
1377         }
1378
1379         if (player->pipeline)
1380                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1381
1382         /* post eos message to application */
1383         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1384
1385         /* reset last position */
1386         player->last_position = 0;
1387
1388         MMPLAYER_FLEAVE();
1389         return;
1390 }
1391
1392 static void
1393 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1394 {
1395         GError *error = NULL;
1396         gchar *debug = NULL;
1397
1398         MMPLAYER_FENTER();
1399
1400         /* generating debug info before returning error */
1401         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1402
1403         /* get error code */
1404         gst_message_parse_error(msg, &error, &debug);
1405
1406         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1407                 /* Note : the streaming error from the streaming source is handled
1408                  *       using __mmplayer_handle_streaming_error.
1409                  */
1410                 __mmplayer_handle_streaming_error(player, msg, error);
1411
1412                 /* dump state of all element */
1413                 _mmplayer_dump_pipeline_state(player);
1414         } else {
1415                 /* translate gst error code to msl error code. then post it
1416                  * to application if needed
1417                  */
1418                 __mmplayer_handle_gst_error(player, msg, error);
1419
1420                 if (debug)
1421                         LOGE("error debug : %s", debug);
1422         }
1423
1424         MMPLAYER_FREEIF(debug);
1425         g_error_free(error);
1426
1427         MMPLAYER_FLEAVE();
1428         return;
1429 }
1430
1431 static void
1432 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1433 {
1434         MMMessageParamType msg_param = {0, };
1435         int bRet = MM_ERROR_NONE;
1436
1437         MMPLAYER_FENTER();
1438         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1439
1440         if (!MMPLAYER_IS_STREAMING(player)) {
1441                 LOGW("this is not streaming playback.");
1442                 return;
1443         }
1444
1445         MMPLAYER_CMD_LOCK(player);
1446
1447         if (!player->streamer) {
1448                 LOGW("Pipeline is shutting down");
1449                 MMPLAYER_CMD_UNLOCK(player);
1450                 return;
1451         }
1452
1453         /* ignore the remained buffering message till getting 100% msg */
1454         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1455                 gint buffer_percent = 0;
1456
1457                 gst_message_parse_buffering(msg, &buffer_percent);
1458
1459                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1460                         LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1461                         __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1462                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1463                 }
1464                 MMPLAYER_CMD_UNLOCK(player);
1465                 return;
1466         }
1467
1468         /* ignore the remained buffering message */
1469         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1470                 gint buffer_percent = 0;
1471
1472                 gst_message_parse_buffering(msg, &buffer_percent);
1473
1474                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1475                                         player->streamer->buffering_percent, buffer_percent);
1476
1477                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1478                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1479                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1480
1481                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1482                 } else {
1483                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1484                         MMPLAYER_CMD_UNLOCK(player);
1485                         return;
1486                 }
1487         }
1488
1489         __mmplayer_update_buffer_setting(player, msg);
1490
1491         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1492
1493         if (bRet == MM_ERROR_NONE) {
1494                 msg_param.connection.buffering = player->streamer->buffering_percent;
1495                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1496
1497                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1498                         player->pending_resume &&
1499                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1500
1501                         player->is_external_subtitle_added_now = FALSE;
1502                         player->pending_resume = FALSE;
1503                         _mmplayer_resume((MMHandleType)player);
1504                 }
1505
1506                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1507                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1508
1509                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1510                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1511                                         player->seek_state = MMPLAYER_SEEK_NONE;
1512                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1513                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1514                                         /* Considering the async state transition in case of RTSP.
1515                                            After getting state change gst msg, seek completed msg will be posted. */
1516                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1517                                 }
1518                         }
1519                 }
1520         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1521                 if (!player->streamer) {
1522                         LOGW("player->streamer is NULL, so discarding the buffering percent update");
1523                         MMPLAYER_CMD_UNLOCK(player);
1524                         return;
1525                 }
1526
1527                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1528
1529                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1530                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1531
1532                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1533                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1534                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1535                         } else {
1536                                 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1537                         }
1538                 } else {
1539                         msg_param.connection.buffering = player->streamer->buffering_percent;
1540                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1541                 }
1542         }
1543         MMPLAYER_CMD_UNLOCK(player);
1544
1545         MMPLAYER_FLEAVE();
1546         return;
1547
1548 }
1549
1550 static void
1551 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1552 {
1553         mmplayer_gst_element_t *mainbin;
1554         const GValue *voldstate, *vnewstate, *vpending;
1555         GstState oldstate = GST_STATE_NULL;
1556         GstState newstate = GST_STATE_NULL;
1557         GstState pending = GST_STATE_NULL;
1558
1559         MMPLAYER_FENTER();
1560         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1561
1562         mainbin = player->pipeline->mainbin;
1563
1564         /* we only handle messages from pipeline */
1565         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1566                 return;
1567
1568         /* get state info from msg */
1569         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1570         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1571         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1572
1573         if (!voldstate || !vnewstate) {
1574                 LOGE("received msg has wrong format.");
1575                 return;
1576         }
1577
1578         oldstate = (GstState)voldstate->data[0].v_int;
1579         newstate = (GstState)vnewstate->data[0].v_int;
1580         if (vpending)
1581                 pending = (GstState)vpending->data[0].v_int;
1582
1583         LOGD("state changed [%s] : %s ---> %s     final : %s",
1584                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1585                 gst_element_state_get_name((GstState)oldstate),
1586                 gst_element_state_get_name((GstState)newstate),
1587                 gst_element_state_get_name((GstState)pending));
1588
1589         if (newstate == GST_STATE_PLAYING) {
1590                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1591
1592                         int retVal = MM_ERROR_NONE;
1593                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1594
1595                         retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1596
1597                         if (MM_ERROR_NONE != retVal)
1598                                 LOGE("failed to seek pending position. just keep staying current position.");
1599
1600                         player->pending_seek.is_pending = false;
1601                 }
1602         }
1603
1604         if (oldstate == newstate) {
1605                 LOGD("pipeline reports state transition to old state");
1606                 return;
1607         }
1608
1609         switch (newstate) {
1610         case GST_STATE_PAUSED:
1611                 {
1612                         gboolean prepare_async = FALSE;
1613
1614                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1615                                 // managed prepare async case
1616                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1617                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1618                         }
1619
1620                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1621                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1622
1623                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1624                                         _mm_player_streaming_set_content_bitrate(player->streamer,
1625                                                 player->total_maximum_bitrate, player->total_bitrate);
1626
1627                                 if (player->pending_seek.is_pending) {
1628                                         LOGW("trying to do pending seek");
1629                                         MMPLAYER_CMD_LOCK(player);
1630                                         __mmplayer_gst_pending_seek(player);
1631                                         MMPLAYER_CMD_UNLOCK(player);
1632                                 }
1633                         }
1634                 }
1635                 break;
1636
1637         case GST_STATE_PLAYING:
1638                 {
1639                         if (MMPLAYER_IS_STREAMING(player)) {
1640                                 // managed prepare async case when buffering is completed
1641                                 // pending state should be reset otherwise, it's still playing even though it's resumed after buffering.
1642                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1643                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1644                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1645
1646                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1647
1648                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1649                                         if (player->streamer->buffering_percent < 100) {
1650
1651                                                 MMMessageParamType msg_param = {0, };
1652                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1653
1654                                                 msg_param.connection.buffering = 100;
1655                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1656                                         }
1657                                 }
1658                         }
1659
1660                         if (player->gapless.stream_changed) {
1661                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1662                                 player->gapless.stream_changed = FALSE;
1663                         }
1664
1665                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1666                                 player->seek_state = MMPLAYER_SEEK_NONE;
1667                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1668                         }
1669                 }
1670                 break;
1671         case GST_STATE_VOID_PENDING:
1672         case GST_STATE_NULL:
1673         case GST_STATE_READY:
1674         default:
1675                 break;
1676         }
1677
1678         MMPLAYER_FLEAVE();
1679         return;
1680 }
1681
1682 static void
1683 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1684 {
1685         const gchar *structure_name;
1686         gint count = 0, idx = 0;
1687
1688         MMPLAYER_FENTER();
1689         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1690
1691         if (gst_message_get_structure(msg) == NULL)
1692                 return;
1693
1694         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1695         if (!structure_name)
1696                 return;
1697
1698         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1699
1700         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1701                 const GValue *var_info = NULL;
1702
1703                 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1704                 if (var_info != NULL) {
1705                         if (player->adaptive_info.var_list)
1706                                 g_list_free_full(player->adaptive_info.var_list, g_free);
1707
1708                         /* share addr or copy the list */
1709                         player->adaptive_info.var_list =
1710                                 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1711
1712                         count = g_list_length(player->adaptive_info.var_list);
1713                         if (count > 0) {
1714                                 stream_variant_t *temp = NULL;
1715
1716                                 /* print out for debug */
1717                                 LOGD("num of variant_info %d", count);
1718                                 for (idx = 0; idx < count; idx++) {
1719                                         temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1720                                         if (temp)
1721                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1722                                 }
1723                         }
1724                 }
1725         }
1726
1727         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1728                 gint num_buffers = 0;
1729                 gint extra_num_buffers = 0;
1730
1731                 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1732                         LOGD("video_num_buffers : %d", num_buffers);
1733                         mm_player_set_attribute((MMHandleType)player, NULL,
1734                                         MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1735                 }
1736
1737                 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1738                         LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1739                         mm_player_set_attribute((MMHandleType)player, NULL,
1740                                         MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1741                 }
1742                 return;
1743         }
1744
1745         if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1746                 _mmplayer_track_update_text_attr_info(player, msg);
1747
1748         /* custom message */
1749         if (!strcmp(structure_name, "audio_codec_not_supported")) {
1750                 MMMessageParamType msg_param = {0,};
1751                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1752                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1753         }
1754
1755         /* custom message for RTSP attribute :
1756                 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state changed.
1757                 sdp which has contents info is received when rtsp connection is opened.
1758                 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1759         if (!strcmp(structure_name, "rtspsrc_properties")) {
1760                 g_autofree gchar *audio_codec = NULL;
1761                 g_autofree gchar *video_codec = NULL;
1762                 g_autofree gchar *video_frame_size = NULL;
1763
1764                 gst_structure_get(gst_message_get_structure(msg),
1765                                         "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1766                 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1767                 player->streaming_type = _mmplayer_get_stream_service_type(player);
1768
1769                 gst_structure_get(gst_message_get_structure(msg),
1770                                         "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1771                 LOGD("rtsp_audio_codec : %s", audio_codec);
1772                 if (audio_codec)
1773                         mm_player_set_attribute((MMHandleType)player, NULL,
1774                                         "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1775
1776                 gst_structure_get(gst_message_get_structure(msg),
1777                                         "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1778                 LOGD("rtsp_video_codec : %s", video_codec);
1779                 if (video_codec)
1780                         mm_player_set_attribute((MMHandleType)player, NULL,
1781                                         "content_video_codec", video_codec, strlen(video_codec), NULL);
1782
1783                 gst_structure_get(gst_message_get_structure(msg),
1784                                         "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1785                 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1786                 if (video_frame_size) {
1787                         gchar **res_str = g_strsplit(video_frame_size, "-", 0);
1788                         mm_player_set_attribute((MMHandleType)player, NULL,
1789                                 MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]),
1790                                 MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]),
1791                                 NULL);
1792                         g_strfreev(res_str);
1793                 }
1794         }
1795
1796         MMPLAYER_FLEAVE();
1797         return;
1798 }
1799
1800 static void
1801 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1802 {
1803         mmplayer_gst_element_t *mainbin;
1804
1805         MMPLAYER_FENTER();
1806         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1807
1808         mainbin = player->pipeline->mainbin;
1809
1810         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1811
1812         /* we only handle messages from pipeline */
1813         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1814                 return;
1815
1816         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1817                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1818                         player->seek_state = MMPLAYER_SEEK_NONE;
1819                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1820                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1821                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1822                                 LOGD("sync %s state(%s) with parent state(%s)",
1823                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1824                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1825                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1826
1827                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1828                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1829                                    Because the buffering state is controlled according to the state transition for force resume,
1830                                    the decodebin state should be paused as player state. */
1831                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1832                         }
1833
1834                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1835                                 (player->streamer) &&
1836                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1837                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1838                                 GstQuery *query = NULL;
1839                                 gboolean busy = FALSE;
1840                                 gint percent = 0;
1841
1842                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1843                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1844                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1845                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1846                                         gst_query_unref(query);
1847
1848                                         LOGD("buffered percent(%s): %d",
1849                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1850                                 }
1851
1852                                 if (percent >= 100)
1853                                         __mmplayer_handle_buffering_playback(player);
1854                         }
1855
1856                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1857                 }
1858         }
1859
1860         MMPLAYER_FLEAVE();
1861         return;
1862 }
1863
1864 #ifdef __DEBUG__
1865 static void
1866 __mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data)
1867 {
1868         GValue val = { 0, };
1869         gchar *str = NULL;
1870         guint indent = GPOINTER_TO_UINT(user_data);
1871
1872         if (!gst_tag_list_copy_value(&val, tags, tag))
1873                 return;
1874
1875         if (G_VALUE_HOLDS_STRING(&val))
1876                 str = g_value_dup_string(&val);
1877         else
1878                 str = gst_value_serialize(&val);
1879
1880         LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str);
1881         g_free(str);
1882         g_value_unset(&val);
1883 }
1884 #endif
1885
1886 static void
1887 __mmplayer_dump_collection(GstStreamCollection * collection)
1888 {
1889         guint i = 0;
1890 #ifdef __DEBUG__
1891         GstTagList *tags = NULL;
1892 #endif
1893         GstCaps *caps = NULL;
1894
1895         for (i = 0; i < gst_stream_collection_get_size(collection); i++) {
1896                 GstStream *stream = gst_stream_collection_get_stream(collection, i);
1897                 LOGD ("collection: [%u] Stream, type: %s, flags 0x%x\n", i,
1898                                 gst_stream_type_get_name(gst_stream_get_stream_type(stream)),
1899                                 gst_stream_get_stream_flags(stream));
1900                 LOGD ("  ID: %s\n", gst_stream_get_stream_id(stream));
1901
1902                 caps = gst_stream_get_caps(stream);
1903                 if (caps) {
1904                         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1905                         gst_caps_unref(caps);
1906                 }
1907
1908 #ifdef __DEBUG__
1909                 tags = gst_stream_get_tags(stream);
1910                 if (tags) {
1911                         LOGD ("  tags:\n");
1912                         gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1913                         gst_tag_list_unref(tags);
1914                 }
1915 #endif
1916         }
1917 }
1918
1919 static void
1920 __mmplayer_stream_notify_cb(GstStreamCollection *collection,
1921                         GstStream *stream, GParamSpec *pspec, gpointer data)
1922 {
1923         LOGD ("Got stream-notify from stream %s for %s (collection %p)\n",
1924                                 gst_stream_get_stream_id(stream), pspec->name, collection);
1925         if (g_str_equal(pspec->name, "caps")) {
1926                 GstCaps *caps = gst_stream_get_caps(stream);
1927                 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1928                 gst_caps_unref(caps);
1929         }
1930
1931 #ifdef __DEBUG__
1932         if (g_str_equal (pspec->name, "tags")) {
1933                 GstTagList *tags = gst_stream_get_tags(stream);
1934                 if (tags) {
1935                         LOGD ("  tags:\n");
1936                         gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
1937                         gst_tag_list_unref(tags);
1938                 }
1939         }
1940 #endif
1941 }
1942
1943 static void
1944 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1945 {
1946         mmplayer_t *player = (mmplayer_t *)(data);
1947
1948         MMPLAYER_RETURN_IF_FAIL(player);
1949         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1950
1951         switch (GST_MESSAGE_TYPE(msg)) {
1952         case GST_MESSAGE_UNKNOWN:
1953                 LOGD("unknown message received");
1954                 break;
1955
1956         case GST_MESSAGE_EOS:
1957                 LOGD("GST_MESSAGE_EOS received");
1958                 __mmplayer_gst_handle_eos_message(player, msg);
1959                 break;
1960
1961         case GST_MESSAGE_ERROR:
1962                 _mmplayer_set_reconfigure_state(player, FALSE);
1963                 __mmplayer_gst_handle_error_message(player, msg);
1964                 break;
1965
1966         case GST_MESSAGE_WARNING:
1967                 {
1968                         char *debug = NULL;
1969                         GError *error = NULL;
1970
1971                         gst_message_parse_warning(msg, &error, &debug);
1972
1973                         LOGD("warning : %s", error->message);
1974                         LOGD("debug : %s", debug);
1975
1976                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1977
1978                         MMPLAYER_FREEIF(debug);
1979                         g_error_free(error);
1980                 }
1981                 break;
1982
1983         case GST_MESSAGE_TAG:
1984                 {
1985                         LOGD("GST_MESSAGE_TAG");
1986                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1987                                 LOGW("failed to extract tags from gstmessage");
1988                 }
1989                 break;
1990
1991         case GST_MESSAGE_BUFFERING:
1992                 __mmplayer_gst_handle_buffering_message(player, msg);
1993                 break;
1994
1995         case GST_MESSAGE_STATE_CHANGED:
1996                 __mmplayer_gst_handle_state_message(player, msg);
1997                 break;
1998
1999         case GST_MESSAGE_CLOCK_LOST:
2000                         {
2001                                 GstClock *clock = NULL;
2002                                 gboolean need_new_clock = FALSE;
2003
2004                                 gst_message_parse_clock_lost(msg, &clock);
2005                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2006
2007                                 if (!player->videodec_linked)
2008                                         need_new_clock = TRUE;
2009                                 else if (!player->ini.use_system_clock)
2010                                         need_new_clock = TRUE;
2011
2012                                 if (need_new_clock) {
2013                                         LOGD("Provide clock is TRUE, do pause->resume");
2014                                         _mmplayer_gst_pause(player, FALSE);
2015                                         _mmplayer_gst_resume(player, FALSE);
2016                                 }
2017                         }
2018                         break;
2019
2020         case GST_MESSAGE_NEW_CLOCK:
2021                         {
2022                                 GstClock *clock = NULL;
2023                                 gst_message_parse_new_clock(msg, &clock);
2024                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2025                         }
2026                         break;
2027
2028         case GST_MESSAGE_ELEMENT:
2029                 __mmplayer_gst_handle_element_message(player, msg);
2030                         break;
2031
2032         case GST_MESSAGE_DURATION_CHANGED:
2033                 {
2034                         LOGD("GST_MESSAGE_DURATION_CHANGED");
2035                         if (!__mmplayer_gst_handle_duration(player, msg))
2036                                 LOGW("failed to update duration");
2037                 }
2038                 break;
2039
2040         case GST_MESSAGE_ASYNC_START:
2041                         LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2042                 break;
2043
2044         case GST_MESSAGE_ASYNC_DONE:
2045                 __mmplayer_gst_handle_async_done_message(player, msg);
2046                 break;
2047         case GST_MESSAGE_STREAM_COLLECTION:
2048         {
2049                 GstStreamCollection *collection = NULL;
2050                 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2051
2052                 gst_message_parse_stream_collection(msg, &collection);
2053                 if (collection) {
2054                         __mmplayer_dump_collection(collection);
2055                         if (player->collection && player->stream_notify_id) {
2056                                 g_signal_handler_disconnect(player->collection, player->stream_notify_id);
2057                                 player->stream_notify_id = 0;
2058                         }
2059                         gst_object_replace((GstObject **)&player->collection, (GstObject *)collection);
2060                         if (player->collection) {
2061                                 player->stream_notify_id = g_signal_connect(player->collection, "stream-notify",
2062                                                         (GCallback)__mmplayer_stream_notify_cb, player);
2063                         }
2064                         gst_object_unref(collection);
2065                 }
2066         } break;
2067         case GST_MESSAGE_STREAMS_SELECTED:
2068         {
2069                 GstStreamCollection *collection = NULL;
2070                 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2071
2072                 gst_message_parse_streams_selected(msg, &collection);
2073                 if (collection) {
2074                         guint i = 0, len = 0;
2075                         len = gst_message_streams_selected_get_size(msg);
2076                         for (i = 0; i < len; i++) {
2077                                 GstStream *stream = gst_message_streams_selected_get_stream(msg, i);
2078                                 LOGD ("  Stream #%d : %s\n", i, gst_stream_get_stream_id(stream));
2079                                 gst_object_unref(stream);
2080                         }
2081                         gst_object_unref (collection);
2082                 }
2083         } break;
2084
2085 #ifdef __DEBUG__
2086         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2087         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START"); break;
2088         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS"); break;
2089         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS"); break;
2090         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY"); break;
2091         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2092         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2093         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE"); break;
2094         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2095         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2096         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2097         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION"); break;
2098         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START"); break;
2099         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2100         case GST_MESSAGE_LATENCY:                       LOGD("GST_MESSAGE_LATENCY"); break;
2101 #endif
2102
2103         default:
2104                 break;
2105         }
2106
2107         /* should not call 'gst_message_unref(msg)' */
2108         return;
2109 }
2110
2111 static GstBusSyncReply
2112 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2113 {
2114         mmplayer_t *player = (mmplayer_t *)data;
2115         GstBusSyncReply reply = GST_BUS_DROP;
2116
2117         if (!(player->pipeline && player->pipeline->mainbin)) {
2118                 LOGE("player pipeline handle is null");
2119                 return GST_BUS_PASS;
2120         }
2121
2122         if (!__mmplayer_gst_check_useful_message(player, message)) {
2123                 gst_message_unref(message);
2124                 return GST_BUS_DROP;
2125         }
2126
2127         switch (GST_MESSAGE_TYPE(message)) {
2128         case GST_MESSAGE_TAG:
2129                 __mmplayer_gst_extract_tag_from_msg(player, message);
2130
2131 #ifdef __DEBUG__
2132                 {
2133                         GstTagList *tags = NULL;
2134
2135                         gst_message_parse_tag(message, &tags);
2136                         if (tags) {
2137                                 LOGE("TAGS received from element \"%s\".",
2138                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2139
2140                                 gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT));
2141                                 gst_tag_list_unref(tags);
2142                                 tags = NULL;
2143                         }
2144                         break;
2145                 }
2146 #endif
2147                 break;
2148
2149         case GST_MESSAGE_DURATION_CHANGED:
2150                 __mmplayer_gst_handle_duration(player, message);
2151                 break;
2152         case GST_MESSAGE_ELEMENT:
2153                 {
2154                         const gchar *klass = NULL;
2155                         klass = gst_element_factory_get_metadata
2156                                 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2157                         if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2158                                 reply = GST_BUS_PASS;
2159                                 break;
2160                         }
2161                         __mmplayer_gst_handle_element_message(player, message);
2162                 }
2163                 break;
2164         case GST_MESSAGE_ASYNC_DONE:
2165                 /* NOTE:Don't call gst_callback directly
2166                  * because previous frame can be showed even though this message is received for seek.
2167                  */
2168         default:
2169                 reply = GST_BUS_PASS;
2170                 break;
2171         }
2172
2173         if (reply == GST_BUS_DROP)
2174                 gst_message_unref(message);
2175
2176         return reply;
2177 }
2178
2179 static void
2180 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2181 {
2182         GstElement *appsrc = element;
2183         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2184         GstBuffer *buffer = NULL;
2185         GstFlowReturn ret = GST_FLOW_OK;
2186         gint len = size;
2187
2188         MMPLAYER_RETURN_IF_FAIL(element);
2189         MMPLAYER_RETURN_IF_FAIL(buf);
2190
2191         buffer = gst_buffer_new();
2192
2193         if (buf->offset < 0 || buf->len < 0) {
2194                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2195                 return;
2196         }
2197
2198         if (buf->offset >= buf->len) {
2199                 LOGD("call eos appsrc");
2200                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2201                 return;
2202         }
2203
2204         if (buf->len - buf->offset < size)
2205                 len = buf->len - buf->offset;
2206
2207         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2208         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2209         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2210
2211 #ifdef __DEBUG__
2212         LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2213 #endif
2214         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2215
2216         buf->offset += len;
2217 }
2218
2219 static gboolean
2220 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2221 {
2222         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2223
2224         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2225
2226         buf->offset  = (int)size;
2227
2228         return TRUE;
2229 }
2230
2231 void
2232 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2233 {
2234         mmplayer_t *player  = (mmplayer_t *)user_data;
2235         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2236         MMMessageParamType msg_param = {0,};
2237         guint64 current_level_bytes = 0;
2238
2239         MMPLAYER_RETURN_IF_FAIL(player);
2240
2241         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2242                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2243         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2244                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2245         } else {
2246                 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2247                 return;
2248         }
2249
2250         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2251
2252         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2253
2254         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2255         msg_param.buffer_status.stream_type = stream_type;
2256         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2257         msg_param.buffer_status.bytes = current_level_bytes;
2258
2259         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2260 }
2261
2262 void
2263 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2264 {
2265         mmplayer_t *player  = (mmplayer_t *)user_data;
2266         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2267         MMMessageParamType msg_param = {0,};
2268         guint64 current_level_bytes = 0;
2269
2270         MMPLAYER_RETURN_IF_FAIL(player);
2271
2272         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2273                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2274         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2275                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2276         } else {
2277                 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2278                 return;
2279         }
2280
2281         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2282
2283         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2284
2285         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2286         msg_param.buffer_status.stream_type = stream_type;
2287         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2288         msg_param.buffer_status.bytes = current_level_bytes;
2289
2290         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2291 }
2292
2293 gboolean
2294 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2295 {
2296         mmplayer_t *player  = (mmplayer_t *)user_data;
2297         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2298         MMMessageParamType msg_param = {0,};
2299
2300         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2301
2302         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2303                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2304         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2305                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2306         } else {
2307                 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2308                 return TRUE;
2309         }
2310
2311         LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2312
2313         msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2314         msg_param.seek_data.stream_type = stream_type;
2315         msg_param.seek_data.offset = position;
2316
2317         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2318
2319         return TRUE;
2320 }
2321
2322 static gboolean
2323 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2324 {
2325 #define MAX_LEN_NAME 20
2326
2327         gboolean ret = FALSE;
2328         GstPad *sinkpad = NULL;
2329         gchar *prefix = NULL;
2330         gchar dec_name[MAX_LEN_NAME] = {0, };
2331         main_element_id_e elem_id = MMPLAYER_M_NUM;
2332
2333         mmplayer_gst_element_t *mainbin = NULL;
2334         GstElement *decodebin = NULL;
2335         GstCaps *dec_caps = NULL;
2336
2337         MMPLAYER_FENTER();
2338
2339         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2340                                                 player->pipeline &&
2341                                                 player->pipeline->mainbin, FALSE);
2342         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2343
2344         mainbin = player->pipeline->mainbin;
2345         switch (type) {
2346         case MM_PLAYER_STREAM_TYPE_AUDIO:
2347                 prefix = "audio";
2348                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2349         break;
2350         case MM_PLAYER_STREAM_TYPE_VIDEO:
2351                 prefix = "video";
2352                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2353         break;
2354         default:
2355                 LOGE("invalid type %d", type);
2356                 return FALSE;
2357         }
2358
2359         if (mainbin[elem_id].gst) {
2360                 LOGE("elem(%d) is already created", elem_id);
2361                 return FALSE;
2362         }
2363
2364         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2365
2366         /* create decodebin */
2367         decodebin = gst_element_factory_make("decodebin", dec_name);
2368         if (!decodebin) {
2369                 LOGE("failed to create %s", dec_name);
2370                 return FALSE;
2371         }
2372
2373         /* raw pad handling signal */
2374         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2375                                                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2376
2377         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2378         before looking for any elements that can handle that stream.*/
2379         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2380                                                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2381
2382         if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2383                 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2384                                                         G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2385
2386         /* This signal is emitted when a element is added to the bin.*/
2387         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2388                                                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2389
2390         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2391                 LOGE("failed to add new decodebin");
2392                 return FALSE;
2393         }
2394
2395         dec_caps = gst_pad_query_caps(srcpad, NULL);
2396         if (dec_caps) {
2397 #ifdef __DEBUG__
2398                 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2399 #endif
2400                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2401                 gst_caps_unref(dec_caps);
2402         }
2403
2404         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2405
2406         if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2407                 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2408                 goto ERROR;
2409         }
2410         gst_object_unref(GST_OBJECT(sinkpad));
2411
2412         gst_element_sync_state_with_parent(decodebin);
2413
2414         mainbin[elem_id].id = elem_id;
2415         mainbin[elem_id].gst = decodebin;
2416
2417         MMPLAYER_FLEAVE();
2418         return TRUE;
2419
2420 ERROR:
2421         if (sinkpad)
2422                 gst_object_unref(GST_OBJECT(sinkpad));
2423
2424         if (decodebin) {
2425                 gst_element_set_state(decodebin, GST_STATE_NULL);
2426                 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin))
2427                         gst_object_unref(decodebin);
2428         }
2429
2430         MMPLAYER_FLEAVE();
2431         return ret;
2432 }
2433
2434 static gboolean
2435 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2436 {
2437 #define MAX_LEN_NAME 20
2438         mmplayer_gst_element_t *mainbin = NULL;
2439         gchar *prefix = NULL;
2440         main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2441
2442         gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2443         GstElement *src = NULL, *queue = NULL;
2444         GstPad *srcpad = NULL;
2445
2446         MMPLAYER_FENTER();
2447         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2448                                 player->pipeline->mainbin, FALSE);
2449
2450         mainbin = player->pipeline->mainbin;
2451
2452         LOGD("type(%d) path is creating", type);
2453         switch (type) {
2454         case MM_PLAYER_STREAM_TYPE_AUDIO:
2455                 prefix = "audio";
2456                 if (mainbin[MMPLAYER_M_SRC].gst)
2457                         src_id = MMPLAYER_M_2ND_SRC;
2458                 else
2459                         src_id = MMPLAYER_M_SRC;
2460                 queue_id = MMPLAYER_M_A_BUFFER;
2461         break;
2462         case MM_PLAYER_STREAM_TYPE_VIDEO:
2463                 prefix = "video";
2464                 src_id = MMPLAYER_M_SRC;
2465                 queue_id = MMPLAYER_M_V_BUFFER;
2466         break;
2467         case MM_PLAYER_STREAM_TYPE_TEXT:
2468                 prefix = "subtitle";
2469                 src_id = MMPLAYER_M_SUBSRC;
2470                 queue_id = MMPLAYER_M_S_BUFFER;
2471         break;
2472         default:
2473                 LOGE("invalid type %d", type);
2474                 return FALSE;
2475         }
2476
2477         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2478         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2479
2480         /* create source */
2481         src = gst_element_factory_make("appsrc", src_name);
2482         if (!src) {
2483                 LOGF("failed to create %s", src_name);
2484                 goto ERROR;
2485         }
2486
2487         mainbin[src_id].id = src_id;
2488         mainbin[src_id].gst = src;
2489
2490         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2491                                                                 "caps", caps, NULL);
2492
2493         /* size of many video frames are larger than default blocksize as 4096 */
2494         if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2495                 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2496
2497         if (player->media_stream_buffer_max_size[type] > 0)
2498                 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2499
2500         if (player->media_stream_buffer_min_percent[type] > 0)
2501                 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2502
2503         /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2504         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2505
2506         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2507                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2508         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2509                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2510         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2511                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2512
2513         /* create queue */
2514         queue = gst_element_factory_make("queue2", queue_name);
2515         if (!queue) {
2516                 LOGE("failed to create %s", queue_name);
2517                 goto ERROR;
2518         }
2519         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2520
2521         mainbin[queue_id].id = queue_id;
2522         mainbin[queue_id].gst = queue;
2523
2524         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2525                 LOGE("failed to add src");
2526                 goto ERROR;
2527         }
2528
2529         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2530                 LOGE("failed to add queue");
2531                 goto ERROR;
2532         }
2533
2534         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2535                 LOGE("failed to link src and queue");
2536                 goto ERROR;
2537         }
2538
2539         /* create decoder */
2540         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2541         if (!srcpad) {
2542                 LOGE("failed to get srcpad of queue");
2543                 goto ERROR;
2544         }
2545
2546         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2547                 _mmplayer_gst_create_decoder(player, srcpad, caps);
2548         } else {
2549                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2550                         LOGE("failed to create decoder");
2551                         gst_object_unref(GST_OBJECT(srcpad));
2552                         goto ERROR;
2553                 }
2554         }
2555         gst_object_unref(GST_OBJECT(srcpad));
2556         return TRUE;
2557
2558 ERROR:
2559         if (mainbin[src_id].gst) {
2560                 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2561                 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst))
2562                         gst_object_unref(mainbin[src_id].gst);
2563                 mainbin[src_id].gst = NULL;
2564         }
2565
2566         if (mainbin[queue_id].gst) {
2567                 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2568                 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst))
2569                         gst_object_unref(mainbin[queue_id].gst);
2570                 mainbin[queue_id].gst = NULL;
2571         }
2572
2573         return FALSE;
2574 }
2575
2576 static void
2577 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2578 {
2579         GstPad *sinkpad = NULL;
2580         GstCaps *caps = NULL;
2581         GstElement *new_element = NULL;
2582         GstStructure *str = NULL;
2583         const gchar *name = NULL;
2584
2585         mmplayer_t *player = (mmplayer_t *)data;
2586
2587         MMPLAYER_FENTER();
2588
2589         MMPLAYER_RETURN_IF_FAIL(element && pad);
2590         MMPLAYER_RETURN_IF_FAIL(player &&
2591                                         player->pipeline &&
2592                                         player->pipeline->mainbin);
2593
2594         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2595          * num_dynamic_pad will decreased after creating a sinkbin.
2596          */
2597         player->num_dynamic_pad++;
2598         LOGD("stream count inc : %d", player->num_dynamic_pad);
2599
2600         caps = gst_pad_query_caps(pad, NULL);
2601         MMPLAYER_CHECK_NULL(caps);
2602
2603         str = gst_caps_get_structure(caps, 0);
2604         name = gst_structure_get_string(str, "media");
2605         if (!name) {
2606                 LOGE("cannot get mimetype from structure.");
2607                 goto ERROR;
2608         }
2609
2610         if (strstr(name, "video")) {
2611                 gint stype = 0;
2612                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2613
2614                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2615                         if (player->v_stream_caps) {
2616                                 gst_caps_unref(player->v_stream_caps);
2617                                 player->v_stream_caps = NULL;
2618                         }
2619
2620                         new_element = gst_element_factory_make("fakesink", NULL);
2621                         player->num_dynamic_pad--;
2622                         goto NEW_ELEMENT;
2623                 }
2624         }
2625
2626         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2627                 LOGE("failed to autoplug for caps");
2628                 goto ERROR;
2629         }
2630
2631         gst_caps_unref(caps);
2632         caps = NULL;
2633
2634 NEW_ELEMENT:
2635
2636         /* execute new_element if created*/
2637         if (new_element) {
2638                 LOGD("adding new element to pipeline");
2639
2640                 /* set state to READY before add to bin */
2641                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2642
2643                 /* add new element to the pipeline */
2644                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2645                         LOGE("failed to add autoplug element to bin");
2646                         goto ERROR;
2647                 }
2648
2649                 /* get pad from element */
2650                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2651                 if (!sinkpad) {
2652                         LOGE("failed to get sinkpad from autoplug element");
2653                         goto ERROR;
2654                 }
2655
2656                 /* link it */
2657                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2658                         LOGE("failed to link autoplug element");
2659                         goto ERROR;
2660                 }
2661
2662                 gst_object_unref(sinkpad);
2663                 sinkpad = NULL;
2664
2665                 /* run. setting PLAYING here since streaming source is live source */
2666                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2667         }
2668
2669         if (caps)
2670                 gst_caps_unref(caps);
2671
2672         MMPLAYER_FLEAVE();
2673
2674         return;
2675
2676 STATE_CHANGE_FAILED:
2677 ERROR:
2678         /* FIXIT : take care if new_element has already added to pipeline */
2679         if (new_element)
2680                 gst_object_unref(GST_OBJECT(new_element));
2681
2682         if (sinkpad)
2683                 gst_object_unref(GST_OBJECT(sinkpad));
2684
2685         if (caps)
2686                 gst_caps_unref(caps);
2687
2688         /* FIXIT : how to inform this error to MSL ????? */
2689         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2690          * then post an error to application
2691          */
2692 }
2693
2694 static void
2695 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2696 {
2697         mmplayer_t *player = (mmplayer_t *)data;
2698
2699         MMPLAYER_FENTER();
2700
2701         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2702          * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2703          * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2704          * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2705
2706          * [1] audio and video will be dumped with filesink.
2707          * [2] autoplugging is done by just using pad caps.
2708          * [3] typefinding has happened in audio but audiosink is created already before no-more-pad signal
2709          * and the video will be dumped via filesink.
2710          */
2711         if (player->num_dynamic_pad == 0) {
2712                 LOGD("it seems pad caps is directly used for autoplugging. removing fakesink now");
2713
2714                 if (!_mmplayer_gst_remove_fakesink(player,
2715                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2716                         /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2717                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2718                          * source element are not same. To overcome this situation, this function will called
2719                          * several places and several times. Therefore, this is not an error case.
2720                          */
2721                         return;
2722         }
2723
2724         /* create dot before error-return. for debugging */
2725         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2726
2727         player->no_more_pad = TRUE;
2728
2729         MMPLAYER_FLEAVE();
2730 }
2731
2732 static GstElement *
2733 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2734 {
2735         GstElement *element = NULL;
2736         gchar *user_agent = NULL;
2737         MMHandleType attrs = 0;
2738
2739         MMPLAYER_FENTER();
2740         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2741
2742         /* get profile attribute */
2743         attrs = MMPLAYER_GET_ATTRS(player);
2744         if (!attrs) {
2745                 LOGE("failed to get content attribute");
2746                 return NULL;
2747         }
2748
2749         element = gst_element_factory_make("rtspsrc", "rtsp source");
2750         if (!element) {
2751                 LOGE("failed to create rtspsrc element");
2752                 return NULL;
2753         }
2754
2755         /* get attribute */
2756         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2757
2758         SECURE_LOGD("user_agent : %s", user_agent);
2759
2760         /* setting property to streaming source */
2761         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2762         if (user_agent)
2763                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2764
2765         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2766                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2767         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2768                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2769
2770         MMPLAYER_FLEAVE();
2771         return element;
2772 }
2773
2774 static void __mmplayer_http_src_setup(GstElement *source, gpointer data)
2775 {
2776 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2777
2778         mmplayer_t *player = (mmplayer_t *)data;
2779         MMHandleType attrs = 0;
2780         gchar *user_agent, *cookies, **cookie_list;
2781         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2782         user_agent = cookies = NULL;
2783         cookie_list = NULL;
2784
2785         MMPLAYER_FENTER();
2786         MMPLAYER_RETURN_IF_FAIL(player);
2787
2788         LOGD("source element %s", GST_ELEMENT_NAME(source));
2789
2790         attrs = MMPLAYER_GET_ATTRS(player);
2791         if (!attrs) {
2792                 LOGE("failed to get content attribute");
2793                 return;
2794         }
2795
2796         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2797         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2798
2799         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2800                 http_timeout = player->ini.http_timeout;
2801
2802         SECURE_LOGD("cookies : %s", cookies);
2803         SECURE_LOGD("user_agent :  %s", user_agent);
2804         LOGD("timeout : %d", http_timeout);
2805
2806         g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2807
2808         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2809                 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2810                 g_strfreev(cookie_list);
2811         }
2812
2813         if (user_agent)
2814                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2815
2816         MMPLAYER_FLEAVE();
2817         return;
2818 }
2819
2820 static void __mmplayer_rtsp_src_setup(GstElement *source, gpointer data)
2821 {
2822         mmplayer_t *player = (mmplayer_t *)data;
2823         gchar *user_agent = NULL;
2824         MMHandleType attrs = 0;
2825
2826         MMPLAYER_FENTER();
2827         MMPLAYER_RETURN_IF_FAIL(player);
2828
2829         attrs = MMPLAYER_GET_ATTRS(player);
2830         if (!attrs) {
2831                 LOGE("failed to get content attribute");
2832                 return;
2833         }
2834
2835         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2836
2837         SECURE_LOGD("user_agent : %s", user_agent);
2838
2839         if (user_agent)
2840                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2841
2842         MMPLAYER_FLEAVE();
2843 }
2844
2845 static void
2846 __mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data)
2847 {
2848         mmplayer_t *player = (mmplayer_t *)data;
2849         GstElement *source = NULL;
2850
2851         MMPLAYER_FENTER();
2852         LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name);
2853
2854         g_object_get(orig, pspec->name, &source, NULL);
2855
2856         player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2857         player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2858
2859         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
2860                 __mmplayer_http_src_setup(source, data);
2861         } else if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2862                 __mmplayer_rtsp_src_setup(source, data);
2863         } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) {
2864                 g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL);
2865         } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
2866                 g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS,
2867                         "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
2868
2869                 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2870                                                 G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
2871                 _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2872                                                 G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
2873         }
2874         gst_object_unref (source);
2875
2876         MMPLAYER_FLEAVE();
2877 }
2878
2879 static gboolean
2880 __mmplayer_stream_equal(gconstpointer stream1, gconstpointer stream2)
2881 {
2882         const gchar *stream1_id = gst_stream_get_stream_id((GstStream *)stream1);
2883         const gchar *stream2_id = gst_stream_get_stream_id((GstStream *)stream2);
2884
2885         return (g_strcmp0(stream1_id, stream2_id) == 0);
2886 }
2887
2888 static gboolean
2889 __mmplayer_has_duplicated_stream(mmplayer_t *player, GstStreamType stype, GstStream *stream)
2890 {
2891         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2892         MMPLAYER_FENTER();
2893         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2894
2895         switch (stype) {
2896         case GST_STREAM_TYPE_AUDIO:
2897                 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2898                 break;
2899         case GST_STREAM_TYPE_VIDEO:
2900                 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2901                 break;
2902         case GST_STREAM_TYPE_TEXT:
2903                 type = MM_PLAYER_TRACK_TYPE_TEXT;
2904                 break;
2905         default:
2906                 LOGD("Skip not supported stream stype");
2907                 return FALSE;
2908         }
2909
2910         return g_ptr_array_find_with_equal_func(player->track[type].streams, stream, __mmplayer_stream_equal, NULL);
2911 }
2912
2913 static gint
2914 __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2915     GstStream * stream, gpointer data)
2916 {
2917         gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */
2918         GstStreamType stype = gst_stream_get_stream_type(stream);
2919         mmplayer_t *player = (mmplayer_t *)data;
2920         mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX;
2921         GstCaps *caps = gst_stream_get_caps(stream);
2922         GstStructure *caps_structure = NULL;
2923         gchar *caps_str = NULL;
2924
2925         LOGD("Stream type %s flags 0x%x",
2926                         gst_stream_type_get_name(stype),
2927                         gst_stream_get_stream_flags(stream));
2928         LOGD("  ID: %s", gst_stream_get_stream_id(stream));
2929
2930         if (__mmplayer_has_duplicated_stream(player, stype, stream)) {
2931                 LOGD("Already added stream, skip it");
2932                 ret = 0;
2933                 goto EXIT;
2934         }
2935
2936         if (caps) {
2937                 caps_str = gst_caps_to_string(caps);
2938                 caps_structure = gst_caps_get_structure(caps, 0);
2939                 const gchar *mime = gst_structure_get_name(caps_structure);
2940
2941                 LOGD("  caps: %s", caps_str);
2942
2943                 for (int idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
2944                         if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
2945                                 LOGW("skip [%s] by unsupported codec keyword [%s]",
2946                                                 mime, player->ini.unsupported_codec_keyword[idx]);
2947
2948                                 _mmplayer_update_not_supported_codec_info(player, NULL, mime);
2949                                 ret = 0;
2950                                 goto EXIT;
2951                         }
2952                 }
2953         }
2954
2955         switch (stype) {
2956         case GST_STREAM_TYPE_AUDIO:
2957         {
2958                 gint samplerate = 0;
2959                 gint channels = 0;
2960
2961                 type = MM_PLAYER_TRACK_TYPE_AUDIO;
2962
2963                 if (caps_structure) {
2964                         gst_structure_get_int(caps_structure, "rate", &samplerate);
2965                         gst_structure_get_int(caps_structure, "channels", &channels);
2966
2967                         if (channels > 0 && samplerate == 0) {
2968                                 LOGW("Skip corrupted audio stream");
2969                                 goto EXIT;
2970                         }
2971
2972                         if (g_strrstr(caps_str, "mobile-xmf"))
2973                                 mm_player_set_attribute((MMHandleType)player, NULL,
2974                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
2975                 }
2976                 break;
2977         }
2978         case GST_STREAM_TYPE_VIDEO:
2979         {
2980                 gint stype = 0;
2981                 gint width = 0;
2982
2983                 type = MM_PLAYER_TRACK_TYPE_VIDEO;
2984
2985                 /* do not support multi track video */
2986                 if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1)
2987                         goto EXIT;
2988
2989                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2990
2991                 /* don't make video because of not required */
2992                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
2993                         (!player->set_mode.video_export)) {
2994                         LOGD("no need video decoding, skip video stream");
2995                         goto EXIT;
2996                 }
2997
2998                 if (caps_structure) {
2999                         gst_structure_get_int(caps_structure, "width", &width);
3000
3001                         if (width != 0) {
3002                                 if (player->v_stream_caps) {
3003                                         gst_caps_unref(player->v_stream_caps);
3004                                         player->v_stream_caps = NULL;
3005                                 }
3006
3007                                 player->v_stream_caps = gst_caps_copy(caps);
3008                                 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
3009                         }
3010                 }
3011                 break;
3012         }
3013         case GST_STREAM_TYPE_TEXT:
3014                 type = MM_PLAYER_TRACK_TYPE_TEXT;
3015                 break;
3016         default:
3017                 LOGW("Skip not supported stream type");
3018                 goto EXIT;
3019         }
3020
3021         _mmplayer_track_update_stream(player, type, stream);
3022
3023         if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) {
3024                 LOGD("select this stream, active idx : %d", player->track[type].active_track_index);
3025                 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
3026                         _mmplayer_set_audio_attrs(player, caps);
3027                 ret = 1;
3028         }
3029
3030 EXIT:
3031         g_free(caps_str);
3032         if (caps)
3033                 gst_caps_unref(caps);
3034
3035         LOGD("ret %d", ret);
3036         return ret;
3037 }
3038
3039 static gboolean
3040 __mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection,
3041     GstStream * stream, gpointer data)
3042 {
3043         mmplayer_t *player = (mmplayer_t *)data;
3044         GstStreamType stype = gst_stream_get_stream_type(stream);
3045
3046         MMPLAYER_FENTER();
3047         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3048
3049         LOGD("stream type %s", gst_stream_type_get_name(stype));
3050
3051         /* public does not support audio hw decoder at the moment */
3052
3053         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
3054                 LOGW("video decoder resource is already acquired, skip it.");
3055                 return TRUE;
3056         }
3057
3058         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
3059                 LOGE("failed to acquire video decoder resource");
3060                 return FALSE;
3061         }
3062         player->interrupted_by_resource = FALSE;
3063         MMPLAYER_FLEAVE();
3064         return TRUE;
3065 }
3066
3067 static GstElement *
3068 __mmplayer_gst_find_child_element(GstBin *bin, const gchar *element_name)
3069 {
3070         GstIterator *iter = NULL;
3071         GValue item = {0, };
3072         GstElement *ch_element = NULL;
3073         GstElementFactory *ch_factory = NULL;
3074
3075         MMPLAYER_FENTER();
3076         MMPLAYER_RETURN_VAL_IF_FAIL(bin && element_name, NULL);
3077
3078         iter = gst_bin_iterate_recurse(bin);
3079         MMPLAYER_RETURN_VAL_IF_FAIL(iter, NULL);
3080
3081         while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) {
3082                 ch_element = g_value_get_object(&item);
3083                 ch_factory = gst_element_get_factory(ch_element);
3084                 LOGD("children factory %s", GST_OBJECT_NAME(ch_factory));
3085                 if (g_strrstr(GST_OBJECT_NAME(ch_factory), element_name)) {
3086                         LOGD("Find %s element", element_name);
3087                         break;
3088                 }
3089                 ch_element = NULL;
3090                 g_value_reset(&item);
3091         }
3092         gst_iterator_free(iter);
3093
3094         MMPLAYER_FLEAVE();
3095         return ch_element;
3096 }
3097
3098 static void __mmplayer_parsebin_setup(GstBin *bin, gpointer data)
3099 {
3100         mmplayer_t *player = (mmplayer_t *)data;
3101
3102         g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3103
3104         _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3105         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
3106                         G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
3107
3108         _mmplayer_add_signal_connection(player, G_OBJECT(bin),
3109         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
3110                         G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
3111 }
3112
3113 static void __mmplayer_decodebin3_setup(GstBin *bin, gpointer data)
3114 {
3115         mmplayer_t *player = (mmplayer_t *)data;
3116         int video_codec_type = 0;
3117         int audio_codec_type = 0;
3118
3119         g_object_set(G_OBJECT(bin), "message-forward", TRUE, NULL);
3120
3121         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
3122         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
3123
3124         LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type);
3125
3126         if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3127                 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-video", TRUE, NULL);
3128         if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW)
3129                 g_object_set(G_OBJECT(bin), "force-sw-decoders-for-audio", TRUE, NULL);
3130
3131         _mmplayer_add_signal_connection(player, G_OBJECT(bin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
3132                         "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player);
3133 }
3134
3135 static void
3136 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3137 {
3138         gchar *factory_name = NULL;
3139         mmplayer_t *player = (mmplayer_t *)data;
3140
3141         MMPLAYER_FENTER();
3142         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3143
3144         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
3145
3146         LOGD("child: %s, elem: %s (%s)", GST_ELEMENT_NAME(child), factory_name, GST_ELEMENT_NAME(element));
3147
3148         if (g_strrstr(factory_name, "urisourcebin")) {
3149                 GstElement *dbin3 = __mmplayer_gst_find_child_element(child, "decodebin3");
3150                 if (dbin3)
3151                         __mmplayer_decodebin3_setup(GST_BIN(dbin3), data);
3152                 else
3153                         LOGW("failed to find decodebin3");
3154         } else if (g_strrstr(factory_name, "parsebin")) {
3155                 g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); /* urisourcebin */
3156                 __mmplayer_parsebin_setup(GST_BIN(element), data);
3157         } else {
3158                 _mmplayer_gst_element_added(child, element, data);
3159         }
3160 }
3161
3162 static void
3163 __mmplayer_delete_signal_connection(mmplayer_t *player, GstElement *removed_element)
3164 {
3165         MMPLAYER_FENTER();
3166
3167         MMPLAYER_RETURN_IF_FAIL(player);
3168         MMPLAYER_RETURN_IF_FAIL(removed_element);
3169
3170         LOGD("delete signal on %s", GST_ELEMENT_NAME(removed_element));
3171
3172         for (int type = MM_PLAYER_SIGNAL_TYPE_AUTOPLUG; type < MM_PLAYER_SIGNAL_TYPE_ALL; type++) {
3173                 GList *node = player->signals[type];
3174                 while (node) {
3175                         GList *next_node = node->next;
3176                         mmplayer_signal_item_t *item = node->data;
3177                         if (item && item->obj == G_OBJECT(removed_element)) {
3178                                 player->signals[type] = g_list_delete_link(player->signals[type], node);
3179                                 MMPLAYER_FREEIF(item);
3180                         }
3181                         node = next_node;
3182                 }
3183         }
3184
3185         MMPLAYER_FLEAVE();
3186 }
3187
3188 void
3189 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
3190 {
3191         mmplayer_t *player = (mmplayer_t *)data;
3192
3193         MMPLAYER_FENTER();
3194
3195         MMPLAYER_RETURN_IF_FAIL(player);
3196
3197         LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
3198
3199         __mmplayer_delete_signal_connection(player, element);
3200
3201         MMPLAYER_FLEAVE();
3202 }
3203
3204 static GstElement *
3205 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
3206 {
3207         GstElement *uridecodebin3 = NULL;
3208
3209         MMPLAYER_FENTER();
3210         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3211
3212         uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
3213         if (!uridecodebin3) {
3214                 LOGE("failed to create uridecodebin3");
3215                 return NULL;
3216         }
3217
3218         /* get attribute */
3219         SECURE_LOGD("uri : %s", player->profile.uri);
3220
3221         /* setting property to streaming source */
3222         g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri,
3223                         "message-forward", TRUE,
3224                         "buffer-size", DEFAULT_BUFFER_SIZE_BYTES,
3225                         "use-buffering", TRUE, NULL);
3226
3227         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3228                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player);
3229
3230         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3231                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
3232
3233         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3234                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
3235
3236         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3237                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
3238
3239         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3240                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
3241
3242         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3243                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player);
3244
3245         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3246                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
3247
3248         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
3249                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
3250
3251         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3252                 LOGW("[DASH] this is still experimental feature");
3253
3254         MMPLAYER_FLEAVE();
3255         return uridecodebin3;
3256 }
3257
3258 static GstElement *
3259 __mmplayer_gst_make_http_src(mmplayer_t *player)
3260 {
3261 #define MAX_RETRY_COUNT 10
3262         GstElement *element = NULL;
3263         MMHandleType attrs = 0;
3264         gchar *user_agent, *cookies, **cookie_list;
3265         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3266
3267         user_agent = cookies = NULL;
3268         cookie_list = NULL;
3269
3270         MMPLAYER_FENTER();
3271         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3272
3273         /* get profile attribute */
3274         attrs = MMPLAYER_GET_ATTRS(player);
3275         if (!attrs) {
3276                 LOGE("failed to get content attribute");
3277                 return NULL;
3278         }
3279
3280         LOGD("using http streaming source [%s]", player->ini.httpsrc_element);
3281
3282         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
3283         if (!element) {
3284                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3285                 return NULL;
3286         }
3287
3288         /* get attribute */
3289         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
3290         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
3291
3292         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
3293                 http_timeout = player->ini.http_timeout;
3294
3295         /* get attribute */
3296         SECURE_LOGD("location : %s", player->profile.uri);
3297         SECURE_LOGD("cookies : %s", cookies);
3298         SECURE_LOGD("user_agent :  %s", user_agent);
3299         LOGD("timeout : %d", http_timeout);
3300
3301         /* setting property to streaming source */
3302         g_object_set(G_OBJECT(element), "location", player->profile.uri,
3303                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
3304                                 "retries", MAX_RETRY_COUNT, NULL);
3305
3306         /* parsing cookies */
3307         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
3308                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
3309                 g_strfreev(cookie_list);
3310         }
3311
3312         if (user_agent)
3313                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
3314
3315         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
3316                 LOGW("[DASH] this is still experimental feature");
3317
3318         MMPLAYER_FLEAVE();
3319         return element;
3320 }
3321
3322 static GstElement *
3323 __mmplayer_gst_make_file_src(mmplayer_t *player)
3324 {
3325         GstElement *element = NULL;
3326
3327         MMPLAYER_FENTER();
3328         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3329
3330         LOGD("using filesrc for 'file://' handler");
3331         if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
3332                 LOGE("failed to get storage info");
3333                 return NULL;
3334         }
3335
3336         element = gst_element_factory_make("filesrc", "source");
3337         if (!element) {
3338                 LOGE("failed to create filesrc");
3339                 return NULL;
3340         }
3341
3342         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
3343
3344         MMPLAYER_FLEAVE();
3345         return element;
3346 }
3347
3348 static gboolean
3349 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
3350 {
3351         mmplayer_t *player = (mmplayer_t *)data;
3352
3353         g_return_val_if_fail(player, FALSE);
3354         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
3355         gst_message_ref(msg);
3356
3357         g_mutex_lock(&player->bus_msg_q_lock);
3358         g_queue_push_tail(player->bus_msg_q, msg);
3359         g_mutex_unlock(&player->bus_msg_q_lock);
3360
3361         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3362         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
3363         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3364         return TRUE;
3365 }
3366
3367 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
3368 {
3369         mmplayer_t *player = (mmplayer_t *)(data);
3370         GstMessage *msg = NULL;
3371
3372         MMPLAYER_FENTER();
3373         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3374                                                 player->pipeline &&
3375                                                 player->pipeline->mainbin &&
3376                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3377                                                 NULL);
3378
3379         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3380
3381         LOGD("[handle: %p] gst bus msg thread will be started.", player);
3382         while (!player->bus_msg_thread_exit) {
3383                 g_mutex_lock(&player->bus_msg_q_lock);
3384                 msg = g_queue_pop_head(player->bus_msg_q);
3385                 g_mutex_unlock(&player->bus_msg_q_lock);
3386                 if (msg == NULL) {
3387                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3388                         continue;
3389                 }
3390                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3391                 /* handle the gst msg */
3392                 __mmplayer_gst_bus_msg_callback(msg, player);
3393                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3394                 gst_message_unref(msg);
3395         }
3396
3397         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3398         MMPLAYER_FLEAVE();
3399
3400         return NULL;
3401 }
3402
3403 static int
3404 __mmplayer_gst_check_position(mmplayer_t *player, gint64 position)
3405 {
3406         gint64 dur_nsec = 0;
3407         gint64 pos_nsec = 0;
3408
3409         MMPLAYER_FENTER();
3410         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3411
3412         if (MMPLAYER_IS_MS_BUFF_SRC(player))
3413                 return MM_ERROR_NONE;
3414
3415         /* NOTE : duration cannot be zero except live streaming.
3416          *              Since some element could have some timing problem with querying duration, try again.
3417          */
3418         if (player->duration == 0) {
3419                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3420                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3421                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3422                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3423                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3424                                 player->pending_seek.is_pending = true;
3425                                 player->pending_seek.pos = position;
3426                                 player->seek_state = MMPLAYER_SEEK_NONE;
3427                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3428                                 return MM_ERROR_PLAYER_NO_OP;
3429                         } else {
3430                                 player->seek_state = MMPLAYER_SEEK_NONE;
3431                                 return MM_ERROR_PLAYER_SEEK;
3432                         }
3433                 }
3434                 player->duration = dur_nsec;
3435         }
3436
3437         if (player->duration > 0 && player->duration < position) {
3438                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3439                 return MM_ERROR_INVALID_ARGUMENT;
3440         }
3441
3442         if (gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) {
3443                 if ((pos_nsec == player->duration) && /* current pos is end of stream  */
3444                         ((position / GST_MSECOND) == (player->duration / GST_MSECOND))) {
3445                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3446                         player->seek_state = MMPLAYER_SEEK_NONE;
3447                         return MM_ERROR_PLAYER_NO_OP;
3448                 }
3449         }
3450
3451         MMPLAYER_FLEAVE();
3452         return MM_ERROR_NONE;
3453 }
3454
3455 static gboolean
3456 __mmplayer_gst_check_seekable(mmplayer_t *player)
3457 {
3458         GstQuery *query = NULL;
3459         gboolean seekable = FALSE;
3460
3461         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3462                 return TRUE;
3463         }
3464
3465         query = gst_query_new_seeking(GST_FORMAT_TIME);
3466         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3467                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3468                 gst_query_unref(query);
3469
3470                 if (!seekable) {
3471                         LOGW("non-seekable content");
3472                         player->seek_state = MMPLAYER_SEEK_NONE;
3473                         return FALSE;
3474                 }
3475         } else {
3476                 LOGW("failed to get seeking query");
3477                 gst_query_unref(query); /* keep seeking operation */
3478         }
3479
3480         return TRUE;
3481 }
3482
3483 int
3484 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
3485 {
3486         GstState element_state = GST_STATE_VOID_PENDING;
3487         GstState element_pending_state = GST_STATE_VOID_PENDING;
3488         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3489
3490         MMPLAYER_FENTER();
3491
3492         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3493         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3494
3495         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3496
3497         /* set state */
3498         ret = gst_element_set_state(element, state);
3499         if (ret == GST_STATE_CHANGE_FAILURE) {
3500                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3501
3502                 /* dump state of all element */
3503                 _mmplayer_dump_pipeline_state(player);
3504
3505                 return MM_ERROR_PLAYER_INTERNAL;
3506         }
3507
3508         /* return here so state transition to be done in async mode */
3509         if (async) {
3510                 LOGD("async state transition. not waiting for state complete.");
3511                 return MM_ERROR_NONE;
3512         }
3513
3514         /* wait for state transition */
3515         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3516         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3517                 LOGE("failed to change [%s] element state to [%s] within %d sec",
3518                         GST_ELEMENT_NAME(element),
3519                         gst_element_state_get_name(state), timeout);
3520
3521                 LOGE(" [%s] state : %s   pending : %s",
3522                         GST_ELEMENT_NAME(element),
3523                         gst_element_state_get_name(element_state),
3524                         gst_element_state_get_name(element_pending_state));
3525
3526                 /* dump state of all element */
3527                 _mmplayer_dump_pipeline_state(player);
3528
3529                 return MM_ERROR_PLAYER_INTERNAL;
3530         }
3531
3532         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3533
3534         MMPLAYER_FLEAVE();
3535
3536         return MM_ERROR_NONE;
3537 }
3538
3539 int
3540 _mmplayer_gst_start(mmplayer_t *player)
3541 {
3542         int ret = MM_ERROR_NONE;
3543         gboolean async = FALSE;
3544
3545         MMPLAYER_FENTER();
3546
3547         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3548
3549         /* NOTE : if SetPosition was called before Start. do it now
3550          * streaming doesn't support it. so it should be always sync
3551          * !!create one more api to check if there is pending seek rather than checking variables
3552          */
3553         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3554                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3555                 ret = _mmplayer_gst_pause(player, FALSE);
3556                 if (ret != MM_ERROR_NONE) {
3557                         LOGE("failed to set state to PAUSED for pending seek");
3558                         return ret;
3559                 }
3560
3561                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3562                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3563                                 LOGW("failed to seek pending position. starting from the begin of content");
3564         }
3565
3566         LOGD("current state before doing transition");
3567         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3568         MMPLAYER_PRINT_STATE(player);
3569
3570         /* set pipeline state to PLAYING  */
3571         ret = _mmplayer_gst_set_state(player,
3572                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3573         if (ret != MM_ERROR_NONE) {
3574                 LOGE("failed to set state to PLAYING");
3575                 return ret;
3576         }
3577
3578         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3579
3580         /* generating debug info before returning error */
3581         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3582
3583         MMPLAYER_FLEAVE();
3584
3585         return ret;
3586 }
3587
3588 int
3589 _mmplayer_gst_stop(mmplayer_t *player)
3590 {
3591         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3592         MMHandleType attrs = 0;
3593         gboolean rewind = FALSE;
3594         gint timeout = 0;
3595         int ret = MM_ERROR_NONE;
3596
3597         MMPLAYER_FENTER();
3598
3599         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3600         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3601
3602         LOGD("current state before doing transition");
3603         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3604         MMPLAYER_PRINT_STATE(player);
3605
3606         attrs = MMPLAYER_GET_ATTRS(player);
3607         if (!attrs) {
3608                 LOGE("cannot get content attribute");
3609                 return MM_ERROR_PLAYER_INTERNAL;
3610         }
3611
3612         /* Just set state to PAUSED and the rewind. it's usual player behavior. */
3613         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3614
3615         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3616                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3617                 rewind = TRUE;
3618
3619         if (player->es_player_push_mode)
3620                 /* disable the async state transition because there could be no data in the pipeline */
3621                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3622
3623         /* set gst state */
3624         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3625
3626         if (player->es_player_push_mode) {
3627                 /* enable the async state transition as default operation */
3628                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3629         }
3630
3631         /* return if set_state has failed */
3632         if (ret != MM_ERROR_NONE) {
3633                 LOGE("failed to set state.");
3634                 return ret;
3635         }
3636
3637         /* rewind */
3638         if (rewind) {
3639                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3640                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3641                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3642                         LOGW("failed to rewind");
3643                         ret = MM_ERROR_PLAYER_SEEK;
3644                 }
3645         }
3646
3647         /* initialize */
3648         player->sent_bos = FALSE;
3649
3650         if (player->es_player_push_mode) //for cloudgame
3651                 timeout = 0;
3652
3653         /* wait for seek to complete */
3654         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3655         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3656                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3657         } else {
3658                 LOGE("fail to stop player.");
3659                 ret = MM_ERROR_PLAYER_INTERNAL;
3660                 _mmplayer_dump_pipeline_state(player);
3661         }
3662
3663         /* generate dot file if enabled */
3664         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3665
3666         MMPLAYER_FLEAVE();
3667
3668         return ret;
3669 }
3670
3671 int
3672 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3673 {
3674         int ret = MM_ERROR_NONE;
3675
3676         MMPLAYER_FENTER();
3677
3678         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3679         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3680
3681         LOGD("current state before doing transition");
3682         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3683         MMPLAYER_PRINT_STATE(player);
3684
3685         /* set pipeline status to PAUSED */
3686         ret = _mmplayer_gst_set_state(player,
3687                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3688
3689         if (async)
3690                 goto EXIT;
3691
3692         if (ret != MM_ERROR_NONE) {
3693                 GstMessage *msg = NULL;
3694                 GTimer *timer = NULL;
3695                 gdouble MAX_TIMEOUT_SEC = 3;
3696
3697                 LOGE("failed to set state to PAUSED");
3698
3699                 if (!player->bus_watcher) {
3700                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3701                         return ret;
3702                 }
3703
3704                 if (player->msg_posted) {
3705                         LOGE("error msg is already posted.");
3706                         return ret;
3707                 }
3708
3709                 timer = g_timer_new();
3710                 g_timer_start(timer);
3711
3712                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3713
3714                 do {
3715                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3716                         if (msg) {
3717                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3718                                         GError *error = NULL;
3719
3720                                         /* parse error code */
3721                                         gst_message_parse_error(msg, &error, NULL);
3722
3723                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3724                                                 /* Note : the streaming error from the streaming source is handled
3725                                                         *   using __mmplayer_handle_streaming_error.
3726                                                         */
3727                                                 __mmplayer_handle_streaming_error(player, msg, error);
3728
3729                                         } else if (error) {
3730                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3731
3732                                                 if (error->domain == GST_STREAM_ERROR)
3733                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3734                                                 else if (error->domain == GST_RESOURCE_ERROR)
3735                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3736                                                 else if (error->domain == GST_LIBRARY_ERROR)
3737                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3738                                                 else if (error->domain == GST_CORE_ERROR)
3739                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3740
3741                                                 g_error_free(error);
3742                                         }
3743                                         player->msg_posted = TRUE;
3744                                 }
3745                                 gst_message_unref(msg);
3746                         }
3747                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3748                 /* clean */
3749                 gst_object_unref(bus);
3750                 g_timer_stop(timer);
3751                 g_timer_destroy(timer);
3752
3753                 return ret;
3754         }
3755
3756         if (MMPLAYER_USE_DECODEBIN(player)) {
3757                 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3758                         (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3759                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3760         }
3761
3762         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3763
3764 EXIT:
3765         /* generate dot file before returning error */
3766         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3767
3768         MMPLAYER_FLEAVE();
3769
3770         return ret;
3771 }
3772
3773 int
3774 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3775 {
3776         int ret = MM_ERROR_NONE;
3777         gint timeout = 0;
3778
3779         MMPLAYER_FENTER();
3780
3781         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3782                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3783
3784         LOGD("current state before doing transition");
3785         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3786         MMPLAYER_PRINT_STATE(player);
3787
3788         if (async)
3789                 LOGD("do async state transition to PLAYING");
3790
3791         /* set pipeline state to PLAYING */
3792         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3793
3794         ret = _mmplayer_gst_set_state(player,
3795                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3796         if (ret != MM_ERROR_NONE) {
3797                 LOGE("failed to set state to PLAYING");
3798                 goto EXIT;
3799         }
3800
3801         if (!async)
3802                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3803
3804 EXIT:
3805         /* generate dot file */
3806         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3807
3808         MMPLAYER_FLEAVE();
3809
3810         return ret;
3811 }
3812
3813 /* sending event to one of sinkelements */
3814 gboolean
3815 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3816 {
3817         GstEvent *event2 = NULL;
3818         GList *sinks = NULL;
3819         gboolean res = FALSE;
3820         MMPLAYER_FENTER();
3821
3822         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3823         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3824
3825         /* While adding subtitles in live feeds seek is getting called.
3826            Adding defensive check in framework layer.*/
3827         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3828                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3829                         LOGE("Should not send seek event during live playback");
3830                         return TRUE;
3831                 }
3832         }
3833
3834         if (player->play_subtitle)
3835                 event2 = gst_event_copy((const GstEvent *)event);
3836
3837         sinks = player->sink_elements;
3838         while (sinks) {
3839                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3840
3841                 if (GST_IS_ELEMENT(sink)) {
3842                         /* keep ref to the event */
3843                         gst_event_ref(event);
3844
3845                         if ((res = gst_element_send_event(sink, event))) {
3846                                 LOGD("sending event[%s] to sink element [%s] success!",
3847                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3848
3849                                 /* rtsp case, async_done is not called after seek during pause state */
3850                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3851                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3852                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3853                                                         LOGD("RTSP seek completed, after pause state..");
3854                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3855                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3856                                                 }
3857
3858                                         }
3859                                 }
3860
3861                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3862                                         sinks = g_list_next(sinks);
3863                                         continue;
3864                                 } else {
3865                                         break;
3866                                 }
3867                         }
3868
3869                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3870                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3871                 }
3872
3873                 sinks = g_list_next(sinks);
3874         }
3875
3876         /* Note : Textbin is not linked to the video or audio bin.
3877          * It needs to send the event to the text sink separately.
3878          */
3879         if (player->play_subtitle && player->pipeline) {
3880                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3881
3882                 if (GST_IS_ELEMENT(text_sink)) {
3883                         /* keep ref to the event */
3884                         gst_event_ref(event2);
3885
3886                         if ((res = gst_element_send_event(text_sink, event2)))
3887                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3888                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3889                         else
3890                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3891                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3892
3893                         gst_event_unref(event2);
3894                 }
3895         }
3896
3897         gst_event_unref(event);
3898
3899         MMPLAYER_FLEAVE();
3900
3901         return res;
3902 }
3903
3904 gboolean
3905 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3906                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3907                         gint64 cur, GstSeekType stop_type, gint64 stop)
3908 {
3909         GstEvent *event = NULL;
3910         gboolean result = FALSE;
3911
3912         MMPLAYER_FENTER();
3913
3914         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3915
3916         if (player->pipeline && player->pipeline->textbin)
3917                 __mmplayer_drop_subtitle(player, FALSE);
3918
3919         event = gst_event_new_seek(rate, format, flags, cur_type,
3920                 cur, stop_type, stop);
3921
3922         result = _mmplayer_gst_send_event_to_sink(player, event);
3923
3924         MMPLAYER_FLEAVE();
3925
3926         return result;
3927 }
3928
3929 int
3930 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3931 {
3932         int ret = MM_ERROR_NONE;
3933         gint64 pos_nsec = 0;
3934         gboolean accurate = FALSE;
3935         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3936
3937         MMPLAYER_FENTER();
3938         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3939         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3940
3941         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3942                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3943                 goto PENDING;
3944
3945         ret = __mmplayer_gst_check_position(player, position);
3946         if (ret != MM_ERROR_NONE) {
3947                 LOGW("result of check position info 0x%X", ret);
3948                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3949         }
3950
3951         if (!__mmplayer_gst_check_seekable(player))
3952                 return MM_ERROR_PLAYER_NO_OP;
3953
3954         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3955                                 position, player->playback_rate, player->duration);
3956
3957         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3958            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3959            This causes problem is position calculation during normal pause resume scenarios also.
3960            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3961         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3962                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3963                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3964                         LOGW("getting current position failed in seek");
3965
3966                 player->last_position = pos_nsec;
3967                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3968         }
3969
3970         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3971                 LOGD("not completed seek");
3972                 return MM_ERROR_PLAYER_DOING_SEEK;
3973         }
3974
3975         if (!internal_called)
3976                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3977
3978         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3979                 that's why set position through property. */
3980         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3981                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3982                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3983                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3984
3985                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3986                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3987
3988                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3989                 player->seek_state = MMPLAYER_SEEK_NONE;
3990                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3991         } else {
3992                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurate);
3993                 if (accurate)
3994                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3995                 else
3996                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3997
3998                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3999                                                 GST_FORMAT_TIME, seek_flags,
4000                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
4001                         LOGE("failed to set position");
4002                         goto SEEK_ERROR;
4003                 }
4004         }
4005
4006         /* NOTE : store last seeking point to overcome some bad operation
4007          *     (returning zero when getting current position) of some elements
4008          */
4009         player->last_position = position;
4010
4011         /* MSL should guarantee playback rate when seek is selected during trick play of fast forward. */
4012         if (player->playback_rate > 1.0)
4013                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
4014
4015         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
4016                 LOGD("buffering should be reset after seeking");
4017                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
4018                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
4019         }
4020
4021         MMPLAYER_FLEAVE();
4022         return MM_ERROR_NONE;
4023
4024 PENDING:
4025         player->pending_seek.is_pending = true;
4026         player->pending_seek.pos = position;
4027
4028         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
4029                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
4030                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
4031                 player->pending_seek.pos);
4032
4033         return MM_ERROR_NONE;
4034
4035 SEEK_ERROR:
4036         player->seek_state = MMPLAYER_SEEK_NONE;
4037         return MM_ERROR_PLAYER_SEEK;
4038 }
4039
4040 int
4041 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
4042 {
4043 #define TRICKPLAY_OFFSET GST_MSECOND
4044
4045         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
4046         gint64 pos_nsec = 0;
4047         gboolean ret = TRUE;
4048
4049         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
4050                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4051
4052         current_state = MMPLAYER_CURRENT_STATE(player);
4053
4054         /* NOTE : query position except paused state to overcome some bad operation
4055          * please refer to below comments in details
4056          */
4057         if (current_state != MM_PLAYER_STATE_PAUSED)
4058                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
4059
4060         /* NOTE : get last point to overcome some bad operation of some elements
4061          *(returning zero when getting current position in paused state
4062          * and when failed to get position during seeking
4063          */
4064         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
4065                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
4066
4067                 if (player->playback_rate < 0.0)
4068                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
4069                 else
4070                         pos_nsec = player->last_position;
4071
4072                 if (!ret)
4073                         pos_nsec = player->last_position;
4074                 else
4075                         player->last_position = pos_nsec;
4076
4077                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
4078
4079         } else {
4080                 if (player->duration > 0 && pos_nsec > player->duration)
4081                         pos_nsec = player->duration;
4082
4083                 player->last_position = pos_nsec;
4084         }
4085
4086         *position = pos_nsec;
4087
4088         return MM_ERROR_NONE;
4089 }
4090
4091 int
4092 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
4093 {
4094 #define STREAMING_IS_FINISHED   0
4095 #define BUFFERING_MAX_PER       100
4096 #define DEFAULT_PER_VALUE       -1
4097 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
4098
4099         mmplayer_gst_element_t *mainbin = NULL;
4100         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
4101         gint64 buffered_total = 0;
4102         gint64 position = 0;
4103         gint buffered_sec = -1;
4104         GstBufferingMode mode = GST_BUFFERING_STREAM;
4105         gint64 content_size_time = player->duration;
4106         guint64 content_size_bytes = player->http_content_size;
4107
4108         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4109                                                 player->pipeline &&
4110                                                 player->pipeline->mainbin,
4111                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
4112
4113         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
4114
4115         *start_pos = 0;
4116         *end_pos = 0;
4117
4118         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4119                 /* and rtsp is not ready yet. */
4120                 LOGW("it's only used for http streaming case");
4121                 return MM_ERROR_PLAYER_NO_OP;
4122         }
4123
4124         if (content_size_time <= 0 || content_size_bytes <= 0) {
4125                 LOGW("there is no content size");
4126                 return MM_ERROR_NONE;
4127         }
4128
4129         if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
4130                 LOGW("fail to get current position");
4131                 return MM_ERROR_NONE;
4132         }
4133
4134         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
4135                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
4136
4137         mainbin = player->pipeline->mainbin;
4138         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
4139
4140         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
4141                 GstQuery *query = NULL;
4142                 gint byte_in_rate = 0, byte_out_rate = 0;
4143                 gint64 estimated_total = 0;
4144
4145                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
4146                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
4147                         LOGW("fail to get buffering query from queue2");
4148                         if (query)
4149                                 gst_query_unref(query);
4150                         return MM_ERROR_NONE;
4151                 }
4152
4153                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
4154                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
4155
4156                 if (mode == GST_BUFFERING_STREAM) {
4157                         /* using only queue in case of push mode(ts / mp3) */
4158                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
4159                                 GST_FORMAT_BYTES, &buffered_total)) {
4160                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
4161                                 end_per = 100 * buffered_total / content_size_bytes;
4162                         }
4163                 } else {
4164                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
4165                         guint idx = 0;
4166                         guint num_of_ranges = 0;
4167                         gint64 start_byte = 0, stop_byte = 0;
4168
4169                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
4170                         if (estimated_total != STREAMING_IS_FINISHED) {
4171                                 /* buffered size info from queue2 */
4172                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
4173                                 for (idx = 0; idx < num_of_ranges; idx++) {
4174                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
4175                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
4176
4177                                         buffered_total += (stop_byte - start_byte);
4178                                 }
4179                         } else {
4180                                 end_per = BUFFERING_MAX_PER;
4181                         }
4182                 }
4183                 gst_query_unref(query);
4184         }
4185
4186         if (end_per == DEFAULT_PER_VALUE) {
4187                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
4188                 if (dur_sec > 0) {
4189                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
4190
4191                         /* buffered size info from multiqueue */
4192                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
4193                                 guint curr_size_bytes = 0;
4194                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
4195                                         "curr-size-bytes", &curr_size_bytes, NULL);
4196                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
4197                                 buffered_total += curr_size_bytes;
4198                         }
4199
4200                         if (avg_byterate > 0)
4201                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
4202                         else if (player->total_maximum_bitrate > 0)
4203                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
4204                         else if (player->total_bitrate > 0)
4205                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
4206
4207                         if (buffered_sec >= 0)
4208                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
4209                 }
4210         }
4211
4212         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
4213         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
4214
4215         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
4216                 buffered_total, buffered_sec, *start_pos, *end_pos);
4217
4218         return MM_ERROR_NONE;
4219 }
4220
4221 GstElement *
4222 _mmplayer_gst_create_source(mmplayer_t *player)
4223 {
4224         GstElement *element = NULL;
4225
4226         MMPLAYER_FENTER();
4227         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4228                                 player->pipeline->mainbin, NULL);
4229
4230         /* setup source for gapless play */
4231         switch (player->profile.uri_type) {
4232         /* file source */
4233         case MM_PLAYER_URI_TYPE_FILE:
4234                 element = __mmplayer_gst_make_file_src(player);
4235                 break;
4236         case MM_PLAYER_URI_TYPE_URL_HTTP:
4237                 element = __mmplayer_gst_make_http_src(player);
4238                 break;
4239         default:
4240                 LOGE("not support uri type %d", player->profile.uri_type);
4241                 break;
4242         }
4243
4244         if (!element) {
4245                 LOGE("failed to create source element");
4246                 return NULL;
4247         }
4248
4249         MMPLAYER_FLEAVE();
4250         return element;
4251 }
4252
4253 int
4254 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
4255 {
4256         MMPLAYER_FENTER();
4257         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4258                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4259
4260         SECURE_LOGD("uri : %s", player->profile.uri);
4261
4262         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
4263
4264         if ((player->v_stream_caps) &&
4265                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
4266                 return MM_ERROR_PLAYER_INTERNAL;
4267
4268         if ((player->a_stream_caps) &&
4269                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
4270                 return MM_ERROR_PLAYER_INTERNAL;
4271
4272         if ((player->s_stream_caps) &&
4273                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
4274                 return MM_ERROR_PLAYER_INTERNAL;
4275
4276         MMPLAYER_FLEAVE();
4277         return MM_ERROR_NONE;
4278 }
4279
4280 int
4281 _mmplayer_gst_build_pipeline_with_src(mmplayer_t *player)
4282 {
4283         mmplayer_gst_element_t *mainbin = NULL;
4284         GstElement *autoplug_elem = NULL;
4285
4286         MMPLAYER_FENTER();
4287         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4288                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4289
4290         mainbin = player->pipeline->mainbin;
4291
4292         LOGD("uri type %d", player->profile.uri_type);
4293
4294         if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) &&
4295                 (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) {
4296                 return MM_ERROR_PLAYER_INTERNAL;
4297         }
4298
4299         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
4300                 g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN);
4301         }
4302
4303         autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
4304         if (!autoplug_elem) {
4305                 LOGE("failed to create uridecodebin3 element");
4306                 goto ERROR;
4307         }
4308
4309         LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4310         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4311         mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem;
4312
4313         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) {
4314                 LOGE("failed to add uridecodebin to pipeline");
4315                 goto ERROR;
4316         }
4317
4318         /* FIXME: required ?*/
4319         /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4320         mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4321         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4322
4323         if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4324                 LOGE("failed to create fakesink");
4325                 goto ERROR;
4326         }
4327         GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4328
4329         /* take ownership of fakesink. we are reusing it */
4330         gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4331
4332         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4333                 LOGE("failed to add fakesink to bin");
4334                 gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4335                 goto ERROR;
4336         }
4337
4338         MMPLAYER_FLEAVE();
4339         return MM_ERROR_NONE;
4340
4341 ERROR:
4342
4343         if (mainbin[MMPLAYER_M_AUTOPLUG].gst)
4344                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst));
4345
4346         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4347                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4348
4349         mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL;
4350         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4351
4352         return MM_ERROR_PLAYER_INTERNAL;
4353 }
4354
4355 int
4356 _mmplayer_gst_build_pipeline(mmplayer_t *player)
4357 {
4358         mmplayer_gst_element_t *mainbin = NULL;
4359         GstElement *src_elem = NULL;
4360         GstElement *autoplug_elem = NULL;
4361         GList *element_bucket = NULL;
4362         main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
4363
4364         MMPLAYER_FENTER();
4365         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4366                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4367
4368         LOGD("uri type %d", player->profile.uri_type);
4369
4370         /* create source element */
4371         switch (player->profile.uri_type) {
4372         case MM_PLAYER_URI_TYPE_URL_RTSP:
4373                 src_elem = __mmplayer_gst_make_rtsp_src(player);
4374                 break;
4375         case MM_PLAYER_URI_TYPE_URL_HTTP:
4376                 src_elem = __mmplayer_gst_make_http_src(player);
4377                 break;
4378         case MM_PLAYER_URI_TYPE_FILE:
4379                 src_elem = __mmplayer_gst_make_file_src(player);
4380                 break;
4381         case MM_PLAYER_URI_TYPE_SS:
4382                 {
4383                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
4384                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
4385                         if (!src_elem) {
4386                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
4387                                 break;
4388                         }
4389
4390                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
4391                                 LOGD("get timeout from ini");
4392                                 http_timeout = player->ini.http_timeout;
4393                         }
4394
4395                         /* setting property to streaming source */
4396                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
4397                 }
4398                 break;
4399         case MM_PLAYER_URI_TYPE_MEM:
4400                 {
4401                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4402
4403                         src_elem = gst_element_factory_make("appsrc", "mem-source");
4404                         if (!src_elem) {
4405                                 LOGE("failed to create appsrc element");
4406                                 break;
4407                         }
4408
4409                         g_object_set(src_elem, "stream-type", stream_type,
4410                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
4411
4412                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
4413                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
4414                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
4415                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
4416                 }
4417                 break;
4418         default:
4419                 LOGE("not support uri type");
4420                 break;
4421         }
4422
4423         if (!src_elem) {
4424                 LOGE("failed to create source element");
4425                 return MM_ERROR_PLAYER_INTERNAL;
4426         }
4427
4428         mainbin = player->pipeline->mainbin;
4429
4430         /* take source element */
4431         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
4432
4433         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4434         mainbin[MMPLAYER_M_SRC].gst = src_elem;
4435         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4436
4437         /* create next element for auto-plugging */
4438         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4439                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4440                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4441                 if (!autoplug_elem) {
4442                         LOGE("failed to create typefind element");
4443                         goto ERROR;
4444                 }
4445
4446                 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4447                                                                         G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4448         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4449                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4450                 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4451                 if (!autoplug_elem) {
4452                         LOGE("failed to create decodebin");
4453                         goto ERROR;
4454                 }
4455
4456                 /* default size of mq in decodebin is 2M
4457                  * but it can cause blocking issue during seeking depends on content. */
4458                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4459         }
4460
4461         if (autoplug_elem) {
4462                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4463                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4464                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4465
4466                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4467         }
4468
4469         /* add elements to pipeline */
4470         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4471                 LOGE("failed to add elements to pipeline");
4472                 goto ERROR;
4473         }
4474
4475         /* linking elements in the bucket by added order. */
4476         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4477                 LOGE("failed to link some elements");
4478                 goto ERROR;
4479         }
4480
4481         /* FIXME: need to check whether this is required or not. */
4482         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4483                 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4484                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4485                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4486                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4487
4488                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4489                         LOGE("failed to create fakesink");
4490                         goto ERROR;
4491                 }
4492                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4493
4494                 /* take ownership of fakesink. we are reusing it */
4495                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4496
4497                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4498                         LOGE("failed to add fakesink to bin");
4499                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4500                         goto ERROR;
4501                 }
4502         }
4503
4504         g_list_free(element_bucket);
4505
4506         MMPLAYER_FLEAVE();
4507         return MM_ERROR_NONE;
4508
4509 ERROR:
4510         g_list_free(element_bucket);
4511
4512         if (mainbin[MMPLAYER_M_SRC].gst)
4513                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4514
4515         if (mainbin[autoplug_elem_id].gst)
4516                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4517
4518         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4519                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4520
4521         mainbin[MMPLAYER_M_SRC].gst = NULL;
4522         mainbin[autoplug_elem_id].gst = NULL;
4523         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4524
4525         return MM_ERROR_PLAYER_INTERNAL;
4526 }
4527
4528 int
4529 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4530 {
4531         GstBus  *bus = NULL;
4532         mmplayer_gst_element_t *mainbin = NULL;
4533
4534         MMPLAYER_FENTER();
4535         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4536                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4537
4538         mainbin = player->pipeline->mainbin;
4539
4540         /* connect bus callback */
4541         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4542         if (!bus) {
4543                 LOGE("cannot get bus from pipeline");
4544                 return MM_ERROR_PLAYER_INTERNAL;
4545         }
4546
4547         player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT,
4548                                                         (GstBusFunc)__mmplayer_gst_msg_push, player,
4549                                                         (GDestroyNotify)_mmplayer_watcher_removed_notify);
4550         if (player->bus_watcher == 0) {
4551                 LOGE("failed to add bus watch");
4552                 return MM_ERROR_PLAYER_INTERNAL;
4553         }
4554
4555         g_mutex_init(&player->bus_watcher_mutex);
4556         g_cond_init(&player->bus_watcher_cond);
4557
4558         player->context.thread_default = g_main_context_get_thread_default();
4559         if (player->context.thread_default == NULL) {
4560                 player->context.thread_default = g_main_context_default();
4561                 LOGD("thread-default context is the global default context");
4562         }
4563         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4564
4565         /* set sync handler to get tag synchronously */
4566         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4567         gst_object_unref(GST_OBJECT(bus));
4568
4569         /* create gst bus_msb_cb thread */
4570         g_mutex_init(&player->bus_msg_thread_mutex);
4571         g_cond_init(&player->bus_msg_thread_cond);
4572         player->bus_msg_thread_exit = FALSE;
4573         player->bus_msg_thread =
4574                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4575         if (!player->bus_msg_thread) {
4576                 LOGE("failed to create gst BUS msg thread");
4577                 g_mutex_clear(&player->bus_msg_thread_mutex);
4578                 g_cond_clear(&player->bus_msg_thread_cond);
4579                 return MM_ERROR_PLAYER_INTERNAL;
4580         }
4581
4582         MMPLAYER_FLEAVE();
4583         return MM_ERROR_NONE;
4584 }
4585
4586 void
4587 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4588 {
4589         int ret = MM_ERROR_NONE;
4590         mmplayer_gst_element_t *mainbin = NULL;
4591         MMMessageParamType msg_param = {0,};
4592         GstElement *element = NULL;
4593         MMHandleType attrs = 0;
4594         char *uri = NULL;
4595         main_element_id_e elem_idx = MMPLAYER_M_NUM;
4596
4597         MMPLAYER_FENTER();
4598
4599         if (!player || !player->pipeline || !player->pipeline->mainbin) {
4600                 LOGE("player is not initialized");
4601                 goto ERROR;
4602         }
4603
4604         mainbin = player->pipeline->mainbin;
4605         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4606
4607         attrs = MMPLAYER_GET_ATTRS(player);
4608         if (!attrs) {
4609                 LOGE("fail to get attributes");
4610                 goto ERROR;
4611         }
4612
4613         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4614
4615         if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4616                 LOGE("failed to parse profile");
4617                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4618                 goto ERROR;
4619         }
4620
4621         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4622                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4623                 LOGE("dash or hls is not supportable");
4624                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4625                 goto ERROR;
4626         }
4627
4628         if (!MMPLAYER_USE_DECODEBIN(player)) {
4629                 ret = _mmplayer_gst_build_pipeline_with_src(player);
4630                 if (ret != MM_ERROR_NONE)
4631                         goto ERROR;
4632
4633                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4634                         LOGE("Failed to change state of uridecodebin3 element");
4635                         goto ERROR;
4636                 }
4637                 goto DONE;
4638         }
4639
4640         element = _mmplayer_gst_create_source(player);
4641         if (!element) {
4642                 LOGE("no source element was created");
4643                 goto ERROR;
4644         }
4645
4646         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4647                 LOGE("failed to add source element to pipeline");
4648                 gst_object_unref(GST_OBJECT(element));
4649                 element = NULL;
4650                 goto ERROR;
4651         }
4652
4653         /* take source element */
4654         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4655         mainbin[MMPLAYER_M_SRC].gst = element;
4656
4657         element = NULL;
4658
4659         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4660                 if (player->streamer == NULL) {
4661                         player->streamer = _mm_player_streaming_create();
4662                         _mm_player_streaming_initialize(player->streamer, TRUE);
4663                 }
4664
4665                 elem_idx = MMPLAYER_M_TYPEFIND;
4666                 element = gst_element_factory_make("typefind", "typefinder");
4667                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4668                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4669         } else {
4670                 elem_idx = MMPLAYER_M_AUTOPLUG;
4671                 element = _mmplayer_gst_make_decodebin(player);
4672         }
4673
4674         /* check autoplug element is OK */
4675         if (!element) {
4676                 LOGE("can not create element(%d)", elem_idx);
4677                 goto ERROR;
4678         }
4679
4680         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4681                 LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element));
4682                 gst_object_unref(GST_OBJECT(element));
4683                 element = NULL;
4684                 goto ERROR;
4685         }
4686
4687         mainbin[elem_idx].id = elem_idx;
4688         mainbin[elem_idx].gst = element;
4689
4690         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4691                 LOGE("Failed to link src - autoplug(or typefind)");
4692                 goto ERROR;
4693         }
4694
4695         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4696                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {  // ????
4697                         LOGE("Failed to change state of src element");
4698                         goto ERROR;
4699                 }
4700         } else {
4701                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4702                         LOGE("Failed to change state of decodebin");
4703                         goto ERROR;
4704                 }
4705         }
4706
4707         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4708                 LOGE("Failed to change state of src element");
4709                 goto ERROR;
4710         }
4711
4712 DONE:
4713         player->gapless.stream_changed = TRUE;
4714         player->gapless.running = TRUE;
4715         MMPLAYER_FLEAVE();
4716         return;
4717
4718 ERROR:
4719         if (player) {
4720                 _mmplayer_set_reconfigure_state(player, FALSE);
4721                 if (!player->msg_posted) {
4722                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4723                         player->msg_posted = TRUE;
4724                 }
4725         }
4726         return;
4727 }