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