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