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