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