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