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