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