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