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