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