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