[0.6.164] Apply tizen coding rule
[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         MMHandleType attrs = 0;
1043         guint64 data_size = 0;
1044         gchar *path = NULL;
1045         gint64 pos_nsec = 0;
1046         struct stat sb;
1047
1048         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1049
1050         __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */
1051
1052         attrs = MMPLAYER_GET_ATTRS(player);
1053         if (!attrs) {
1054                 LOGE("fail to get attributes.");
1055                 return;
1056         }
1057
1058         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1059                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1060                 if (stat(path, &sb) == 0)
1061                         data_size = (guint64)sb.st_size;
1062         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1063                 data_size = player->http_content_size;
1064         }
1065
1066         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1067         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1068
1069         return;
1070 }
1071
1072 static int
1073 __mmplayer_handle_buffering_playback(mm_player_t *player)
1074 {
1075         int ret = MM_ERROR_NONE;
1076         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1077         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1078         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1079         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1080
1081         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1082                 LOGW("do nothing for buffering msg");
1083                 ret = MM_ERROR_PLAYER_INVALID_STATE;
1084                 goto exit;
1085         }
1086
1087         prev_state = MMPLAYER_PREV_STATE(player);
1088         current_state = MMPLAYER_CURRENT_STATE(player);
1089         target_state = MMPLAYER_TARGET_STATE(player);
1090         pending_state = MMPLAYER_PENDING_STATE(player);
1091
1092         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1093                 MMPLAYER_STATE_GET_NAME(prev_state),
1094                 MMPLAYER_STATE_GET_NAME(current_state),
1095                 MMPLAYER_STATE_GET_NAME(pending_state),
1096                 MMPLAYER_STATE_GET_NAME(target_state),
1097                 player->streamer->buffering_state);
1098
1099         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1100                 /* NOTE : if buffering has done, player has to go to target state. */
1101                 switch (target_state) {
1102                 case MM_PLAYER_STATE_PAUSED:
1103                         {
1104                                 switch (pending_state) {
1105                                 case MM_PLAYER_STATE_PLAYING:
1106                                         __mmplayer_gst_pause(player, TRUE);
1107                                         break;
1108
1109                                 case MM_PLAYER_STATE_PAUSED:
1110                                         LOGD("player is already going to paused state, there is nothing to do.");
1111                                         break;
1112
1113                                 case MM_PLAYER_STATE_NONE:
1114                                 case MM_PLAYER_STATE_NULL:
1115                                 case MM_PLAYER_STATE_READY:
1116                                 default:
1117                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1118                                         break;
1119                                 }
1120                         }
1121                         break;
1122
1123                 case MM_PLAYER_STATE_PLAYING:
1124                         {
1125                                 switch (pending_state) {
1126                                 case MM_PLAYER_STATE_NONE:
1127                                         {
1128                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1129                                                         __mmplayer_gst_resume(player, TRUE);
1130                                         }
1131                                         break;
1132
1133                                 case MM_PLAYER_STATE_PAUSED:
1134                                         /* NOTE: It should be worked as asynchronously.
1135                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1136                                          */
1137                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
1138                                                 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1139                                                  * The current state should be changed to paused purposely to prevent state conflict.
1140                                                  */
1141                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1142                                         }
1143                                         __mmplayer_gst_resume(player, TRUE);
1144                                         break;
1145
1146                                 case MM_PLAYER_STATE_PLAYING:
1147                                         LOGD("player is already going to playing state, there is nothing to do.");
1148                                         break;
1149
1150                                 case MM_PLAYER_STATE_NULL:
1151                                 case MM_PLAYER_STATE_READY:
1152                                 default:
1153                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1154                                         break;
1155                                 }
1156                         }
1157                         break;
1158
1159                 case MM_PLAYER_STATE_NULL:
1160                 case MM_PLAYER_STATE_READY:
1161                 case MM_PLAYER_STATE_NONE:
1162                 default:
1163                         LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1164                         break;
1165                 }
1166         } else {
1167                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1168                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1169                  */
1170                 switch (pending_state) {
1171                 case MM_PLAYER_STATE_NONE:
1172                         {
1173                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1174                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1175                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1176                                                 LOGD("set pause state during buffering");
1177                                                 __mmplayer_gst_pause(player, TRUE);
1178                                         }
1179                                 }
1180                         }
1181                         break;
1182
1183                 case MM_PLAYER_STATE_PLAYING:
1184                         /* rtsp streaming pause makes rtsp server stop sending data. */
1185                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1186                                 __mmplayer_gst_pause(player, TRUE);
1187                         break;
1188
1189                 case MM_PLAYER_STATE_PAUSED:
1190                         break;
1191
1192                 case MM_PLAYER_STATE_NULL:
1193                 case MM_PLAYER_STATE_READY:
1194                 default:
1195                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1196                         break;
1197                 }
1198         }
1199
1200 exit:
1201         return ret;
1202 }
1203
1204 static VariantData *
1205 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1206 {
1207         VariantData *var_info = NULL;
1208         g_return_val_if_fail(self != NULL, NULL);
1209
1210         var_info = g_new0(VariantData, 1);
1211         if (!var_info) return NULL;
1212         var_info->bandwidth = self->bandwidth;
1213         var_info->width = self->width;
1214         var_info->height = self->height;
1215         return var_info;
1216 }
1217
1218 static gboolean
1219 __mmplayer_gst_handle_duration(mm_player_t *player, GstMessage *msg)
1220 {
1221         gint64 bytes = 0;
1222
1223         MMPLAYER_FENTER();
1224
1225         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1226         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1227
1228         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1229                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1230                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1231
1232                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1233                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1234                         player->http_content_size = (bytes > 0) ? bytes : 0;
1235                 }
1236         } else {
1237                 /* handling audio clip which has vbr. means duration is keep changing */
1238                 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1239         }
1240
1241         MMPLAYER_FLEAVE();
1242
1243         return TRUE;
1244 }
1245
1246 static gboolean
1247 __mmplayer_eos_timer_cb(gpointer u_data)
1248 {
1249         mm_player_t *player = NULL;
1250         MMHandleType attrs = 0;
1251         int count = 0;
1252
1253         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1254
1255         player = (mm_player_t *)u_data;
1256         attrs = MMPLAYER_GET_ATTRS(player);
1257
1258         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1259
1260         if (count == -1) {
1261                 gint ret_value = 0;
1262                 ret_value = __mmplayer_gst_set_position(player, 0, TRUE);
1263                 if (ret_value != MM_ERROR_NONE)
1264                         LOGE("seeking to 0 failed in repeat play");
1265         } else {
1266                 /* posting eos */
1267                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1268         }
1269
1270         /* we are returning FALSE as we need only one posting */
1271         return FALSE;
1272 }
1273
1274 static void
1275 __mmplayer_handle_eos_delay(mm_player_t *player, int delay_in_ms)
1276 {
1277         MMPLAYER_RETURN_IF_FAIL(player);
1278
1279         /* post now if delay is zero */
1280         if (delay_in_ms == 0 || player->audio_stream_render_cb) {
1281                 LOGD("eos delay is zero. posting EOS now");
1282                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1283
1284                 if (player->audio_stream_render_cb)
1285                         __mmplayer_cancel_eos_timer(player);
1286
1287                 return;
1288         }
1289
1290         /* cancel if existing */
1291         __mmplayer_cancel_eos_timer(player);
1292
1293         /* init new timeout */
1294         /* NOTE : consider give high priority to this timer */
1295         LOGD("posting EOS message after [%d] msec", delay_in_ms);
1296
1297         player->eos_timer = g_timeout_add(delay_in_ms,
1298                 __mmplayer_eos_timer_cb, player);
1299
1300         player->context.global_default = g_main_context_default();
1301         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1302
1303         /* check timer is valid. if not, send EOS now */
1304         if (player->eos_timer == 0) {
1305                 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1306                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1307         }
1308 }
1309
1310 static int
1311 __mmplayer_gst_pending_seek(mm_player_t *player)
1312 {
1313         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1314         int ret = MM_ERROR_NONE;
1315
1316         MMPLAYER_FENTER();
1317
1318         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1319
1320         if (!player->pending_seek.is_pending) {
1321                 LOGD("pending seek is not reserved. nothing to do.");
1322                 return ret;
1323         }
1324
1325         /* check player state if player could pending seek or not. */
1326         current_state = MMPLAYER_CURRENT_STATE(player);
1327
1328         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1329                 LOGW("try to pending seek in %s state, try next time. ",
1330                         MMPLAYER_STATE_GET_NAME(current_state));
1331                 return ret;
1332         }
1333
1334         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1335
1336         ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1337         if (ret != MM_ERROR_NONE)
1338                 LOGE("failed to seek pending postion. just keep staying current position.");
1339
1340         player->pending_seek.is_pending = false;
1341
1342         MMPLAYER_FLEAVE();
1343
1344         return ret;
1345 }
1346
1347 static void
1348 __mmplayer_gst_set_async(mm_player_t *player, gboolean async, enum MMPlayerSinkType type)
1349 {
1350         MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1351
1352         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1353
1354         audiobin = player->pipeline->audiobin; /* can be null */
1355         videobin = player->pipeline->videobin; /* can be null */
1356         textbin = player->pipeline->textbin;   /* can be null */
1357
1358         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1359
1360         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1361                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1362
1363         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1364                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1365
1366         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1367                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1368
1369         return;
1370 }
1371
1372 static void
1373 __mmplayer_drop_subtitle(mm_player_t *player, gboolean is_drop)
1374 {
1375         MMPlayerGstElement *textbin;
1376         MMPLAYER_FENTER();
1377
1378         MMPLAYER_RETURN_IF_FAIL(player &&
1379                                         player->pipeline &&
1380                                         player->pipeline->textbin);
1381
1382         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1383
1384         textbin = player->pipeline->textbin;
1385
1386         if (is_drop) {
1387                 LOGD("Drop subtitle text after getting EOS");
1388
1389                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1390                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1391
1392                 player->is_subtitle_force_drop = TRUE;
1393         } else {
1394                 if (player->is_subtitle_force_drop == TRUE) {
1395                         LOGD("Enable subtitle data path without drop");
1396
1397                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1398                         __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1399
1400                         LOGD("non-connected with external display");
1401
1402                         player->is_subtitle_force_drop = FALSE;
1403                 }
1404         }
1405 }
1406
1407 static void
1408 __mmplayer_gst_handle_eos_message(mm_player_t *player, GstMessage *msg)
1409 {
1410         MMHandleType attrs = 0;
1411         gint count = 0;
1412
1413         MMPLAYER_FENTER();
1414
1415         /* NOTE : EOS event is comming multiple time. watch out it */
1416         /* check state. we only process EOS when pipeline state goes to PLAYING */
1417         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1418                 LOGD("EOS received on non-playing state. ignoring it");
1419                 return;
1420         }
1421
1422         if (player->pipeline && player->pipeline->textbin)
1423                 __mmplayer_drop_subtitle(player, TRUE);
1424
1425         if ((player->audio_stream_render_cb) && (!player->audio_stream_sink_sync))
1426                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1427
1428         /* rewind if repeat count is greater then zero */
1429         /* get play count */
1430         attrs = MMPLAYER_GET_ATTRS(player);
1431         if (attrs) {
1432                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1433
1434                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1435
1436                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1437                         if (player->playback_rate < 0.0) {
1438                                 player->resumed_by_rewind = TRUE;
1439                                 _mmplayer_set_mute((MMHandleType)player, 0);
1440                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1441                         }
1442
1443                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1444
1445                         /* initialize */
1446                         player->sent_bos = FALSE;
1447
1448                         LOGD("do not post eos msg for repeating");
1449                         return;
1450                 }
1451         }
1452
1453         if (player->pipeline)
1454                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1455
1456         /* post eos message to application */
1457         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1458
1459         /* reset last position */
1460         player->last_position = 0;
1461
1462         MMPLAYER_FLEAVE();
1463         return;
1464 }
1465
1466 static void
1467 __mmplayer_gst_handle_error_message(mm_player_t *player, GstMessage *msg)
1468 {
1469         GError *error = NULL;
1470         gchar *debug = NULL;
1471
1472         MMPLAYER_FENTER();
1473
1474         /* generating debug info before returning error */
1475         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1476
1477         /* get error code */
1478         gst_message_parse_error(msg, &error, &debug);
1479
1480         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1481                 /* Note : the streaming error from the streaming source is handled
1482                  *       using __mmplayer_handle_streaming_error.
1483                  */
1484                 __mmplayer_handle_streaming_error(player, msg);
1485
1486                 /* dump state of all element */
1487                 __mmplayer_dump_pipeline_state(player);
1488         } else {
1489                 /* traslate gst error code to msl error code. then post it
1490                  * to application if needed
1491                  */
1492                 __mmplayer_handle_gst_error(player, msg, error);
1493
1494                 if (debug)
1495                         LOGE("error debug : %s", debug);
1496         }
1497
1498         MMPLAYER_FREEIF(debug);
1499         g_error_free(error);
1500
1501         MMPLAYER_FLEAVE();
1502         return;
1503 }
1504
1505 static void
1506 __mmplayer_gst_handle_buffering_message(mm_player_t *player, GstMessage *msg)
1507 {
1508         MMMessageParamType msg_param = {0, };
1509         int bRet = MM_ERROR_NONE;
1510
1511         MMPLAYER_FENTER();
1512         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1513
1514         if (!MMPLAYER_IS_STREAMING(player)) {
1515                 LOGW("this is not streaming playback.");
1516                 return;
1517         }
1518
1519         MMPLAYER_CMD_LOCK(player);
1520
1521         if (!player->streamer) {
1522                 LOGW("Pipeline is shutting down");
1523                 MMPLAYER_CMD_UNLOCK(player);
1524                 return;
1525         }
1526
1527         /* ignore the remained buffering message till getting 100% msg */
1528         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1529                 gint buffer_percent = 0;
1530
1531                 gst_message_parse_buffering(msg, &buffer_percent);
1532
1533                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1534                         LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1535                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1536                 }
1537                 MMPLAYER_CMD_UNLOCK(player);
1538                 return;
1539         }
1540
1541         /* ignore the remained buffering message */
1542         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1543                 gint buffer_percent = 0;
1544
1545                 gst_message_parse_buffering(msg, &buffer_percent);
1546
1547                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1548                                         player->streamer->buffering_percent, buffer_percent);
1549
1550                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1551                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1552                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1553
1554                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1555                 } else {
1556                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1557                         MMPLAYER_CMD_UNLOCK(player);
1558                         return;
1559                 }
1560         }
1561
1562         __mmplayer_update_buffer_setting(player, msg);
1563
1564         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1565
1566         if (bRet == MM_ERROR_NONE) {
1567                 msg_param.connection.buffering = player->streamer->buffering_percent;
1568                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1569
1570                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1571                         player->pending_resume &&
1572                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1573
1574                         player->is_external_subtitle_added_now = FALSE;
1575                         player->pending_resume = FALSE;
1576                         _mmplayer_resume((MMHandleType)player);
1577                 }
1578
1579                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1580                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1581
1582                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1583                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1584                                         player->seek_state = MMPLAYER_SEEK_NONE;
1585                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1586                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1587                                         /* Considering the async state trasition in case of RTSP.
1588                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1589                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1590                                 }
1591                         }
1592                 }
1593         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1594                 if (!player->streamer) {
1595                         LOGW("player->streamer is NULL, so discarding the buffering percent update");
1596                         MMPLAYER_CMD_UNLOCK(player);
1597                         return;
1598                 }
1599
1600                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1601
1602                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1603                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1604
1605                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1606                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1607                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1608                         } else {
1609                                 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1610                         }
1611                 } else {
1612                         msg_param.connection.buffering = player->streamer->buffering_percent;
1613                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1614                 }
1615         }
1616         MMPLAYER_CMD_UNLOCK(player);
1617
1618         MMPLAYER_FLEAVE();
1619         return;
1620
1621 }
1622
1623 static void
1624 __mmplayer_gst_handle_state_message(mm_player_t *player, GstMessage *msg)
1625 {
1626         MMPlayerGstElement *mainbin;
1627         const GValue *voldstate, *vnewstate, *vpending;
1628         GstState oldstate = GST_STATE_NULL;
1629         GstState newstate = GST_STATE_NULL;
1630         GstState pending = GST_STATE_NULL;
1631
1632         MMPLAYER_FENTER();
1633         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1634
1635         mainbin = player->pipeline->mainbin;
1636
1637         /* we only handle messages from pipeline */
1638         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1639                 return;
1640
1641         /* get state info from msg */
1642         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1643         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1644         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1645
1646         if (!voldstate || !vnewstate) {
1647                 LOGE("received msg has wrong format.");
1648                 return;
1649         }
1650
1651         oldstate = (GstState)voldstate->data[0].v_int;
1652         newstate = (GstState)vnewstate->data[0].v_int;
1653         if (vpending)
1654                 pending = (GstState)vpending->data[0].v_int;
1655
1656         LOGD("state changed [%s] : %s ---> %s     final : %s",
1657                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1658                 gst_element_state_get_name((GstState)oldstate),
1659                 gst_element_state_get_name((GstState)newstate),
1660                 gst_element_state_get_name((GstState)pending));
1661
1662         if (newstate == GST_STATE_PLAYING) {
1663                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1664
1665                         int retVal = MM_ERROR_NONE;
1666                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1667
1668                         retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1669
1670                         if (MM_ERROR_NONE != retVal)
1671                                 LOGE("failed to seek pending postion. just keep staying current position.");
1672
1673                         player->pending_seek.is_pending = false;
1674                 }
1675         }
1676
1677         if (oldstate == newstate) {
1678                 LOGD("pipeline reports state transition to old state");
1679                 return;
1680         }
1681
1682         switch (newstate) {
1683         case GST_STATE_PAUSED:
1684                 {
1685                         gboolean prepare_async = FALSE;
1686
1687                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1688                                 // managed prepare async case
1689                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1690                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1691                         }
1692
1693                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1694                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1695
1696                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1697                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1698                                                 player->total_maximum_bitrate, player->total_bitrate);
1699
1700                                 if (player->pending_seek.is_pending) {
1701                                         LOGW("trying to do pending seek");
1702                                         MMPLAYER_CMD_LOCK(player);
1703                                         __mmplayer_gst_pending_seek(player);
1704                                         MMPLAYER_CMD_UNLOCK(player);
1705                                 }
1706                         }
1707                 }
1708                 break;
1709
1710         case GST_STATE_PLAYING:
1711                 {
1712                         if (MMPLAYER_IS_STREAMING(player)) {
1713                                 // managed prepare async case when buffering is completed
1714                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1715                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1716                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1717                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1718
1719                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1720
1721                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1722                                         if (player->streamer->buffering_percent < 100) {
1723
1724                                                 MMMessageParamType msg_param = {0, };
1725                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1726
1727                                                 msg_param.connection.buffering = 100;
1728                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1729                                         }
1730                                 }
1731                         }
1732
1733                         if (player->gapless.stream_changed) {
1734                                 __mmplayer_update_content_attrs(player, ATTR_ALL);
1735                                 player->gapless.stream_changed = FALSE;
1736                         }
1737
1738                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1739                                 player->seek_state = MMPLAYER_SEEK_NONE;
1740                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1741                         }
1742                 }
1743                 break;
1744         case GST_STATE_VOID_PENDING:
1745         case GST_STATE_NULL:
1746         case GST_STATE_READY:
1747         default:
1748                 break;
1749         }
1750
1751         MMPLAYER_FLEAVE();
1752         return;
1753 }
1754
1755 static void
1756 __mmplayer_gst_handle_element_message(mm_player_t *player, GstMessage *msg)
1757 {
1758         const gchar *structure_name;
1759         gint count = 0, idx = 0;
1760         MMHandleType attrs = 0;
1761
1762         MMPLAYER_FENTER();
1763         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1764
1765         attrs = MMPLAYER_GET_ATTRS(player);
1766         if (!attrs) {
1767                 LOGE("Failed to get content attribute");
1768                 return;
1769         }
1770
1771         if (gst_message_get_structure(msg) == NULL)
1772                 return;
1773
1774         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1775         if (!structure_name)
1776                 return;
1777
1778         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1779
1780         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1781                 const GValue *var_info = NULL;
1782
1783                 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1784                 if (var_info != NULL) {
1785                         if (player->adaptive_info.var_list)
1786                                 g_list_free_full(player->adaptive_info.var_list, g_free);
1787
1788                         /* share addr or copy the list */
1789                         player->adaptive_info.var_list =
1790                                 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1791
1792                         count = g_list_length(player->adaptive_info.var_list);
1793                         if (count > 0) {
1794                                 VariantData *temp = NULL;
1795
1796                                 /* print out for debug */
1797                                 LOGD("num of variant_info %d", count);
1798                                 for (idx = 0; idx < count; idx++) {
1799                                         temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1800                                         if (temp)
1801                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1802                                 }
1803                         }
1804                 }
1805         }
1806
1807         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1808                 gint num_buffers = 0;
1809                 gint extra_num_buffers = 0;
1810
1811                 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1812                         player->video_num_buffers = num_buffers;
1813                         LOGD("video_num_buffers : %d", player->video_num_buffers);
1814                 }
1815
1816                 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1817                         player->video_extra_num_buffers = extra_num_buffers;
1818                         LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1819                 }
1820                 return;
1821         }
1822
1823         if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1824                 __mmplayer_track_update_text_attr_info(player, msg);
1825
1826         /* custom message */
1827         if (!strcmp(structure_name, "audio_codec_not_supported")) {
1828                 MMMessageParamType msg_param = {0,};
1829                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1830                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1831         }
1832
1833         /* custom message for RTSP attribute :
1834                 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1835                 sdp which has contents info is received when rtsp connection is opened.
1836                 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1837         if (!strcmp(structure_name, "rtspsrc_properties")) {
1838                 gchar *audio_codec = NULL;
1839                 gchar *video_codec = NULL;
1840                 gchar *video_frame_size = NULL;
1841
1842                 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1843                 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1844                 player->streaming_type = __mmplayer_get_stream_service_type(player);
1845
1846                 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1847                 LOGD("rtsp_audio_codec : %s", audio_codec);
1848                 if (audio_codec)
1849                         mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec);
1850
1851                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1852                 LOGD("rtsp_video_codec : %s", video_codec);
1853                 if (video_codec)
1854                         mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec);
1855
1856                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1857                 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1858                 if (video_frame_size) {
1859                         char *seperator = strchr(video_frame_size, '-');
1860                         if (seperator) {
1861                                 char video_width[10] = {0,};
1862                                 int frame_size_len = strlen(video_frame_size);
1863                                 int separtor_len = strlen(seperator);
1864
1865                                 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1866                                 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1867
1868                                 seperator++;
1869                                 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1870                         }
1871                 }
1872
1873                 if (mm_attrs_commit_all(attrs))
1874                         LOGE("failed to commit.");
1875         }
1876
1877         MMPLAYER_FLEAVE();
1878         return;
1879 }
1880
1881 static void
1882 __mmplayer_gst_handle_async_done_message(mm_player_t *player, GstMessage *msg)
1883 {
1884         MMPlayerGstElement *mainbin;
1885
1886         MMPLAYER_FENTER();
1887         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1888
1889         mainbin = player->pipeline->mainbin;
1890
1891         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1892
1893         /* we only handle messages from pipeline */
1894         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1895                 return;
1896
1897         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1898                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1899                         player->seek_state = MMPLAYER_SEEK_NONE;
1900                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1901                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1902                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1903                                 LOGD("sync %s state(%s) with parent state(%s)",
1904                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1905                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1906                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1907
1908                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1909                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1910                                    Because the buffering state is controlled according to the state transition for force resume,
1911                                    the decodebin state should be paused as player state. */
1912                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1913                         }
1914
1915                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1916                                 (player->streamer) &&
1917                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1918                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1919                                 GstQuery *query = NULL;
1920                                 gboolean busy = FALSE;
1921                                 gint percent = 0;
1922
1923                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1924                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1925                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1926                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1927                                         gst_query_unref(query);
1928
1929                                         LOGD("buffered percent(%s): %d",
1930                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1931                                 }
1932
1933                                 if (percent >= 100)
1934                                         __mmplayer_handle_buffering_playback(player);
1935                         }
1936
1937                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1938                 }
1939         }
1940
1941         MMPLAYER_FLEAVE();
1942         return;
1943 }
1944
1945 static void
1946 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1947 {
1948         mm_player_t *player = (mm_player_t *)(data);
1949
1950         MMPLAYER_RETURN_IF_FAIL(player);
1951         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1952
1953         switch (GST_MESSAGE_TYPE(msg)) {
1954         case GST_MESSAGE_UNKNOWN:
1955                 LOGD("unknown message received");
1956                 break;
1957
1958         case GST_MESSAGE_EOS:
1959                 LOGD("GST_MESSAGE_EOS received");
1960                 __mmplayer_gst_handle_eos_message(player, msg);
1961                 break;
1962
1963         case GST_MESSAGE_ERROR:
1964                 __mmplayer_gst_handle_error_message(player, msg);
1965                 break;
1966
1967         case GST_MESSAGE_WARNING:
1968                 {
1969                         char *debug = NULL;
1970                         GError *error = NULL;
1971
1972                         gst_message_parse_warning(msg, &error, &debug);
1973
1974                         LOGD("warning : %s", error->message);
1975                         LOGD("debug : %s", debug);
1976
1977                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1978
1979                         MMPLAYER_FREEIF(debug);
1980                         g_error_free(error);
1981                 }
1982                 break;
1983
1984         case GST_MESSAGE_TAG:
1985                 {
1986                         LOGD("GST_MESSAGE_TAG");
1987                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1988                                 LOGW("failed to extract tags from gstmessage");
1989                 }
1990                 break;
1991
1992         case GST_MESSAGE_BUFFERING:
1993                 __mmplayer_gst_handle_buffering_message(player, msg);
1994                 break;
1995
1996         case GST_MESSAGE_STATE_CHANGED:
1997                 __mmplayer_gst_handle_state_message(player, msg);
1998                 break;
1999
2000         case GST_MESSAGE_CLOCK_LOST:
2001                         {
2002                                 GstClock *clock = NULL;
2003                                 gboolean need_new_clock = FALSE;
2004
2005                                 gst_message_parse_clock_lost(msg, &clock);
2006                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2007
2008                                 if (!player->videodec_linked)
2009                                         need_new_clock = TRUE;
2010                                 else if (!player->ini.use_system_clock)
2011                                         need_new_clock = TRUE;
2012
2013                                 if (need_new_clock) {
2014                                         LOGD("Provide clock is TRUE, do pause->resume");
2015                                         __mmplayer_gst_pause(player, FALSE);
2016                                         __mmplayer_gst_resume(player, FALSE);
2017                                 }
2018                         }
2019                         break;
2020
2021         case GST_MESSAGE_NEW_CLOCK:
2022                         {
2023                                 GstClock *clock = NULL;
2024                                 gst_message_parse_new_clock(msg, &clock);
2025                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2026                         }
2027                         break;
2028
2029         case GST_MESSAGE_ELEMENT:
2030                 __mmplayer_gst_handle_element_message(player, msg);
2031                         break;
2032
2033         case GST_MESSAGE_DURATION_CHANGED:
2034                 {
2035                         LOGD("GST_MESSAGE_DURATION_CHANGED");
2036                         if (!__mmplayer_gst_handle_duration(player, msg))
2037                                 LOGW("failed to update duration");
2038                 }
2039                 break;
2040
2041         case GST_MESSAGE_ASYNC_START:
2042                         LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2043                 break;
2044
2045         case GST_MESSAGE_ASYNC_DONE:
2046                 __mmplayer_gst_handle_async_done_message(player, msg);
2047                 break;
2048
2049         #if 0 /* delete unnecessary logs */
2050         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2051         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START"); break;
2052         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS"); break;
2053         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS"); break;
2054         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY"); break;
2055         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2056         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2057         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE"); break;
2058         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2059         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2060         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2061         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION"); break;
2062         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START"); break;
2063         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2064         case GST_MESSAGE_LATENCY:                       LOGD("GST_MESSAGE_LATENCY"); break;
2065         #endif
2066
2067         default:
2068                 break;
2069         }
2070
2071         /* should not call 'gst_message_unref(msg)' */
2072         return;
2073 }
2074
2075 static GstBusSyncReply
2076 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2077 {
2078         mm_player_t *player = (mm_player_t *)data;
2079         GstBusSyncReply reply = GST_BUS_DROP;
2080
2081         if (!(player->pipeline && player->pipeline->mainbin)) {
2082                 LOGE("player pipeline handle is null");
2083                 return GST_BUS_PASS;
2084         }
2085
2086         if (!__mmplayer_gst_check_useful_message(player, message)) {
2087                 gst_message_unref(message);
2088                 return GST_BUS_DROP;
2089         }
2090
2091         switch (GST_MESSAGE_TYPE(message)) {
2092         case GST_MESSAGE_TAG:
2093                 __mmplayer_gst_extract_tag_from_msg(player, message);
2094
2095                 #if 0 // debug
2096                 {
2097                         GstTagList *tags = NULL;
2098
2099                         gst_message_parse_tag(message, &tags);
2100                         if (tags) {
2101                                 LOGE("TAGS received from element \"%s\".",
2102                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2103
2104                                 gst_tag_list_foreach(tags, print_tag, NULL);
2105                                 gst_tag_list_unref(tags);
2106                                 tags = NULL;
2107                         }
2108                         break;
2109                 }
2110                 #endif
2111                 break;
2112
2113         case GST_MESSAGE_DURATION_CHANGED:
2114                 __mmplayer_gst_handle_duration(player, message);
2115                 break;
2116         case GST_MESSAGE_ASYNC_DONE:
2117                 /* NOTE:Don't call gst_callback directly
2118                  * because previous frame can be showed even though this message is received for seek.
2119                  */
2120         default:
2121                 reply = GST_BUS_PASS;
2122                 break;
2123         }
2124
2125         if (reply == GST_BUS_DROP)
2126                 gst_message_unref(message);
2127
2128         return reply;
2129 }
2130
2131 static void
2132 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2133 {
2134         GstElement *appsrc = element;
2135         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2136         GstBuffer *buffer = NULL;
2137         GstFlowReturn ret = GST_FLOW_OK;
2138         gint len = size;
2139
2140         MMPLAYER_RETURN_IF_FAIL(element);
2141         MMPLAYER_RETURN_IF_FAIL(buf);
2142
2143         buffer = gst_buffer_new();
2144
2145         if (buf->offset < 0 || buf->len < 0) {
2146                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2147                 return;
2148         }
2149
2150         if (buf->offset >= buf->len) {
2151                 LOGD("call eos appsrc");
2152                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2153                 return;
2154         }
2155
2156         if (buf->len - buf->offset < size)
2157                 len = buf->len - buf->offset;
2158
2159         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2160         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2161         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2162
2163         //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2164         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2165
2166         buf->offset += len;
2167 }
2168
2169 static gboolean
2170 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2171 {
2172         MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
2173
2174         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2175
2176         buf->offset  = (int)size;
2177
2178         return TRUE;
2179 }
2180
2181 void
2182 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2183 {
2184         mm_player_t *player  = (mm_player_t *)user_data;
2185         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2186         guint64 current_level_bytes = 0;
2187
2188         MMPLAYER_RETURN_IF_FAIL(player);
2189
2190         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2191                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2192         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2193                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2194         } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2195                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2196         } else {
2197                 LOGE("can not enter here");
2198                 return;
2199         }
2200
2201         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2202
2203         LOGI("type: %d, level: %"G_GUINT64_FORMAT, type, current_level_bytes);
2204
2205         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2206         if (player->media_stream_buffer_status_cb[type])
2207                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
2208         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2209 }
2210
2211 void
2212 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2213 {
2214         mm_player_t *player  = (mm_player_t *)user_data;
2215         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2216         guint64 current_level_bytes = 0;
2217
2218         MMPLAYER_RETURN_IF_FAIL(player);
2219
2220         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2221                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2222         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2223                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2224         } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2225                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2226         } else {
2227                 LOGE("can not enter here");
2228                 return;
2229         }
2230
2231         LOGI("type: %d, buffer is full", type);
2232
2233         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2234
2235         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2236
2237         if (player->media_stream_buffer_status_cb[type])
2238                 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
2239
2240         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2241 }
2242
2243 gboolean
2244 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2245 {
2246         mm_player_t *player  = (mm_player_t *)user_data;
2247         MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2248
2249         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2250
2251         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2252                 type = MM_PLAYER_STREAM_TYPE_AUDIO;
2253         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2254                 type = MM_PLAYER_STREAM_TYPE_VIDEO;
2255         } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) {
2256                 type = MM_PLAYER_STREAM_TYPE_TEXT;
2257         } else {
2258                 LOGE("can not enter here");
2259                 return TRUE;
2260         }
2261
2262         LOGD("type: %d, pos: %"G_GUINT64_FORMAT, type, position);
2263         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
2264
2265         if (player->media_stream_seek_data_cb[type])
2266                 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
2267         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
2268
2269         return TRUE;
2270 }
2271
2272 static gboolean
2273 __mmplayer_gst_create_es_decoder(mm_player_t *player, MMPlayerStreamType type, GstPad *srcpad)
2274 {
2275 #define MAX_LEN_NAME 20
2276
2277         gboolean ret = FALSE;
2278         GstPad *sinkpad = NULL;
2279         gchar *prefix = NULL;
2280         gchar dec_name[MAX_LEN_NAME] = {0, };
2281         enum MainElementID elem_id = MMPLAYER_M_NUM;
2282
2283         MMPlayerGstElement *mainbin = NULL;
2284         GstElement *decodebin = NULL;
2285         GstCaps *dec_caps = NULL;
2286
2287         MMPLAYER_FENTER();
2288
2289         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2290                                                 player->pipeline &&
2291                                                 player->pipeline->mainbin, FALSE);
2292         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2293
2294         mainbin = player->pipeline->mainbin;
2295         switch (type) {
2296         case MM_PLAYER_STREAM_TYPE_AUDIO:
2297                 prefix = "audio";
2298                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2299         break;
2300         case MM_PLAYER_STREAM_TYPE_VIDEO:
2301                 prefix = "video";
2302                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2303         break;
2304         default:
2305                 LOGE("invalid type %d", type);
2306                 return FALSE;
2307         }
2308
2309         if (mainbin[elem_id].gst) {
2310                 LOGE("elem(%d) is already created", elem_id);
2311                 return FALSE;
2312         }
2313
2314         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2315
2316         /* create decodebin */
2317         decodebin = gst_element_factory_make("decodebin", dec_name);
2318         if (!decodebin) {
2319                 LOGE("failed to create %s", dec_name);
2320                 return FALSE;
2321         }
2322
2323         mainbin[elem_id].id = elem_id;
2324         mainbin[elem_id].gst = decodebin;
2325
2326         /* raw pad handling signal */
2327         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2328                                                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
2329
2330         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2331         before looking for any elements that can handle that stream.*/
2332         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2333                                                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
2334
2335         /* This signal is emitted when a element is added to the bin.*/
2336         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2337                                                                                 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
2338
2339         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2340                 LOGE("failed to add new decodebin");
2341                 return FALSE;
2342         }
2343
2344         dec_caps = gst_pad_query_caps(srcpad, NULL);
2345         if (dec_caps) {
2346                 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2347                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2348                 gst_caps_unref(dec_caps);
2349         }
2350
2351         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2352
2353         if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2354                 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2355                 goto ERROR;
2356         }
2357         gst_object_unref(GST_OBJECT(sinkpad));
2358
2359         gst_element_sync_state_with_parent(decodebin);
2360         MMPLAYER_FLEAVE();
2361         return TRUE;
2362
2363 ERROR:
2364         if (sinkpad)
2365                 gst_object_unref(GST_OBJECT(sinkpad));
2366
2367         if (mainbin[elem_id].gst) {
2368                 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2369                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2370                 gst_object_unref(mainbin[elem_id].gst);
2371                 mainbin[elem_id].gst = NULL;
2372         }
2373
2374         MMPLAYER_FLEAVE();
2375         return ret;
2376 }
2377
2378 static gboolean
2379 __mmplayer_gst_create_es_path(mm_player_t *player, MMPlayerStreamType type, GstCaps *caps)
2380 {
2381 #define MAX_LEN_NAME 20
2382         MMPlayerGstElement *mainbin = NULL;
2383         gchar *prefix = NULL;
2384         enum MainElementID src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2385
2386         gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2387         GstElement *src = NULL, *queue = NULL;
2388         GstPad *srcpad = NULL;
2389
2390         MMPLAYER_FENTER();
2391         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2392                                 player->pipeline->mainbin, FALSE);
2393
2394         mainbin = player->pipeline->mainbin;
2395
2396         LOGD("type(%d) path is creating", type);
2397         switch (type) {
2398         case MM_PLAYER_STREAM_TYPE_AUDIO:
2399                 prefix = "audio";
2400                 if (mainbin[MMPLAYER_M_SRC].gst)
2401                         src_id = MMPLAYER_M_2ND_SRC;
2402                 else
2403                         src_id = MMPLAYER_M_SRC;
2404                 queue_id = MMPLAYER_M_A_BUFFER;
2405         break;
2406         case MM_PLAYER_STREAM_TYPE_VIDEO:
2407                 prefix = "video";
2408                 src_id = MMPLAYER_M_SRC;
2409                 queue_id = MMPLAYER_M_V_BUFFER;
2410         break;
2411         case MM_PLAYER_STREAM_TYPE_TEXT:
2412                 prefix = "subtitle";
2413                 src_id = MMPLAYER_M_SUBSRC;
2414                 queue_id = MMPLAYER_M_S_BUFFER;
2415         break;
2416         default:
2417                 LOGE("invalid type %d", type);
2418                 return FALSE;
2419         }
2420
2421         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2422         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2423
2424         /* create source */
2425         src = gst_element_factory_make("appsrc", src_name);
2426         if (!src) {
2427                 LOGF("failed to create %s", src_name);
2428                 goto ERROR;
2429         }
2430
2431         mainbin[src_id].id = src_id;
2432         mainbin[src_id].gst = src;
2433
2434         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2435                                                                 "caps", caps, NULL);
2436
2437         /* size of many video frames are larger than default blocksize as 4096 */
2438         if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2439                 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2440
2441         if (player->media_stream_buffer_max_size[type] > 0)
2442                 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2443
2444         if (player->media_stream_buffer_min_percent[type] > 0)
2445                 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2446
2447         /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2448         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2449
2450         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2451                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2452         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2453                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2454         __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2455                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2456
2457         /* create queue */
2458         queue = gst_element_factory_make("queue2", queue_name);
2459         if (!queue) {
2460                 LOGE("failed to create %s", queue_name);
2461                 goto ERROR;
2462         }
2463         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2464
2465         mainbin[queue_id].id = queue_id;
2466         mainbin[queue_id].gst = queue;
2467
2468         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2469                 LOGE("failed to add src");
2470                 goto ERROR;
2471         }
2472
2473         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2474                 LOGE("failed to add queue");
2475                 goto ERROR;
2476         }
2477
2478         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2479                 LOGE("failed to link src and queue");
2480                 goto ERROR;
2481         }
2482
2483         /* create decoder */
2484         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2485         if (!srcpad) {
2486                 LOGE("failed to get srcpad of queue");
2487                 goto ERROR;
2488         }
2489
2490         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2491                 __mmplayer_gst_create_decoder(player, gst_element_get_static_pad(mainbin[queue_id].gst, "src"), caps);
2492         } else {
2493                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2494                         LOGE("failed to create decoder");
2495                         gst_object_unref(GST_OBJECT(srcpad));
2496                         goto ERROR;
2497                 }
2498         }
2499         gst_object_unref(GST_OBJECT(srcpad));
2500         return TRUE;
2501
2502 ERROR:
2503         if (mainbin[src_id].gst) {
2504                 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2505                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2506                 gst_object_unref(mainbin[src_id].gst);
2507                 mainbin[src_id].gst = NULL;
2508         }
2509
2510         if (mainbin[queue_id].gst) {
2511                 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2512                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2513                 gst_object_unref(mainbin[queue_id].gst);
2514                 mainbin[queue_id].gst = NULL;
2515         }
2516
2517         return FALSE;
2518 }
2519
2520 static void
2521 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2522 {
2523         GstPad *sinkpad = NULL;
2524         GstCaps *caps = NULL;
2525         GstElement *new_element = NULL;
2526         GstStructure *str = NULL;
2527         const gchar *name = NULL;
2528
2529         mm_player_t *player = (mm_player_t *)data;
2530
2531         MMPLAYER_FENTER();
2532
2533         MMPLAYER_RETURN_IF_FAIL(element && pad);
2534         MMPLAYER_RETURN_IF_FAIL(player &&
2535                                         player->pipeline &&
2536                                         player->pipeline->mainbin);
2537
2538         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2539          * num_dynamic_pad will decreased after creating a sinkbin.
2540          */
2541         player->num_dynamic_pad++;
2542         LOGD("stream count inc : %d", player->num_dynamic_pad);
2543
2544         caps = gst_pad_query_caps(pad, NULL);
2545         MMPLAYER_CHECK_NULL(caps);
2546
2547         str = gst_caps_get_structure (caps, 0);
2548         name = gst_structure_get_string(str, "media");
2549         if (!name) {
2550                 LOGE("cannot get mimetype from structure.");
2551                 goto ERROR;
2552         }
2553
2554         if (strstr(name, "video")) {
2555                 gint stype = 0;
2556                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2557
2558                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
2559                         if (player->v_stream_caps) {
2560                                 gst_caps_unref(player->v_stream_caps);
2561                                 player->v_stream_caps = NULL;
2562                         }
2563
2564                         new_element = gst_element_factory_make("fakesink", NULL);
2565                         player->num_dynamic_pad--;
2566                         goto NEW_ELEMENT;
2567                 }
2568         }
2569
2570         if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
2571                 LOGE("failed to autoplug for caps");
2572                 goto ERROR;
2573         }
2574
2575         gst_caps_unref(caps);
2576         caps = NULL;
2577
2578 NEW_ELEMENT:
2579
2580         /* excute new_element if created*/
2581         if (new_element) {
2582                 LOGD("adding new element to pipeline");
2583
2584                 /* set state to READY before add to bin */
2585                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2586
2587                 /* add new element to the pipeline */
2588                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2589                         LOGE("failed to add autoplug element to bin");
2590                         goto ERROR;
2591                 }
2592
2593                 /* get pad from element */
2594                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2595                 if (!sinkpad) {
2596                         LOGE("failed to get sinkpad from autoplug element");
2597                         goto ERROR;
2598                 }
2599
2600                 /* link it */
2601                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2602                         LOGE("failed to link autoplug element");
2603                         goto ERROR;
2604                 }
2605
2606                 gst_object_unref(sinkpad);
2607                 sinkpad = NULL;
2608
2609                 /* run. setting PLAYING here since streamming source is live source */
2610                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2611         }
2612
2613         if (caps)
2614                 gst_caps_unref(caps);
2615
2616         MMPLAYER_FLEAVE();
2617
2618         return;
2619
2620 STATE_CHANGE_FAILED:
2621 ERROR:
2622         /* FIXIT : take care if new_element has already added to pipeline */
2623         if (new_element)
2624                 gst_object_unref(GST_OBJECT(new_element));
2625
2626         if (sinkpad)
2627                 gst_object_unref(GST_OBJECT(sinkpad));
2628
2629         if (caps)
2630                 gst_caps_unref(caps);
2631
2632         /* FIXIT : how to inform this error to MSL ????? */
2633         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2634          * then post an error to application
2635          */
2636 }
2637
2638 static void
2639 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2640 {
2641         mm_player_t *player = (mm_player_t *)data;
2642
2643         MMPLAYER_FENTER();
2644
2645         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2646          * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2647          * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2648          * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2649
2650          * [1] audio and video will be dumped with filesink.
2651          * [2] autoplugging is done by just using pad caps.
2652          * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2653          * and the video will be dumped via filesink.
2654          */
2655         if (player->num_dynamic_pad == 0) {
2656                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2657
2658                 if (!__mmplayer_gst_remove_fakesink(player,
2659                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2660                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2661                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2662                          * source element are not same. To overcome this situation, this function will called
2663                          * several places and several times. Therefore, this is not an error case.
2664                          */
2665                         return;
2666         }
2667
2668         /* create dot before error-return. for debugging */
2669         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2670
2671         player->no_more_pad = TRUE;
2672
2673         MMPLAYER_FLEAVE();
2674 }
2675
2676 static GstElement *
2677 __mmplayer_gst_make_rtsp_src(mm_player_t *player)
2678 {
2679         GstElement *element = NULL;
2680         gchar *user_agent = NULL;
2681         MMHandleType attrs = 0;
2682
2683         MMPLAYER_FENTER();
2684         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2685
2686         /* get profile attribute */
2687         attrs = MMPLAYER_GET_ATTRS(player);
2688         if (!attrs) {
2689                 LOGE("failed to get content attribute");
2690                 return NULL;
2691         }
2692
2693         element = gst_element_factory_make("rtspsrc", "rtsp source");
2694         if (!element) {
2695                 LOGE("failed to create rtspsrc element");
2696                 return NULL;
2697         }
2698
2699         /* get attribute */
2700         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2701
2702         SECURE_LOGD("user_agent : %s", user_agent);
2703
2704         /* setting property to streaming source */
2705         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2706         if (user_agent)
2707                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2708
2709         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2710                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2711         __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2712                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2713
2714         MMPLAYER_FLEAVE();
2715         return element;
2716 }
2717
2718 static GstElement *
2719 __mmplayer_gst_make_http_src(mm_player_t *player)
2720 {
2721         GstElement *element = NULL;
2722         MMHandleType attrs = 0;
2723         gchar *user_agent, *cookies, **cookie_list;
2724         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2725         user_agent = cookies = NULL;
2726         cookie_list = NULL;
2727
2728         MMPLAYER_FENTER();
2729         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2730
2731         /* get profile attribute */
2732         attrs = MMPLAYER_GET_ATTRS(player);
2733         if (!attrs) {
2734                 LOGE("failed to get content attribute");
2735                 return NULL;
2736         }
2737
2738         LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2739
2740         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2741         if (!element) {
2742                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2743                 return NULL;
2744         }
2745
2746         /* get attribute */
2747         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2748         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2749
2750         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2751                 http_timeout = player->ini.http_timeout;
2752
2753         /* get attribute */
2754         SECURE_LOGD("location : %s", player->profile.uri);
2755         SECURE_LOGD("cookies : %s", cookies);
2756         SECURE_LOGD("user_agent :  %s", user_agent);
2757         LOGD("timeout : %d", http_timeout);
2758
2759         /* setting property to streaming source */
2760         g_object_set(G_OBJECT(element), "location", player->profile.uri,
2761                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), NULL);
2762
2763         /* parsing cookies */
2764         if ((cookie_list = util_get_cookie_list((const char *)cookies))) {
2765                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2766                 g_strfreev(cookie_list);
2767         }
2768
2769         if (user_agent)
2770                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2771
2772         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2773                 LOGW("[DASH] this is still experimental feature");
2774
2775         MMPLAYER_FLEAVE();
2776         return element;
2777 }
2778
2779 static GstElement *
2780 __mmplayer_gst_make_file_src(mm_player_t *player)
2781 {
2782         GstElement *element = NULL;
2783
2784         MMPLAYER_FENTER();
2785         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2786
2787         LOGD("using filesrc for 'file://' handler");
2788         if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2789                 LOGE("failed to get storage info");
2790                 return NULL;
2791         }
2792
2793         element = gst_element_factory_make("filesrc", "source");
2794         if (!element) {
2795                 LOGE("failed to create filesrc");
2796                 return NULL;
2797         }
2798
2799         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2800
2801         MMPLAYER_FLEAVE();
2802         return element;
2803 }
2804
2805 static gboolean
2806 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2807 {
2808         mm_player_t *player = (mm_player_t *)data;
2809
2810         g_return_val_if_fail(player, FALSE);
2811         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2812
2813         gst_message_ref(msg);
2814
2815         g_mutex_lock(&player->bus_msg_q_lock);
2816         g_queue_push_tail(player->bus_msg_q, msg);
2817         g_mutex_unlock(&player->bus_msg_q_lock);
2818
2819         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2820         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2821         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2822         return TRUE;
2823 }
2824
2825 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2826 {
2827         mm_player_t *player = (mm_player_t *)(data);
2828         GstMessage *msg = NULL;
2829         GstBus *bus = NULL;
2830
2831         MMPLAYER_FENTER();
2832         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2833                                                 player->pipeline &&
2834                                                 player->pipeline->mainbin &&
2835                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2836                                                 NULL);
2837
2838         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2839         if (!bus) {
2840                 LOGE("cannot get BUS from the pipeline");
2841                 return NULL;
2842         }
2843
2844         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2845
2846         LOGD("[handle: %p] gst bus msg thread will be started.", player);
2847         while (!player->bus_msg_thread_exit) {
2848                 g_mutex_lock(&player->bus_msg_q_lock);
2849                 msg = g_queue_pop_head(player->bus_msg_q);
2850                 g_mutex_unlock(&player->bus_msg_q_lock);
2851                 if (msg == NULL) {
2852                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2853                         continue;
2854                 }
2855                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2856                 /* handle the gst msg */
2857                 __mmplayer_gst_bus_msg_callback(msg, player);
2858                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2859                 gst_message_unref(msg);
2860         }
2861
2862         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2863         gst_object_unref(GST_OBJECT(bus));
2864
2865         MMPLAYER_FLEAVE();
2866         return NULL;
2867 }
2868
2869 static int
2870 __mmplayer_gst_check_duration(mm_player_t *player, gint64 position)
2871 {
2872         gint64 dur_nsec = 0;
2873
2874         MMPLAYER_FENTER();
2875         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2876
2877         if (MMPLAYER_IS_MS_BUFF_SRC(player))
2878                 return MM_ERROR_NONE;
2879
2880         /* NOTE : duration cannot be zero except live streaming.
2881          *              Since some element could have some timing problemn with quering duration, try again.
2882          */
2883         if (player->duration == 0) {
2884                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2885                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2886                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2887                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2888                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2889                                 player->pending_seek.is_pending = true;
2890                                 player->pending_seek.pos = position;
2891                                 player->seek_state = MMPLAYER_SEEK_NONE;
2892                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2893                                 return MM_ERROR_PLAYER_NO_OP;
2894                         } else {
2895                                 player->seek_state = MMPLAYER_SEEK_NONE;
2896                                 return MM_ERROR_PLAYER_SEEK;
2897                         }
2898                 }
2899                 player->duration = dur_nsec;
2900         }
2901
2902         if (player->duration > 0 && player->duration < position) {
2903                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2904                 return MM_ERROR_INVALID_ARGUMENT;
2905         }
2906
2907         MMPLAYER_FLEAVE();
2908         return MM_ERROR_NONE;
2909 }
2910
2911 static gboolean
2912 __mmplayer_gst_check_seekable(mm_player_t *player)
2913 {
2914         GstQuery *query = NULL;
2915         gboolean seekable = FALSE;
2916
2917         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2918                 return TRUE;
2919         }
2920
2921         query = gst_query_new_seeking(GST_FORMAT_TIME);
2922         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2923                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2924                 gst_query_unref(query);
2925
2926                 if (!seekable) {
2927                         LOGW("non-seekable content");
2928                         player->seek_state = MMPLAYER_SEEK_NONE;
2929                         return FALSE;
2930                 }
2931         } else {
2932                 LOGW("failed to get seeking query");
2933                 gst_query_unref(query); /* keep seeking operation */
2934         }
2935
2936         return TRUE;
2937 }
2938
2939 int
2940 __mmplayer_gst_set_state(mm_player_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
2941 {
2942         GstState element_state = GST_STATE_VOID_PENDING;
2943         GstState element_pending_state = GST_STATE_VOID_PENDING;
2944         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2945
2946         MMPLAYER_FENTER();
2947
2948         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2949         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2950
2951         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2952
2953         /* set state */
2954         ret = gst_element_set_state(element, state);
2955         if (ret == GST_STATE_CHANGE_FAILURE) {
2956                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2957
2958                 /* dump state of all element */
2959                 __mmplayer_dump_pipeline_state(player);
2960
2961                 return MM_ERROR_PLAYER_INTERNAL;
2962         }
2963
2964         /* return here so state transition to be done in async mode */
2965         if (async) {
2966                 LOGD("async state transition. not waiting for state complete.");
2967                 return MM_ERROR_NONE;
2968         }
2969
2970         /* wait for state transition */
2971         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2972         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2973                 LOGE("failed to change [%s] element state to [%s] within %d sec",
2974                         GST_ELEMENT_NAME(element),
2975                         gst_element_state_get_name(state), timeout);
2976
2977                 LOGE(" [%s] state : %s   pending : %s",
2978                         GST_ELEMENT_NAME(element),
2979                         gst_element_state_get_name(element_state),
2980                         gst_element_state_get_name(element_pending_state));
2981
2982                 /* dump state of all element */
2983                 __mmplayer_dump_pipeline_state(player);
2984
2985                 return MM_ERROR_PLAYER_INTERNAL;
2986         }
2987
2988         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2989
2990         MMPLAYER_FLEAVE();
2991
2992         return MM_ERROR_NONE;
2993 }
2994
2995 int
2996 __mmplayer_gst_start(mm_player_t *player)
2997 {
2998         int ret = MM_ERROR_NONE;
2999         gboolean async = FALSE;
3000
3001         MMPLAYER_FENTER();
3002
3003         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3004
3005         /* NOTE : if SetPosition was called before Start. do it now
3006          * streaming doesn't support it. so it should be always sync
3007          * !!create one more api to check if there is pending seek rather than checking variables
3008          */
3009         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3010                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3011                 ret = __mmplayer_gst_pause(player, FALSE);
3012                 if (ret != MM_ERROR_NONE) {
3013                         LOGE("failed to set state to PAUSED for pending seek");
3014                         return ret;
3015                 }
3016
3017                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3018                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3019                                 LOGW("failed to seek pending postion. starting from the begin of content");
3020         }
3021
3022         LOGD("current state before doing transition");
3023         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3024         MMPLAYER_PRINT_STATE(player);
3025
3026         /* set pipeline state to PLAYING  */
3027         ret = __mmplayer_gst_set_state(player,
3028                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3029         if (ret != MM_ERROR_NONE) {
3030                 LOGE("failed to set state to PLAYING");
3031                 return ret;
3032         }
3033
3034         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3035
3036         /* generating debug info before returning error */
3037         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3038
3039         MMPLAYER_FLEAVE();
3040
3041         return ret;
3042 }
3043
3044 int
3045 __mmplayer_gst_stop(mm_player_t *player)
3046 {
3047         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3048         MMHandleType attrs = 0;
3049         gboolean rewind = FALSE;
3050         gint timeout = 0;
3051         int ret = MM_ERROR_NONE;
3052
3053         MMPLAYER_FENTER();
3054
3055         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3056         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3057
3058         LOGD("current state before doing transition");
3059         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3060         MMPLAYER_PRINT_STATE(player);
3061
3062         attrs = MMPLAYER_GET_ATTRS(player);
3063         if (!attrs) {
3064                 LOGE("cannot get content attribute");
3065                 return MM_ERROR_PLAYER_INTERNAL;
3066         }
3067
3068         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3069         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3070
3071         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3072                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3073                 rewind = TRUE;
3074
3075         if (player->es_player_push_mode)
3076                 /* disable the async state transition because there could be no data in the pipeline */
3077                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3078
3079         /* set gst state */
3080         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3081
3082         if (player->es_player_push_mode) {
3083                 /* enable the async state transition as default operation */
3084                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3085         }
3086
3087         /* return if set_state has failed */
3088         if (ret != MM_ERROR_NONE) {
3089                 LOGE("failed to set state.");
3090                 return ret;
3091         }
3092
3093         /* rewind */
3094         if (rewind) {
3095                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3096                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3097                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3098                         LOGW("failed to rewind");
3099                         ret = MM_ERROR_PLAYER_SEEK;
3100                 }
3101         }
3102
3103         /* initialize */
3104         player->sent_bos = FALSE;
3105
3106         if (player->es_player_push_mode) //for cloudgame
3107                 timeout = 0;
3108
3109         /* wait for seek to complete */
3110         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3111         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3112                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3113         } else {
3114                 LOGE("fail to stop player.");
3115                 ret = MM_ERROR_PLAYER_INTERNAL;
3116                 __mmplayer_dump_pipeline_state(player);
3117         }
3118
3119         /* generate dot file if enabled */
3120         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3121
3122         MMPLAYER_FLEAVE();
3123
3124         return ret;
3125 }
3126
3127 int
3128 __mmplayer_gst_pause(mm_player_t *player, gboolean async)
3129 {
3130         int ret = MM_ERROR_NONE;
3131
3132         MMPLAYER_FENTER();
3133
3134         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3135         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3136
3137         LOGD("current state before doing transition");
3138         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3139         MMPLAYER_PRINT_STATE(player);
3140
3141         /* set pipeline status to PAUSED */
3142         ret = __mmplayer_gst_set_state(player,
3143                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3144
3145         if (async)
3146                 goto EXIT;
3147
3148         if (ret != MM_ERROR_NONE) {
3149                 GstMessage *msg = NULL;
3150                 GTimer *timer = NULL;
3151                 gdouble MAX_TIMEOUT_SEC = 3;
3152
3153                 LOGE("failed to set state to PAUSED");
3154
3155                 if (!player->bus_watcher) {
3156                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3157                         return ret;
3158                 }
3159
3160                 if (player->msg_posted) {
3161                         LOGE("error msg is already posted.");
3162                         return ret;
3163                 }
3164
3165                 timer = g_timer_new();
3166                 g_timer_start(timer);
3167
3168                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3169
3170                 do {
3171                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3172                         if (msg) {
3173                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3174                                         GError *error = NULL;
3175
3176                                         /* parse error code */
3177                                         gst_message_parse_error(msg, &error, NULL);
3178
3179                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3180                                                 /* Note : the streaming error from the streaming source is handled
3181                                                         *   using __mmplayer_handle_streaming_error.
3182                                                         */
3183                                                 __mmplayer_handle_streaming_error(player, msg);
3184
3185                                         } else if (error) {
3186                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3187
3188                                                 if (error->domain == GST_STREAM_ERROR)
3189                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3190                                                 else if (error->domain == GST_RESOURCE_ERROR)
3191                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3192                                                 else if (error->domain == GST_LIBRARY_ERROR)
3193                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3194                                                 else if (error->domain == GST_CORE_ERROR)
3195                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3196
3197                                                 g_error_free(error);
3198                                         }
3199                                         player->msg_posted = TRUE;
3200                                 }
3201                                 gst_message_unref(msg);
3202                         }
3203                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3204                 /* clean */
3205                 gst_object_unref(bus);
3206                 g_timer_stop(timer);
3207                 g_timer_destroy(timer);
3208
3209                 return ret;
3210         }
3211
3212         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
3213                 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3214                 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3215
3216         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3217
3218 EXIT:
3219         /* generate dot file before returning error */
3220         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3221
3222         MMPLAYER_FLEAVE();
3223
3224         return ret;
3225 }
3226
3227 int
3228 __mmplayer_gst_resume(mm_player_t *player, gboolean async)
3229 {
3230         int ret = MM_ERROR_NONE;
3231         gint timeout = 0;
3232
3233         MMPLAYER_FENTER();
3234
3235         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3236                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3237
3238         LOGD("current state before doing transition");
3239         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3240         MMPLAYER_PRINT_STATE(player);
3241
3242         if (async)
3243                 LOGD("do async state transition to PLAYING");
3244
3245         /* set pipeline state to PLAYING */
3246         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3247
3248         ret = __mmplayer_gst_set_state(player,
3249                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3250         if (ret != MM_ERROR_NONE) {
3251                 LOGE("failed to set state to PLAYING");
3252                 goto EXIT;
3253         }
3254
3255         if (!async)
3256                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3257
3258 EXIT:
3259         /* generate dot file */
3260         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3261
3262         MMPLAYER_FLEAVE();
3263
3264         return ret;
3265 }
3266
3267 /* sending event to one of sinkelements */
3268 gboolean
3269 __mmplayer_gst_send_event_to_sink(mm_player_t *player, GstEvent *event)
3270 {
3271         GstEvent *event2 = NULL;
3272         GList *sinks = NULL;
3273         gboolean res = FALSE;
3274         MMPLAYER_FENTER();
3275
3276         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3277         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3278
3279         /* While adding subtitles in live feeds seek is getting called.
3280            Adding defensive check in framework layer.*/
3281         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3282                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3283                         LOGE("Should not send seek event during live playback");
3284                         return TRUE;
3285                 }
3286         }
3287
3288         if (player->play_subtitle)
3289                 event2 = gst_event_copy((const GstEvent *)event);
3290
3291         sinks = player->sink_elements;
3292         while (sinks) {
3293                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3294
3295                 if (GST_IS_ELEMENT(sink)) {
3296                         /* keep ref to the event */
3297                         gst_event_ref(event);
3298
3299                         if ((res = gst_element_send_event(sink, event))) {
3300                                 LOGD("sending event[%s] to sink element [%s] success!",
3301                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3302
3303                                 /* rtsp case, asyn_done is not called after seek during pause state */
3304                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3305                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3306                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3307                                                         LOGD("RTSP seek completed, after pause state..");
3308                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3309                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3310                                                 }
3311
3312                                         }
3313                                 }
3314
3315                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3316                                         sinks = g_list_next(sinks);
3317                                         continue;
3318                                 } else {
3319                                         break;
3320                                 }
3321                         }
3322
3323                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3324                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3325                 }
3326
3327                 sinks = g_list_next(sinks);
3328         }
3329
3330         /* Note : Textbin is not linked to the video or audio bin.
3331          * It needs to send the event to the text sink seperatelly.
3332          */
3333         if (player->play_subtitle && player->pipeline) {
3334                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3335
3336                 if (GST_IS_ELEMENT(text_sink)) {
3337                         /* keep ref to the event */
3338                         gst_event_ref(event2);
3339
3340                         if ((res = gst_element_send_event(text_sink, event2)))
3341                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3342                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3343                         else
3344                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3345                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3346
3347                         gst_event_unref(event2);
3348                 }
3349         }
3350
3351         gst_event_unref(event);
3352
3353         MMPLAYER_FLEAVE();
3354
3355         return res;
3356 }
3357
3358 gboolean
3359 __mmplayer_gst_seek(mm_player_t *player, GstElement *element, gdouble rate,
3360                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3361                         gint64 cur, GstSeekType stop_type, gint64 stop)
3362 {
3363         GstEvent *event = NULL;
3364         gboolean result = FALSE;
3365
3366         MMPLAYER_FENTER();
3367
3368         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3369
3370         if (player->pipeline && player->pipeline->textbin)
3371                 __mmplayer_drop_subtitle(player, FALSE);
3372
3373         event = gst_event_new_seek(rate, format, flags, cur_type,
3374                 cur, stop_type, stop);
3375
3376         result = __mmplayer_gst_send_event_to_sink(player, event);
3377
3378         MMPLAYER_FLEAVE();
3379
3380         return result;
3381 }
3382
3383 int
3384 __mmplayer_gst_set_position(mm_player_t *player, gint64 position, gboolean internal_called)
3385 {
3386         int ret = MM_ERROR_NONE;
3387         gint64 pos_nsec = 0;
3388         gboolean accurated = FALSE;
3389         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3390
3391         MMPLAYER_FENTER();
3392         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3393         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3394
3395         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3396                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3397                 goto PENDING;
3398
3399         ret = __mmplayer_gst_check_duration(player, position);
3400         if (ret != MM_ERROR_NONE) {
3401                 LOGE("failed to check duration 0x%X", ret);
3402                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3403         }
3404
3405         if (!__mmplayer_gst_check_seekable(player))
3406                 return MM_ERROR_PLAYER_NO_OP;
3407
3408         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3409                                 position, player->playback_rate, player->duration);
3410
3411         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3412            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3413            This causes problem is position calculation during normal pause resume scenarios also.
3414            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3415         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3416                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3417                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3418                         LOGW("getting current position failed in seek");
3419
3420                 player->last_position = pos_nsec;
3421                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3422         }
3423
3424         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3425                 LOGD("not completed seek");
3426                 return MM_ERROR_PLAYER_DOING_SEEK;
3427         }
3428
3429         if (!internal_called)
3430                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3431
3432         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3433                 that's why set position through property. */
3434         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3435                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3436                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3437                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3438
3439                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3440                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3441
3442                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3443                 player->seek_state = MMPLAYER_SEEK_NONE;
3444                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3445         } else {
3446                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3447                 if (accurated)
3448                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3449                 else
3450                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3451
3452                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3453                                                 GST_FORMAT_TIME, seek_flags,
3454                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3455                         LOGE("failed to set position");
3456                         goto SEEK_ERROR;
3457                 }
3458         }
3459
3460         /* NOTE : store last seeking point to overcome some bad operation
3461          *     (returning zero when getting current position) of some elements
3462          */
3463         player->last_position = position;
3464
3465         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3466         if (player->playback_rate > 1.0)
3467                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3468
3469         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3470                 LOGD("buffering should be reset after seeking");
3471                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3472                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3473         }
3474
3475         MMPLAYER_FLEAVE();
3476         return MM_ERROR_NONE;
3477
3478 PENDING:
3479         player->pending_seek.is_pending = true;
3480         player->pending_seek.pos = position;
3481
3482         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3483                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3484                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3485                 player->pending_seek.pos);
3486
3487         return MM_ERROR_NONE;
3488
3489 SEEK_ERROR:
3490         player->seek_state = MMPLAYER_SEEK_NONE;
3491         return MM_ERROR_PLAYER_SEEK;
3492 }
3493
3494 int
3495 __mmplayer_gst_get_position(mm_player_t *player, gint64 *position)
3496 {
3497 #define TRICKPLAY_OFFSET GST_MSECOND
3498
3499         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
3500         gint64 pos_nsec = 0;
3501         gboolean ret = TRUE;
3502
3503         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3504                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3505
3506         current_state = MMPLAYER_CURRENT_STATE(player);
3507
3508         /* NOTE : query position except paused state to overcome some bad operation
3509          * please refer to below comments in details
3510          */
3511         if (current_state != MM_PLAYER_STATE_PAUSED)
3512                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3513
3514         /* NOTE : get last point to overcome some bad operation of some elements
3515          *(returning zero when getting current position in paused state
3516          * and when failed to get postion during seeking
3517          */
3518         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3519                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3520
3521                 if (player->playback_rate < 0.0)
3522                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3523                 else
3524                         pos_nsec = player->last_position;
3525
3526                 if (!ret)
3527                         pos_nsec = player->last_position;
3528                 else
3529                         player->last_position = pos_nsec;
3530
3531                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3532
3533         } else {
3534                 if (player->duration > 0 && pos_nsec > player->duration)
3535                         pos_nsec = player->duration;
3536
3537                 player->last_position = pos_nsec;
3538         }
3539
3540         *position = pos_nsec;
3541
3542         return MM_ERROR_NONE;
3543 }
3544
3545 int
3546 __mmplayer_gst_get_buffer_position(mm_player_t *player, int *start_pos, int *end_pos)
3547 {
3548 #define STREAMING_IS_FINISHED   0
3549 #define BUFFERING_MAX_PER       100
3550 #define DEFAULT_PER_VALUE       -1
3551 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3552
3553         MMPlayerGstElement *mainbin = NULL;
3554         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3555         gint64 buffered_total = 0;
3556         gint64 position = 0;
3557         gint buffered_sec = -1;
3558         GstBufferingMode mode = GST_BUFFERING_STREAM;
3559         gint64 content_size_time = player->duration;
3560         guint64 content_size_bytes = player->http_content_size;
3561
3562         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3563                                                 player->pipeline &&
3564                                                 player->pipeline->mainbin,
3565                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3566
3567         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3568
3569         *start_pos = 0;
3570         *end_pos = 0;
3571
3572         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3573                 /* and rtsp is not ready yet. */
3574                 LOGW("it's only used for http streaming case");
3575                 return MM_ERROR_PLAYER_NO_OP;
3576         }
3577
3578         if (content_size_time <= 0 || content_size_bytes <= 0) {
3579                 LOGW("there is no content size");
3580                 return MM_ERROR_NONE;
3581         }
3582
3583         if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3584                 LOGW("fail to get current position");
3585                 return MM_ERROR_NONE;
3586         }
3587
3588         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3589                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3590
3591         mainbin = player->pipeline->mainbin;
3592         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3593
3594         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3595                 GstQuery *query = NULL;
3596                 gint byte_in_rate = 0, byte_out_rate = 0;
3597                 gint64 estimated_total = 0;
3598
3599                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3600                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3601                         LOGW("fail to get buffering query from queue2");
3602                         if (query)
3603                                 gst_query_unref(query);
3604                         return MM_ERROR_NONE;
3605                 }
3606
3607                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3608                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3609
3610                 if (mode == GST_BUFFERING_STREAM) {
3611                         /* using only queue in case of push mode(ts / mp3) */
3612                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3613                                 GST_FORMAT_BYTES, &buffered_total)) {
3614                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3615                                 end_per = 100 * buffered_total / content_size_bytes;
3616                         }
3617                 } else {
3618                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3619                         guint idx = 0;
3620                         guint num_of_ranges = 0;
3621                         gint64 start_byte = 0, stop_byte = 0;
3622
3623                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3624                         if (estimated_total != STREAMING_IS_FINISHED) {
3625                                 /* buffered size info from queue2 */
3626                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3627                                 for (idx = 0; idx < num_of_ranges; idx++) {
3628                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3629                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3630
3631                                         buffered_total += (stop_byte - start_byte);
3632                                 }
3633                         } else {
3634                                 end_per = BUFFERING_MAX_PER;
3635                         }
3636                 }
3637                 gst_query_unref(query);
3638         }
3639
3640         if (end_per == DEFAULT_PER_VALUE) {
3641                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3642                 if (dur_sec > 0) {
3643                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3644
3645                         /* buffered size info from multiqueue */
3646                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3647                                 guint curr_size_bytes = 0;
3648                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3649                                         "curr-size-bytes", &curr_size_bytes, NULL);
3650                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3651                                 buffered_total += curr_size_bytes;
3652                         }
3653
3654                         if (avg_byterate > 0)
3655                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3656                         else if (player->total_maximum_bitrate > 0)
3657                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3658                         else if (player->total_bitrate > 0)
3659                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3660
3661                         if (buffered_sec >= 0)
3662                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3663                 }
3664         }
3665
3666         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3667         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3668
3669         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3670                 buffered_total, buffered_sec, *start_pos, *end_pos);
3671
3672         return MM_ERROR_NONE;
3673 }
3674
3675 GstElement *
3676 __mmplayer_gst_create_source(mm_player_t *player)
3677 {
3678         GstElement *element = NULL;
3679
3680         MMPLAYER_FENTER();
3681         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3682                                 player->pipeline->mainbin, NULL);
3683
3684         /* setup source for gapless play */
3685         switch (player->profile.uri_type) {
3686         /* file source */
3687         case MM_PLAYER_URI_TYPE_FILE:
3688                 element = __mmplayer_gst_make_file_src(player);
3689                 break;
3690         case MM_PLAYER_URI_TYPE_URL_HTTP:
3691                 element = __mmplayer_gst_make_http_src(player);
3692                 break;
3693         default:
3694                 LOGE("not support uri type %d", player->profile.uri_type);
3695                 break;
3696         }
3697
3698         if (!element) {
3699                 LOGE("failed to create source element");
3700                 return NULL;
3701         }
3702
3703         MMPLAYER_FLEAVE();
3704         return element;
3705 }
3706
3707 int
3708 __mmplayer_gst_build_es_pipeline(mm_player_t *player)
3709 {
3710         MMHandleType attrs = 0;
3711
3712         MMPLAYER_FENTER();
3713         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3714                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3715
3716         /* get profile attribute */
3717         attrs = MMPLAYER_GET_ATTRS(player);
3718         if (!attrs) {
3719                 LOGE("failed to get content attribute");
3720                 return MM_ERROR_PLAYER_INTERNAL;
3721         }
3722
3723         SECURE_LOGD("uri : %s", player->profile.uri);
3724
3725         mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
3726         if (mm_attrs_commit_all(attrs)) /* return -1 if error */
3727                 LOGE("failed to commit");
3728
3729         if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))
3730                 return MM_ERROR_PLAYER_INTERNAL;
3731
3732         if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))
3733                 return MM_ERROR_PLAYER_INTERNAL;
3734
3735         if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))
3736                 return MM_ERROR_PLAYER_INTERNAL;
3737
3738         MMPLAYER_FLEAVE();
3739         return MM_ERROR_NONE;
3740 }
3741
3742 int
3743 __mmplayer_gst_build_pipeline(mm_player_t *player)
3744 {
3745         MMPlayerGstElement *mainbin = NULL;
3746         GstElement *src_elem = NULL;
3747         GstElement *autoplug_elem = NULL;
3748         GList *element_bucket = NULL;
3749         MMHandleType attrs = 0;
3750         enum MainElementID autoplug_elem_id = MMPLAYER_M_NUM;
3751
3752         MMPLAYER_FENTER();
3753         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3754                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3755
3756         /* get profile attribute */
3757         attrs = MMPLAYER_GET_ATTRS(player);
3758         if (!attrs) {
3759                 LOGE("failed to get content attribute");
3760                 return MM_ERROR_PLAYER_INTERNAL;
3761         }
3762
3763         LOGD("uri type %d", player->profile.uri_type);
3764
3765         /* create source element */
3766         switch (player->profile.uri_type) {
3767         case MM_PLAYER_URI_TYPE_URL_RTSP:
3768                 src_elem = __mmplayer_gst_make_rtsp_src(player);
3769                 break;
3770         case MM_PLAYER_URI_TYPE_URL_HTTP:
3771                 src_elem = __mmplayer_gst_make_http_src(player);
3772                 break;
3773         case MM_PLAYER_URI_TYPE_FILE:
3774                 src_elem = __mmplayer_gst_make_file_src(player);
3775                 break;
3776         case MM_PLAYER_URI_TYPE_SS:
3777                 {
3778                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3779                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3780                         if (!src_elem) {
3781                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3782                                 break;
3783                         }
3784
3785                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3786                                 LOGD("get timeout from ini");
3787                                 http_timeout = player->ini.http_timeout;
3788                         }
3789
3790                         /* setting property to streaming source */
3791                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3792                 }
3793                 break;
3794         case MM_PLAYER_URI_TYPE_MEM:
3795                 {
3796                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3797
3798                         src_elem = gst_element_factory_make("appsrc", "mem-source");
3799                         if (!src_elem) {
3800                                 LOGE("failed to create appsrc element");
3801                                 break;
3802                         }
3803
3804                         g_object_set(src_elem, "stream-type", stream_type,
3805                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3806
3807                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3808                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3809                         __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3810                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3811                 }
3812                 break;
3813         default:
3814                 LOGE("not support uri type");
3815                 break;
3816         }
3817
3818         if (!src_elem) {
3819                 LOGE("failed to create source element");
3820                 return MM_ERROR_PLAYER_INTERNAL;
3821         }
3822
3823         mainbin = player->pipeline->mainbin;
3824
3825         /* take source element */
3826         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3827
3828         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3829         mainbin[MMPLAYER_M_SRC].gst = src_elem;
3830         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3831
3832         /* create next element for auto-plugging */
3833         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3834                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3835                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3836                 if (!autoplug_elem) {
3837                         LOGE("failed to create typefind element");
3838                         goto ERROR;
3839                 }
3840
3841                 __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3842                                                                         G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
3843         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3844                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3845                 autoplug_elem = __mmplayer_gst_make_decodebin(player);
3846                 if (!autoplug_elem) {
3847                         LOGE("failed to create decodebin");
3848                         goto ERROR;
3849                 }
3850
3851                 /* default size of mq in decodebin is 2M
3852                  * but it can cause blocking issue during seeking depends on content. */
3853                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3854         }
3855
3856         if (autoplug_elem) {
3857                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3858                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3859                 mainbin[autoplug_elem_id].gst = autoplug_elem;
3860
3861                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3862         }
3863
3864         /* add elements to pipeline */
3865         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3866                 LOGE("failed to add elements to pipeline");
3867                 goto ERROR;
3868         }
3869
3870         /* linking elements in the bucket by added order. */
3871         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3872                 LOGE("failed to link some elements");
3873                 goto ERROR;
3874         }
3875
3876         /* FIXME: need to check whether this is required or not. */
3877         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) {
3878                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3879                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3880                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3881
3882                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3883                         LOGE("failed to create fakesink");
3884                         goto ERROR;
3885                 }
3886                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3887
3888                 /* take ownership of fakesink. we are reusing it */
3889                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3890
3891                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3892                         LOGE("failed to add fakesink to bin");
3893                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3894                         goto ERROR;
3895                 }
3896         }
3897
3898         g_list_free(element_bucket);
3899
3900         MMPLAYER_FLEAVE();
3901         return MM_ERROR_NONE;
3902
3903 ERROR:
3904         g_list_free(element_bucket);
3905
3906         if (mainbin[MMPLAYER_M_SRC].gst)
3907                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3908
3909         if (mainbin[autoplug_elem_id].gst)
3910                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3911
3912         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3913                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3914
3915         mainbin[MMPLAYER_M_SRC].gst = NULL;
3916         mainbin[autoplug_elem_id].gst = NULL;
3917         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3918
3919         return MM_ERROR_PLAYER_INTERNAL;
3920 }
3921
3922 int
3923 __mmplayer_gst_add_bus_watch(mm_player_t *player)
3924 {
3925         GstBus  *bus = NULL;
3926         MMPlayerGstElement *mainbin = NULL;
3927
3928         MMPLAYER_FENTER();
3929         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3930                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3931
3932         mainbin = player->pipeline->mainbin;
3933
3934         /* connect bus callback */
3935         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3936         if (!bus) {
3937                 LOGE("cannot get bus from pipeline");
3938                 return MM_ERROR_PLAYER_INTERNAL;
3939         }
3940
3941         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3942         player->context.thread_default = g_main_context_get_thread_default();
3943         if (player->context.thread_default == NULL) {
3944                 player->context.thread_default = g_main_context_default();
3945                 LOGD("thread-default context is the global default context");
3946         }
3947         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3948
3949         /* set sync handler to get tag synchronously */
3950         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3951         gst_object_unref(GST_OBJECT(bus));
3952
3953         /* create gst bus_msb_cb thread */
3954         g_mutex_init(&player->bus_msg_thread_mutex);
3955         g_cond_init(&player->bus_msg_thread_cond);
3956         player->bus_msg_thread_exit = FALSE;
3957         player->bus_msg_thread =
3958                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3959         if (!player->bus_msg_thread) {
3960                 LOGE("failed to create gst BUS msg thread");
3961                 g_mutex_clear(&player->bus_msg_thread_mutex);
3962                 g_cond_clear(&player->bus_msg_thread_cond);
3963                 return MM_ERROR_PLAYER_INTERNAL;
3964         }
3965
3966         MMPLAYER_FLEAVE();
3967         return MM_ERROR_NONE;
3968 }