[0.6.195] apply the RM policy about audio offload
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.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 <glib.h>
29 #include <gst/gst.h>
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <sys/time.h>
36 #include <stdlib.h>
37 #include <dlog.h>
38 #include <gio/gio.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_sound.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
52
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
57
58 /*===========================================================================================
59 |                                                                                                                                                                                       |
60 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
61 |                                                                                                                                                                                       |
62 ========================================================================================== */
63
64 /*---------------------------------------------------------------------------
65 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
66 ---------------------------------------------------------------------------*/
67
68 /*---------------------------------------------------------------------------
69 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
70 ---------------------------------------------------------------------------*/
71
72 /*---------------------------------------------------------------------------
73 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
74 ---------------------------------------------------------------------------*/
75
76 /*---------------------------------------------------------------------------
77 |    LOCAL #defines:                                                                                                            |
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
81
82 #define MM_VOLUME_FACTOR_DEFAULT                1.0
83 #define MM_VOLUME_FACTOR_MIN                    0
84 #define MM_VOLUME_FACTOR_MAX                    1.0
85
86 /* Don't need to sleep for sound fadeout
87  * fadeout related fucntion will be deleted(Deprecated)
88  */
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
90
91 #define DEFAULT_PLAYBACK_RATE                   1.0
92
93 #define PLAYER_DISPLAY_MODE_DST_ROI             5
94
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96
97 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101
102 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
104
105 #define FAKE_SINK_MAX_LATENESS         G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106
107 #define DEFAULT_PCM_OUT_FORMAT         "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE     44100
109 #define DEFAULT_PCM_OUT_CHANNEL        2
110
111 /*---------------------------------------------------------------------------
112 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
113 ---------------------------------------------------------------------------*/
114
115 /*---------------------------------------------------------------------------
116 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119  We are defining our own and will be removed when it actually exposed */
120 typedef enum {
121         GST_AUTOPLUG_SELECT_TRY,
122         GST_AUTOPLUG_SELECT_EXPOSE,
123         GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
125
126 /*---------------------------------------------------------------------------
127 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
128 ---------------------------------------------------------------------------*/
129
130 /*---------------------------------------------------------------------------
131 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
134
135 /*---------------------------------------------------------------------------
136 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
137 ---------------------------------------------------------------------------*/
138 static int              __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int              __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int              __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int              __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int              __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int              __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
144
145 static void             __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void             __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void             __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad, GstCaps *caps,  gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void     __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void     __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
155
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void             __mmplayer_release_misc(mmplayer_t *player);
158 static void             __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
164
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int              __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int              __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void             __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void             __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void             __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int              __mmplayer_gst_realize(mmplayer_t *player);
176 static int              __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int              __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int              __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
179
180 /* util */
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void             __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void             __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void             __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
194
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
198
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
203
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
207 |                                                                                                                                                                                       |
208 |  FUNCTION DEFINITIONS                                                                                                                                         |
209 |                                                                                                                                                                                       |
210 ========================================================================================== */
211
212 #if 0 //debug
213 static void
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
215 {
216         gint i, count;
217
218         count = gst_tag_list_get_tag_size(list, tag);
219
220         LOGD("count = %d", count);
221
222         for (i = 0; i < count; i++) {
223                 gchar *str;
224
225                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
227                                 g_assert_not_reached();
228                 } else {
229                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
230                 }
231
232                 if (i == 0)
233                         g_print("  %15s: %s", gst_tag_get_nick(tag), str);
234                 else
235                         g_print("                 : %s", str);
236
237                 g_free(str);
238         }
239 }
240 #endif
241
242 /* This function should be called after the pipeline goes PAUSED or higher
243 state. */
244 gboolean
245 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
246 {
247         static gboolean has_duration = FALSE;
248         static gboolean has_video_attrs = FALSE;
249         static gboolean has_audio_attrs = FALSE;
250         static gboolean has_bitrate = FALSE;
251         gboolean missing_only = FALSE;
252         gboolean all = FALSE;
253         MMHandleType attrs = 0;
254
255         MMPLAYER_FENTER();
256
257         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
258
259         /* check player state here */
260         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262                 /* give warning now only */
263                 LOGW("be careful. content attributes may not available in this state ");
264         }
265
266         /* get content attribute first */
267         attrs = MMPLAYER_GET_ATTRS(player);
268         if (!attrs) {
269                 LOGE("cannot get content attribute");
270                 return FALSE;
271         }
272
273         /* get update flag */
274
275         if (flag & ATTR_MISSING_ONLY) {
276                 missing_only = TRUE;
277                 LOGD("updating missed attr only");
278         }
279
280         if (flag & ATTR_ALL) {
281                 all = TRUE;
282                 has_duration = FALSE;
283                 has_video_attrs = FALSE;
284                 has_audio_attrs = FALSE;
285                 has_bitrate = FALSE;
286
287                 LOGD("updating all attrs");
288         }
289
290         if (missing_only && all) {
291                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292                 missing_only = FALSE;
293         }
294
295         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296                 has_duration = __mmplayer_update_duration_value(player);
297
298         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299                 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
300
301         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302                 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
303
304         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305                 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306
307         /* validate all */
308         if (mm_attrs_commit_all(attrs)) {
309                 LOGE("failed to update attributes");
310                 return FALSE;
311         }
312
313         MMPLAYER_FLEAVE();
314
315         return TRUE;
316 }
317
318 MMStreamingType
319 _mmplayer_get_stream_service_type(mmplayer_t *player)
320 {
321         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
322
323         MMPLAYER_FENTER();
324
325         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
326                         player->pipeline &&
327                         player->pipeline->mainbin &&
328                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329                         STREAMING_SERVICE_NONE);
330
331         /* streaming service type if streaming */
332         if (!MMPLAYER_IS_STREAMING(player))
333                 return STREAMING_SERVICE_NONE;
334
335         streaming_type = (player->duration == 0) ?
336                 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
337
338         switch (streaming_type) {
339         case STREAMING_SERVICE_LIVE:
340                 LOGD("it's live streaming");
341                 break;
342         case STREAMING_SERVICE_VOD:
343                 LOGD("it's vod streaming");
344                 break;
345         default:
346                 LOGE("should not get here");
347                 break;
348         }
349
350         MMPLAYER_FLEAVE();
351
352         return streaming_type;
353 }
354
355 /* this function sets the player state and also report
356  * it to applicaton by calling callback function
357  */
358 void
359 _mmplayer_set_state(mmplayer_t *player, int state)
360 {
361         MMMessageParamType msg = {0, };
362
363         MMPLAYER_RETURN_IF_FAIL(player);
364
365         if (MMPLAYER_CURRENT_STATE(player) == state) {
366                 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
368                 return;
369         }
370
371         /* update player states */
372         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373         MMPLAYER_CURRENT_STATE(player) = state;
374
375         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377
378         /* print state */
379         MMPLAYER_PRINT_STATE(player);
380
381         switch (MMPLAYER_CURRENT_STATE(player)) {
382         case MM_PLAYER_STATE_NULL:
383         case MM_PLAYER_STATE_READY:
384                 break;
385         case MM_PLAYER_STATE_PAUSED:
386                 __mmplayer_set_pause_state(player);
387                 break;
388         case MM_PLAYER_STATE_PLAYING:
389                 __mmplayer_set_playing_state(player);
390                 break;
391         case MM_PLAYER_STATE_NONE:
392         default:
393                 LOGW("invalid target state, there is nothing to do.");
394                 break;
395         }
396
397
398         /* post message to application */
399         if (MMPLAYER_TARGET_STATE(player) == state) {
400                 /* fill the message with state of player */
401                 msg.union_type = MM_MSG_UNION_STATE;
402                 msg.state.previous = MMPLAYER_PREV_STATE(player);
403                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
404
405                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
406
407                 /* state changed by resource callback */
408                 if (player->interrupted_by_resource)
409                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410                 else /* state changed by usecase */
411                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412
413         } else {
414                 LOGD("intermediate state, do nothing.");
415                 MMPLAYER_PRINT_STATE(player);
416                 return;
417         }
418
419         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420                 && !player->sent_bos) {
421                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422                 player->sent_bos = TRUE;
423         }
424
425         return;
426 }
427
428 int
429 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
430 {
431         mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432         mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
433
434         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
435
436         //LOGD("incomming command : %d ", command);
437
438         current_state = MMPLAYER_CURRENT_STATE(player);
439         pending_state = MMPLAYER_PENDING_STATE(player);
440
441         MMPLAYER_PRINT_STATE(player);
442
443         switch (command) {
444         case MMPLAYER_COMMAND_CREATE:
445         {
446                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
447
448                 if (current_state == MM_PLAYER_STATE_NULL ||
449                         current_state == MM_PLAYER_STATE_READY ||
450                         current_state == MM_PLAYER_STATE_PAUSED ||
451                         current_state == MM_PLAYER_STATE_PLAYING)
452                         goto NO_OP;
453         }
454         break;
455
456         case MMPLAYER_COMMAND_DESTROY:
457         {
458                 /* destroy can called anytime */
459
460                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
461         }
462         break;
463
464         case MMPLAYER_COMMAND_REALIZE:
465         {
466                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
467
468                 if (pending_state != MM_PLAYER_STATE_NONE) {
469                         goto INVALID_STATE;
470                 } else {
471                         /* need ready state to realize */
472                         if (current_state == MM_PLAYER_STATE_READY)
473                                 goto NO_OP;
474
475                         if (current_state != MM_PLAYER_STATE_NULL)
476                                 goto INVALID_STATE;
477                 }
478         }
479         break;
480
481         case MMPLAYER_COMMAND_UNREALIZE:
482         {
483                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
484
485                 if (current_state == MM_PLAYER_STATE_NULL)
486                         goto NO_OP;
487         }
488         break;
489
490         case MMPLAYER_COMMAND_START:
491         {
492                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
493
494                 if (pending_state == MM_PLAYER_STATE_NONE) {
495                         if (current_state == MM_PLAYER_STATE_PLAYING)
496                                 goto NO_OP;
497                         else if (current_state  != MM_PLAYER_STATE_READY &&
498                                 current_state != MM_PLAYER_STATE_PAUSED)
499                                 goto INVALID_STATE;
500                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
501                         goto ALREADY_GOING;
502                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503                         LOGD("player is going to paused state, just change the pending state as playing");
504                 } else {
505                         goto INVALID_STATE;
506                 }
507         }
508         break;
509
510         case MMPLAYER_COMMAND_STOP:
511         {
512                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
513
514                 if (current_state == MM_PLAYER_STATE_READY)
515                         goto NO_OP;
516
517                 /* need playing/paused state to stop */
518                 if (current_state != MM_PLAYER_STATE_PLAYING &&
519                          current_state != MM_PLAYER_STATE_PAUSED)
520                         goto INVALID_STATE;
521         }
522         break;
523
524         case MMPLAYER_COMMAND_PAUSE:
525         {
526                 if (MMPLAYER_IS_LIVE_STREAMING(player))
527                         goto NO_OP;
528
529                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530                         goto NOT_COMPLETED_SEEK;
531
532                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
533
534                 if (pending_state == MM_PLAYER_STATE_NONE) {
535                         if (current_state == MM_PLAYER_STATE_PAUSED)
536                                 goto NO_OP;
537                         else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
538                                 goto INVALID_STATE;
539                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
540                         goto ALREADY_GOING;
541                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542                         if (current_state == MM_PLAYER_STATE_PAUSED)
543                                 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
544                         else
545                                 goto INVALID_STATE;
546                 }
547         }
548         break;
549
550         case MMPLAYER_COMMAND_RESUME:
551         {
552                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553                         goto NOT_COMPLETED_SEEK;
554
555                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
556
557                 if (pending_state == MM_PLAYER_STATE_NONE) {
558                         if (current_state == MM_PLAYER_STATE_PLAYING)
559                                 goto NO_OP;
560                         else if (current_state != MM_PLAYER_STATE_PAUSED)
561                                 goto INVALID_STATE;
562                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
563                         goto ALREADY_GOING;
564                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565                         LOGD("player is going to paused state, just change the pending state as playing");
566                 } else {
567                         goto INVALID_STATE;
568                 }
569         }
570                 break;
571
572         default:
573                 break;
574         }
575         player->cmd = command;
576
577         return MM_ERROR_NONE;
578
579 INVALID_STATE:
580         LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581                 MMPLAYER_STATE_GET_NAME(current_state), command);
582         return MM_ERROR_PLAYER_INVALID_STATE;
583
584 NOT_COMPLETED_SEEK:
585         LOGW("not completed seek");
586         return MM_ERROR_PLAYER_DOING_SEEK;
587
588 NO_OP:
589         LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590         return MM_ERROR_PLAYER_NO_OP;
591
592 ALREADY_GOING:
593         LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594         return MM_ERROR_PLAYER_NO_OP;
595 }
596
597 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
598 {
599         int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
600         mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
601
602         switch (type) {
603                 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
604                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
605                         break;
606                 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
607                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
608                         break;
609                 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
610                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
611                         break;
612                 default:
613                         LOGE("invalid mmplayer resource type %d", type);
614                         return MM_ERROR_PLAYER_INTERNAL;
615         }
616
617         if (player->hw_resource[type] != NULL) {
618                 LOGD("[%d type] resource was already acquired", type);
619                 return MM_ERROR_NONE;
620         }
621
622         LOGD("mark for acquire [%d type] resource", type);
623         rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
624                         rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
625         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626                 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
627                 return MM_ERROR_PLAYER_INTERNAL;
628         }
629
630         rm_ret = mm_resource_manager_commit(player->resource_manager);
631         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632                 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633                 return MM_ERROR_PLAYER_INTERNAL;
634         }
635
636         MMPLAYER_FLEAVE();
637         return MM_ERROR_NONE;
638 }
639
640 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
641 {
642         int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
643
644         MMPLAYER_FENTER();
645
646         if (player->hw_resource[type] == NULL) {
647                 LOGD("there is no acquired [%d type] resource", type);
648                 return MM_ERROR_NONE;
649         }
650
651         LOGD("mark for release [%d type] resource", type);
652         rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
653         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
654                 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
655                 return MM_ERROR_PLAYER_INTERNAL;
656         }
657
658         player->hw_resource[type] = NULL;
659
660         rm_ret = mm_resource_manager_commit(player->resource_manager);
661         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
662                 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
663                 return MM_ERROR_PLAYER_INTERNAL;
664         }
665
666         MMPLAYER_FLEAVE();
667         return MM_ERROR_NONE;
668 }
669
670 static void
671 __mmplayer_initialize_gapless_play(mmplayer_t *player)
672 {
673         int i;
674
675         MMPLAYER_FENTER();
676
677         player->smooth_streaming = FALSE;
678         player->videodec_linked = 0;
679         player->audiodec_linked = 0;
680         player->textsink_linked = 0;
681         player->is_external_subtitle_present = FALSE;
682         player->is_external_subtitle_added_now = FALSE;
683         player->not_supported_codec = MISSING_PLUGIN_NONE;
684         player->can_support_codec = FOUND_PLUGIN_NONE;
685         player->pending_seek.is_pending = false;
686         player->pending_seek.pos = 0;
687         player->msg_posted = FALSE;
688         player->has_many_types = FALSE;
689         player->no_more_pad = FALSE;
690         player->not_found_demuxer = 0;
691         player->seek_state = MMPLAYER_SEEK_NONE;
692         player->is_subtitle_force_drop = FALSE;
693         player->play_subtitle = FALSE;
694         player->adjust_subtitle_pos = 0;
695
696         player->total_bitrate = 0;
697         player->total_maximum_bitrate = 0;
698
699         _mmplayer_track_initialize(player);
700         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
701
702         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
703                 player->bitrate[i] = 0;
704                 player->maximum_bitrate[i] = 0;
705         }
706
707         if (player->v_stream_caps) {
708                 gst_caps_unref(player->v_stream_caps);
709                 player->v_stream_caps = NULL;
710         }
711
712         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
713
714         /* clean found audio decoders */
715         if (player->audio_decoders) {
716                 GList *a_dec = player->audio_decoders;
717                 for (; a_dec; a_dec = g_list_next(a_dec)) {
718                         gchar *name = a_dec->data;
719                         MMPLAYER_FREEIF(name);
720                 }
721                 g_list_free(player->audio_decoders);
722                 player->audio_decoders = NULL;
723         }
724
725         __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
726
727         MMPLAYER_FLEAVE();
728 }
729
730 static gpointer
731 __mmplayer_gapless_play_thread(gpointer data)
732 {
733         mmplayer_t *player = (mmplayer_t *)data;
734         mmplayer_gst_element_t *mainbin = NULL;
735
736         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
737
738         MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
739         while (!player->gapless_play_thread_exit) {
740                 LOGD("gapless play thread started. waiting for signal.");
741                 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
742
743                 LOGD("reconfigure pipeline for gapless play.");
744
745                 if (player->gapless_play_thread_exit) {
746                         if (player->gapless.reconfigure) {
747                                 player->gapless.reconfigure = false;
748                                 MMPLAYER_PLAYBACK_UNLOCK(player);
749                         }
750                         LOGD("exiting gapless play thread");
751                         break;
752                 }
753
754                 mainbin = player->pipeline->mainbin;
755
756                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
757                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
758                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
759                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
760                 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
761
762                 /* Initialize Player values */
763                 __mmplayer_initialize_gapless_play(player);
764
765                 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
766         }
767         MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
768
769         return NULL;
770 }
771
772 static void
773 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
774 {
775         GSource *source = NULL;
776
777         MMPLAYER_FENTER();
778
779         source = g_main_context_find_source_by_id(context, source_id);
780         if (source != NULL) {
781                 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
782                 g_source_destroy(source);
783         }
784
785         MMPLAYER_FLEAVE();
786 }
787
788 void
789 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
790 {
791         mmplayer_t *player = (mmplayer_t *)hplayer;
792         GstMessage *msg = NULL;
793         GQueue *queue = NULL;
794
795         MMPLAYER_FENTER();
796         MMPLAYER_RETURN_IF_FAIL(player);
797
798         /* disconnecting bus watch */
799         if (player->bus_watcher)
800                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
801         player->bus_watcher = 0;
802
803         /* destroy the gst bus msg thread */
804         if (player->bus_msg_thread) {
805                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
806                 player->bus_msg_thread_exit = TRUE;
807                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
808                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
809
810                 LOGD("gst bus msg thread exit.");
811                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
812                 player->bus_msg_thread = NULL;
813
814                 g_mutex_clear(&player->bus_msg_thread_mutex);
815                 g_cond_clear(&player->bus_msg_thread_cond);
816         }
817
818         g_mutex_lock(&player->bus_msg_q_lock);
819         queue = player->bus_msg_q;
820         while (!g_queue_is_empty(queue)) {
821                 msg = (GstMessage *)g_queue_pop_head(queue);
822                 if (!msg) {
823                         LOGW("msg is null");
824                         continue;
825                 }
826                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
827                 gst_message_unref(msg);
828         }
829         g_mutex_unlock(&player->bus_msg_q_lock);
830
831         MMPLAYER_FLEAVE();
832 }
833
834 gboolean
835 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
836 {
837         GstElement *parent = NULL;
838
839         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
840         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
841
842         /* lock */
843         MMPLAYER_FSINK_LOCK(player);
844
845         /* get parent of fakesink */
846         parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
847         if (!parent) {
848                 LOGD("fakesink already removed");
849                 goto ERROR;
850         }
851
852         gst_element_set_locked_state(fakesink->gst, TRUE);
853
854         /* setting the state to NULL never returns async
855          * so no need to wait for completion of state transiton
856          */
857         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
858                 LOGE("fakesink state change failure!");
859                 /* FIXIT : should I return here? or try to proceed to next? */
860                 /* return FALSE; */
861
862         /* remove fakesink from it's parent */
863         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
864                 LOGE("failed to remove fakesink");
865
866                 gst_object_unref(parent);
867
868                 goto ERROR;
869         }
870
871         gst_object_unref(parent);
872
873         LOGD("state-holder removed");
874
875         gst_element_set_locked_state(fakesink->gst, FALSE);
876
877         MMPLAYER_FSINK_UNLOCK(player);
878         return TRUE;
879
880 ERROR:
881         if (fakesink->gst)
882                 gst_element_set_locked_state(fakesink->gst, FALSE);
883
884         MMPLAYER_FSINK_UNLOCK(player);
885         return FALSE;
886 }
887
888 static GstPadProbeReturn
889 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
890 {
891         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
892         return GST_PAD_PROBE_OK;
893 }
894
895 static void
896 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
897 {
898         gint64 stop_running_time = 0;
899         gint64 position_running_time = 0;
900         gint64 position = 0;
901         gint idx = 0;
902
903         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
904                 if ((player->gapless.update_segment[idx] == TRUE) ||
905                         !(player->selector[idx].event_probe_id)) {
906                         /* LOGW("[%d] skip", idx); */
907                         continue;
908                 }
909
910                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
911                         stop_running_time =
912                                 gst_segment_to_running_time(&player->gapless.segment[idx],
913                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
914                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
915                         stop_running_time =
916                                 gst_segment_to_running_time(&player->gapless.segment[idx],
917                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
918                 } else {
919                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
920                         stop_running_time =
921                                 gst_segment_to_running_time(&player->gapless.segment[idx],
922                                                 GST_FORMAT_TIME, player->duration);
923                 }
924
925                 position_running_time =
926                         gst_segment_to_running_time(&player->gapless.segment[idx],
927                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
928
929                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
930                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
931                         idx,
932                         GST_TIME_ARGS(stop_running_time),
933                         GST_TIME_ARGS(position_running_time),
934                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
935                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
936
937                 position_running_time = MAX(position_running_time, stop_running_time);
938                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
939                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
940                 position_running_time = MAX(0, position_running_time);
941                 position = MAX(position, position_running_time);
942         }
943
944         if (position != 0) {
945                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
946                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
947                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
948
949                 player->gapless.start_time[stream_type] += position;
950         }
951
952         return;
953 }
954
955 static GstPadProbeReturn
956 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
957 {
958         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
959         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
960         mmplayer_t *player = (mmplayer_t *)data;
961         GstCaps *caps = NULL;
962         GstStructure *str = NULL;
963         const gchar *name = NULL;
964         mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
965         gboolean caps_ret = TRUE;
966
967         if (GST_EVENT_IS_DOWNSTREAM(event) &&
968             GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
969             GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
970             GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
971             GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
972                 return ret;
973         } else if (GST_EVENT_IS_UPSTREAM(event) &&
974                            GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
975                 return ret;
976         }
977
978         MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
979         if (!caps_ret)
980                 goto ERROR;
981
982         if (strstr(name, "audio")) {
983                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
984         } else if (strstr(name, "video")) {
985                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
986         } else {
987                 /* text track is not supportable */
988                 LOGE("invalid name %s", name);
989                 goto ERROR;
990         }
991
992         switch (GST_EVENT_TYPE(event)) {
993         case GST_EVENT_EOS:
994                 {
995                         /* in case of gapless, drop eos event not to send it to sink */
996                         if (player->gapless.reconfigure && !player->msg_posted) {
997                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
998                                 ret = GST_PAD_PROBE_DROP;
999                         }
1000                         break;
1001                 }
1002         case GST_EVENT_STREAM_START:
1003                 {
1004                         __mmplayer_gst_selector_update_start_time(player, stream_type);
1005                         break;
1006                 }
1007         case GST_EVENT_FLUSH_STOP:
1008                 {
1009                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1010                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1011                         player->gapless.start_time[stream_type] = 0;
1012                         break;
1013                 }
1014         case GST_EVENT_SEGMENT:
1015                 {
1016                         GstSegment segment;
1017                         GstEvent *tmpev;
1018
1019                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1020                         gst_event_copy_segment(event, &segment);
1021
1022                         if (segment.format != GST_FORMAT_TIME)
1023                                 break;
1024
1025                         LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1026                                  ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1027                                  ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1028                                 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1029                                 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1030                                 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1031
1032                         /* keep the all the segment ev to cover the seeking */
1033                         gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1034                         player->gapless.update_segment[stream_type] = TRUE;
1035
1036                         if (!player->gapless.running)
1037                                 break;
1038
1039                         player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1040
1041                         LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1042
1043                         tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1044                         gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1045                         gst_event_unref(event);
1046                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1047
1048                         break;
1049                 }
1050         case GST_EVENT_QOS:
1051                 {
1052                         gdouble proportion = 0.0;
1053                         GstClockTimeDiff diff = 0;
1054                         GstClockTime timestamp = 0;
1055                         gint64 running_time_diff = -1;
1056                         GstQOSType type = 0;
1057                         GstEvent *tmpev = NULL;
1058
1059                         running_time_diff = player->gapless.segment[stream_type].base;
1060
1061                         if (running_time_diff <= 0) /* don't need to adjust */
1062                                 break;
1063
1064                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
1065                         gst_event_unref(event);
1066
1067                         if (timestamp < running_time_diff) {
1068                                 LOGW("QOS event from previous group");
1069                                 ret = GST_PAD_PROBE_DROP;
1070                                 break;
1071                         }
1072
1073                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1074                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1075                                                 stream_type, GST_TIME_ARGS(timestamp),
1076                                                 GST_TIME_ARGS(running_time_diff),
1077                                                 GST_TIME_ARGS(timestamp - running_time_diff));
1078
1079                         timestamp -= running_time_diff;
1080
1081                         /* That case is invalid for QoS events */
1082                         if (diff < 0 && -diff > timestamp) {
1083                                 LOGW("QOS event from previous group");
1084                                 ret = GST_PAD_PROBE_DROP;
1085                                 break;
1086                         }
1087
1088                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1089                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1090
1091                         break;
1092                 }
1093         default:
1094                 break;
1095         }
1096
1097 ERROR:
1098         if (caps)
1099                 gst_caps_unref(caps);
1100         return ret;
1101 }
1102
1103 /* create fakesink for audio or video path witout audiobin or videobin */
1104 static void
1105 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1106 {
1107         GstElement *pipeline = NULL;
1108         GstElement *fakesink = NULL;
1109         GstPad *sinkpad = NULL;
1110
1111         MMPLAYER_FENTER();
1112         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1113
1114         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1115
1116         /* fake sink */
1117         fakesink = gst_element_factory_make("fakesink", NULL);
1118         if (fakesink == NULL) {
1119                 LOGE("failed to create fakesink");
1120                 goto EXIT;
1121         }
1122
1123         /* store it as it's sink element */
1124         __mmplayer_add_sink(player, fakesink);
1125
1126         gst_bin_add(GST_BIN(pipeline), fakesink);
1127
1128         /* link */
1129         sinkpad = gst_element_get_static_pad(fakesink, "sink");
1130
1131         LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1132
1133         if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1134                 LOGE("failed to link fakesink");
1135                 gst_object_unref(GST_OBJECT(fakesink));
1136                 goto EXIT;
1137         }
1138
1139         if (strstr(name, "video")) {
1140                 if (player->v_stream_caps) {
1141                         gst_caps_unref(player->v_stream_caps);
1142                         player->v_stream_caps = NULL;
1143                 }
1144                 if (player->ini.set_dump_element_flag)
1145                         __mmplayer_add_dump_buffer_probe(player, fakesink);
1146         }
1147
1148         g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1149         gst_element_set_state(fakesink, GST_STATE_PAUSED);
1150
1151 EXIT:
1152         if (sinkpad)
1153                 gst_object_unref(GST_OBJECT(sinkpad));
1154
1155         MMPLAYER_FLEAVE();
1156         return;
1157 }
1158
1159 static GstElement *
1160 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1161 {
1162         GstElement *pipeline = NULL;
1163         GstElement *selector = NULL;
1164         GstPad *srcpad = NULL;
1165
1166         MMPLAYER_FENTER();
1167         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1168
1169         selector = gst_element_factory_make("input-selector", NULL);
1170         if (!selector) {
1171                 LOGE("failed to create input-selector");
1172                 return NULL;
1173         }
1174         g_object_set(selector, "sync-streams", TRUE, NULL);
1175
1176         player->pipeline->mainbin[elem_idx].id = elem_idx;
1177         player->pipeline->mainbin[elem_idx].gst = selector;
1178
1179         /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1180
1181         srcpad = gst_element_get_static_pad(selector, "src");
1182
1183         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1184         player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1185                 __mmplayer_gst_selector_blocked, NULL, NULL);
1186         player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1187                 __mmplayer_gst_selector_event_probe, player, NULL);
1188
1189         gst_element_set_state(selector, GST_STATE_PAUSED);
1190
1191         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1192         gst_bin_add(GST_BIN(pipeline), selector);
1193
1194         gst_object_unref(GST_OBJECT(srcpad));
1195
1196         MMPLAYER_FLEAVE();
1197         return selector;
1198 }
1199
1200 void
1201 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1202 {
1203         mmplayer_t *player = (mmplayer_t *)data;
1204         GstElement *selector = NULL;
1205         GstCaps *caps = NULL;
1206         GstStructure *str = NULL;
1207         const gchar *name = NULL;
1208         GstPad *sinkpad = NULL;
1209         gboolean first_track = FALSE;
1210         gboolean caps_ret = TRUE;
1211
1212         main_element_id_e elem_idx = MMPLAYER_M_NUM;
1213         mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1214
1215         MMPLAYER_FENTER();
1216         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1217         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1218
1219         LOGD("pad-added signal handling");
1220
1221         /* get mimetype from caps */
1222         MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1223         if (!caps_ret)
1224                 goto ERROR;
1225
1226         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1227         /* LOGD("detected mimetype : %s", name); */
1228
1229         if (strstr(name, "video")) {
1230                 gint stype = 0;
1231                 gchar *caps_str = NULL;
1232
1233                 caps_str = gst_caps_to_string(caps);
1234                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1235                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1236                         player->set_mode.video_zc = true;
1237
1238                 MMPLAYER_FREEIF(caps_str);
1239
1240                 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1241                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1242
1243                 LOGD("surface type : %d", stype);
1244
1245                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1246                         __mmplayer_gst_create_sinkbin(elem, pad, player);
1247                         goto DONE;
1248                 }
1249
1250                 /* in case of exporting video frame, it requires the 360 video filter.
1251                  * it will be handled in _no_more_pads(). */
1252                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1253                         __mmplayer_gst_make_fakesink(player, pad, name);
1254                         goto DONE;
1255                 }
1256
1257                 LOGD("video selector is required");
1258                 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1259                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1260         } else if (strstr(name, "audio")) {
1261                 gint samplerate = 0;
1262                 gint channels = 0;
1263
1264                 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1265                         if (player->build_audio_offload)
1266                                 player->no_more_pad = TRUE; /* remove state holder */
1267                         __mmplayer_gst_create_sinkbin(elem, pad, player);
1268                         goto DONE;
1269                 }
1270
1271                 gst_structure_get_int(str, "rate", &samplerate);
1272                 gst_structure_get_int(str, "channels", &channels);
1273
1274                 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1275                         __mmplayer_gst_make_fakesink(player, pad, name);
1276                         goto DONE;
1277                 }
1278
1279                 LOGD("audio selector is required");
1280                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1281                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1282
1283         } else if (strstr(name, "text")) {
1284                 LOGD("text selector is required");
1285                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1286                 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1287         } else {
1288                 LOGE("invalid caps info");
1289                 goto ERROR;
1290         }
1291
1292         /* check selector and create it */
1293         if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1294                 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1295                 if (!selector)
1296                         goto ERROR;
1297                 first_track = TRUE;
1298         } else {
1299                 LOGD("input-selector is already created.");
1300         }
1301
1302         /* link */
1303         sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1304
1305         LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1306
1307         if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1308                 LOGE("failed to link selector");
1309                 gst_object_unref(GST_OBJECT(selector));
1310                 goto ERROR;
1311         }
1312
1313         if (first_track) {
1314                 LOGD("this track will be activated");
1315                 g_object_set(selector, "active-pad", sinkpad, NULL);
1316         }
1317
1318         _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1319
1320 DONE:
1321 ERROR:
1322
1323         if (caps)
1324                 gst_caps_unref(caps);
1325
1326         if (sinkpad) {
1327                 gst_object_unref(GST_OBJECT(sinkpad));
1328                 sinkpad = NULL;
1329         }
1330
1331         return;
1332 }
1333
1334 static gboolean
1335 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1336 {
1337         GstPad *srcpad = NULL;
1338
1339         MMPLAYER_FENTER();
1340         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1341
1342         LOGD("type %d", type);
1343
1344         if (!selector) {
1345                 LOGD("there is no %d track", type);
1346                 return TRUE;
1347         }
1348
1349         srcpad = gst_element_get_static_pad(selector, "src");
1350         if (!srcpad) {
1351                 LOGE("failed to get srcpad from selector");
1352                 return FALSE;
1353         }
1354
1355         LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1356
1357         __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1358
1359         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1360         if (player->selector[type].block_id) {
1361                 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1362                 player->selector[type].block_id = 0;
1363         }
1364
1365         if (srcpad) {
1366                 gst_object_unref(GST_OBJECT(srcpad));
1367                 srcpad = NULL;
1368         }
1369
1370         MMPLAYER_FLEAVE();
1371         return TRUE;
1372 }
1373
1374 static void
1375 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1376 {
1377         MMHandleType attrs = 0;
1378         gint active_index = 0;
1379
1380         MMPLAYER_FENTER();
1381         MMPLAYER_RETURN_IF_FAIL(player);
1382
1383         LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1384
1385         /* change track to active pad */
1386         active_index = player->selector[type].active_pad_index;
1387         if ((active_index != DEFAULT_TRACK) &&
1388                 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1389                 LOGW("failed to change %d type track to %d", type, active_index);
1390                 player->selector[type].active_pad_index = DEFAULT_TRACK;
1391                 return;
1392         }
1393
1394         if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1395                 attrs = MMPLAYER_GET_ATTRS(player);
1396                 if (attrs) {
1397                         mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1398                         mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1399
1400                         if (mm_attrs_commit_all(attrs))
1401                                 LOGW("failed to commit attrs.");
1402                 } else {
1403                         LOGW("cannot get content attribute");
1404                 }
1405         }
1406
1407         MMPLAYER_FLEAVE();
1408         return;
1409 }
1410
1411 static gboolean
1412 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1413 {
1414         MMPLAYER_FENTER();
1415         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1416
1417         if (!audio_selector) {
1418                 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1419
1420                 /* in case the source is changed, output can be changed. */
1421                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1422                         LOGD("remove previous audiobin if it exist");
1423
1424                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1425                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1426
1427                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1428                         MMPLAYER_FREEIF(player->pipeline->audiobin);
1429                 }
1430
1431                 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1432                         __mmplayer_pipeline_complete(NULL, player);
1433
1434                 return TRUE;
1435         }
1436
1437         /* apply the audio track information */
1438         __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1439
1440         /* create audio sink path */
1441         if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1442                 LOGE("failed to create audio sink path");
1443                 return FALSE;
1444         }
1445
1446         MMPLAYER_FLEAVE();
1447         return TRUE;
1448 }
1449
1450 static gboolean
1451 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1452 {
1453         MMPLAYER_FENTER();
1454         MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1455
1456         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1457                 LOGD("text path is not supproted");
1458                 return TRUE;
1459         }
1460
1461         /* apply the text track information */
1462         __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1463
1464         if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1465                 player->has_closed_caption = TRUE;
1466
1467         /* create text decode path */
1468         player->no_more_pad = TRUE;
1469
1470         if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1471                 LOGE("failed to create text sink path");
1472                 return FALSE;
1473         }
1474
1475         MMPLAYER_FLEAVE();
1476         return TRUE;
1477 }
1478
1479 static gboolean
1480 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1481 {
1482         gint64 dur_bytes = 0L;
1483
1484         MMPLAYER_FENTER();
1485         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1486                 player->pipeline->mainbin && player->streamer, FALSE);
1487
1488         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1489                 LOGE("fail to get duration.");
1490
1491         /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1492          * use file information was already set on Q2 when it was created. */
1493         _mm_player_streaming_set_queue2(player->streamer,
1494                                         player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1495                                         TRUE,                                                           /* use_buffering */
1496                                         MUXED_BUFFER_TYPE_MAX,                          /* use previous buffer type setting */
1497                                         ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1498
1499         MMPLAYER_FLEAVE();
1500         return TRUE;
1501 }
1502
1503 static void
1504 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1505 {
1506         mmplayer_t *player = NULL;
1507         GstElement *video_selector = NULL;
1508         GstElement *audio_selector = NULL;
1509         GstElement *text_selector = NULL;
1510
1511         MMPLAYER_FENTER();
1512         player = (mmplayer_t *)data;
1513
1514         LOGD("no-more-pad signal handling");
1515
1516         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1517                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1518                 LOGW("player is shutting down");
1519                 goto EXIT;
1520         }
1521
1522         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1523                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1524                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1525                 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1526                         LOGE("failed to set queue2 buffering");
1527                         goto EXIT;
1528                 }
1529         }
1530
1531         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1532         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1533         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1534
1535         if (!video_selector && !audio_selector && !text_selector) {
1536                 LOGW("there is no selector");
1537                 player->no_more_pad = TRUE;
1538                 goto EXIT;
1539         }
1540
1541         /* create video path followed by video-select */
1542         if (video_selector && !audio_selector && !text_selector)
1543                 player->no_more_pad = TRUE;
1544
1545         if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1546                 goto EXIT;
1547
1548         /* create audio path followed by audio-select */
1549         if (audio_selector && !text_selector)
1550                 player->no_more_pad = TRUE;
1551
1552         if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1553                 goto EXIT;
1554
1555         /* create text path followed by text-select */
1556         __mmplayer_create_text_sink_path(player, text_selector);
1557
1558 EXIT:
1559         if (player->gapless.reconfigure) {
1560                 player->gapless.reconfigure = FALSE;
1561                 MMPLAYER_PLAYBACK_UNLOCK(player);
1562         }
1563
1564         MMPLAYER_FLEAVE();
1565 }
1566
1567 static gboolean
1568 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1569 {
1570         gboolean ret = FALSE;
1571         GstElement *pipeline = NULL;
1572         GstPad *sinkpad = NULL;
1573
1574         MMPLAYER_FENTER();
1575         MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1576         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1577
1578         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1579
1580         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1581         if (!sinkpad) {
1582                 LOGE("failed to get pad from sinkbin");
1583                 goto EXIT;
1584         }
1585
1586         if (reusing) {
1587                 /* link only */
1588                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1589                         LOGE("failed to link sinkbin for reusing");
1590                         goto EXIT; /* exit either pass or fail */
1591                 }
1592         } else {
1593                 /* warm up */
1594                 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1595                         LOGE("failed to set state(READY) to sinkbin");
1596                         goto EXIT;
1597                 }
1598
1599                 /* add */
1600                 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1601                         LOGE("failed to add sinkbin to pipeline");
1602                         goto EXIT;
1603                 }
1604
1605                 /* link */
1606                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1607                         LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1608                         goto EXIT;
1609                 }
1610
1611                 /* run */
1612                 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1613                         LOGE("failed to set state(PAUSED) to sinkbin");
1614                         goto EXIT;
1615                 }
1616         }
1617
1618         ret = TRUE;
1619
1620 EXIT:
1621         if (sinkpad)
1622                 gst_object_unref(GST_OBJECT(sinkpad));
1623         sinkpad = NULL;
1624
1625         MMPLAYER_FLEAVE();
1626         return ret;
1627 }
1628
1629 static void
1630 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1631 {
1632         mmplayer_t *player = NULL;
1633         GstCaps *caps = NULL;
1634         gchar *caps_str = NULL;
1635         GstStructure *str = NULL;
1636         const gchar *name = NULL;
1637         GstElement *sinkbin = NULL;
1638         gboolean reusing = FALSE;
1639         gboolean caps_ret = TRUE;
1640         gchar *sink_pad_name = "sink";
1641
1642         /* check handles */
1643         player = (mmplayer_t *)data;
1644
1645         MMPLAYER_FENTER();
1646         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1647         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1648
1649         MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1650         if (!caps_ret)
1651                 goto ERROR;
1652
1653         caps_str = gst_caps_to_string(caps);
1654
1655         /* LOGD("detected mimetype : %s", name); */
1656         if (strstr(name, "audio")) {
1657                 if (player->pipeline->audiobin == NULL) {
1658                         const gchar *audio_format = gst_structure_get_string(str, "format");
1659                         if (audio_format) {
1660                                 LOGD("original audio format %s", audio_format);
1661                                 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1662                         }
1663
1664                         if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1665                                 LOGE("failed to create audiobin. continuing without audio");
1666                                 goto ERROR;
1667                         }
1668
1669                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1670                         LOGD("creating audiobin success");
1671                 } else {
1672                         reusing = TRUE;
1673                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1674                         LOGD("reusing audiobin");
1675                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1676                 }
1677         } else if (strstr(name, "video")) {
1678                 /* 1. zero copy is updated at _decode_pad_added()
1679                  * 2. NULL surface type is handled in _decode_pad_added() */
1680                 LOGD("zero copy %d", player->set_mode.video_zc);
1681                 if (player->pipeline->videobin == NULL) {
1682                         int surface_type = 0;
1683                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1684                         LOGD("display_surface_type (%d)", surface_type);
1685
1686                         if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1687                                 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1688                                 LOGE("failed to acquire video overlay resource");
1689                                 goto ERROR;
1690                         }
1691
1692                         player->interrupted_by_resource = FALSE;
1693
1694                         if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1695                                 LOGE("failed to create videobin. continuing without video");
1696                                 goto ERROR;
1697                         }
1698
1699                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1700                         LOGD("creating videosink bin success");
1701                 } else {
1702                         reusing = TRUE;
1703                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1704                         LOGD("re-using videobin");
1705                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1706                 }
1707         } else if (strstr(name, "text")) {
1708                 if (player->pipeline->textbin == NULL) {
1709                         if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1710                                 LOGE("failed to create text sink bin. continuing without text");
1711                                 goto ERROR;
1712                         }
1713
1714                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1715                         player->textsink_linked  = 1;
1716                         LOGD("creating textsink bin success");
1717                 } else {
1718                         if (!player->textsink_linked) {
1719                                 LOGD("re-using textbin");
1720                                 reusing = TRUE;
1721                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1722                                 player->textsink_linked  = 1;
1723                         } else {
1724                                 /* linked textbin exist which means that the external subtitle path exist already */
1725                                 LOGW("ignoring internal subtutle since external subtitle is available");
1726                         }
1727                 }
1728                 sink_pad_name = "text_sink";
1729         } else {
1730                 LOGW("unknown mime type %s, ignoring it", name);
1731                 goto ERROR;
1732         }
1733
1734         if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1735                 goto ERROR;
1736
1737         LOGD("[handle: %p] success to create and link sink bin", player);
1738
1739         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1740          * streaming task. if the task blocked, then buffer will not flow to the next element
1741          *(autoplugging element). so this is special hack for streaming. please try to remove it
1742          */
1743         /* dec stream count. we can remove fakesink if it's zero */
1744         if (player->num_dynamic_pad)
1745                 player->num_dynamic_pad--;
1746
1747         LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1748
1749         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1750                 __mmplayer_pipeline_complete(NULL, player);
1751
1752 ERROR:
1753
1754         MMPLAYER_FREEIF(caps_str);
1755
1756         if (caps)
1757                 gst_caps_unref(caps);
1758
1759         return;
1760 }
1761
1762 static gboolean
1763 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1764 {
1765         int required_angle = 0; /* Angle required for straight view */
1766         int rotation_angle = 0;
1767
1768         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1769         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1770
1771         /* Counter clockwise */
1772         switch (orientation) {
1773         case 0:
1774                 required_angle = 0;
1775                 break;
1776         case 90:
1777                 required_angle = 270;
1778                 break;
1779         case 180:
1780                 required_angle = 180;
1781                 break;
1782         case 270:
1783                 required_angle = 90;
1784                 break;
1785         }
1786
1787         rotation_angle = display_angle + required_angle;
1788         if (rotation_angle >= 360)
1789                 rotation_angle -= 360;
1790
1791         /* chech if supported or not */
1792         if (rotation_angle % 90) {
1793                 LOGD("not supported rotation angle = %d", rotation_angle);
1794                 return FALSE;
1795         }
1796
1797         switch (rotation_angle) {
1798         case 0:
1799                 *value = MM_DISPLAY_ROTATION_NONE;
1800                 break;
1801         case 90:
1802                 *value = MM_DISPLAY_ROTATION_90;
1803                 break;
1804         case 180:
1805                 *value = MM_DISPLAY_ROTATION_180;
1806                 break;
1807         case 270:
1808                 *value = MM_DISPLAY_ROTATION_270;
1809                 break;
1810         }
1811
1812         LOGD("setting rotation property value : %d", *value);
1813
1814         return TRUE;
1815 }
1816
1817 int
1818 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1819 {
1820         /* check video sinkbin is created */
1821         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1822                 player->pipeline &&
1823                 player->pipeline->videobin &&
1824                 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1825                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1826                 MM_ERROR_PLAYER_NOT_INITIALIZED);
1827
1828         return MM_ERROR_NONE;
1829 }
1830
1831 int
1832 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1833 {
1834         int display_rotation = 0;
1835         gchar *org_orient = NULL;
1836         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1837
1838         if (!attrs) {
1839                 LOGE("cannot get content attribute");
1840                 return MM_ERROR_PLAYER_INTERNAL;
1841         }
1842
1843         if (display_angle) {
1844                 /* update user roation */
1845                 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1846
1847                 /* Counter clockwise */
1848                 switch (display_rotation) {
1849                 case MM_DISPLAY_ROTATION_NONE:
1850                         *display_angle = 0;
1851                         break;
1852                 case MM_DISPLAY_ROTATION_90:
1853                         *display_angle = 90;
1854                         break;
1855                 case MM_DISPLAY_ROTATION_180:
1856                         *display_angle = 180;
1857                         break;
1858                 case MM_DISPLAY_ROTATION_270:
1859                         *display_angle = 270;
1860                         break;
1861                 default:
1862                         LOGW("wrong angle type : %d", display_rotation);
1863                         break;
1864                 }
1865                 LOGD("check user angle: %d", *display_angle);
1866         }
1867
1868         if (orientation) {
1869                 /* Counter clockwise */
1870                 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1871
1872                 if (org_orient) {
1873                         if (!strcmp(org_orient, "rotate-90"))
1874                                 *orientation = 90;
1875                         else if (!strcmp(org_orient, "rotate-180"))
1876                                 *orientation = 180;
1877                         else if (!strcmp(org_orient, "rotate-270"))
1878                                 *orientation = 270;
1879                         else
1880                                 LOGD("original rotation is %s", org_orient);
1881                 } else {
1882                         LOGD("content_video_orientation get fail");
1883                 }
1884
1885                 LOGD("check orientation: %d", *orientation);
1886         }
1887
1888         return MM_ERROR_NONE;
1889 }
1890
1891 void
1892 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1893 {
1894         int rotation_value = 0;
1895         int orientations = 0; // current supported angle values are 0, 90, 180, 270
1896         int display_angle = 0;
1897         MMPLAYER_FENTER();
1898
1899         /* check video sinkbin is created */
1900         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1901                 return;
1902
1903         _mmplayer_get_video_angle(player, &display_angle, &orientations);
1904
1905         /* get rotation value to set */
1906         __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1907         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1908         LOGD("set video param : rotate %d", rotation_value);
1909 }
1910
1911 void
1912 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1913 {
1914         MMHandleType attrs = 0;
1915         int visible = 0;
1916         MMPLAYER_FENTER();
1917
1918         /* check video sinkbin is created */
1919         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1920                 return;
1921
1922         attrs = MMPLAYER_GET_ATTRS(player);
1923         MMPLAYER_RETURN_IF_FAIL(attrs);
1924
1925         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1926         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1927         LOGD("set video param : visible %d", visible);
1928 }
1929
1930 void
1931 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1932 {
1933         MMHandleType attrs = 0;
1934         int display_method = 0;
1935         MMPLAYER_FENTER();
1936
1937         /* check video sinkbin is created */
1938         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1939                 return;
1940
1941         attrs = MMPLAYER_GET_ATTRS(player);
1942         MMPLAYER_RETURN_IF_FAIL(attrs);
1943
1944         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1945         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1946         LOGD("set video param : method %d", display_method);
1947 }
1948
1949 void
1950 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1951 {
1952         MMHandleType attrs = 0;
1953         void *handle = NULL;
1954         MMPLAYER_FENTER();
1955
1956         /* check video sinkbin is created */
1957         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1958                 LOGW("There is no video sink");
1959                 return;
1960         }
1961
1962         attrs = MMPLAYER_GET_ATTRS(player);
1963         MMPLAYER_RETURN_IF_FAIL(attrs);
1964         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1965         if (handle) {
1966                 gst_video_overlay_set_video_roi_area(
1967                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1968                          player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1969                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1970                         player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1971         }
1972 }
1973
1974 void
1975 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1976 {
1977         MMHandleType attrs = 0;
1978         void *handle = NULL;
1979         /*set wl_display*/
1980         int win_roi_x = 0;
1981         int win_roi_y = 0;
1982         int win_roi_width = 0;
1983         int win_roi_height = 0;
1984         MMPLAYER_FENTER();
1985
1986         /* check video sinkbin is created */
1987         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1988                 LOGW("There is no video sink");
1989                 return;
1990         }
1991
1992         attrs = MMPLAYER_GET_ATTRS(player);
1993         MMPLAYER_RETURN_IF_FAIL(attrs);
1994
1995         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1996
1997         if (handle) {
1998                 /* It should be set after setting window */
1999                 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2000                 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2001                 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2002                 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2003
2004                 /* After setting window handle, set display roi area */
2005                 gst_video_overlay_set_display_roi_area(
2006                          GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2007                          win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2008                 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2009                         win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2010         }
2011 }
2012
2013 void
2014 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2015 {
2016         MMHandleType attrs = 0;
2017         void *handle = NULL;
2018
2019         /* check video sinkbin is created */
2020         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2021                 return;
2022
2023         attrs = MMPLAYER_GET_ATTRS(player);
2024         MMPLAYER_RETURN_IF_FAIL(attrs);
2025
2026         /* common case if using overlay surface */
2027         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2028
2029         if (handle) {
2030                 /* default is using wl_surface_id */
2031                 unsigned int wl_surface_id      = 0;
2032                 wl_surface_id = *(int *)handle;
2033                 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2034                 gst_video_overlay_set_wl_window_wl_surface_id(
2035                                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2036                                 *(int *)handle);
2037         } else {
2038                 /* FIXIT : is it error case? */
2039                 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2040         }
2041 }
2042
2043 int
2044 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2045 {
2046         gboolean update_all_param = FALSE;
2047         MMPLAYER_FENTER();
2048
2049         /* check video sinkbin is created */
2050         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2051                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2052
2053         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2054                 LOGE("can not find tizenwlsink");
2055                 return MM_ERROR_PLAYER_INTERNAL;
2056         }
2057
2058         LOGD("param_name : %s", param_name);
2059         if (!g_strcmp0(param_name, "update_all_param"))
2060                 update_all_param = TRUE;
2061
2062         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2063                 __mmplayer_video_param_set_display_overlay(player);
2064         if (update_all_param || !g_strcmp0(param_name, "display_method"))
2065                 __mmplayer_video_param_set_display_method(player);
2066         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2067                 __mmplayer_video_param_set_display_visible(player);
2068         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2069                 __mmplayer_video_param_set_display_rotation(player);
2070         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2071                 __mmplayer_video_param_set_roi_area(player);
2072         if (update_all_param)
2073                 __mmplayer_video_param_set_video_roi_area(player);
2074
2075         return MM_ERROR_NONE;
2076 }
2077
2078 int
2079 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2080 {
2081         MMHandleType attrs = 0;
2082         int surface_type = 0;
2083         int ret = MM_ERROR_NONE;
2084
2085         MMPLAYER_FENTER();
2086
2087         /* check video sinkbin is created */
2088         if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2089                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2090
2091         attrs = MMPLAYER_GET_ATTRS(player);
2092         if (!attrs) {
2093                 LOGE("cannot get content attribute");
2094                 return MM_ERROR_PLAYER_INTERNAL;
2095         }
2096         LOGD("param_name : %s", param_name);
2097
2098         /* update display surface */
2099         mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2100         LOGD("check display surface type attribute: %d", surface_type);
2101
2102         /* configuring display */
2103         switch (surface_type) {
2104         case MM_DISPLAY_SURFACE_OVERLAY:
2105                 {
2106                         ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2107                         if (ret != MM_ERROR_NONE)
2108                                 return ret;
2109                 }
2110                 break;
2111         }
2112
2113         MMPLAYER_FLEAVE();
2114
2115         return MM_ERROR_NONE;
2116 }
2117
2118 int
2119 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2120 {
2121         gboolean disable_overlay = FALSE;
2122         mmplayer_t *player = (mmplayer_t *)hplayer;
2123
2124         MMPLAYER_FENTER();
2125         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2126         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2127                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2128                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2129
2130         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2131                 LOGW("Display control is not supported");
2132                 return MM_ERROR_PLAYER_INTERNAL;
2133         }
2134
2135         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2136
2137         if (audio_only == (bool)disable_overlay) {
2138                 LOGE("It's the same with current setting: (%d)", audio_only);
2139                 return MM_ERROR_NONE;
2140         }
2141
2142         if (audio_only) {
2143                 LOGE("disable overlay");
2144                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2145
2146                 /* release overlay resource */
2147                 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2148                         LOGE("failed to release overlay resource");
2149                         goto ERROR;
2150                 }
2151         } else {
2152                 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2153                         LOGE("failed to acquire video overlay resource");
2154                         goto ERROR;
2155                 }
2156                 player->interrupted_by_resource = FALSE;
2157
2158                 LOGD("enable overlay");
2159                 __mmplayer_video_param_set_display_overlay(player);
2160                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2161         }
2162
2163 ERROR:
2164         MMPLAYER_FLEAVE();
2165         return MM_ERROR_NONE;
2166 }
2167
2168 int
2169 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2170 {
2171         mmplayer_t *player = (mmplayer_t *)hplayer;
2172         gboolean disable_overlay = FALSE;
2173
2174         MMPLAYER_FENTER();
2175
2176         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2177         MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2178         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2179                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2180                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2181
2182         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2183                 LOGW("Display control is not supported");
2184                 return MM_ERROR_PLAYER_INTERNAL;
2185         }
2186
2187         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2188
2189         *paudio_only = (bool)disable_overlay;
2190
2191         LOGD("audio_only : %d", *paudio_only);
2192
2193         MMPLAYER_FLEAVE();
2194
2195         return MM_ERROR_NONE;
2196 }
2197
2198 int
2199 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2200 {
2201         GList *bucket = element_bucket;
2202         mmplayer_gst_element_t *element = NULL;
2203         mmplayer_gst_element_t *prv_element = NULL;
2204         GstElement *tee_element = NULL;
2205         gint successful_link_count = 0;
2206
2207         MMPLAYER_FENTER();
2208
2209         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2210
2211         prv_element = (mmplayer_gst_element_t *)bucket->data;
2212         bucket = bucket->next;
2213
2214         for (; bucket; bucket = bucket->next) {
2215                 element = (mmplayer_gst_element_t *)bucket->data;
2216
2217                 if (element && element->gst) {
2218                         if (prv_element && prv_element->gst) {
2219                                 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2220                                         if (tee_element) {
2221                                                 prv_element->gst = tee_element;
2222                                         } else {
2223                                                 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2224                                                         GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2225                                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226                                                 return -1;
2227                                         }
2228                                 }
2229                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2230                                         LOGD("linking [%s] to [%s] success",
2231                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2232                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2233                                         successful_link_count++;
2234                                         if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2235                                                 LOGD("keep audio-tee element for next audio pipeline branch");
2236                                                 tee_element = prv_element->gst;
2237                                         }
2238                                 } else {
2239                                         LOGD("linking [%s] to [%s] failed",
2240                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2241                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2242                                         return -1;
2243                                 }
2244                         }
2245                 }
2246
2247                 prv_element = element;
2248         }
2249
2250         MMPLAYER_FLEAVE();
2251
2252         return successful_link_count;
2253 }
2254
2255 int
2256 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2257 {
2258         GList *bucket = element_bucket;
2259         mmplayer_gst_element_t *element = NULL;
2260         int successful_add_count = 0;
2261
2262         MMPLAYER_FENTER();
2263
2264         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2265         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2266
2267         for (; bucket; bucket = bucket->next) {
2268                 element = (mmplayer_gst_element_t *)bucket->data;
2269
2270                 if (element && element->gst) {
2271                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2272                                 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed",
2273                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2274                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2275                                 return 0;
2276                         }
2277                         successful_add_count++;
2278                 }
2279         }
2280
2281         MMPLAYER_FLEAVE();
2282
2283         return successful_add_count;
2284 }
2285
2286 static void
2287 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2288 {
2289         mmplayer_t *player = (mmplayer_t *)data;
2290         GstCaps *caps = NULL;
2291         GstStructure *str = NULL;
2292         const char *name;
2293         gboolean caps_ret = TRUE;
2294
2295         MMPLAYER_FENTER();
2296
2297         MMPLAYER_RETURN_IF_FAIL(pad);
2298         MMPLAYER_RETURN_IF_FAIL(unused);
2299         MMPLAYER_RETURN_IF_FAIL(data);
2300
2301         caps = gst_pad_get_current_caps(pad);
2302         if (!caps)
2303                 return;
2304
2305         MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2306         if (!caps_ret)
2307                 goto ERROR;
2308
2309         LOGD("name = %s", name);
2310
2311         if (strstr(name, "audio")) {
2312                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2313
2314                 if (player->audio_stream_changed_cb) {
2315                         LOGE("call the audio stream changed cb");
2316                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2317                 }
2318         } else if (strstr(name, "video")) {
2319                 if ((name = gst_structure_get_string(str, "format")))
2320                         player->set_mode.video_zc = name[0] == 'S';
2321
2322                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2323                 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2324         } else {
2325                 LOGW("invalid caps info");
2326         }
2327
2328 ERROR:
2329         if (caps)
2330                 gst_caps_unref(caps);
2331
2332         MMPLAYER_FLEAVE();
2333
2334         return;
2335 }
2336
2337 void
2338 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2339 {
2340         GList *l = NULL;
2341
2342         MMPLAYER_FENTER();
2343         MMPLAYER_RETURN_IF_FAIL(player);
2344
2345         if (player->audio_stream_buff_list) {
2346                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2347                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2348                         if (tmp) {
2349                                 if (send_all) {
2350                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2351                                         __mmplayer_audio_stream_send_data(player, tmp);
2352                                 }
2353                                 MMPLAYER_FREEIF(tmp->pcm_data);
2354                                 MMPLAYER_FREEIF(tmp);
2355                         }
2356                 }
2357                 g_list_free(player->audio_stream_buff_list);
2358                 player->audio_stream_buff_list = NULL;
2359         }
2360
2361         MMPLAYER_FLEAVE();
2362 }
2363
2364 static void
2365 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2366 {
2367         mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2368
2369         MMPLAYER_FENTER();
2370         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2371
2372         audio_stream.bitrate = a_buffer->bitrate;
2373         audio_stream.channel = a_buffer->channel;
2374         audio_stream.depth = a_buffer->depth;
2375         audio_stream.is_little_endian = a_buffer->is_little_endian;
2376         audio_stream.channel_mask = a_buffer->channel_mask;
2377         audio_stream.data_size = a_buffer->data_size;
2378         audio_stream.data = a_buffer->pcm_data;
2379         audio_stream.pcm_format = a_buffer->pcm_format;
2380
2381         /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2382         player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2383
2384         MMPLAYER_FLEAVE();
2385 }
2386
2387 static void
2388 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2389 {
2390         mmplayer_t *player = (mmplayer_t *)data;
2391         const gchar *pcm_format = NULL;
2392         gint channel = 0;
2393         gint rate = 0;
2394         gint depth = 0;
2395         gint endianness = 0;
2396         guint64 channel_mask = 0;
2397         void *a_data = NULL;
2398         gint a_size = 0;
2399         mmplayer_audio_stream_buff_t *a_buffer = NULL;
2400         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2401         GList *l = NULL;
2402
2403         MMPLAYER_FENTER();
2404         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2405
2406         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2407         a_data = mapinfo.data;
2408         a_size = mapinfo.size;
2409
2410         GstCaps *caps = gst_pad_get_current_caps(pad);
2411         GstStructure *structure = gst_caps_get_structure(caps, 0);
2412
2413         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2414         pcm_format = gst_structure_get_string(structure, "format");
2415         gst_structure_get_int(structure, "rate", &rate);
2416         gst_structure_get_int(structure, "channels", &channel);
2417         gst_structure_get_int(structure, "depth", &depth);
2418         gst_structure_get_int(structure, "endianness", &endianness);
2419         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2420         gst_caps_unref(GST_CAPS(caps));
2421
2422         /* In case of the sync is false, use buffer list.              *
2423          * The num of buffer list depends on the num of audio channels */
2424         if (player->audio_stream_buff_list) {
2425                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2426                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2427                         if (tmp) {
2428                                 if (channel_mask == tmp->channel_mask) {
2429                                         /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2430                                         if (tmp->data_size + a_size < tmp->buff_size) {
2431                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2432                                                 tmp->data_size += a_size;
2433                                         } else {
2434                                                 /* send data to client */
2435                                                 __mmplayer_audio_stream_send_data(player, tmp);
2436
2437                                                 if (a_size > tmp->buff_size) {
2438                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2439                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2440                                                         if (tmp->pcm_data == NULL) {
2441                                                                 LOGE("failed to realloc data.");
2442                                                                 goto DONE;
2443                                                         }
2444                                                         tmp->buff_size = a_size;
2445                                                 }
2446                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2447                                                 memcpy(tmp->pcm_data, a_data, a_size);
2448                                                 tmp->data_size = a_size;
2449                                         }
2450                                         goto DONE;
2451                                 }
2452                         } else {
2453                                 LOGE("data is empty in list.");
2454                                 goto DONE;
2455                         }
2456                 }
2457         }
2458
2459         /* create new audio stream data for newly found audio channel */
2460         a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2461         if (a_buffer == NULL) {
2462                 LOGE("failed to alloc data.");
2463                 goto DONE;
2464         }
2465         a_buffer->bitrate = rate;
2466         a_buffer->channel = channel;
2467         a_buffer->depth = depth;
2468         a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2469         a_buffer->channel_mask = channel_mask;
2470         a_buffer->data_size = a_size;
2471         a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2472
2473         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2474                 /* If sync is FALSE, use buffer list to reduce the IPC. */
2475                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2476                 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2477                 if (a_buffer->pcm_data == NULL) {
2478                         LOGE("failed to alloc data.");
2479                         MMPLAYER_FREEIF(a_buffer);
2480                         goto DONE;
2481                 }
2482                 memcpy(a_buffer->pcm_data, a_data, a_size);
2483                 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2484                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2485         } else {
2486                 /* If sync is TRUE, send data directly. */
2487                 a_buffer->pcm_data = a_data;
2488                 __mmplayer_audio_stream_send_data(player, a_buffer);
2489                 MMPLAYER_FREEIF(a_buffer);
2490         }
2491
2492 DONE:
2493         gst_buffer_unmap(buffer, &mapinfo);
2494         MMPLAYER_FLEAVE();
2495 }
2496
2497 static void
2498 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2499 {
2500         mmplayer_t *player = (mmplayer_t *)data;
2501         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2502         GstPad *sinkpad = NULL;
2503         GstElement *queue = NULL, *sink = NULL;
2504
2505         MMPLAYER_FENTER();
2506         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2507
2508         queue = gst_element_factory_make("queue", NULL);
2509         if (queue == NULL) {
2510                 LOGD("fail make queue");
2511                 goto ERROR;
2512         }
2513
2514         sink = gst_element_factory_make("fakesink", NULL);
2515         if (sink == NULL) {
2516                 LOGD("fail make fakesink");
2517                 goto ERROR;
2518         }
2519
2520         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2521
2522         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2523                 LOGW("failed to link queue & sink");
2524                 goto ERROR;
2525         }
2526
2527         sinkpad = gst_element_get_static_pad(queue, "sink");
2528
2529         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2530                 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2531                 goto ERROR;
2532         }
2533
2534         LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2535
2536         gst_object_unref(sinkpad);
2537         if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2538                 g_object_set(sink, "sync", TRUE, NULL);
2539         g_object_set(sink, "signal-handoffs", TRUE, NULL);
2540
2541         /* keep the first sink reference only */
2542         if (!audiobin[MMPLAYER_A_SINK].gst) {
2543                 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2544                 audiobin[MMPLAYER_A_SINK].gst = sink;
2545         }
2546
2547         gst_element_set_state(sink, GST_STATE_PAUSED);
2548         gst_element_set_state(queue, GST_STATE_PAUSED);
2549
2550         _mmplayer_add_signal_connection(player,
2551                 G_OBJECT(sink),
2552                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2553                 "handoff",
2554                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2555                 (gpointer)player);
2556
2557         __mmplayer_add_sink(player, sink);
2558
2559         MMPLAYER_FLEAVE();
2560         return;
2561
2562 ERROR:
2563         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2564         if (queue) {
2565                 gst_object_unref(GST_OBJECT(queue));
2566                 queue = NULL;
2567         }
2568         if (sink) {
2569                 gst_object_unref(GST_OBJECT(sink));
2570                 sink = NULL;
2571         }
2572         if (sinkpad) {
2573                 gst_object_unref(GST_OBJECT(sinkpad));
2574                 sinkpad = NULL;
2575         }
2576
2577         return;
2578 }
2579
2580 void
2581 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2582 {
2583         #define MAX_PROPS_LEN 128
2584         mmplayer_gst_element_t *audiobin = NULL;
2585         gint latency_mode = 0;
2586         gchar *stream_type = NULL;
2587         gchar *latency = NULL;
2588         gint stream_id = 0;
2589         gchar stream_props[MAX_PROPS_LEN] = {0,};
2590         GstStructure *props = NULL;
2591
2592         /* set volume table
2593          * It should be set after player creation through attribute.
2594          * But, it can not be changed during playing.
2595          */
2596         MMPLAYER_FENTER();
2597         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2598
2599         audiobin = player->pipeline->audiobin;
2600
2601         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2602         if (player->sound.mute) {
2603                 LOGD("mute enabled");
2604                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2605         }
2606
2607         mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2608         mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2609
2610         if (!stream_type)
2611                 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2612         else
2613                 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2614                                 stream_type, stream_id, player->client_pid);
2615
2616         props = gst_structure_from_string(stream_props, NULL);
2617         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2618         LOGI("props result[%s].", stream_props);
2619         gst_structure_free(props);
2620
2621         mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2622
2623         switch (latency_mode) {
2624         case AUDIO_LATENCY_MODE_LOW:
2625                 latency = g_strndup("low", 3);
2626                 break;
2627         case AUDIO_LATENCY_MODE_MID:
2628                 latency = g_strndup("mid", 3);
2629                 break;
2630         case AUDIO_LATENCY_MODE_HIGH:
2631                 latency = g_strndup("high", 4);
2632                 break;
2633         };
2634
2635         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2636
2637         LOGD("audiosink property - latency=%s", latency);
2638
2639         MMPLAYER_FREEIF(latency);
2640
2641         MMPLAYER_FLEAVE();
2642 }
2643
2644 void
2645 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2646 {
2647         mmplayer_gst_element_t *audiobin = NULL;
2648
2649         MMPLAYER_FENTER();
2650         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2651
2652         audiobin = player->pipeline->audiobin;
2653
2654         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2655         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2656         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2657
2658         if (player->video360_yaw_radians <= M_PI &&
2659                         player->video360_yaw_radians >= -M_PI &&
2660                         player->video360_pitch_radians <= M_PI_2 &&
2661                         player->video360_pitch_radians >= -M_PI_2) {
2662                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2663                                 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2664                                 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2665         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2666                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2667                                 "source-orientation-y", player->video360_metadata.init_view_heading,
2668                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2669         }
2670
2671         MMPLAYER_FLEAVE();
2672 }
2673
2674 static int
2675 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2676 {
2677         mmplayer_gst_element_t *audiobin = NULL;
2678         GstPad *sink_pad = NULL;
2679         GstCaps *acaps = NULL;
2680         gint channels = 0;
2681         int pitch_control = 0;
2682         double pitch_value = 1.0;
2683
2684         MMPLAYER_FENTER();
2685         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2686                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2687
2688         audiobin = player->pipeline->audiobin;
2689
2690         LOGD("make element for normal audio playback");
2691
2692         /* audio bin structure for playback. {} means optional.
2693            optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2694
2695          * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2696                         {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2697          */
2698
2699         /* for pitch control */
2700         mm_attrs_multiple_get(player->attrs, NULL,
2701                                 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2702                                 MM_PLAYER_PITCH_VALUE, &pitch_value,
2703                                 NULL);
2704
2705         LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2706         if (pitch_control && (player->videodec_linked == 0)) {
2707                 GstElementFactory *factory;
2708
2709                 factory = gst_element_factory_find("pitch");
2710                 if (factory) {
2711                         gst_object_unref(factory);
2712
2713                         /* converter */
2714                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2715
2716                         /* pitch */
2717                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2718                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2719                 } else {
2720                         LOGW("there is no pitch element");
2721                 }
2722         }
2723
2724         /* converter */
2725         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2726
2727         /* replaygain volume */
2728         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2729         if (player->sound.rg_enable)
2730                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2731         else
2732                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2733
2734         /* resampler */
2735         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", *bucket, player);
2736
2737         if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2738                 /* currently, only openalsink uses volume element */
2739                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2740                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2741
2742                 if (player->sound.mute) {
2743                         LOGD("mute enabled");
2744                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2745                 }
2746         }
2747
2748         mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2749
2750         /* audio effect element. if audio effect is enabled */
2751         if ((strcmp(player->ini.audioeffect_element, ""))
2752                 && (channels <= 2)
2753                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2754                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2755
2756                 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2757
2758                 if ((!player->bypass_audio_effect)
2759                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2760                         if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2761                                 if (!_mmplayer_audio_effect_custom_apply(player))
2762                                         LOGI("apply audio effect(custom) setting success");
2763                         }
2764                 }
2765
2766                 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2767                         && (player->set_mode.rich_audio)) {
2768                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2769                 }
2770         }
2771
2772         /* create audio sink */
2773         LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2774                         player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2775                         player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2776
2777         /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2778         if (player->is_360_feature_enabled &&
2779                 player->is_content_spherical &&
2780                 channels == 4 &&
2781                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2782                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2783                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2784
2785                 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2786
2787                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2788
2789                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2790                 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2791                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2792                 gst_caps_unref(acaps);
2793
2794                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2795
2796                 player->is_openal_plugin_used = TRUE;
2797         } else {
2798                 if (player->is_360_feature_enabled && player->is_content_spherical)
2799                         LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2800                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2801         }
2802
2803         if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2804                 (player->videodec_linked && player->ini.use_system_clock)) {
2805                 LOGD("system clock will be used.");
2806                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2807         }
2808
2809         if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2810                 __mmplayer_gst_set_pulsesink_property(player);
2811         else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2812                 __mmplayer_gst_set_openalsink_property(player);
2813
2814         /* qos on */
2815         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2816         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2817
2818         sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2819         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2820                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2821         gst_object_unref(GST_OBJECT(sink_pad));
2822
2823         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2824
2825         MMPLAYER_FLEAVE();
2826         return MM_ERROR_NONE;
2827
2828 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2829         MMPLAYER_FLEAVE();
2830         return MM_ERROR_PLAYER_INTERNAL;
2831 }
2832
2833 static int
2834 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2835 {
2836         mmplayer_gst_element_t *audiobin = NULL;
2837         enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2838
2839         gchar *dst_format = NULL;
2840         int dst_len = 0;
2841         int dst_samplerate = 0;
2842         int dst_channels = 0;
2843         GstCaps *caps = NULL;
2844         char *caps_str = NULL;
2845
2846         MMPLAYER_FENTER();
2847         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2848                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2849
2850         audiobin = player->pipeline->audiobin;
2851
2852         LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2853
2854         /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2855
2856            [case 1] extract interleave audio pcm without playback
2857                                 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2858                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2859
2860                                 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2861
2862            [case 2] deinterleave for each channel without playback
2863                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2864                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2865
2866                                 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2867                                                                                                                                                    - fakesink (sync or not)
2868                                                                                                                                                    - ...      (sync or not)
2869
2870            [case 3] [case 1(sync only)] + playback
2871                                 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2872
2873                                 * src - ... - tee - queue1 - playback path
2874                                                                   - queue2 - [case1 pipeline with sync]
2875
2876            [case 4] [case 2(sync only)] + playback
2877                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2878
2879                                 * src - ... - tee - queue1 - playback path
2880                                                                   - queue2 - [case2 pipeline with sync]
2881
2882          */
2883
2884         /* 1. create tee and playback path
2885               'tee' should be added at first to copy the decoded stream
2886          */
2887         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2888                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2889                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2890
2891                 /* tee - path 1 : for playback path */
2892                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2893                 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2894
2895                 /* tee - path 2 : for extract path */
2896                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2897                 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2898         }
2899
2900         /* if there is tee, 'tee - path 2' is linked here */
2901         /* converter */
2902         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2903
2904         /* resampler */
2905         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER,  player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2906
2907         /* 2. decide the extract pcm format */
2908         mm_attrs_multiple_get(player->attrs, NULL,
2909                                 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2910                                 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2911                                 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2912                                 NULL);
2913
2914         LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2915                         dst_format, dst_len, dst_samplerate, dst_channels);
2916
2917         if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2918                 mm_attrs_multiple_get(player->attrs, NULL,
2919                                         "content_audio_format", &dst_format, &dst_len, /* get string and len */
2920                                         "content_audio_samplerate", &dst_samplerate,
2921                                         "content_audio_channels", &dst_channels,
2922                                         NULL);
2923
2924                 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2925                                 dst_format, dst_len, dst_samplerate, dst_channels);
2926
2927                 /* If there is no enough information, set it to platform default value. */
2928                 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2929                         LOGD("set platform default format");
2930                         dst_format = DEFAULT_PCM_OUT_FORMAT;
2931                 }
2932                 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2933                 if (dst_channels <= 0)   dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2934         }
2935
2936         /* 3. create capsfilter */
2937         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2938         caps = gst_caps_new_simple("audio/x-raw",
2939                         "format", G_TYPE_STRING, dst_format,
2940                         "rate", G_TYPE_INT, dst_samplerate,
2941                         "channels", G_TYPE_INT, dst_channels,
2942                         NULL);
2943
2944         caps_str = gst_caps_to_string(caps);
2945         LOGD("new caps : %s", caps_str);
2946
2947         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2948
2949         /* clean */
2950         gst_caps_unref(caps);
2951         MMPLAYER_FREEIF(caps_str);
2952
2953         /* 4-1. create deinterleave to extract pcm for each channel */
2954         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2955                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2956                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2957
2958                 /* audiosink will be added after getting signal for each channel */
2959                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2960                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2961         } else {
2962         /* 4-2. create fakesink to extract interlevaed pcm */
2963                 LOGD("add audio fakesink for interleaved audio");
2964                 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2965                 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2966                         g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2967                 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2968
2969                 _mmplayer_add_signal_connection(player,
2970                         G_OBJECT(audiobin[extract_sink_id].gst),
2971                         MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2972                         "handoff",
2973                         G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2974                         (gpointer)player);
2975
2976                 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2977         }
2978
2979         MMPLAYER_FLEAVE();
2980         return MM_ERROR_NONE;
2981
2982 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2983         MMPLAYER_FLEAVE();
2984         return MM_ERROR_PLAYER_INTERNAL;
2985 }
2986
2987 static int
2988 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2989 {
2990         int ret = MM_ERROR_NONE;
2991         mmplayer_gst_element_t *audiobin = NULL;
2992         GList *element_bucket = NULL;
2993
2994         MMPLAYER_FENTER();
2995         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2996                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2997
2998         audiobin = player->pipeline->audiobin;
2999
3000         if (player->build_audio_offload) { /* skip all the audio filters */
3001                 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3002
3003                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3004                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3005                                 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3006
3007                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3008                 goto DONE;
3009         }
3010
3011         /* FIXME: need to mention the supportable condition at API reference */
3012         if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3013                 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3014         else
3015                 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3016
3017         if (ret != MM_ERROR_NONE)
3018                 goto ERROR;
3019 DONE:
3020         LOGD("success to make audio bin element");
3021         *bucket = element_bucket;
3022
3023         MMPLAYER_FLEAVE();
3024         return MM_ERROR_NONE;
3025
3026 ERROR:
3027         LOGE("failed to make audio bin element");
3028         g_list_free(element_bucket);
3029
3030         *bucket = NULL;
3031         MMPLAYER_FLEAVE();
3032         return MM_ERROR_PLAYER_INTERNAL;
3033 }
3034
3035 static int
3036 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3037 {
3038         mmplayer_gst_element_t *first_element = NULL;
3039         mmplayer_gst_element_t *audiobin = NULL;
3040         GstPad *pad = NULL;
3041         GstPad *ghostpad = NULL;
3042         GList *element_bucket = NULL;
3043         int i = 0;
3044
3045         MMPLAYER_FENTER();
3046         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3047
3048         /* alloc handles */
3049         audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3050         if (!audiobin) {
3051                 LOGE("failed to allocate memory for audiobin");
3052                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3053         }
3054
3055         /* create bin */
3056         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3057         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3058         if (!audiobin[MMPLAYER_A_BIN].gst) {
3059                 LOGE("failed to create audiobin");
3060                 goto ERROR;
3061         }
3062
3063         /* take it */
3064         player->pipeline->audiobin = audiobin;
3065
3066         /* create audio filters and audiosink */
3067         if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3068                 goto ERROR;
3069
3070         /* adding created elements to bin */
3071         LOGD("adding created elements to bin");
3072         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3073                 goto ERROR;
3074
3075         /* linking elements in the bucket by added order. */
3076         LOGD("Linking elements in the bucket by added order.");
3077         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3078                 goto ERROR;
3079
3080         /* get first element's sinkpad for creating ghostpad */
3081         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3082         if (!first_element) {
3083                 LOGE("failed to get first elem");
3084                 goto ERROR;
3085         }
3086
3087         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3088         if (!pad) {
3089                 LOGE("failed to get pad from first element of audiobin");
3090                 goto ERROR;
3091         }
3092
3093         ghostpad = gst_ghost_pad_new("sink", pad);
3094         if (!ghostpad) {
3095                 LOGE("failed to create ghostpad");
3096                 goto ERROR;
3097         }
3098
3099         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3100                 LOGE("failed to add ghostpad to audiobin");
3101                 goto ERROR;
3102         }
3103
3104         gst_object_unref(pad);
3105
3106         g_list_free(element_bucket);
3107         MMPLAYER_FLEAVE();
3108
3109         return MM_ERROR_NONE;
3110
3111 ERROR:
3112         LOGD("ERROR : releasing audiobin");
3113
3114         if (pad)
3115                 gst_object_unref(GST_OBJECT(pad));
3116
3117         if (ghostpad)
3118                 gst_object_unref(GST_OBJECT(ghostpad));
3119
3120         if (element_bucket)
3121                 g_list_free(element_bucket);
3122
3123         /* release element which are not added to bin */
3124         for (i = 1; i < MMPLAYER_A_NUM; i++) {
3125                 /* NOTE : skip bin */
3126                 if (audiobin[i].gst) {
3127                         GstObject *parent = NULL;
3128                         parent = gst_element_get_parent(audiobin[i].gst);
3129
3130                         if (!parent) {
3131                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3132                                 audiobin[i].gst = NULL;
3133                         } else
3134                                 gst_object_unref(GST_OBJECT(parent));
3135                 }
3136         }
3137
3138         /* release audiobin with it's childs */
3139         if (audiobin[MMPLAYER_A_BIN].gst)
3140                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3141
3142         MMPLAYER_FREEIF(audiobin);
3143
3144         player->pipeline->audiobin = NULL;
3145
3146         return MM_ERROR_PLAYER_INTERNAL;
3147 }
3148
3149 static guint32
3150 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3151 {
3152         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3153 }
3154
3155 int
3156 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3157 {
3158         int ret = MM_ERROR_NONE;
3159         GList *l = NULL;
3160         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3161         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3162
3163         MMPLAYER_VIDEO_BO_LOCK(player);
3164
3165         if (player->video_bo_list) {
3166                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3167                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3168                         if (tmp && tmp->bo == bo) {
3169                                 tmp->used = FALSE;
3170                                 LOGD("release bo %p", bo);
3171                                 tbm_bo_unref(tmp->bo);
3172                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3173                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
3174                                 return ret;
3175                         }
3176                 }
3177         } else {
3178                 /* hw codec is running or the list was reset for DRC. */
3179                 LOGW("there is no bo list.");
3180         }
3181         MMPLAYER_VIDEO_BO_UNLOCK(player);
3182
3183         LOGW("failed to find bo %p", bo);
3184         return ret;
3185 }
3186
3187 static void
3188 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3189 {
3190         GList *l = NULL;
3191
3192         MMPLAYER_FENTER();
3193         MMPLAYER_RETURN_IF_FAIL(player);
3194
3195         MMPLAYER_VIDEO_BO_LOCK(player);
3196         if (player->video_bo_list) {
3197                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3198                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3199                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3200                         if (tmp) {
3201                                 if (tmp->bo)
3202                                         tbm_bo_unref(tmp->bo);
3203                                 g_free(tmp);
3204                         }
3205                 }
3206                 g_list_free(player->video_bo_list);
3207                 player->video_bo_list = NULL;
3208         }
3209         player->video_bo_size = 0;
3210         MMPLAYER_VIDEO_BO_UNLOCK(player);
3211
3212         MMPLAYER_FLEAVE();
3213         return;
3214 }
3215
3216 static void *
3217 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3218 {
3219         GList *l = NULL;
3220         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3221         gboolean ret = TRUE;
3222
3223         /* check DRC, if it is, destroy the prev bo list to create again */
3224         if (player->video_bo_size != size) {
3225                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3226                 __mmplayer_video_stream_destroy_bo_list(player);
3227                 player->video_bo_size = size;
3228         }
3229
3230         MMPLAYER_VIDEO_BO_LOCK(player);
3231
3232         if ((!player->video_bo_list) ||
3233                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3234
3235                 /* create bo list */
3236                 int idx = 0;
3237                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3238
3239                 if (player->video_bo_list) {
3240                         /* if bo list did not created all, try it again. */
3241                         idx = g_list_length(player->video_bo_list);
3242                         LOGD("bo list exist(len: %d)", idx);
3243                 }
3244
3245                 for (; idx < player->ini.num_of_video_bo; idx++) {
3246                         mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3247                         if (!bo_info) {
3248                                 LOGE("Fail to alloc bo_info.");
3249                                 break;
3250                         }
3251                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3252                         if (!bo_info->bo) {
3253                                 LOGE("Fail to tbm_bo_alloc.");
3254                                 MMPLAYER_FREEIF(bo_info);
3255                                 break;
3256                         }
3257                         bo_info->used = FALSE;
3258                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3259                 }
3260
3261                 /* update video num buffers */
3262                 LOGD("video_num_buffers : %d", idx);
3263                 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3264                 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3265
3266                 if (idx == 0) {
3267                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3268                         return NULL;
3269                 }
3270         }
3271
3272         while (TRUE) {
3273                 /* get bo from list*/
3274                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3275                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3276                         if (tmp && (tmp->used == FALSE)) {
3277                                 LOGD("found bo %p to use", tmp->bo);
3278                                 tmp->used = TRUE;
3279                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3280                                 return tbm_bo_ref(tmp->bo);
3281                         }
3282                 }
3283                 if (!ret) {
3284                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3285                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3286                         return NULL;
3287                 }
3288
3289                 if (player->ini.video_bo_timeout <= 0) {
3290                         MMPLAYER_VIDEO_BO_WAIT(player);
3291                 } else {
3292                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3293                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3294                 }
3295                 continue;
3296         }
3297 }
3298
3299 static void
3300 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3301 {
3302         mmplayer_t *player = (mmplayer_t *)data;
3303         MMPLAYER_FENTER();
3304         MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3305
3306         /* send prerolled pkt */
3307         player->video_stream_prerolled = false;
3308
3309         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3310
3311         /* not to send prerolled pkt again */
3312         player->video_stream_prerolled = true;
3313 }
3314
3315 static void
3316 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3317 {
3318         mmplayer_t *player = (mmplayer_t *)data;
3319         mmplayer_video_decoded_data_info_t *stream = NULL;
3320         GstMemory *mem = NULL;
3321
3322         MMPLAYER_FENTER();
3323         MMPLAYER_RETURN_IF_FAIL(player);
3324         MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3325
3326         if (player->video_stream_prerolled) {
3327                 player->video_stream_prerolled = false;
3328                 LOGD("skip the prerolled pkt not to send it again");
3329                 return;
3330         }
3331
3332         /* clear stream data structure */
3333         stream = __mmplayer_create_stream_from_pad(pad);
3334         if (!stream) {
3335                 LOGE("failed to alloc stream");
3336                 return;
3337         }
3338
3339         _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3340
3341         /* set size and timestamp */
3342         mem = gst_buffer_peek_memory(buffer, 0);
3343         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3344         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3345
3346         /* check zero-copy */
3347         if (player->set_mode.video_zc &&
3348                 player->set_mode.video_export &&
3349                 gst_is_tizen_memory(mem)) {
3350                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3351                 stream->internal_buffer = gst_buffer_ref(buffer);
3352         } else { /* sw codec */
3353                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3354                         goto ERROR;
3355
3356                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3357                         goto ERROR;
3358         }
3359
3360         if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3361                 LOGE("failed to send video decoded data.");
3362                 goto ERROR;
3363         }
3364
3365         return;
3366
3367 ERROR:
3368         LOGE("release video stream resource.");
3369         if (gst_is_tizen_memory(mem)) {
3370                 int i = 0;
3371                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3372                         if (stream->bo[i])
3373                                 tbm_bo_unref(stream->bo[i]);
3374                 }
3375
3376                 /* unref gst buffer */
3377                 if (stream->internal_buffer)
3378                         gst_buffer_unref(stream->internal_buffer);
3379         } else {
3380                 if (stream->bo[0])
3381                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3382         }
3383         MMPLAYER_FREEIF(stream);
3384         return;
3385 }
3386
3387 static void
3388 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3389 {
3390         mmplayer_gst_element_t *videobin = NULL;
3391
3392         MMPLAYER_FENTER();
3393         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3394
3395         videobin = player->pipeline->videobin;
3396
3397         /* Set spatial media metadata and/or user settings to the element.
3398          * */
3399         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400                         "projection-type", player->video360_metadata.projection_type, NULL);
3401
3402         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3403                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3404
3405         if (player->video360_metadata.full_pano_width_pixels &&
3406                         player->video360_metadata.full_pano_height_pixels &&
3407                         player->video360_metadata.cropped_area_image_width &&
3408                         player->video360_metadata.cropped_area_image_height) {
3409                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3410                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3411                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3412                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3413                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3414                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3415                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3416                                 NULL);
3417         }
3418
3419         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3420                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3421                                 "horizontal-fov", player->video360_horizontal_fov,
3422                                 "vertical-fov", player->video360_vertical_fov, NULL);
3423         }
3424
3425         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3426                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3427                                 "zoom", 1.0f / player->video360_zoom, NULL);
3428         }
3429
3430         if (player->video360_yaw_radians <= M_PI &&
3431                         player->video360_yaw_radians >= -M_PI &&
3432                         player->video360_pitch_radians <= M_PI_2 &&
3433                         player->video360_pitch_radians >= -M_PI_2) {
3434                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3435                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3436                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3437         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3438                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439                                 "pose-yaw", player->video360_metadata.init_view_heading,
3440                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3441         }
3442
3443         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3444                         "passthrough", !player->is_video360_enabled, NULL);
3445
3446
3447         MMPLAYER_FLEAVE();
3448 }
3449
3450 static int
3451 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3452 {
3453         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3454         GList *element_bucket = NULL;
3455
3456         MMPLAYER_FENTER();
3457         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3458
3459         /* create video360 filter */
3460         if (player->is_360_feature_enabled && player->is_content_spherical) {
3461                 LOGD("create video360 element");
3462                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3463                 __mmplayer_gst_set_video360_property(player);
3464                 goto EXIT;
3465         }
3466
3467         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3468                 LOGD("skip creating the videoconv and rotator");
3469                 return MM_ERROR_NONE;
3470         }
3471
3472         /* in case of sw codec & overlay surface type, except 360 playback.
3473          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3474         LOGD("create video converter: %s", video_csc);
3475         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3476
3477 EXIT:
3478         *bucket = element_bucket;
3479         MMPLAYER_FLEAVE();
3480         return MM_ERROR_NONE;
3481
3482 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3483         g_list_free(element_bucket);
3484
3485         *bucket = NULL;
3486         MMPLAYER_FLEAVE();
3487         return MM_ERROR_PLAYER_INTERNAL;
3488 }
3489
3490 static gchar *
3491 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3492 {
3493         gchar *factory_name = NULL;
3494
3495         switch (surface_type) {
3496         case MM_DISPLAY_SURFACE_OVERLAY:
3497                 if (strlen(player->ini.videosink_element_overlay) > 0)
3498                         factory_name = player->ini.videosink_element_overlay;
3499                 break;
3500         case MM_DISPLAY_SURFACE_REMOTE:
3501         case MM_DISPLAY_SURFACE_NULL:
3502                 if (strlen(player->ini.videosink_element_fake) > 0)
3503                         factory_name = player->ini.videosink_element_fake;
3504                 break;
3505         default:
3506                 LOGE("unidentified surface type");
3507                 break;
3508         }
3509
3510         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3511         return factory_name;
3512 }
3513
3514 static int
3515 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3516 {
3517         gchar *factory_name = NULL;
3518         mmplayer_gst_element_t *videobin = NULL;
3519         MMHandleType attrs;
3520         int gapless = 0;
3521
3522         MMPLAYER_FENTER();
3523         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3524
3525         videobin = player->pipeline->videobin;
3526         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3527
3528         attrs = MMPLAYER_GET_ATTRS(player);
3529         if (!attrs) {
3530                 LOGE("cannot get content attribute");
3531                 return MM_ERROR_PLAYER_INTERNAL;
3532         }
3533
3534         LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3535         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3536                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3537                 if (!use_tbm) {
3538                         /* support shard memory with S/W codec on HawkP */
3539                         if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3540                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3541                                         "use-tbm", use_tbm, NULL);
3542                         }
3543                 }
3544         } else {
3545                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3546                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3547         }
3548
3549         mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3550         if (gapless > 0) {
3551                 LOGD("disable last-sample");
3552                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3553         }
3554
3555         if (player->set_mode.video_export) {
3556                 int enable = 0;
3557                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3558                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3559                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3560
3561                 _mmplayer_add_signal_connection(player,
3562                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3563                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3564                                                                 "handoff",
3565                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3566                                                                 (gpointer)player);
3567
3568                 _mmplayer_add_signal_connection(player,
3569                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3570                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3571                                                                 "preroll-handoff",
3572                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3573                                                                 (gpointer)player);
3574         }
3575
3576         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3577                 return MM_ERROR_PLAYER_INTERNAL;
3578
3579         if (videobin[MMPLAYER_V_SINK].gst) {
3580                 GstPad *sink_pad = NULL;
3581                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3582                 if (sink_pad) {
3583                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3584                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3585                         gst_object_unref(GST_OBJECT(sink_pad));
3586                 } else {
3587                         LOGE("failed to get sink pad from videosink");
3588                 }
3589         }
3590
3591         return MM_ERROR_NONE;
3592 }
3593
3594 /**
3595  * VIDEO BIN
3596  * - video overlay surface(arm/x86) : tizenwlsink
3597  */
3598 static int
3599 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3600 {
3601         GstPad *pad = NULL;
3602         GList *element_bucket = NULL;
3603         mmplayer_gst_element_t *first_element = NULL;
3604         mmplayer_gst_element_t *videobin = NULL;
3605         gchar *videosink_factory_name = NULL;
3606
3607         MMPLAYER_FENTER();
3608         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3609
3610         /* alloc handles */
3611         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3612         if (!videobin)
3613                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3614
3615         player->pipeline->videobin = videobin;
3616
3617         /* create bin */
3618         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3619         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3620         if (!videobin[MMPLAYER_V_BIN].gst) {
3621                 LOGE("failed to create videobin");
3622                 goto ERROR;
3623         }
3624
3625         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3626                 goto ERROR;
3627
3628         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3629         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3630
3631         /* additional setting for sink plug-in */
3632         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3633                 LOGE("failed to set video property");
3634                 goto ERROR;
3635         }
3636
3637         /* store it as it's sink element */
3638         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3639
3640         /* adding created elements to bin */
3641         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3642                 LOGE("failed to add elements");
3643                 goto ERROR;
3644         }
3645
3646         /* Linking elements in the bucket by added order */
3647         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3648                 LOGE("failed to link elements");
3649                 goto ERROR;
3650         }
3651
3652         /* get first element's sinkpad for creating ghostpad */
3653         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3654         if (!first_element) {
3655                 LOGE("failed to get first element from bucket");
3656                 goto ERROR;
3657         }
3658
3659         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3660         if (!pad) {
3661                 LOGE("failed to get pad from first element");
3662                 goto ERROR;
3663         }
3664
3665         /* create ghostpad */
3666         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3667         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3668                 LOGE("failed to add ghostpad to videobin");
3669                 goto ERROR;
3670         }
3671         gst_object_unref(pad);
3672
3673         /* done. free allocated variables */
3674         g_list_free(element_bucket);
3675
3676         MMPLAYER_FLEAVE();
3677
3678         return MM_ERROR_NONE;
3679
3680 ERROR:
3681         LOGE("ERROR : releasing videobin");
3682         g_list_free(element_bucket);
3683
3684         if (pad)
3685                 gst_object_unref(GST_OBJECT(pad));
3686
3687         /* release videobin with it's childs */
3688         if (videobin[MMPLAYER_V_BIN].gst)
3689                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3690
3691         MMPLAYER_FREEIF(videobin);
3692         player->pipeline->videobin = NULL;
3693
3694         return MM_ERROR_PLAYER_INTERNAL;
3695 }
3696
3697 static int
3698 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3699 {
3700         GList *element_bucket = NULL;
3701         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3702
3703         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3704         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3705         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3706                                                         "signal-handoffs", FALSE,
3707                                                         NULL);
3708
3709         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3710         _mmplayer_add_signal_connection(player,
3711                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3712                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3713                                                         "handoff",
3714                                                         G_CALLBACK(__mmplayer_update_subtitle),
3715                                                         (gpointer)player);
3716
3717         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3718                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3719
3720         if (!player->play_subtitle) {
3721                 LOGD("add textbin sink as sink element of whole pipeline.");
3722                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3723         }
3724
3725         /* adding created elements to bin */
3726         LOGD("adding created elements to bin");
3727         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3728                 LOGE("failed to add elements");
3729                 goto ERROR;
3730         }
3731
3732         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3733         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3734         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3735
3736         /* linking elements in the bucket by added order. */
3737         LOGD("Linking elements in the bucket by added order.");
3738         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3739                 LOGE("failed to link elements");
3740                 goto ERROR;
3741         }
3742
3743         /* done. free allocated variables */
3744         g_list_free(element_bucket);
3745
3746         if (textbin[MMPLAYER_T_QUEUE].gst) {
3747                 GstPad *pad = NULL;
3748                 GstPad *ghostpad = NULL;
3749
3750                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3751                 if (!pad) {
3752                         LOGE("failed to get sink pad of text queue");
3753                         goto ERROR;
3754                 }
3755
3756                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3757                 gst_object_unref(pad);
3758
3759                 if (!ghostpad) {
3760                         LOGE("failed to create ghostpad of textbin");
3761                         goto ERROR;
3762                 }
3763
3764                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3765                         LOGE("failed to add ghostpad to textbin");
3766                         gst_object_unref(ghostpad);
3767                         goto ERROR;
3768                 }
3769         }
3770
3771         return MM_ERROR_NONE;
3772
3773 ERROR:
3774         g_list_free(element_bucket);
3775
3776         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3777                 LOGE("remove textbin sink from sink list");
3778                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3779         }
3780
3781         /* release element at __mmplayer_gst_create_text_sink_bin */
3782         return MM_ERROR_PLAYER_INTERNAL;
3783 }
3784
3785 static int
3786 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3787 {
3788         mmplayer_gst_element_t *textbin = NULL;
3789         GList *element_bucket = NULL;
3790         int surface_type = 0;
3791         gint i = 0;
3792
3793         MMPLAYER_FENTER();
3794
3795         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3796
3797         /* alloc handles */
3798         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3799         if (!textbin) {
3800                 LOGE("failed to allocate memory for textbin");
3801                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3802         }
3803
3804         /* create bin */
3805         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3806         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3807         if (!textbin[MMPLAYER_T_BIN].gst) {
3808                 LOGE("failed to create textbin");
3809                 goto ERROR;
3810         }
3811
3812         /* take it */
3813         player->pipeline->textbin = textbin;
3814
3815         /* fakesink */
3816         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3817         LOGD("surface type for subtitle : %d", surface_type);
3818         switch (surface_type) {
3819         case MM_DISPLAY_SURFACE_OVERLAY:
3820         case MM_DISPLAY_SURFACE_NULL:
3821         case MM_DISPLAY_SURFACE_REMOTE:
3822                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3823                         LOGE("failed to make plain text elements");
3824                         goto ERROR;
3825                 }
3826                 break;
3827         default:
3828                 goto ERROR;
3829                 break;
3830         }
3831
3832         MMPLAYER_FLEAVE();
3833
3834         return MM_ERROR_NONE;
3835
3836 ERROR:
3837
3838         LOGD("ERROR : releasing textbin");
3839
3840         g_list_free(element_bucket);
3841
3842         /* release signal */
3843         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3844
3845         /* release element which are not added to bin */
3846         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3847                 /* NOTE : skip bin */
3848                 if (textbin[i].gst) {
3849                         GstObject *parent = NULL;
3850                         parent = gst_element_get_parent(textbin[i].gst);
3851
3852                         if (!parent) {
3853                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3854                                 textbin[i].gst = NULL;
3855                         } else {
3856                                 gst_object_unref(GST_OBJECT(parent));
3857                         }
3858                 }
3859         }
3860
3861         /* release textbin with it's childs */
3862         if (textbin[MMPLAYER_T_BIN].gst)
3863                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3864
3865         MMPLAYER_FREEIF(player->pipeline->textbin);
3866         player->pipeline->textbin = NULL;
3867
3868         MMPLAYER_FLEAVE();
3869         return MM_ERROR_PLAYER_INTERNAL;
3870 }
3871
3872 static int
3873 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3874 {
3875         mmplayer_gst_element_t *mainbin = NULL;
3876         mmplayer_gst_element_t *textbin = NULL;
3877         MMHandleType attrs = 0;
3878         GstElement *subsrc = NULL;
3879         GstElement *subparse = NULL;
3880         gchar *subtitle_uri = NULL;
3881         const gchar *charset = NULL;
3882         GstPad *pad = NULL;
3883
3884         MMPLAYER_FENTER();
3885
3886         /* get mainbin */
3887         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3888                                                                 player->pipeline &&
3889                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3890
3891         mainbin = player->pipeline->mainbin;
3892
3893         attrs = MMPLAYER_GET_ATTRS(player);
3894         if (!attrs) {
3895                 LOGE("cannot get content attribute");
3896                 return MM_ERROR_PLAYER_INTERNAL;
3897         }
3898
3899         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3900         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3901                 LOGE("subtitle uri is not proper filepath.");
3902                 return MM_ERROR_PLAYER_INVALID_URI;
3903         }
3904
3905         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3906                 LOGE("failed to get storage info of subtitle path");
3907                 return MM_ERROR_PLAYER_INVALID_URI;
3908         }
3909
3910         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3911
3912         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3913         player->subtitle_language_list = NULL;
3914         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3915
3916         /* create the subtitle source */
3917         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3918         if (!subsrc) {
3919                 LOGE("failed to create filesrc element");
3920                 goto ERROR;
3921         }
3922         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3923
3924         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3925         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3926
3927         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3928                 LOGW("failed to add queue");
3929                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3930                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3931                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3932                 goto ERROR;
3933         }
3934
3935         /* subparse */
3936         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3937         if (!subparse) {
3938                 LOGE("failed to create subparse element");
3939                 goto ERROR;
3940         }
3941
3942         charset = _mmplayer_get_charset(subtitle_uri);
3943         if (charset) {
3944                 LOGD("detected charset is %s", charset);
3945                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3946         }
3947
3948         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3949         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3950
3951         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3952                 LOGW("failed to add subparse");
3953                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3954                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3955                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3956                 goto ERROR;
3957         }
3958
3959         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3960                 LOGW("failed to link subsrc and subparse");
3961                 goto ERROR;
3962         }
3963
3964         player->play_subtitle = TRUE;
3965         player->adjust_subtitle_pos = 0;
3966
3967         LOGD("play subtitle using subtitle file");
3968
3969         if (player->pipeline->textbin == NULL) {
3970                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3971                         LOGE("failed to create text sink bin. continuing without text");
3972                         goto ERROR;
3973                 }
3974
3975                 textbin = player->pipeline->textbin;
3976
3977                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3978                         LOGW("failed to add textbin");
3979
3980                         /* release signal */
3981                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3982
3983                         /* release textbin with it's childs */
3984                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3985                         MMPLAYER_FREEIF(player->pipeline->textbin);
3986                         player->pipeline->textbin = textbin = NULL;
3987                         goto ERROR;
3988                 }
3989
3990                 LOGD("link text input selector and textbin ghost pad");
3991
3992                 player->textsink_linked = 1;
3993                 player->external_text_idx = 0;
3994                 LOGI("textsink is linked");
3995         } else {
3996                 textbin = player->pipeline->textbin;
3997                 LOGD("text bin has been created. reuse it.");
3998                 player->external_text_idx = 1;
3999         }
4000
4001         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4002                 LOGW("failed to link subparse and textbin");
4003                 goto ERROR;
4004         }
4005
4006         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4007         if (!pad) {
4008                 LOGE("failed to get sink pad from textsink to probe data");
4009                 goto ERROR;
4010         }
4011
4012         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4013                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4014
4015         gst_object_unref(pad);
4016         pad = NULL;
4017
4018         /* create dot. for debugging */
4019         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4020         MMPLAYER_FLEAVE();
4021
4022         return MM_ERROR_NONE;
4023
4024 ERROR:
4025         /* release text pipeline resource */
4026         player->textsink_linked = 0;
4027
4028         /* release signal */
4029         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4030
4031         if (player->pipeline->textbin) {
4032                 LOGE("remove textbin");
4033
4034                 /* release textbin with it's childs */
4035                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4036                 MMPLAYER_FREEIF(player->pipeline->textbin);
4037                 player->pipeline->textbin = NULL;
4038
4039         }
4040
4041         /* release subtitle elem */
4042         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4043         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4044
4045         return MM_ERROR_PLAYER_INTERNAL;
4046 }
4047
4048 gboolean
4049 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4050 {
4051         mmplayer_t *player = (mmplayer_t *)data;
4052         MMMessageParamType msg = {0, };
4053         GstClockTime duration = 0;
4054         gpointer text = NULL;
4055         guint text_size = 0;
4056         gboolean ret = TRUE;
4057         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4058
4059         MMPLAYER_FENTER();
4060
4061         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4062         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4063
4064         if (player->is_subtitle_force_drop) {
4065                 LOGW("subtitle is dropped forcedly.");
4066                 return ret;
4067         }
4068
4069         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4070         text = mapinfo.data;
4071         text_size = mapinfo.size;
4072
4073         if (player->set_mode.subtitle_off) {
4074                 LOGD("subtitle is OFF.");
4075                 return TRUE;
4076         }
4077
4078         if (!text || (text_size == 0)) {
4079                 LOGD("There is no subtitle to be displayed.");
4080                 return TRUE;
4081         }
4082
4083         msg.data = (void *)text;
4084
4085         duration = GST_BUFFER_DURATION(buffer);
4086
4087         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4088                 if (player->duration > GST_BUFFER_PTS(buffer))
4089                         duration = player->duration - GST_BUFFER_PTS(buffer);
4090                 else
4091                         duration = 0;
4092                 LOGI("subtitle duration is invalid, subtitle duration change "
4093                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4094         }
4095         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4096
4097         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4098
4099         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4100         gst_buffer_unmap(buffer, &mapinfo);
4101
4102         MMPLAYER_FLEAVE();
4103
4104         return ret;
4105 }
4106
4107 static GstPadProbeReturn
4108 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4109 {
4110         mmplayer_t *player = (mmplayer_t *)u_data;
4111         GstClockTime cur_timestamp = 0;
4112         gint64 adjusted_timestamp = 0;
4113         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4114
4115         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4116
4117         if (player->set_mode.subtitle_off) {
4118                 LOGD("subtitle is OFF.");
4119                 return TRUE;
4120         }
4121
4122         if (player->adjust_subtitle_pos == 0) {
4123                 LOGD("nothing to do");
4124                 return TRUE;
4125         }
4126
4127         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4128         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4129
4130         if (adjusted_timestamp < 0) {
4131                 LOGD("adjusted_timestamp under zero");
4132                 MMPLAYER_FLEAVE();
4133                 return FALSE;
4134         }
4135
4136         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4137         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4138                                 GST_TIME_ARGS(cur_timestamp),
4139                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4140
4141         return GST_PAD_PROBE_OK;
4142 }
4143
4144 static int
4145 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4146 {
4147         MMPLAYER_FENTER();
4148
4149         /* check player and subtitlebin are created */
4150         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4151         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4152
4153         if (position == 0) {
4154                 LOGD("nothing to do");
4155                 MMPLAYER_FLEAVE();
4156                 return MM_ERROR_NONE;
4157         }
4158
4159         /* check current postion */
4160         player->adjust_subtitle_pos = position;
4161
4162         LOGD("save adjust_subtitle_pos in player");
4163
4164         MMPLAYER_FLEAVE();
4165
4166         return MM_ERROR_NONE;
4167 }
4168
4169 /**
4170  * This function is to create  audio or video pipeline for playing.
4171  *
4172  * @param       player          [in]    handle of player
4173  *
4174  * @return      This function returns zero on success.
4175  * @remark
4176  * @see
4177  */
4178 static int
4179 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4180 {
4181         int ret = MM_ERROR_NONE;
4182         mmplayer_gst_element_t *mainbin = NULL;
4183         MMHandleType attrs = 0;
4184
4185         MMPLAYER_FENTER();
4186         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4187
4188         /* get profile attribute */
4189         attrs = MMPLAYER_GET_ATTRS(player);
4190         if (!attrs) {
4191                 LOGE("failed to get content attribute");
4192                 goto INIT_ERROR;
4193         }
4194
4195         /* create pipeline handles */
4196         if (player->pipeline) {
4197                 LOGE("pipeline should be released before create new one");
4198                 goto INIT_ERROR;
4199         }
4200
4201         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4202         if (player->pipeline == NULL)
4203                 goto INIT_ERROR;
4204
4205         /* create mainbin */
4206         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4207         if (mainbin == NULL)
4208                 goto INIT_ERROR;
4209
4210         /* create pipeline */
4211         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4212         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4213         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4214                 LOGE("failed to create pipeline");
4215                 g_free(mainbin);
4216                 goto INIT_ERROR;
4217         }
4218
4219         player->pipeline->mainbin = mainbin;
4220
4221         /* create the source and decoder elements */
4222         if (MMPLAYER_IS_MS_BUFF_SRC(player))
4223                 ret = _mmplayer_gst_build_es_pipeline(player);
4224         else
4225                 ret = _mmplayer_gst_build_pipeline(player);
4226
4227         if (ret != MM_ERROR_NONE) {
4228                 LOGE("failed to create some elements");
4229                 goto INIT_ERROR;
4230         }
4231
4232         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4233         if (__mmplayer_check_subtitle(player)
4234                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4235                 LOGE("failed to create text pipeline");
4236
4237         /* add bus watch */
4238         ret = _mmplayer_gst_add_bus_watch(player);
4239         if (ret != MM_ERROR_NONE) {
4240                 LOGE("failed to add bus watch");
4241                 goto INIT_ERROR;
4242         }
4243
4244         MMPLAYER_FLEAVE();
4245         return MM_ERROR_NONE;
4246
4247 INIT_ERROR:
4248         __mmplayer_gst_destroy_pipeline(player);
4249         return MM_ERROR_PLAYER_INTERNAL;
4250 }
4251
4252 static void
4253 __mmplayer_reset_gapless_state(mmplayer_t *player)
4254 {
4255         MMPLAYER_FENTER();
4256         MMPLAYER_RETURN_IF_FAIL(player
4257                 && player->pipeline
4258                 && player->pipeline->audiobin
4259                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4260
4261         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4262
4263         MMPLAYER_FLEAVE();
4264         return;
4265 }
4266
4267 static int
4268 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4269 {
4270         gint timeout = 0;
4271         int ret = MM_ERROR_NONE;
4272
4273         MMPLAYER_FENTER();
4274
4275         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4276
4277         /* cleanup stuffs */
4278         MMPLAYER_FREEIF(player->type);
4279         player->no_more_pad = FALSE;
4280         player->num_dynamic_pad = 0;
4281         player->demux_pad_index = 0;
4282
4283         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4284         player->subtitle_language_list = NULL;
4285         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4286
4287         __mmplayer_reset_gapless_state(player);
4288
4289         if (player->streamer) {
4290                 _mm_player_streaming_initialize(player->streamer, FALSE);
4291                 _mm_player_streaming_destroy(player->streamer);
4292                 player->streamer = NULL;
4293         }
4294
4295         /* cleanup unlinked mime type */
4296         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4297         MMPLAYER_FREEIF(player->unlinked_video_mime);
4298         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4299
4300         /* cleanup running stuffs */
4301         _mmplayer_cancel_eos_timer(player);
4302
4303         /* cleanup gst stuffs */
4304         if (player->pipeline) {
4305                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4306                 GstTagList *tag_list = player->pipeline->tag_list;
4307
4308                 /* first we need to disconnect all signal hander */
4309                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4310
4311                 if (mainbin) {
4312                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4313                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4314                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4315                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4316                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4317                         gst_object_unref(bus);
4318
4319                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4320                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4321                         if (ret != MM_ERROR_NONE) {
4322                                 LOGE("fail to change state to NULL");
4323                                 return MM_ERROR_PLAYER_INTERNAL;
4324                         }
4325
4326                         LOGW("succeeded in changing state to NULL");
4327
4328                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4329
4330                         /* free fakesink */
4331                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4332                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4333
4334                         /* free avsysaudiosink
4335                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4336                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4337                         */
4338                         MMPLAYER_FREEIF(audiobin);
4339                         MMPLAYER_FREEIF(videobin);
4340                         MMPLAYER_FREEIF(textbin);
4341                         MMPLAYER_FREEIF(mainbin);
4342                 }
4343
4344                 if (tag_list)
4345                         gst_tag_list_unref(tag_list);
4346
4347                 MMPLAYER_FREEIF(player->pipeline);
4348         }
4349         MMPLAYER_FREEIF(player->album_art);
4350
4351         if (player->v_stream_caps) {
4352                 gst_caps_unref(player->v_stream_caps);
4353                 player->v_stream_caps = NULL;
4354         }
4355
4356         if (player->a_stream_caps) {
4357                 gst_caps_unref(player->a_stream_caps);
4358                 player->a_stream_caps = NULL;
4359         }
4360
4361         if (player->s_stream_caps) {
4362                 gst_caps_unref(player->s_stream_caps);
4363                 player->s_stream_caps = NULL;
4364         }
4365         _mmplayer_track_destroy(player);
4366
4367         if (player->sink_elements)
4368                 g_list_free(player->sink_elements);
4369         player->sink_elements = NULL;
4370
4371         if (player->bufmgr) {
4372                 tbm_bufmgr_deinit(player->bufmgr);
4373                 player->bufmgr = NULL;
4374         }
4375
4376         LOGW("finished destroy pipeline");
4377
4378         MMPLAYER_FLEAVE();
4379
4380         return ret;
4381 }
4382
4383 static int
4384 __mmplayer_gst_realize(mmplayer_t *player)
4385 {
4386         gint timeout = 0;
4387         int ret = MM_ERROR_NONE;
4388
4389         MMPLAYER_FENTER();
4390
4391         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4392
4393         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4394
4395         ret = __mmplayer_gst_create_pipeline(player);
4396         if (ret) {
4397                 LOGE("failed to create pipeline");
4398                 return ret;
4399         }
4400
4401         /* set pipeline state to READY */
4402         /* NOTE : state change to READY must be performed sync. */
4403         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4404         ret = _mmplayer_gst_set_state(player,
4405                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4406
4407         if (ret != MM_ERROR_NONE) {
4408                 /* return error if failed to set state */
4409                 LOGE("failed to set READY state");
4410                 return ret;
4411         }
4412
4413         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4414
4415         /* create dot before error-return. for debugging */
4416         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4417
4418         MMPLAYER_FLEAVE();
4419
4420         return ret;
4421 }
4422
4423 static int
4424 __mmplayer_gst_unrealize(mmplayer_t *player)
4425 {
4426         int ret = MM_ERROR_NONE;
4427
4428         MMPLAYER_FENTER();
4429
4430         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4431
4432         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4433         MMPLAYER_PRINT_STATE(player);
4434
4435         /* release miscellaneous information */
4436         __mmplayer_release_misc(player);
4437
4438         /* destroy pipeline */
4439         ret = __mmplayer_gst_destroy_pipeline(player);
4440         if (ret != MM_ERROR_NONE) {
4441                 LOGE("failed to destory pipeline");
4442                 return ret;
4443         }
4444
4445         /* release miscellaneous information.
4446            these info needs to be released after pipeline is destroyed. */
4447         __mmplayer_release_misc_post(player);
4448
4449         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4450
4451         MMPLAYER_FLEAVE();
4452
4453         return ret;
4454 }
4455
4456 static int
4457 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4458 {
4459         MMPLAYER_FENTER();
4460
4461         if (!player) {
4462                 LOGW("set_message_callback is called with invalid player handle");
4463                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4464         }
4465
4466         player->msg_cb = callback;
4467         player->msg_cb_param = user_param;
4468
4469         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4470
4471         MMPLAYER_FLEAVE();
4472
4473         return MM_ERROR_NONE;
4474 }
4475
4476 int
4477 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4478 {
4479         int ret = MM_ERROR_NONE;
4480         char *path = NULL;
4481
4482         MMPLAYER_FENTER();
4483
4484         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4485         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4486         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4487
4488         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4489
4490         if (strstr(uri, "es_buff://")) {
4491                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4492         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4493                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4494         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4495                 gchar *tmp = NULL;
4496                 tmp = g_ascii_strdown(uri, strlen(uri));
4497                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4498                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4499                 else
4500                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4501                 g_free(tmp);
4502         } else if (strstr(uri, "mms://")) {
4503                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4504         } else if ((path = strstr(uri, "mem://"))) {
4505                 ret = __mmplayer_set_mem_uri(data, path, param);
4506         } else {
4507                 ret = __mmplayer_set_file_uri(data, uri);
4508         }
4509
4510         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4511                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4512         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4513                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4514
4515         /* dump parse result */
4516         SECURE_LOGW("incoming uri : %s", uri);
4517         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4518                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4519
4520         MMPLAYER_FLEAVE();
4521
4522         return ret;
4523 }
4524
4525 static gboolean
4526 __mmplayer_can_do_interrupt(mmplayer_t *player)
4527 {
4528         if (!player || !player->pipeline || !player->attrs) {
4529                 LOGW("not initialized");
4530                 goto FAILED;
4531         }
4532
4533         if (player->audio_decoded_cb) {
4534                 LOGW("not support in pcm extraction mode");
4535                 goto FAILED;
4536         }
4537
4538         /* check if seeking */
4539         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4540                 MMMessageParamType msg_param;
4541                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4542                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4543                 player->seek_state = MMPLAYER_SEEK_NONE;
4544                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4545                 goto FAILED;
4546         }
4547
4548         /* check other thread */
4549         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4550                 LOGW("locked already, cmd state : %d", player->cmd);
4551
4552                 /* check application command */
4553                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4554                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4555
4556                         /* lock will be released at mrp_resource_release_cb() */
4557                         MMPLAYER_CMD_LOCK(player);
4558                         goto INTERRUPT;
4559                 }
4560                 LOGW("nothing to do");
4561                 goto FAILED;
4562         } else {
4563                 LOGW("can interrupt immediately");
4564                 goto INTERRUPT;
4565         }
4566
4567 FAILED:    /* with CMD UNLOCKED */
4568         return FALSE;
4569
4570 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4571         return TRUE;
4572 }
4573
4574 static int
4575 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4576                 void *user_data)
4577 {
4578         mmplayer_t *player = NULL;
4579         MMMessageParamType msg = {0, };
4580         gint64 pos = 0;
4581         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4582
4583         MMPLAYER_FENTER();
4584
4585         if (!user_data) {
4586                 LOGE("user_data is null");
4587                 return FALSE;
4588         }
4589         player = (mmplayer_t *)user_data;
4590
4591         if (!__mmplayer_can_do_interrupt(player)) {
4592                 LOGW("no need to interrupt, so leave");
4593                 /* FIXME: there is no way to avoid releasing resource. */
4594                 return FALSE;
4595         }
4596
4597         player->interrupted_by_resource = TRUE;
4598
4599         /* get last play position */
4600         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4601                 msg.union_type = MM_MSG_UNION_TIME;
4602                 msg.time.elapsed = pos;
4603                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4604         } else {
4605                 LOGW("failed to get play position.");
4606         }
4607
4608         LOGD("video resource conflict so, resource will be freed by unrealizing");
4609         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4610                 LOGE("failed to unrealize");
4611
4612         /* lock is called in __mmplayer_can_do_interrupt() */
4613         MMPLAYER_CMD_UNLOCK(player);
4614
4615         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4616                 player->hw_resource[res_idx] = NULL;
4617         }
4618
4619         MMPLAYER_FLEAVE();
4620         return TRUE; /* release all the resources */
4621 }
4622
4623 static void
4624 __mmplayer_initialize_video_roi(mmplayer_t *player)
4625 {
4626         player->video_roi.scale_x = 0.0;
4627         player->video_roi.scale_y = 0.0;
4628         player->video_roi.scale_width = 1.0;
4629         player->video_roi.scale_height = 1.0;
4630 }
4631
4632 int
4633 _mmplayer_create_player(MMHandleType handle)
4634 {
4635         int ret = MM_ERROR_PLAYER_INTERNAL;
4636         bool enabled = false;
4637
4638         mmplayer_t *player = MM_PLAYER_CAST(handle);
4639
4640         MMPLAYER_FENTER();
4641
4642         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4643
4644         /* initialize player state */
4645         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4646         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4647         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4648         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4649
4650         /* check current state */
4651         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4652
4653         /* construct attributes */
4654         player->attrs = _mmplayer_construct_attribute(handle);
4655
4656         if (!player->attrs) {
4657                 LOGE("Failed to construct attributes");
4658                 return ret;
4659         }
4660
4661         /* initialize gstreamer with configured parameter */
4662         if (!__mmplayer_init_gstreamer(player)) {
4663                 LOGE("Initializing gstreamer failed");
4664                 _mmplayer_deconstruct_attribute(handle);
4665                 return ret;
4666         }
4667
4668         /* create lock. note that g_tread_init() has already called in gst_init() */
4669         g_mutex_init(&player->fsink_lock);
4670
4671         /* create update tag lock */
4672         g_mutex_init(&player->update_tag_lock);
4673
4674         /* create gapless play mutex */
4675         g_mutex_init(&player->gapless_play_thread_mutex);
4676
4677         /* create gapless play cond */
4678         g_cond_init(&player->gapless_play_thread_cond);
4679
4680         /* create gapless play thread */
4681         player->gapless_play_thread =
4682                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4683         if (!player->gapless_play_thread) {
4684                 LOGE("failed to create gapless play thread");
4685                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4686                 g_mutex_clear(&player->gapless_play_thread_mutex);
4687                 g_cond_clear(&player->gapless_play_thread_cond);
4688                 goto ERROR;
4689         }
4690
4691         player->bus_msg_q = g_queue_new();
4692         if (!player->bus_msg_q) {
4693                 LOGE("failed to create queue for bus_msg");
4694                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4695                 goto ERROR;
4696         }
4697
4698         ret = _mmplayer_initialize_video_capture(player);
4699         if (ret != MM_ERROR_NONE) {
4700                 LOGE("failed to initialize video capture");
4701                 goto ERROR;
4702         }
4703
4704         /* initialize resource manager */
4705         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4706                 __resource_release_cb, player, &player->resource_manager)
4707                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4708                 LOGE("failed to initialize resource manager");
4709                 ret = MM_ERROR_PLAYER_INTERNAL;
4710                 goto ERROR;
4711         }
4712
4713         /* create video bo lock and cond */
4714         g_mutex_init(&player->video_bo_mutex);
4715         g_cond_init(&player->video_bo_cond);
4716
4717         /* create subtitle info lock and cond */
4718         g_mutex_init(&player->subtitle_info_mutex);
4719         g_cond_init(&player->subtitle_info_cond);
4720
4721         player->streaming_type = STREAMING_SERVICE_NONE;
4722
4723         /* give default value of audio effect setting */
4724         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4725         player->sound.rg_enable = false;
4726         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4727
4728         player->play_subtitle = FALSE;
4729         player->has_closed_caption = FALSE;
4730         player->pending_resume = FALSE;
4731         if (player->ini.dump_element_keyword[0][0] == '\0')
4732                 player->ini.set_dump_element_flag = FALSE;
4733         else
4734                 player->ini.set_dump_element_flag = TRUE;
4735
4736         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4737         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4738         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4739
4740         /* Set video360 settings to their defaults for just-created player.
4741          * */
4742
4743         player->is_360_feature_enabled = FALSE;
4744         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4745                 LOGI("spherical feature info: %d", enabled);
4746                 if (enabled)
4747                         player->is_360_feature_enabled = TRUE;
4748         } else {
4749                 LOGE("failed to get spherical feature info");
4750         }
4751
4752         player->is_content_spherical = FALSE;
4753         player->is_video360_enabled = TRUE;
4754         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4755         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4756         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4757         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4758         player->video360_zoom = 1.0f;
4759         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4760         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4761
4762         __mmplayer_initialize_video_roi(player);
4763
4764         /* set player state to null */
4765         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4766         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4767
4768         MMPLAYER_FLEAVE();
4769
4770         return MM_ERROR_NONE;
4771
4772 ERROR:
4773         /* free lock */
4774         g_mutex_clear(&player->fsink_lock);
4775         /* free update tag lock */
4776         g_mutex_clear(&player->update_tag_lock);
4777         g_queue_free(player->bus_msg_q);
4778         player->bus_msg_q = NULL;
4779         /* free gapless play thread */
4780         if (player->gapless_play_thread) {
4781                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4782                 player->gapless_play_thread_exit = TRUE;
4783                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4784                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4785
4786                 g_thread_join(player->gapless_play_thread);
4787                 player->gapless_play_thread = NULL;
4788
4789                 g_mutex_clear(&player->gapless_play_thread_mutex);
4790                 g_cond_clear(&player->gapless_play_thread_cond);
4791         }
4792
4793         /* release attributes */
4794         _mmplayer_deconstruct_attribute(handle);
4795
4796         MMPLAYER_FLEAVE();
4797
4798         return ret;
4799 }
4800
4801 static gboolean
4802 __mmplayer_init_gstreamer(mmplayer_t *player)
4803 {
4804         static gboolean initialized = FALSE;
4805         static const int max_argc = 50;
4806         gint *argc = NULL;
4807         gchar **argv = NULL;
4808         gchar **argv2 = NULL;
4809         GError *err = NULL;
4810         int i = 0;
4811         int arg_count = 0;
4812
4813         if (initialized) {
4814                 LOGD("gstreamer already initialized.");
4815                 return TRUE;
4816         }
4817
4818         /* alloc */
4819         argc = malloc(sizeof(int));
4820         argv = malloc(sizeof(gchar *) * max_argc);
4821         argv2 = malloc(sizeof(gchar *) * max_argc);
4822
4823         if (!argc || !argv || !argv2)
4824                 goto ERROR;
4825
4826         memset(argv, 0, sizeof(gchar *) * max_argc);
4827         memset(argv2, 0, sizeof(gchar *) * max_argc);
4828
4829         /* add initial */
4830         *argc = 1;
4831         argv[0] = g_strdup("mmplayer");
4832
4833         /* add gst_param */
4834         for (i = 0; i < 5; i++) {
4835                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4836                 if (strlen(player->ini.gst_param[i]) > 0) {
4837                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4838                         (*argc)++;
4839                 }
4840         }
4841
4842         /* we would not do fork for scanning plugins */
4843         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4844         (*argc)++;
4845
4846         /* check disable registry scan */
4847         if (player->ini.skip_rescan) {
4848                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4849                 (*argc)++;
4850         }
4851
4852         /* check disable segtrap */
4853         if (player->ini.disable_segtrap) {
4854                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4855                 (*argc)++;
4856         }
4857
4858         LOGD("initializing gstreamer with following parameter");
4859         LOGD("argc : %d", *argc);
4860         arg_count = *argc;
4861
4862         for (i = 0; i < arg_count; i++) {
4863                 argv2[i] = argv[i];
4864                 LOGD("argv[%d] : %s", i, argv2[i]);
4865         }
4866
4867         /* initializing gstreamer */
4868         if (!gst_init_check(argc, &argv, &err)) {
4869                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4870                 if (err)
4871                         g_error_free(err);
4872
4873                 goto ERROR;
4874         }
4875         /* release */
4876         for (i = 0; i < arg_count; i++) {
4877                 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4878                 MMPLAYER_FREEIF(argv2[i]);
4879         }
4880
4881         MMPLAYER_FREEIF(argv);
4882         MMPLAYER_FREEIF(argv2);
4883         MMPLAYER_FREEIF(argc);
4884
4885         /* done */
4886         initialized = TRUE;
4887
4888         return TRUE;
4889
4890 ERROR:
4891
4892         /* release */
4893         for (i = 0; i < arg_count; i++) {
4894                 LOGD("free[%d] : %s", i, argv2[i]);
4895                 MMPLAYER_FREEIF(argv2[i]);
4896         }
4897
4898         MMPLAYER_FREEIF(argv);
4899         MMPLAYER_FREEIF(argv2);
4900         MMPLAYER_FREEIF(argc);
4901
4902         return FALSE;
4903 }
4904
4905 static void
4906 __mmplayer_check_async_state_transition(mmplayer_t *player)
4907 {
4908         GstState element_state = GST_STATE_VOID_PENDING;
4909         GstState element_pending_state = GST_STATE_VOID_PENDING;
4910         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4911         GstElement *element = NULL;
4912         gboolean async = FALSE;
4913
4914         /* check player handle */
4915         MMPLAYER_RETURN_IF_FAIL(player &&
4916                                                 player->pipeline &&
4917                                                 player->pipeline->mainbin &&
4918                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4919
4920         if (player->attrs)
4921                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4922
4923         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4924                 LOGD("don't need to check the pipeline state");
4925                 return;
4926         }
4927
4928         MMPLAYER_PRINT_STATE(player);
4929
4930         /* wait for state transition */
4931         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4932         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4933
4934         if (ret == GST_STATE_CHANGE_FAILURE) {
4935                 LOGE(" [%s] state : %s   pending : %s",
4936                         GST_ELEMENT_NAME(element),
4937                         gst_element_state_get_name(element_state),
4938                         gst_element_state_get_name(element_pending_state));
4939
4940                 /* dump state of all element */
4941                 _mmplayer_dump_pipeline_state(player);
4942
4943                 return;
4944         }
4945
4946         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4947         return;
4948 }
4949
4950 int
4951 _mmplayer_destroy(MMHandleType handle)
4952 {
4953         mmplayer_t *player = MM_PLAYER_CAST(handle);
4954
4955         MMPLAYER_FENTER();
4956
4957         /* check player handle */
4958         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4959
4960         /* destroy can called at anytime */
4961         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4962
4963         /* check async state transition */
4964         __mmplayer_check_async_state_transition(player);
4965
4966         /* release gapless play thread */
4967         if (player->gapless_play_thread) {
4968                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4969                 player->gapless_play_thread_exit = TRUE;
4970                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4971                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4972
4973                 LOGD("waitting for gapless play thread exit");
4974                 g_thread_join(player->gapless_play_thread);
4975                 g_mutex_clear(&player->gapless_play_thread_mutex);
4976                 g_cond_clear(&player->gapless_play_thread_cond);
4977                 LOGD("gapless play thread released");
4978         }
4979
4980         _mmplayer_release_video_capture(player);
4981
4982         /* de-initialize resource manager */
4983         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4984                         player->resource_manager))
4985                 LOGE("failed to deinitialize resource manager");
4986
4987         /* release pipeline */
4988         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4989                 LOGE("failed to destory pipeline");
4990                 return MM_ERROR_PLAYER_INTERNAL;
4991         }
4992
4993         g_queue_free(player->bus_msg_q);
4994
4995         /* release subtitle info lock and cond */
4996         g_mutex_clear(&player->subtitle_info_mutex);
4997         g_cond_clear(&player->subtitle_info_cond);
4998
4999         __mmplayer_release_dump_list(player->dump_list);
5000
5001         /* release miscellaneous information */
5002         __mmplayer_release_misc(player);
5003
5004         /* release miscellaneous information.
5005            these info needs to be released after pipeline is destroyed. */
5006         __mmplayer_release_misc_post(player);
5007
5008         /* release attributes */
5009         _mmplayer_deconstruct_attribute(handle);
5010
5011         /* release lock */
5012         g_mutex_clear(&player->fsink_lock);
5013
5014         /* release lock */
5015         g_mutex_clear(&player->update_tag_lock);
5016
5017         /* release video bo lock and cond */
5018         g_mutex_clear(&player->video_bo_mutex);
5019         g_cond_clear(&player->video_bo_cond);
5020
5021         MMPLAYER_FLEAVE();
5022
5023         return MM_ERROR_NONE;
5024 }
5025
5026 int
5027 _mmplayer_realize(MMHandleType hplayer)
5028 {
5029         mmplayer_t *player = (mmplayer_t *)hplayer;
5030         char *uri = NULL;
5031         void *param = NULL;
5032         MMHandleType attrs = 0;
5033         int ret = MM_ERROR_NONE;
5034
5035         MMPLAYER_FENTER();
5036
5037         /* check player handle */
5038         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5039
5040         /* check current state */
5041         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5042
5043         attrs = MMPLAYER_GET_ATTRS(player);
5044         if (!attrs) {
5045                 LOGE("fail to get attributes.");
5046                 return MM_ERROR_PLAYER_INTERNAL;
5047         }
5048         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5049         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
5050
5051         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5052                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5053
5054                 if (ret != MM_ERROR_NONE) {
5055                         LOGE("failed to parse profile");
5056                         return ret;
5057                 }
5058         }
5059
5060         if (uri && (strstr(uri, "es_buff://"))) {
5061                 if (strstr(uri, "es_buff://push_mode"))
5062                         player->es_player_push_mode = TRUE;
5063                 else
5064                         player->es_player_push_mode = FALSE;
5065         }
5066
5067         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5068                 LOGW("mms protocol is not supported format.");
5069                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5070         }
5071
5072         if (MMPLAYER_IS_STREAMING(player))
5073                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5074         else
5075                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5076
5077         player->smooth_streaming = FALSE;
5078         player->videodec_linked  = 0;
5079         player->audiodec_linked  = 0;
5080         player->textsink_linked = 0;
5081         player->is_external_subtitle_present = FALSE;
5082         player->is_external_subtitle_added_now = FALSE;
5083         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5084         player->video360_metadata.is_spherical = -1;
5085         player->is_openal_plugin_used = FALSE;
5086         player->demux_pad_index = 0;
5087         player->subtitle_language_list = NULL;
5088         player->is_subtitle_force_drop = FALSE;
5089
5090         _mmplayer_track_initialize(player);
5091         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5092
5093         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5094                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5095
5096                 player->streamer = _mm_player_streaming_create();
5097                 _mm_player_streaming_initialize(player->streamer, TRUE);
5098
5099                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5100                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5101
5102                 if (prebuffer_ms > 0) {
5103                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5104                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5105                 }
5106
5107                 if (rebuffer_ms > 0) {
5108                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5109                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5110                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5111                 }
5112
5113                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5114                                                                 player->streamer->buffering_req.rebuffer_time);
5115         }
5116
5117         /* realize pipeline */
5118         ret = __mmplayer_gst_realize(player);
5119         if (ret != MM_ERROR_NONE)
5120                 LOGE("fail to realize the player.");
5121
5122         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5123
5124         MMPLAYER_FLEAVE();
5125
5126         return ret;
5127 }
5128
5129 int
5130 _mmplayer_unrealize(MMHandleType hplayer)
5131 {
5132         mmplayer_t *player = (mmplayer_t *)hplayer;
5133         int ret = MM_ERROR_NONE;
5134
5135         MMPLAYER_FENTER();
5136
5137         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5138
5139         MMPLAYER_CMD_UNLOCK(player);
5140         /* destroy the gst bus msg thread which is created during realize.
5141            this funct have to be called before getting cmd lock. */
5142         _mmplayer_bus_msg_thread_destroy(player);
5143         MMPLAYER_CMD_LOCK(player);
5144
5145         /* check current state */
5146         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5147
5148         /* check async state transition */
5149         __mmplayer_check_async_state_transition(player);
5150
5151         /* unrealize pipeline */
5152         ret = __mmplayer_gst_unrealize(player);
5153
5154         if (!player->interrupted_by_resource) {
5155                 int rm_ret = MM_ERROR_NONE;
5156                 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5157
5158                 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5159                         rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5160                         if (rm_ret != MM_ERROR_NONE)
5161                                 LOGE("failed to release [%d] resources", res_idx);
5162                 }
5163         }
5164
5165         MMPLAYER_FLEAVE();
5166         return ret;
5167 }
5168
5169 int
5170 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5171 {
5172         mmplayer_t *player = (mmplayer_t *)hplayer;
5173
5174         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5175
5176         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5177 }
5178
5179 int
5180 _mmplayer_get_state(MMHandleType hplayer, int *state)
5181 {
5182         mmplayer_t *player = (mmplayer_t *)hplayer;
5183
5184         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5185
5186         *state = MMPLAYER_CURRENT_STATE(player);
5187
5188         return MM_ERROR_NONE;
5189 }
5190
5191 static int
5192 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5193 {
5194         GstElement *vol_element = NULL;
5195         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5196
5197         MMPLAYER_FENTER();
5198         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5199         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5200
5201         /* check pipeline handle */
5202         if (!player->pipeline || !player->pipeline->audiobin) {
5203                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5204
5205                 /* NOTE : stored value will be used in create_audiobin
5206                  * returning MM_ERROR_NONE here makes application to able to
5207                  * set audio volume or mute at anytime.
5208                  */
5209                 return MM_ERROR_NONE;
5210         }
5211
5212         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5213                 volume_elem_id = MMPLAYER_A_SINK;
5214
5215         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5216         if (!vol_element) {
5217                 LOGE("failed to get vol element %d", volume_elem_id);
5218                 return MM_ERROR_PLAYER_INTERNAL;
5219         }
5220
5221         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5222
5223         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5224                 LOGE("there is no '%s' property", prop_name);
5225                 return MM_ERROR_PLAYER_INTERNAL;
5226         }
5227
5228         if (!strcmp(prop_name, "volume")) {
5229                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5230         } else if (!strcmp(prop_name, "mute")) {
5231                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5232         } else {
5233                 LOGE("invalid property %s", prop_name);
5234                 return MM_ERROR_PLAYER_INTERNAL;
5235         }
5236
5237         return MM_ERROR_NONE;
5238 }
5239
5240 int
5241 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5242 {
5243         int ret = MM_ERROR_NONE;
5244         mmplayer_t *player = (mmplayer_t *)hplayer;
5245
5246         MMPLAYER_FENTER();
5247         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5248
5249         LOGD("volume = %f", volume);
5250
5251         /* invalid factor range or not */
5252         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5253                 LOGE("Invalid volume value");
5254                 return MM_ERROR_INVALID_ARGUMENT;
5255         }
5256
5257         player->sound.volume = volume;
5258
5259         ret = __mmplayer_gst_set_volume_property(player, "volume");
5260
5261         MMPLAYER_FLEAVE();
5262         return ret;
5263 }
5264
5265 int
5266 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5267 {
5268         mmplayer_t *player = (mmplayer_t *)hplayer;
5269
5270         MMPLAYER_FENTER();
5271
5272         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5274
5275         *volume = player->sound.volume;
5276
5277         LOGD("current vol = %f", *volume);
5278
5279         MMPLAYER_FLEAVE();
5280         return MM_ERROR_NONE;
5281 }
5282
5283 int
5284 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5285 {
5286         int ret = MM_ERROR_NONE;
5287         mmplayer_t *player = (mmplayer_t *)hplayer;
5288
5289         MMPLAYER_FENTER();
5290         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5291
5292         LOGD("mute = %d", mute);
5293
5294         player->sound.mute = mute;
5295
5296         ret = __mmplayer_gst_set_volume_property(player, "mute");
5297
5298         MMPLAYER_FLEAVE();
5299         return ret;
5300 }
5301
5302 int
5303 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5304 {
5305         mmplayer_t *player = (mmplayer_t *)hplayer;
5306
5307         MMPLAYER_FENTER();
5308
5309         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5310         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5311
5312         *mute = player->sound.mute;
5313
5314         LOGD("current mute = %d", *mute);
5315
5316         MMPLAYER_FLEAVE();
5317
5318         return MM_ERROR_NONE;
5319 }
5320
5321 int
5322 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5323 {
5324         mmplayer_t *player = (mmplayer_t *)hplayer;
5325
5326         MMPLAYER_FENTER();
5327
5328         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5329
5330         player->audio_stream_changed_cb = callback;
5331         player->audio_stream_changed_cb_user_param = user_param;
5332         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5333
5334         MMPLAYER_FLEAVE();
5335
5336         return MM_ERROR_NONE;
5337 }
5338
5339 int
5340 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5341 {
5342         mmplayer_t *player = (mmplayer_t *)hplayer;
5343
5344         MMPLAYER_FENTER();
5345
5346         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5347
5348         player->audio_decoded_cb = callback;
5349         player->audio_decoded_cb_user_param = user_param;
5350         player->audio_extract_opt = opt;
5351         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5352
5353         MMPLAYER_FLEAVE();
5354
5355         return MM_ERROR_NONE;
5356 }
5357
5358 int
5359 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5360 {
5361         mmplayer_t *player = (mmplayer_t *)hplayer;
5362
5363         MMPLAYER_FENTER();
5364
5365         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5366
5367         if (callback && !player->bufmgr)
5368                 player->bufmgr = tbm_bufmgr_init(-1);
5369
5370         player->set_mode.video_export = (callback) ? true : false;
5371         player->video_decoded_cb = callback;
5372         player->video_decoded_cb_user_param = user_param;
5373
5374         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5375
5376         MMPLAYER_FLEAVE();
5377
5378         return MM_ERROR_NONE;
5379 }
5380
5381 int
5382 _mmplayer_start(MMHandleType hplayer)
5383 {
5384         mmplayer_t *player = (mmplayer_t *)hplayer;
5385         gint ret = MM_ERROR_NONE;
5386
5387         MMPLAYER_FENTER();
5388
5389         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5390
5391         /* check current state */
5392         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5393
5394         /* start pipeline */
5395         ret = _mmplayer_gst_start(player);
5396         if (ret != MM_ERROR_NONE)
5397                 LOGE("failed to start player.");
5398
5399         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5400                 LOGD("force playing start even during buffering");
5401                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5402         }
5403
5404         MMPLAYER_FLEAVE();
5405
5406         return ret;
5407 }
5408
5409 /* NOTE: post "not supported codec message" to application
5410  * when one codec is not found during AUTOPLUGGING in MSL.
5411  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5412  * And, if any codec is not found, don't send message here.
5413  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5414  */
5415 int
5416 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5417 {
5418         MMMessageParamType msg_param;
5419         memset(&msg_param, 0, sizeof(MMMessageParamType));
5420         gboolean post_msg_direct = FALSE;
5421
5422         MMPLAYER_FENTER();
5423
5424         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5425
5426         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5427                         player->not_supported_codec, player->can_support_codec);
5428
5429         if (player->not_found_demuxer) {
5430                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5431                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5432
5433                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5434                 MMPLAYER_FREEIF(msg_param.data);
5435
5436                 return MM_ERROR_NONE;
5437         }
5438
5439         if (player->not_supported_codec) {
5440                 if (player->can_support_codec) {
5441                         // There is one codec to play
5442                         post_msg_direct = TRUE;
5443                 } else {
5444                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5445                                 post_msg_direct = TRUE;
5446                 }
5447
5448                 if (post_msg_direct) {
5449                         MMMessageParamType msg_param;
5450                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5451
5452                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5453                                 LOGW("not found AUDIO codec, posting error code to application.");
5454
5455                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5456                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5457                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5458                                 LOGW("not found VIDEO codec, posting error code to application.");
5459
5460                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5461                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5462                         }
5463
5464                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5465
5466                         MMPLAYER_FREEIF(msg_param.data);
5467
5468                         return MM_ERROR_NONE;
5469                 } else {
5470                         // no any supported codec case
5471                         LOGW("not found any codec, posting error code to application.");
5472
5473                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5474                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5475                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5476                         } else {
5477                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5478                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5479                         }
5480
5481                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5482
5483                         MMPLAYER_FREEIF(msg_param.data);
5484                 }
5485         }
5486
5487         MMPLAYER_FLEAVE();
5488
5489         return MM_ERROR_NONE;
5490 }
5491
5492 static void
5493 __mmplayer_check_pipeline(mmplayer_t *player)
5494 {
5495         GstState element_state = GST_STATE_VOID_PENDING;
5496         GstState element_pending_state = GST_STATE_VOID_PENDING;
5497         gint timeout = 0;
5498         int ret = MM_ERROR_NONE;
5499
5500         if (!player->gapless.reconfigure)
5501                 return;
5502
5503         LOGW("pipeline is under construction.");
5504
5505         MMPLAYER_PLAYBACK_LOCK(player);
5506         MMPLAYER_PLAYBACK_UNLOCK(player);
5507
5508         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5509
5510         /* wait for state transition */
5511         ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5512         if (ret == GST_STATE_CHANGE_FAILURE)
5513                 LOGE("failed to change pipeline state within %d sec", timeout);
5514 }
5515
5516 /* NOTE : it should be able to call 'stop' anytime*/
5517 int
5518 _mmplayer_stop(MMHandleType hplayer)
5519 {
5520         mmplayer_t *player = (mmplayer_t *)hplayer;
5521         int ret = MM_ERROR_NONE;
5522
5523         MMPLAYER_FENTER();
5524
5525         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5526
5527         /* check current state */
5528         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5529
5530         /* check pipline building state */
5531         __mmplayer_check_pipeline(player);
5532         __mmplayer_reset_gapless_state(player);
5533
5534         /* NOTE : application should not wait for EOS after calling STOP */
5535         _mmplayer_cancel_eos_timer(player);
5536
5537         /* reset */
5538         player->seek_state = MMPLAYER_SEEK_NONE;
5539
5540         /* stop pipeline */
5541         ret = _mmplayer_gst_stop(player);
5542
5543         if (ret != MM_ERROR_NONE)
5544                 LOGE("failed to stop player.");
5545
5546         MMPLAYER_FLEAVE();
5547
5548         return ret;
5549 }
5550
5551 int
5552 _mmplayer_pause(MMHandleType hplayer)
5553 {
5554         mmplayer_t *player = (mmplayer_t *)hplayer;
5555         gint64 pos_nsec = 0;
5556         gboolean async = FALSE;
5557         gint ret = MM_ERROR_NONE;
5558
5559         MMPLAYER_FENTER();
5560
5561         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5562
5563         /* check current state */
5564         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5565
5566         /* check pipline building state */
5567         __mmplayer_check_pipeline(player);
5568
5569         switch (MMPLAYER_CURRENT_STATE(player)) {
5570         case MM_PLAYER_STATE_READY:
5571                 {
5572                         /* check prepare async or not.
5573                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5574                          */
5575                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5576                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5577
5578                         /* Changing back sync of rtspsrc to async */
5579                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5580                                 LOGD("async prepare working mode for rtsp");
5581                                 async = TRUE;
5582                         }
5583                 }
5584                 break;
5585
5586         case MM_PLAYER_STATE_PLAYING:
5587                 {
5588                         /* NOTE : store current point to overcome some bad operation
5589                         *(returning zero when getting current position in paused state) of some
5590                         * elements
5591                         */
5592                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5593                                 LOGW("getting current position failed in paused");
5594
5595                         player->last_position = pos_nsec;
5596
5597                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5598                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5599                            This causes problem is position calculation during normal pause resume scenarios also.
5600                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5601                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5602                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5603                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5604                         }
5605                 }
5606                 break;
5607         }
5608
5609         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5610                 LOGD("doing async pause in case of ms buff src");
5611                 async = TRUE;
5612         }
5613
5614         /* pause pipeline */
5615         ret = _mmplayer_gst_pause(player, async);
5616
5617         if (ret != MM_ERROR_NONE)
5618                 LOGE("failed to pause player. ret : 0x%x", ret);
5619
5620         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5621                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5622                         LOGE("failed to update display_rotation");
5623         }
5624
5625         MMPLAYER_FLEAVE();
5626
5627         return ret;
5628 }
5629
5630 /* in case of streaming, pause could take long time.*/
5631 int
5632 _mmplayer_abort_pause(MMHandleType hplayer)
5633 {
5634         mmplayer_t *player = (mmplayer_t *)hplayer;
5635         int ret = MM_ERROR_NONE;
5636
5637         MMPLAYER_FENTER();
5638
5639         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5640                                                 player->pipeline &&
5641                                                 player->pipeline->mainbin,
5642                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5643
5644         LOGD("set the pipeline state to READY");
5645
5646         /* set state to READY */
5647         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5648                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5649         if (ret != MM_ERROR_NONE) {
5650                 LOGE("fail to change state to READY");
5651                 return MM_ERROR_PLAYER_INTERNAL;
5652         }
5653
5654         LOGD("succeeded in changing state to READY");
5655         return ret;
5656 }
5657
5658 int
5659 _mmplayer_resume(MMHandleType hplayer)
5660 {
5661         mmplayer_t *player = (mmplayer_t *)hplayer;
5662         int ret = MM_ERROR_NONE;
5663         gboolean async = FALSE;
5664
5665         MMPLAYER_FENTER();
5666
5667         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5668
5669         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5670                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5671                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5672                         return ret;
5673                 }
5674
5675                 /* Changing back sync mode rtspsrc to async */
5676                 LOGD("async resume for rtsp case");
5677                 async = TRUE;
5678         }
5679
5680         /* check current state */
5681         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5682
5683         ret = _mmplayer_gst_resume(player, async);
5684         if (ret != MM_ERROR_NONE)
5685                 LOGE("failed to resume player.");
5686
5687         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5688                 LOGD("force resume even during buffering");
5689                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5690         }
5691
5692         MMPLAYER_FLEAVE();
5693
5694         return ret;
5695 }
5696
5697 int
5698 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5699 {
5700         mmplayer_t *player = (mmplayer_t *)hplayer;
5701         gint64 pos_nsec = 0;
5702         int ret = MM_ERROR_NONE;
5703         bool mute = false;
5704         signed long long start = 0, stop = 0;
5705         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5706         MMPLAYER_FENTER();
5707
5708         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5709         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5710
5711         /* The sound of video is not supported under 0.0 and over 2.0. */
5712         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5713                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5714                         mute = true;
5715         }
5716         _mmplayer_set_mute(hplayer, mute);
5717
5718         if (player->playback_rate == rate)
5719                 return MM_ERROR_NONE;
5720
5721         /* If the position is reached at start potion during fast backward, EOS is posted.
5722          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5723          */
5724         player->playback_rate = rate;
5725
5726         current_state = MMPLAYER_CURRENT_STATE(player);
5727
5728         if (current_state != MM_PLAYER_STATE_PAUSED)
5729                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5730
5731         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5732
5733         if ((current_state == MM_PLAYER_STATE_PAUSED)
5734                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5735                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5736                 pos_nsec = player->last_position;
5737         }
5738
5739         if (rate >= 0) {
5740                 start = pos_nsec;
5741                 stop = GST_CLOCK_TIME_NONE;
5742         } else {
5743                 start = GST_CLOCK_TIME_NONE;
5744                 stop = pos_nsec;
5745         }
5746
5747         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5748                                 player->playback_rate,
5749                                 GST_FORMAT_TIME,
5750                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5751                                 GST_SEEK_TYPE_SET, start,
5752                                 GST_SEEK_TYPE_SET, stop)) {
5753                 LOGE("failed to set speed playback");
5754                 return MM_ERROR_PLAYER_SEEK;
5755         }
5756
5757         LOGD("succeeded to set speed playback as %0.1f", rate);
5758
5759         MMPLAYER_FLEAVE();
5760
5761         return MM_ERROR_NONE;;
5762 }
5763
5764 int
5765 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5766 {
5767         mmplayer_t *player = (mmplayer_t *)hplayer;
5768         int ret = MM_ERROR_NONE;
5769
5770         MMPLAYER_FENTER();
5771
5772         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5773
5774         /* check pipline building state */
5775         __mmplayer_check_pipeline(player);
5776
5777         ret = _mmplayer_gst_set_position(player, position, FALSE);
5778
5779         MMPLAYER_FLEAVE();
5780
5781         return ret;
5782 }
5783
5784 int
5785 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5786 {
5787         mmplayer_t *player = (mmplayer_t *)hplayer;
5788         int ret = MM_ERROR_NONE;
5789
5790         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5791         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5792
5793         if (g_strrstr(player->type, "video/mpegts"))
5794                 __mmplayer_update_duration_value(player);
5795
5796         *duration = player->duration;
5797         return ret;
5798 }
5799
5800 int
5801 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5802 {
5803         mmplayer_t *player = (mmplayer_t *)hplayer;
5804         int ret = MM_ERROR_NONE;
5805
5806         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5807
5808         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5809
5810         return ret;
5811 }
5812
5813 int
5814 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5815 {
5816         mmplayer_t *player = (mmplayer_t *)hplayer;
5817         int ret = MM_ERROR_NONE;
5818
5819         MMPLAYER_FENTER();
5820
5821         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5822
5823         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5824
5825         MMPLAYER_FLEAVE();
5826
5827         return ret;
5828 }
5829
5830 static gboolean
5831 __mmplayer_is_midi_type(gchar *str_caps)
5832 {
5833         if ((g_strrstr(str_caps, "audio/midi")) ||
5834                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5835                 (g_strrstr(str_caps, "application/x-smaf")) ||
5836                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5837                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5838                 (g_strrstr(str_caps, "audio/xmf")) ||
5839                 (g_strrstr(str_caps, "audio/mxmf"))) {
5840                 LOGD("midi");
5841                 return TRUE;
5842         }
5843
5844         return FALSE;
5845 }
5846
5847 static gboolean
5848 __mmplayer_is_only_mp3_type(gchar *str_caps)
5849 {
5850         if (g_strrstr(str_caps, "application/x-id3") ||
5851                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5852                 return TRUE;
5853         return FALSE;
5854 }
5855
5856 static void
5857 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5858 {
5859         GstStructure *caps_structure = NULL;
5860         gint samplerate = 0;
5861         gint channels = 0;
5862
5863         MMPLAYER_FENTER();
5864         MMPLAYER_RETURN_IF_FAIL(player && caps);
5865
5866         caps_structure = gst_caps_get_structure(caps, 0);
5867
5868         /* set stream information */
5869         gst_structure_get_int(caps_structure, "rate", &samplerate);
5870         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5871
5872         gst_structure_get_int(caps_structure, "channels", &channels);
5873         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5874
5875         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5876 }
5877
5878 static void
5879 __mmplayer_update_content_type_info(mmplayer_t *player)
5880 {
5881         MMPLAYER_FENTER();
5882         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5883
5884         if (__mmplayer_is_midi_type(player->type)) {
5885                 player->bypass_audio_effect = TRUE;
5886                 return;
5887         }
5888
5889         if (!player->streamer) {
5890                 LOGD("no need to check streaming type");
5891                 return;
5892         }
5893
5894         if (g_strrstr(player->type, "application/x-hls")) {
5895                 /* If it can't know exact type when it parses uri because of redirection case,
5896                  * it will be fixed by typefinder or when doing autoplugging.
5897                  */
5898                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5899                 player->streamer->is_adaptive_streaming = TRUE;
5900         } else if (g_strrstr(player->type, "application/dash+xml")) {
5901                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5902                 player->streamer->is_adaptive_streaming = TRUE;
5903         }
5904
5905         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5906         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5907                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5908
5909                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5910                         if (player->streamer->is_adaptive_streaming)
5911                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5912                         else
5913                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5914                 }
5915         }
5916
5917         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5918         MMPLAYER_FLEAVE();
5919 }
5920
5921 void
5922 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5923         GstCaps *caps, gpointer data)
5924 {
5925         mmplayer_t *player = (mmplayer_t *)data;
5926         GstPad *pad = NULL;
5927
5928         MMPLAYER_FENTER();
5929
5930         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5931
5932         /* store type string */
5933         MMPLAYER_FREEIF(player->type);
5934         player->type = gst_caps_to_string(caps);
5935         if (player->type)
5936                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5937                                 player, player->type, probability, gst_caps_get_size(caps));
5938
5939         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5940                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5941                 LOGE("not support media format");
5942
5943                 if (player->msg_posted == FALSE) {
5944                         MMMessageParamType msg_param;
5945                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5946
5947                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5948                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5949
5950                         /* don't post more if one was sent already */
5951                         player->msg_posted = TRUE;
5952                 }
5953                 return;
5954         }
5955
5956         __mmplayer_update_content_type_info(player);
5957
5958         pad = gst_element_get_static_pad(tf, "src");
5959         if (!pad) {
5960                 LOGE("fail to get typefind src pad.");
5961                 return;
5962         }
5963
5964         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5965                 gboolean async = FALSE;
5966                 LOGE("failed to autoplug %s", player->type);
5967
5968                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5969
5970                 if (async && player->msg_posted == FALSE)
5971                         __mmplayer_handle_missed_plugin(player);
5972
5973         }
5974
5975         gst_object_unref(GST_OBJECT(pad));
5976
5977         MMPLAYER_FLEAVE();
5978
5979         return;
5980 }
5981
5982 GstElement *
5983 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5984 {
5985         GstElement *decodebin = NULL;
5986
5987         MMPLAYER_FENTER();
5988
5989         /* create decodebin */
5990         decodebin = gst_element_factory_make("decodebin", NULL);
5991
5992         if (!decodebin) {
5993                 LOGE("fail to create decodebin");
5994                 goto ERROR;
5995         }
5996
5997         /* raw pad handling signal */
5998         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5999                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6000
6001         /* no-more-pad pad handling signal */
6002         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6003                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6004
6005         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6006                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6007
6008         /* This signal is emitted when a pad for which there is no further possible
6009            decoding is added to the decodebin.*/
6010         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6011                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6012
6013         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6014            before looking for any elements that can handle that stream.*/
6015         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6016                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6017
6018         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6019            before looking for any elements that can handle that stream.*/
6020         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6021                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6022
6023         /* This signal is emitted once decodebin has finished decoding all the data.*/
6024         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6025                                                 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6026
6027         /* This signal is emitted when a element is added to the bin.*/
6028         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6029                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6030
6031 ERROR:
6032         return decodebin;
6033 }
6034
6035 static GstElement *
6036 __mmplayer_gst_make_queue2(mmplayer_t *player)
6037 {
6038         GstElement *queue2 = NULL;
6039         gint64 dur_bytes = 0L;
6040         mmplayer_gst_element_t *mainbin = NULL;
6041         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6042
6043         MMPLAYER_FENTER();
6044         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6045
6046         mainbin = player->pipeline->mainbin;
6047
6048         queue2 = gst_element_factory_make("queue2", "queue2");
6049         if (!queue2) {
6050                 LOGE("failed to create buffering queue element");
6051                 return NULL;
6052         }
6053
6054         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6055                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6056
6057         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6058
6059         /* NOTE : in case of ts streaming, player could not get the correct duration info *
6060          *                skip the pull mode(file or ring buffering) setting. */
6061         if (dur_bytes > 0) {
6062                 if (!g_strrstr(player->type, "video/mpegts")) {
6063                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6064                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6065                 }
6066         } else {
6067                 dur_bytes = 0;
6068         }
6069
6070         _mm_player_streaming_set_queue2(player->streamer,
6071                                                                         queue2,
6072                                                                         FALSE,
6073                                                                         type,
6074                                                                         (guint64)dur_bytes); /* no meaning at the moment */
6075
6076         return queue2;
6077 }
6078
6079 gboolean
6080 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6081 {
6082         mmplayer_gst_element_t *mainbin = NULL;
6083         GstElement *decodebin = NULL;
6084         GstElement *queue2 = NULL;
6085         GstPad *sinkpad = NULL;
6086         GstPad *qsrcpad = NULL;
6087
6088         MMPLAYER_FENTER();
6089         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6090
6091         mainbin = player->pipeline->mainbin;
6092
6093         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6094
6095                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6096                         LOGW("need to check: muxed buffer is not null");
6097                 }
6098
6099                 queue2 = __mmplayer_gst_make_queue2(player);
6100                 if (!queue2) {
6101                         LOGE("failed to make queue2");
6102                         goto ERROR;
6103                 }
6104
6105                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6106                         LOGE("failed to add buffering queue");
6107                         goto ERROR;
6108                 }
6109
6110                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6111                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6112
6113                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6114                         LOGE("failed to link [%s:%s]-[%s:%s]",
6115                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6116                         goto ERROR;
6117                 }
6118
6119                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6120                         LOGE("failed to sync queue2 state with parent");
6121                         goto ERROR;
6122                 }
6123
6124                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6125                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6126
6127                 srcpad = qsrcpad;
6128
6129                 gst_object_unref(GST_OBJECT(sinkpad));
6130                 sinkpad = NULL;
6131         }
6132
6133         /* create decodebin */
6134         decodebin = _mmplayer_gst_make_decodebin(player);
6135         if (!decodebin) {
6136                 LOGE("failed to make decodebin");
6137                 goto ERROR;
6138         }
6139
6140         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6141                 LOGE("failed to add decodebin");
6142                 goto ERROR;
6143         }
6144
6145         /* to force caps on the decodebin element and avoid reparsing stuff by
6146         * typefind. It also avoids a deadlock in the way typefind activates pads in
6147         * the state change */
6148         g_object_set(decodebin, "sink-caps", caps, NULL);
6149
6150         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6151
6152         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6153                 LOGE("failed to link [%s:%s]-[%s:%s]",
6154                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6155                 goto ERROR;
6156         }
6157
6158         gst_object_unref(GST_OBJECT(sinkpad));
6159         sinkpad = NULL;
6160         gst_object_unref(GST_OBJECT(qsrcpad));
6161         qsrcpad = NULL;
6162
6163         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6164         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6165
6166         /* set decodebin property about buffer in streaming playback. *
6167          * in case of HLS/DASH, it does not need to have big buffer   *
6168          * because it is kind of adaptive streaming.                  */
6169         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6170                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6171                 gint high_percent = 0;
6172
6173                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6174                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6175
6176                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6177
6178                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6179
6180                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6181                                                                                         "high-percent", high_percent,
6182                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6183                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6184                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6185         }
6186
6187         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6188                 LOGE("failed to sync decodebin state with parent");
6189                 goto ERROR;
6190         }
6191
6192         MMPLAYER_FLEAVE();
6193
6194         return TRUE;
6195
6196 ERROR:
6197
6198         if (sinkpad)
6199                 gst_object_unref(GST_OBJECT(sinkpad));
6200
6201         if (qsrcpad)
6202                 gst_object_unref(GST_OBJECT(qsrcpad));
6203
6204         if (queue2) {
6205                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6206                  * You need to explicitly set elements to the NULL state before
6207                  * dropping the final reference, to allow them to clean up.
6208                  */
6209                 gst_element_set_state(queue2, GST_STATE_NULL);
6210
6211                 /* And, it still has a parent "player".
6212                  * You need to let the parent manage the object instead of unreffing the object directly.
6213                  */
6214                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6215                 gst_object_unref(queue2);
6216                 queue2 = NULL;
6217         }
6218
6219         if (decodebin) {
6220                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6221                  * You need to explicitly set elements to the NULL state before
6222                  * dropping the final reference, to allow them to clean up.
6223                  */
6224                 gst_element_set_state(decodebin, GST_STATE_NULL);
6225
6226                 /* And, it still has a parent "player".
6227                  * You need to let the parent manage the object instead of unreffing the object directly.
6228                  */
6229
6230                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6231                 gst_object_unref(decodebin);
6232                 decodebin = NULL;
6233         }
6234
6235         return FALSE;
6236 }
6237
6238 static int
6239 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6240 {
6241         MMPLAYER_FENTER();
6242
6243         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6244         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6245
6246         LOGD("class : %s, mime : %s", factory_class, mime);
6247
6248         /* add missing plugin */
6249         /* NOTE : msl should check missing plugin for image mime type.
6250          * Some motion jpeg clips can have playable audio track.
6251          * So, msl have to play audio after displaying popup written video format not supported.
6252          */
6253         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6254                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6255                         LOGD("not found demuxer");
6256                         player->not_found_demuxer = TRUE;
6257                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6258
6259                         goto DONE;
6260                 }
6261         }
6262
6263         if (!g_strrstr(factory_class, "Demuxer")) {
6264                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6265                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6266                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6267
6268                         /* check that clip have multi tracks or not */
6269                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6270                                 LOGD("video plugin is already linked");
6271                         } else {
6272                                 LOGW("add VIDEO to missing plugin");
6273                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6274                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6275                         }
6276                 } else if (g_str_has_prefix(mime, "audio")) {
6277                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6278                                 LOGD("audio plugin is already linked");
6279                         } else {
6280                                 LOGW("add AUDIO to missing plugin");
6281                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6282                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6283                         }
6284                 }
6285         }
6286
6287 DONE:
6288         MMPLAYER_FLEAVE();
6289
6290         return MM_ERROR_NONE;
6291 }
6292
6293 static void
6294 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
6295 {
6296         mmplayer_t *player = (mmplayer_t *)data;
6297
6298         MMPLAYER_FENTER();
6299
6300         MMPLAYER_RETURN_IF_FAIL(player);
6301
6302         /* remove fakesink. */
6303         if (!_mmplayer_gst_remove_fakesink(player,
6304                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6305                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6306                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6307                  * source element are not same. To overcome this situation, this function will called
6308                  * several places and several times. Therefore, this is not an error case.
6309                  */
6310                 return;
6311         }
6312
6313         LOGD("[handle: %p] pipeline has completely constructed", player);
6314
6315         if ((player->ini.async_start) &&
6316                 (player->msg_posted == FALSE) &&
6317                 (player->cmd >= MMPLAYER_COMMAND_START))
6318                 __mmplayer_handle_missed_plugin(player);
6319
6320         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6321 }
6322
6323 static int
6324 __mmplayer_check_profile(void)
6325 {
6326         char *profileName;
6327         static int profile_tv = -1;
6328
6329         if (__builtin_expect(profile_tv != -1, 1))
6330                 return profile_tv;
6331
6332         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6333         switch (*profileName) {
6334         case 't':
6335         case 'T':
6336                 profile_tv = 1;
6337                 break;
6338         default:
6339                 profile_tv = 0;
6340                 break;
6341         }
6342         free(profileName);
6343
6344         return profile_tv;
6345 }
6346
6347 static gboolean
6348 __mmplayer_get_next_uri(mmplayer_t *player)
6349 {
6350         mmplayer_parse_profile_t profile;
6351         gint uri_idx = 0;
6352         guint num_of_list = 0;
6353         char *uri = NULL;
6354
6355         num_of_list = g_list_length(player->uri_info.uri_list);
6356         uri_idx = player->uri_info.uri_idx;
6357
6358         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6359         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6360                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6361                 if (!uri) {
6362                         LOGW("next uri does not exist");
6363                         continue;
6364                 }
6365
6366                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6367                         LOGE("failed to parse profile");
6368                         continue;
6369                 }
6370
6371                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6372                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6373                         LOGW("uri type is not supported(%d)", profile.uri_type);
6374                         continue;
6375                 }
6376
6377                 LOGD("success to find next uri %d", uri_idx);
6378                 break;
6379         }
6380
6381         if (uri_idx == num_of_list) {
6382                 LOGE("failed to find next uri");
6383                 return FALSE;
6384         }
6385
6386         player->uri_info.uri_idx = uri_idx;
6387         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6388
6389         if (mm_attrs_commit_all(player->attrs)) {
6390                 LOGE("failed to commit");
6391                 return FALSE;
6392         }
6393
6394         SECURE_LOGD("next playback uri: %s", uri);
6395         return TRUE;
6396 }
6397
6398 static gboolean
6399 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6400 {
6401 #define REPEAT_COUNT_INFINITE -1
6402 #define REPEAT_COUNT_MIN 2
6403 #define ORIGINAL_URI_ONLY 1
6404
6405         MMHandleType attrs = 0;
6406         gint video = 0;
6407         gint count = 0;
6408         gint gapless = 0;
6409         guint num_of_uri = 0;
6410         int profile_tv = -1;
6411
6412         MMPLAYER_FENTER();
6413
6414         LOGD("checking for gapless play option");
6415
6416         if (player->pipeline->textbin) {
6417                 LOGE("subtitle path is enabled. gapless play is not supported.");
6418                 goto ERROR;
6419         }
6420
6421         attrs = MMPLAYER_GET_ATTRS(player);
6422         if (!attrs) {
6423                 LOGE("fail to get attributes.");
6424                 goto ERROR;
6425         }
6426
6427         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6428
6429         /* gapless playback is not supported in case of video at TV profile. */
6430         profile_tv = __mmplayer_check_profile();
6431         if (profile_tv && video) {
6432                 LOGW("not support video gapless playback");
6433                 goto ERROR;
6434         }
6435
6436         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6437                 LOGE("failed to get play count");
6438
6439         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6440                 LOGE("failed to get gapless mode");
6441
6442         /* check repeat count in case of audio */
6443         if (!gapless &&
6444                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6445                 LOGW("gapless is disabled");
6446                 goto ERROR;
6447         }
6448
6449         num_of_uri = g_list_length(player->uri_info.uri_list);
6450
6451         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6452
6453         if (num_of_uri == ORIGINAL_URI_ONLY) {
6454                 /* audio looping path */
6455                 if (count >= REPEAT_COUNT_MIN) {
6456                         /* decrease play count */
6457                         /* we succeeded to rewind. update play count and then wait for next EOS */
6458                         count--;
6459                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6460                         /* commit attribute */
6461                         if (mm_attrs_commit_all(attrs))
6462                                 LOGE("failed to commit attribute");
6463
6464                 } else if (count != REPEAT_COUNT_INFINITE) {
6465                         LOGD("there is no next uri and no repeat");
6466                         goto ERROR;
6467                 }
6468                 LOGD("looping cnt %d", count);
6469         } else {
6470                 /* gapless playback path */
6471                 if (!__mmplayer_get_next_uri(player)) {
6472                         LOGE("failed to get next uri");
6473                         goto ERROR;
6474                 }
6475         }
6476         return TRUE;
6477
6478 ERROR:
6479         LOGE("unable to play gapless path. EOS will be posted soon");
6480         return FALSE;
6481 }
6482
6483 static gboolean
6484 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6485 {
6486         mmplayer_selector_t *selector = &player->selector[type];
6487         mmplayer_gst_element_t *sinkbin = NULL;
6488         main_element_id_e selectorId = MMPLAYER_M_NUM;
6489         main_element_id_e sinkId = MMPLAYER_M_NUM;
6490         GstPad *srcpad = NULL;
6491         GstPad *sinkpad = NULL;
6492         gboolean send_notice = FALSE;
6493
6494         MMPLAYER_FENTER();
6495         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6496
6497         LOGD("type %d", type);
6498
6499         switch (type) {
6500         case MM_PLAYER_TRACK_TYPE_AUDIO:
6501                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6502                 sinkId = MMPLAYER_A_BIN;
6503                 sinkbin = player->pipeline->audiobin;
6504                 break;
6505         case MM_PLAYER_TRACK_TYPE_VIDEO:
6506                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6507                 sinkId = MMPLAYER_V_BIN;
6508                 sinkbin = player->pipeline->videobin;
6509                 send_notice = TRUE;
6510                 break;
6511         case MM_PLAYER_TRACK_TYPE_TEXT:
6512                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6513                 sinkId = MMPLAYER_T_BIN;
6514                 sinkbin = player->pipeline->textbin;
6515                 break;
6516         default:
6517                 LOGE("requested type is not supportable");
6518                 return FALSE;
6519                 break;
6520         }
6521
6522         if (player->pipeline->mainbin[selectorId].gst) {
6523                 gint n;
6524
6525                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6526
6527                 if (selector->event_probe_id != 0)
6528                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6529                 selector->event_probe_id = 0;
6530
6531                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6532                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6533
6534                         if (srcpad && sinkpad) {
6535                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6536                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6537                                 gst_pad_unlink(srcpad, sinkpad);
6538
6539                                 /* send custom event to sink pad to handle it at video sink */
6540                                 if (send_notice) {
6541                                         LOGD("send custom event to sinkpad");
6542                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6543                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6544                                         gst_pad_send_event(sinkpad, event);
6545                                 }
6546                         }
6547
6548                         gst_object_unref(sinkpad);
6549                         sinkpad = NULL;
6550                 }
6551                 gst_object_unref(srcpad);
6552                 srcpad = NULL;
6553
6554                 LOGD("selector release");
6555
6556                 /* release and unref requests pad from the selector */
6557                 for (n = 0; n < selector->channels->len; n++) {
6558                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6559                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6560                 }
6561                 g_ptr_array_set_size(selector->channels, 0);
6562
6563                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6564                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6565
6566                 player->pipeline->mainbin[selectorId].gst = NULL;
6567                 selector = NULL;
6568         }
6569
6570         return TRUE;
6571 }
6572
6573 static void
6574 __mmplayer_deactivate_old_path(mmplayer_t *player)
6575 {
6576         MMPLAYER_FENTER();
6577         MMPLAYER_RETURN_IF_FAIL(player);
6578
6579         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6580                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6581                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6582                 LOGE("deactivate selector error");
6583                 goto ERROR;
6584         }
6585
6586         _mmplayer_track_destroy(player);
6587         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6588
6589         if (player->streamer) {
6590                 _mm_player_streaming_initialize(player->streamer, FALSE);
6591                 _mm_player_streaming_destroy(player->streamer);
6592                 player->streamer = NULL;
6593         }
6594
6595         MMPLAYER_PLAYBACK_LOCK(player);
6596         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6597
6598         MMPLAYER_FLEAVE();
6599         return;
6600
6601 ERROR:
6602
6603         if (!player->msg_posted) {
6604                 MMMessageParamType msg = {0,};
6605
6606                 /*post error*/
6607                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6608                 LOGE("gapless_uri_play> deactivate error");
6609
6610                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6611                 player->msg_posted = TRUE;
6612         }
6613         return;
6614 }
6615
6616 int
6617 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6618 {
6619         int result = MM_ERROR_NONE;
6620         mmplayer_t *player = (mmplayer_t *)hplayer;
6621         MMPLAYER_FENTER();
6622
6623         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6624
6625         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6626         if (mm_attrs_commit_all(player->attrs)) {
6627                 LOGE("failed to commit the original uri.");
6628                 result = MM_ERROR_PLAYER_INTERNAL;
6629         } else {
6630                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6631                         LOGE("failed to add the original uri in the uri list.");
6632         }
6633
6634         MMPLAYER_FLEAVE();
6635         return result;
6636 }
6637
6638 int
6639 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6640 {
6641         mmplayer_t *player = (mmplayer_t *)hplayer;
6642         guint num_of_list = 0;
6643
6644         MMPLAYER_FENTER();
6645
6646         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6647         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6648
6649         if (player->pipeline && player->pipeline->textbin) {
6650                 LOGE("subtitle path is enabled.");
6651                 return MM_ERROR_PLAYER_INVALID_STATE;
6652         }
6653
6654         num_of_list = g_list_length(player->uri_info.uri_list);
6655
6656         if (is_first_path) {
6657                 if (num_of_list == 0) {
6658                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6659                         SECURE_LOGD("add original path : %s", uri);
6660                 } else {
6661                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6662                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6663
6664                         SECURE_LOGD("change original path : %s", uri);
6665                 }
6666         } else {
6667                 MMHandleType attrs = 0;
6668                 attrs = MMPLAYER_GET_ATTRS(player);
6669
6670                 if (num_of_list == 0) {
6671                         char *original_uri = NULL;
6672
6673                         if (attrs) {
6674                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6675
6676                                 if (!original_uri) {
6677                                         LOGE("there is no original uri.");
6678                                         return MM_ERROR_PLAYER_INVALID_STATE;
6679                                 }
6680
6681                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6682                                 player->uri_info.uri_idx = 0;
6683
6684                                 SECURE_LOGD("add original path at first : %s", original_uri);
6685                         }
6686                 }
6687
6688                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6689                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6690         }
6691
6692         MMPLAYER_FLEAVE();
6693         return MM_ERROR_NONE;
6694 }
6695
6696 int
6697 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6698 {
6699         mmplayer_t *player = (mmplayer_t *)hplayer;
6700         char *next_uri = NULL;
6701         guint num_of_list = 0;
6702
6703         MMPLAYER_FENTER();
6704         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6705
6706         num_of_list = g_list_length(player->uri_info.uri_list);
6707
6708         if (num_of_list > 0) {
6709                 gint uri_idx = player->uri_info.uri_idx;
6710
6711                 if (uri_idx < num_of_list-1)
6712                         uri_idx++;
6713                 else
6714                         uri_idx = 0;
6715
6716                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6717                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6718
6719                 *uri = g_strdup(next_uri);
6720         }
6721
6722         MMPLAYER_FLEAVE();
6723         return MM_ERROR_NONE;
6724 }
6725
6726 static void
6727 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad,
6728         GstCaps *caps, gpointer data)
6729 {
6730         mmplayer_t *player = (mmplayer_t *)data;
6731         const gchar *klass = NULL;
6732         const gchar *mime = NULL;
6733         gchar *caps_str = NULL;
6734
6735         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6736         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6737         caps_str = gst_caps_to_string(caps);
6738
6739         LOGW("unknown type of caps : %s from %s",
6740                                         caps_str, GST_ELEMENT_NAME(elem));
6741
6742         MMPLAYER_FREEIF(caps_str);
6743
6744         /* There is no available codec. */
6745         __mmplayer_check_not_supported_codec(player, klass, mime);
6746 }
6747
6748 static gboolean
6749 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
6750         GstCaps *caps,  gpointer data)
6751 {
6752         mmplayer_t *player = (mmplayer_t *)data;
6753         const char *mime = NULL;
6754         gboolean ret = TRUE;
6755
6756         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6757         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6758
6759         if (g_str_has_prefix(mime, "audio")) {
6760                 GstStructure *caps_structure = NULL;
6761                 gint samplerate = 0;
6762                 gint channels = 0;
6763                 gchar *caps_str = NULL;
6764
6765                 caps_structure = gst_caps_get_structure(caps, 0);
6766                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6767                 gst_structure_get_int(caps_structure, "channels", &channels);
6768
6769                 if ((channels > 0 && samplerate == 0)) {
6770                         LOGD("exclude audio...");
6771                         ret = FALSE;
6772                 }
6773
6774                 caps_str = gst_caps_to_string(caps);
6775                 /* set it directly because not sent by TAG */
6776                 if (g_strrstr(caps_str, "mobile-xmf"))
6777                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6778                 MMPLAYER_FREEIF(caps_str);
6779         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6780                 MMMessageParamType msg_param;
6781                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6782                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6783                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6784                 LOGD("video file is not supported on this device");
6785                 ret = FALSE;
6786         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6787                 LOGD("already video linked");
6788                 ret = FALSE;
6789         } else {
6790                 LOGD("found new stream");
6791         }
6792
6793         return ret;
6794 }
6795
6796 static gboolean
6797 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6798 {
6799         gboolean ret = TRUE;
6800         GDBusConnection *conn = NULL;
6801         GError *err = NULL;
6802         GVariant *result = NULL;
6803         const gchar *dbus_device_type = NULL;
6804         const gchar *dbus_ret = NULL;
6805         gint idx = 0;
6806
6807         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6808         if (!conn || err) {
6809                 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6810                 g_error_free(err);
6811                 ret = FALSE;
6812                 goto DONE;
6813         }
6814
6815         result = g_dbus_connection_call_sync(conn,
6816                                         "org.pulseaudio.Server",
6817                                         "/org/pulseaudio/StreamManager",
6818                                         "org.pulseaudio.StreamManager",
6819                                         "GetCurrentMediaRoutingPath",
6820                                         g_variant_new("(s)", "out"),
6821                                         G_VARIANT_TYPE("(ss)"),
6822                                         G_DBUS_CALL_FLAGS_NONE,
6823                                         2000,
6824                                         NULL,
6825                                         &err);
6826         if (!result || err) {
6827                 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6828                 g_error_free(err);
6829                 ret = FALSE;
6830                 goto DONE;
6831         }
6832
6833         /* device type is listed in stream-map.json at mmfw-sysconf */
6834         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6835
6836         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6837         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6838                 ret = FALSE;
6839                 goto DONE;
6840         }
6841
6842         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6843         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6844                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6845                         LOGD("audio offload is supportable");
6846                         ret = TRUE;
6847                         goto DONE;
6848                 }
6849         }
6850
6851         LOGD("audio offload is not supportable");
6852         ret = FALSE;
6853
6854 DONE:
6855         g_variant_unref(result);
6856         g_object_unref(conn);
6857
6858         return ret;
6859 }
6860
6861 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6862 {
6863         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6864         gint64 position = 0;
6865
6866         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6867                 player->pipeline && player->pipeline->mainbin);
6868
6869         MMPLAYER_CMD_LOCK(player);
6870         current_state = MMPLAYER_CURRENT_STATE(player);
6871
6872         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6873                 LOGW("getting current position failed in paused");
6874
6875         _mmplayer_unrealize((MMHandleType)player);
6876         _mmplayer_realize((MMHandleType)player);
6877
6878         _mmplayer_set_position((MMHandleType)player, position);
6879
6880         /* async not to be blocked in streaming case */
6881         mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6882         if (mm_attrs_commit_all(player->attrs))
6883                 LOGE("failed to commit");
6884
6885         _mmplayer_pause((MMHandleType)player);
6886
6887         if (current_state == MM_PLAYER_STATE_PLAYING)
6888                 _mmplayer_start((MMHandleType)player);
6889         MMPLAYER_CMD_UNLOCK(player);
6890
6891         LOGD("rebuilding audio pipeline is completed.");
6892 }
6893
6894 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6895 {
6896         mmplayer_t *player = (mmplayer_t *)user_data;
6897         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6898         gboolean is_supportable = FALSE;
6899
6900         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6901                 LOGW("failed to get device type");
6902         else
6903                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6904
6905         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6906                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6907                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6908                 LOGD("ignore this dev connected info");
6909                 return;
6910         }
6911
6912         is_supportable = __mmplayer_is_audio_offload_device_type(player);
6913         if (player->build_audio_offload == is_supportable) {
6914                 LOGD("keep current pipeline without re-building");
6915                 return;
6916         }
6917
6918         /* rebuild pipeline */
6919         LOGD("re-build pipeline - offload: %d", is_supportable);
6920         player->build_audio_offload = FALSE;
6921         __mmplayer_rebuild_audio_pipeline(player);
6922
6923         return;
6924 }
6925
6926 static gboolean
6927 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6928 {
6929         unsigned int id = 0;
6930
6931         if (player->audio_device_cb_id != 0) {
6932                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6933                 return TRUE;
6934         }
6935
6936         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6937                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6938                 LOGD("added device connected cb (%u)", id);
6939                 player->audio_device_cb_id = id;
6940         } else {
6941                 LOGW("failed to add device connected cb");
6942                 return FALSE;
6943         }
6944
6945         return TRUE;
6946 }
6947
6948 static gboolean
6949 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6950 {
6951         gboolean ret = FALSE;
6952         GstElementFactory *factory = NULL;
6953
6954         MMPLAYER_FENTER();
6955         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6956
6957         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6958         if (!__mmplayer_is_only_mp3_type(player->type))
6959                 goto DONE;
6960
6961         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6962                 LOGD("there is no audio offload sink");
6963                 goto DONE;
6964         }
6965
6966         if (player->ini.audio_offload_device_type[0][0] == '\0') {
6967                 LOGW("there is no audio device type to support offload");
6968                 goto DONE;
6969         }
6970
6971         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6972         if (!factory) {
6973                 LOGW("there is no installed audio offload sink element");
6974                 goto DONE;
6975         }
6976         gst_object_unref(factory);
6977
6978         if (__mmplayer_acquire_hw_resource(player,
6979                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6980                 LOGE("failed to acquire audio offload decoder resource");
6981                 goto DONE;
6982         }
6983
6984         if (!__mmplayer_add_audio_device_connected_cb(player))
6985                 goto DONE;
6986
6987         if (!__mmplayer_is_audio_offload_device_type(player))
6988                 goto DONE;
6989
6990         LOGD("audio offload can be built");
6991         ret = TRUE;
6992
6993 DONE:
6994         if (!ret)
6995                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6996
6997         MMPLAYER_FLEAVE();
6998         return ret;
6999 }
7000
7001 static GstAutoplugSelectResult
7002 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7003 {
7004         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7005         int idx = 0;
7006         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7007         int audio_offload = 0;
7008
7009         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7010                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7011
7012                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7013                         LOGD("expose audio path to build offload output path");
7014                         player->build_audio_offload = TRUE;
7015                         /* update codec info */
7016                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7017                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7018                         player->audiodec_linked = 1;
7019
7020                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7021                         goto DONE;
7022                 }
7023
7024                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7025
7026                 LOGD("audio codec type: %d", codec_type);
7027                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7028                         /* sw codec will be skipped */
7029                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7030                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7031                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7032                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7033                                         goto DONE;
7034                                 }
7035                         }
7036                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7037                         /* hw codec will be skipped */
7038                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
7039                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7040                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7041                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7042                                 goto DONE;
7043                         }
7044                 }
7045
7046                 /* set stream information */
7047                 if (!player->audiodec_linked)
7048                         __mmplayer_set_audio_attrs(player, caps);
7049
7050                 /* update codec info */
7051                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7052                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7053                 player->audiodec_linked = 1;
7054
7055         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7056
7057                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7058
7059                 LOGD("video codec type: %d", codec_type);
7060                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7061                         /* sw codec is skipped */
7062                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7063                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7064                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7065                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7066                                         goto DONE;
7067                                 }
7068                         }
7069                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7070                         /* hw codec is skipped */
7071                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7072                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7073                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7074                                 goto DONE;
7075                         }
7076                 }
7077
7078                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7079                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7080
7081                         /* mark video decoder for acquire */
7082                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7083                                 LOGW("video decoder resource is already acquired, skip it.");
7084                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7085                                 goto DONE;
7086                         }
7087
7088                         if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7089                                 LOGE("failed to acquire video decoder resource");
7090                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7091                                 goto DONE;
7092                         }
7093                         player->interrupted_by_resource = FALSE;
7094                 }
7095
7096                 /* update codec info */
7097                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7098                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7099                 player->videodec_linked = 1;
7100         }
7101
7102 DONE:
7103         return ret;
7104 }
7105
7106 gint
7107 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7108         GstCaps *caps, GstElementFactory *factory, gpointer data)
7109 {
7110         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7111         mmplayer_t *player = (mmplayer_t *)data;
7112
7113         gchar *factory_name = NULL;
7114         gchar *caps_str = NULL;
7115         const gchar *klass = NULL;
7116         gint idx = 0;
7117
7118         factory_name = GST_OBJECT_NAME(factory);
7119         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7120         caps_str = gst_caps_to_string(caps);
7121
7122         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7123
7124         /* store type string */
7125         if (player->type == NULL) {
7126                 player->type = gst_caps_to_string(caps);
7127                 __mmplayer_update_content_type_info(player);
7128         }
7129
7130         /* filtering exclude keyword */
7131         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7132                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7133                         LOGW("skipping [%s] by exculde keyword [%s]",
7134                                         factory_name, player->ini.exclude_element_keyword[idx]);
7135
7136                         result = GST_AUTOPLUG_SELECT_SKIP;
7137                         goto DONE;
7138                 }
7139         }
7140
7141         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7142                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7143                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7144                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7145                         result = GST_AUTOPLUG_SELECT_SKIP;
7146                         goto DONE;
7147                 }
7148         }
7149
7150         /* exclude webm format */
7151         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7152          * because webm format is not supportable.
7153          * If webm is disabled in "autoplug-continue", there is no state change
7154          * failure or error because the decodebin will expose the pad directly.
7155          * It make MSL invoke _prepare_async_callback.
7156          * So, we need to disable webm format in "autoplug-select" */
7157         if (caps_str && strstr(caps_str, "webm")) {
7158                 LOGW("webm is not supported");
7159                 result = GST_AUTOPLUG_SELECT_SKIP;
7160                 goto DONE;
7161         }
7162
7163         /* check factory class for filtering */
7164         /* NOTE : msl don't need to use image plugins.
7165          * So, those plugins should be skipped for error handling.
7166          */
7167         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7168                 LOGD("skipping [%s] by not required", factory_name);
7169                 result = GST_AUTOPLUG_SELECT_SKIP;
7170                 goto DONE;
7171         }
7172
7173         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7174                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7175                 // TO CHECK : subtitle if needed, add subparse exception.
7176                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7177                 result = GST_AUTOPLUG_SELECT_SKIP;
7178                 goto DONE;
7179         }
7180
7181         if (g_strrstr(factory_name, "mpegpsdemux")) {
7182                 LOGD("skipping PS container - not support");
7183                 result = GST_AUTOPLUG_SELECT_SKIP;
7184                 goto DONE;
7185         }
7186
7187         if (g_strrstr(factory_name, "mssdemux"))
7188                 player->smooth_streaming = TRUE;
7189
7190         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7191                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7192                 gint stype = 0;
7193                 gint width = 0;
7194                 GstStructure *str = NULL;
7195                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7196
7197                 /* don't make video because of not required */
7198                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7199                         (!player->set_mode.video_export)) {
7200                         LOGD("no need video decoding, expose pad");
7201                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7202                         goto DONE;
7203                 }
7204
7205                 /* get w/h for omx state-tune */
7206                 /* FIXME: deprecated? */
7207                 str = gst_caps_get_structure(caps, 0);
7208                 gst_structure_get_int(str, "width", &width);
7209
7210                 if (width != 0) {
7211                         if (player->v_stream_caps) {
7212                                 gst_caps_unref(player->v_stream_caps);
7213                                 player->v_stream_caps = NULL;
7214                         }
7215
7216                         player->v_stream_caps = gst_caps_copy(caps);
7217                         LOGD("take caps for video state tune");
7218                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7219                 }
7220         }
7221
7222         if (g_strrstr(klass, "Codec/Decoder")) {
7223                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7224                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7225                         LOGW("skip add decoder");
7226                         goto DONE;
7227                 }
7228         }
7229
7230 DONE:
7231         MMPLAYER_FREEIF(caps_str);
7232
7233         return result;
7234 }
7235
7236 static void
7237 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad,
7238         gpointer data)
7239 {
7240         //mmplayer_t *player = (mmplayer_t *)data;
7241         GstCaps *caps = NULL;
7242
7243         LOGD("[Decodebin2] pad-removed signal");
7244
7245         caps = gst_pad_query_caps(new_pad, NULL);
7246         if (!caps) {
7247                 LOGW("query caps is NULL");
7248                 return;
7249         }
7250
7251         gchar *caps_str = NULL;
7252         caps_str = gst_caps_to_string(caps);
7253
7254         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7255
7256         MMPLAYER_FREEIF(caps_str);
7257         gst_caps_unref(caps);
7258 }
7259
7260 static void
7261 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7262 {
7263         mmplayer_t *player = (mmplayer_t *)data;
7264         GstIterator *iter = NULL;
7265         GValue item = { 0, };
7266         GstPad *pad = NULL;
7267         gboolean done = FALSE;
7268         gboolean is_all_drained = TRUE;
7269
7270         MMPLAYER_FENTER();
7271         MMPLAYER_RETURN_IF_FAIL(player);
7272
7273         LOGD("__mmplayer_gst_decode_drained");
7274
7275         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7276                 LOGW("Fail to get cmd lock");
7277                 return;
7278         }
7279
7280         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7281                 !__mmplayer_verify_gapless_play_path(player)) {
7282                 LOGD("decoding is finished.");
7283                 __mmplayer_reset_gapless_state(player);
7284                 MMPLAYER_CMD_UNLOCK(player);
7285                 return;
7286         }
7287
7288         player->gapless.reconfigure = TRUE;
7289
7290         /* check decodebin src pads whether they received EOS or not */
7291         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7292
7293         while (!done) {
7294                 switch (gst_iterator_next(iter, &item)) {
7295                 case GST_ITERATOR_OK:
7296                         pad = g_value_get_object(&item);
7297                         if (pad && !GST_PAD_IS_EOS(pad)) {
7298                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7299                                 is_all_drained = FALSE;
7300                                 break;
7301                         }
7302                         g_value_reset(&item);
7303                         break;
7304                 case GST_ITERATOR_RESYNC:
7305                         gst_iterator_resync(iter);
7306                         break;
7307                 case GST_ITERATOR_ERROR:
7308                 case GST_ITERATOR_DONE:
7309                         done = TRUE;
7310                         break;
7311                 }
7312         }
7313         g_value_unset(&item);
7314         gst_iterator_free(iter);
7315
7316         if (!is_all_drained) {
7317                 LOGD("Wait util the all pads get EOS.");
7318                 MMPLAYER_CMD_UNLOCK(player);
7319                 MMPLAYER_FLEAVE();
7320                 return;
7321         }
7322
7323         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7324         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7325
7326         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7327         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7328         __mmplayer_deactivate_old_path(player);
7329         MMPLAYER_CMD_UNLOCK(player);
7330
7331         MMPLAYER_FLEAVE();
7332 }
7333
7334 void
7335 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7336 {
7337         mmplayer_t *player = (mmplayer_t *)data;
7338         const gchar *klass = NULL;
7339         gchar *factory_name = NULL;
7340
7341         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7342         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7343
7344         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7345
7346         if (__mmplayer_add_dump_buffer_probe(player, element))
7347                 LOGD("add buffer probe");
7348
7349         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7350                 gchar *selected = NULL;
7351                 selected = g_strdup(GST_ELEMENT_NAME(element));
7352                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7353         }
7354
7355         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7356                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7357                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7358
7359                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7360                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7361
7362                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7363                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7364                                                 "max-video-width", player->adaptive_info.limit.width,
7365                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7366
7367         } else if (g_strrstr(klass, "Demuxer")) {
7368                 //LOGD("plugged element is demuxer. take it");
7369                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7370                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7371         }
7372
7373         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7374                 int surface_type = 0;
7375
7376                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7377         }
7378
7379         // to support trust-zone only
7380         if (g_strrstr(factory_name, "asfdemux")) {
7381                 LOGD("set file-location %s", player->profile.uri);
7382                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7383         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7384                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7385                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7386         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7387                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7388                         (__mmplayer_is_only_mp3_type(player->type))) {
7389                         LOGD("[mpegaudioparse] set streaming pull mode.");
7390                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7391                 }
7392         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7393                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7394         }
7395
7396         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7397                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7398                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7399
7400                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7401                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7402
7403                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7404                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7405                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7406                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7407                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7408                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7409                 }
7410
7411         }
7412
7413         return;
7414 }
7415
7416 static void
7417 __mmplayer_release_misc(mmplayer_t *player)
7418 {
7419         int i;
7420         bool cur_mode = player->set_mode.rich_audio;
7421         MMPLAYER_FENTER();
7422
7423         MMPLAYER_RETURN_IF_FAIL(player);
7424
7425         player->video_decoded_cb = NULL;
7426         player->video_decoded_cb_user_param = NULL;
7427         player->video_stream_prerolled = false;
7428
7429         player->audio_decoded_cb = NULL;
7430         player->audio_decoded_cb_user_param = NULL;
7431         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7432
7433         player->audio_stream_changed_cb = NULL;
7434         player->audio_stream_changed_cb_user_param = NULL;
7435
7436         player->sent_bos = FALSE;
7437         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7438
7439         player->seek_state = MMPLAYER_SEEK_NONE;
7440
7441         player->total_bitrate = 0;
7442         player->total_maximum_bitrate = 0;
7443
7444         player->not_found_demuxer = 0;
7445
7446         player->last_position = 0;
7447         player->duration = 0;
7448         player->http_content_size = 0;
7449         player->not_supported_codec = MISSING_PLUGIN_NONE;
7450         player->can_support_codec = FOUND_PLUGIN_NONE;
7451         player->pending_seek.is_pending = false;
7452         player->pending_seek.pos = 0;
7453         player->msg_posted = FALSE;
7454         player->has_many_types = FALSE;
7455         player->is_subtitle_force_drop = FALSE;
7456         player->play_subtitle = FALSE;
7457         player->adjust_subtitle_pos = 0;
7458         player->has_closed_caption = FALSE;
7459         player->set_mode.video_export = false;
7460         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7461         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7462         /* recover mode */
7463         player->set_mode.rich_audio = cur_mode;
7464
7465         if (player->audio_device_cb_id > 0 &&
7466                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7467                 LOGW("failed to remove audio device_connected_callback");
7468         player->audio_device_cb_id = 0;
7469
7470         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7471                 player->bitrate[i] = 0;
7472                 player->maximum_bitrate[i] = 0;
7473         }
7474
7475         /* free memory related to audio effect */
7476         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7477
7478         if (player->adaptive_info.var_list) {
7479                 g_list_free_full(player->adaptive_info.var_list, g_free);
7480                 player->adaptive_info.var_list = NULL;
7481         }
7482
7483         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7484         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7485         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7486
7487         /* Reset video360 settings to their defaults in case if the pipeline is to be
7488          * re-created.
7489          * */
7490         player->video360_metadata.is_spherical = -1;
7491         player->is_openal_plugin_used = FALSE;
7492
7493         player->is_content_spherical = FALSE;
7494         player->is_video360_enabled = TRUE;
7495         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7496         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7497         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7498         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7499         player->video360_zoom = 1.0f;
7500         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7501         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7502
7503         player->sound.rg_enable = false;
7504
7505         __mmplayer_initialize_video_roi(player);
7506         MMPLAYER_FLEAVE();
7507 }
7508
7509 static void
7510 __mmplayer_release_misc_post(mmplayer_t *player)
7511 {
7512         char *original_uri = NULL;
7513         MMPLAYER_FENTER();
7514
7515         /* player->pipeline is already released before. */
7516
7517         MMPLAYER_RETURN_IF_FAIL(player);
7518
7519         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7520
7521         /* clean found audio decoders */
7522         if (player->audio_decoders) {
7523                 GList *a_dec = player->audio_decoders;
7524                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7525                         gchar *name = a_dec->data;
7526                         MMPLAYER_FREEIF(name);
7527                 }
7528                 g_list_free(player->audio_decoders);
7529                 player->audio_decoders = NULL;
7530         }
7531
7532         /* clean the uri list except original uri */
7533         if (player->uri_info.uri_list) {
7534                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7535
7536                 if (player->attrs) {
7537                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7538                         LOGD("restore original uri = %s", original_uri);
7539
7540                         if (mm_attrs_commit_all(player->attrs))
7541                                 LOGE("failed to commit the original uri.");
7542                 }
7543
7544                 GList *uri_list = player->uri_info.uri_list;
7545                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7546                         gchar *uri = uri_list->data;
7547                         MMPLAYER_FREEIF(uri);
7548                 }
7549                 g_list_free(player->uri_info.uri_list);
7550                 player->uri_info.uri_list = NULL;
7551         }
7552
7553         /* clear the audio stream buffer list */
7554         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7555
7556         /* clear the video stream bo list */
7557         __mmplayer_video_stream_destroy_bo_list(player);
7558         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7559
7560         if (player->profile.input_mem.buf) {
7561                 free(player->profile.input_mem.buf);
7562                 player->profile.input_mem.buf = NULL;
7563         }
7564         player->profile.input_mem.len = 0;
7565         player->profile.input_mem.offset = 0;
7566
7567         player->uri_info.uri_idx = 0;
7568         MMPLAYER_FLEAVE();
7569 }
7570
7571 gboolean
7572 __mmplayer_check_subtitle(mmplayer_t *player)
7573 {
7574         MMHandleType attrs = 0;
7575         char *subtitle_uri = NULL;
7576
7577         MMPLAYER_FENTER();
7578
7579         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7580
7581         /* get subtitle attribute */
7582         attrs = MMPLAYER_GET_ATTRS(player);
7583         if (!attrs)
7584                 return FALSE;
7585
7586         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7587         if (!subtitle_uri || !strlen(subtitle_uri))
7588                 return FALSE;
7589
7590         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7591         player->is_external_subtitle_present = TRUE;
7592
7593         MMPLAYER_FLEAVE();
7594
7595         return TRUE;
7596 }
7597
7598 void
7599 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7600 {
7601         MMPLAYER_RETURN_IF_FAIL(player);
7602
7603         if (player->eos_timer) {
7604                 LOGD("cancel eos timer");
7605                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7606                 player->eos_timer = 0;
7607         }
7608
7609         return;
7610 }
7611
7612 static void
7613 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7614 {
7615         MMPLAYER_FENTER();
7616
7617         MMPLAYER_RETURN_IF_FAIL(player);
7618         MMPLAYER_RETURN_IF_FAIL(sink);
7619
7620         player->sink_elements = g_list_append(player->sink_elements, sink);
7621
7622         MMPLAYER_FLEAVE();
7623 }
7624
7625 static void
7626 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7627 {
7628         MMPLAYER_FENTER();
7629
7630         MMPLAYER_RETURN_IF_FAIL(player);
7631         MMPLAYER_RETURN_IF_FAIL(sink);
7632
7633         player->sink_elements = g_list_remove(player->sink_elements, sink);
7634
7635         MMPLAYER_FLEAVE();
7636 }
7637
7638 void
7639 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7640         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7641 {
7642         mmplayer_signal_item_t *item = NULL;
7643
7644         MMPLAYER_FENTER();
7645         MMPLAYER_RETURN_IF_FAIL(player);
7646
7647         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7648                 LOGE("invalid signal type [%d]", type);
7649                 return;
7650         }
7651
7652         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7653         if (!item) {
7654                 LOGE("cannot connect signal [%s]", signal);
7655                 return;
7656         }
7657
7658         item->obj = object;
7659         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7660         player->signals[type] = g_list_append(player->signals[type], item);
7661
7662         MMPLAYER_FLEAVE();
7663         return;
7664 }
7665
7666 /* NOTE : be careful with calling this api. please refer to below glib comment
7667  * glib comment : Note that there is a bug in GObject that makes this function much
7668  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7669  * will no longer be called, but, the signal handler is not currently disconnected.
7670  * If the instance is itself being freed at the same time than this doesn't matter,
7671  * since the signal will automatically be removed, but if instance persists,
7672  * then the signal handler will leak. You should not remove the signal yourself
7673  * because in a future versions of GObject, the handler will automatically be
7674  * disconnected.
7675  *
7676  * It's possible to work around this problem in a way that will continue to work
7677  * with future versions of GObject by checking that the signal handler is still
7678  * connected before disconnected it:
7679  *
7680  *  if (g_signal_handler_is_connected(instance, id))
7681  *    g_signal_handler_disconnect(instance, id);
7682  */
7683 static void
7684 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7685 {
7686         GList *sig_list = NULL;
7687         mmplayer_signal_item_t *item = NULL;
7688
7689         MMPLAYER_FENTER();
7690
7691         MMPLAYER_RETURN_IF_FAIL(player);
7692
7693         LOGD("release signals type : %d", type);
7694
7695         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7696                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7697                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7698                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7699                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7700                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7701                 return;
7702         }
7703
7704         sig_list = player->signals[type];
7705
7706         for (; sig_list; sig_list = sig_list->next) {
7707                 item = sig_list->data;
7708
7709                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7710                         if (g_signal_handler_is_connected(item->obj, item->sig))
7711                                 g_signal_handler_disconnect(item->obj, item->sig);
7712                 }
7713
7714                 MMPLAYER_FREEIF(item);
7715         }
7716
7717         g_list_free(player->signals[type]);
7718         player->signals[type] = NULL;
7719
7720         MMPLAYER_FLEAVE();
7721
7722         return;
7723 }
7724
7725 int
7726 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7727 {
7728         mmplayer_t *player = 0;
7729         int prev_display_surface_type = 0;
7730         void *prev_display_overlay = NULL;
7731
7732         MMPLAYER_FENTER();
7733
7734         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7735         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7736
7737         player = MM_PLAYER_CAST(handle);
7738
7739         /* check video sinkbin is created */
7740         if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7741                 LOGE("Videosink is already created");
7742                 return MM_ERROR_NONE;
7743         }
7744
7745         LOGD("videosink element is not yet ready");
7746
7747         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7748                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7749                 MMPLAYER_FLEAVE();
7750                 return MM_ERROR_INVALID_ARGUMENT;
7751         }
7752
7753         /* load previous attributes */
7754         if (player->attrs) {
7755                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7756                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7757                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7758                 if (prev_display_surface_type == surface_type) {
7759                         LOGD("incoming display surface type is same as previous one, do nothing..");
7760                         MMPLAYER_FLEAVE();
7761                         return MM_ERROR_NONE;
7762                 }
7763         } else {
7764                 LOGE("failed to load attributes");
7765                 MMPLAYER_FLEAVE();
7766                 return MM_ERROR_PLAYER_INTERNAL;
7767         }
7768
7769         /* videobin is not created yet, so we just set attributes related to display surface */
7770         LOGD("store display attribute for given surface type(%d)", surface_type);
7771         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7772         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7773         if (mm_attrs_commit_all(player->attrs)) {
7774                 LOGE("failed to commit attribute");
7775                 MMPLAYER_FLEAVE();
7776                 return MM_ERROR_PLAYER_INTERNAL;
7777         }
7778
7779         MMPLAYER_FLEAVE();
7780         return MM_ERROR_NONE;
7781 }
7782
7783 /* Note : if silent is true, then subtitle would not be displayed. :*/
7784 int
7785 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7786 {
7787         mmplayer_t *player = (mmplayer_t *)hplayer;
7788
7789         MMPLAYER_FENTER();
7790
7791         /* check player handle */
7792         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7793
7794         player->set_mode.subtitle_off = silent;
7795
7796         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7797
7798         MMPLAYER_FLEAVE();
7799
7800         return MM_ERROR_NONE;
7801 }
7802
7803 int
7804 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7805 {
7806         mmplayer_gst_element_t *mainbin = NULL;
7807         mmplayer_gst_element_t *textbin = NULL;
7808         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7809         GstState current_state = GST_STATE_VOID_PENDING;
7810         GstState element_state = GST_STATE_VOID_PENDING;
7811         GstState element_pending_state = GST_STATE_VOID_PENDING;
7812         gint64 time = 0;
7813         GstEvent *event = NULL;
7814         int result = MM_ERROR_NONE;
7815
7816         GstClock *curr_clock = NULL;
7817         GstClockTime base_time, start_time, curr_time;
7818
7819
7820         MMPLAYER_FENTER();
7821
7822         /* check player handle */
7823         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7824                                                                 player->pipeline &&
7825                                                                 player->pipeline->mainbin &&
7826                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7827
7828         mainbin = player->pipeline->mainbin;
7829         textbin = player->pipeline->textbin;
7830
7831         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7832
7833         // sync clock with current pipeline
7834         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7835         curr_time = gst_clock_get_time(curr_clock);
7836
7837         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7838         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7839
7840         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7841                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7842
7843         if (current_state > GST_STATE_READY) {
7844                 // sync state with current pipeline
7845                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7846                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7847                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7848
7849                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7850                 if (GST_STATE_CHANGE_FAILURE == ret) {
7851                         LOGE("fail to state change.");
7852                         result = MM_ERROR_PLAYER_INTERNAL;
7853                         goto ERROR;
7854                 }
7855         }
7856         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7857         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7858
7859         if (curr_clock) {
7860                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7861                 gst_object_unref(curr_clock);
7862         }
7863
7864         // seek to current position
7865         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7866                 result = MM_ERROR_PLAYER_INVALID_STATE;
7867                 LOGE("gst_element_query_position failed, invalid state");
7868                 goto ERROR;
7869         }
7870
7871         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7872         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
7873         if (event) {
7874                 _mmplayer_gst_send_event_to_sink(player, event);
7875         } else {
7876                 result = MM_ERROR_PLAYER_INTERNAL;
7877                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7878                 goto ERROR;
7879         }
7880
7881         /* sync state with current pipeline */
7882         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7883         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7884         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7885
7886         return MM_ERROR_NONE;
7887
7888 ERROR:
7889         /* release text pipeline resource */
7890         player->textsink_linked = 0;
7891
7892         /* release signal */
7893         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7894
7895         /* release textbin with it's childs */
7896         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7897         MMPLAYER_FREEIF(player->pipeline->textbin);
7898         player->pipeline->textbin = NULL;
7899
7900         /* release subtitle elem */
7901         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7902         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7903
7904         return result;
7905 }
7906
7907 static int
7908 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7909 {
7910         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7911         GstState current_state = GST_STATE_VOID_PENDING;
7912
7913         MMHandleType attrs = 0;
7914         mmplayer_gst_element_t *mainbin = NULL;
7915         mmplayer_gst_element_t *textbin = NULL;
7916
7917         gchar *subtitle_uri = NULL;
7918         int result = MM_ERROR_NONE;
7919         const gchar *charset = NULL;
7920
7921         MMPLAYER_FENTER();
7922
7923         /* check player handle */
7924         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7925                                                                 player->pipeline &&
7926                                                                 player->pipeline->mainbin &&
7927                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7928         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7929
7930         mainbin = player->pipeline->mainbin;
7931         textbin = player->pipeline->textbin;
7932
7933         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7934         if (current_state < GST_STATE_READY) {
7935                 result = MM_ERROR_PLAYER_INVALID_STATE;
7936                 LOGE("Pipeline is not in proper state");
7937                 goto EXIT;
7938         }
7939
7940         attrs = MMPLAYER_GET_ATTRS(player);
7941         if (!attrs) {
7942                 LOGE("cannot get content attribute");
7943                 result = MM_ERROR_PLAYER_INTERNAL;
7944                 goto EXIT;
7945         }
7946
7947         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7948         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7949                 LOGE("subtitle uri is not proper filepath");
7950                 result = MM_ERROR_PLAYER_INVALID_URI;
7951                 goto EXIT;
7952         }
7953
7954         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7955                 LOGE("failed to get storage info of subtitle path");
7956                 result = MM_ERROR_PLAYER_INVALID_URI;
7957                 goto EXIT;
7958         }
7959
7960         LOGD("old subtitle file path is [%s]", subtitle_uri);
7961         LOGD("new subtitle file path is [%s]", filepath);
7962
7963         if (!strcmp(filepath, subtitle_uri)) {
7964                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7965                 goto EXIT;
7966         } else {
7967                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7968                 if (mm_attrs_commit_all(player->attrs)) {
7969                         LOGE("failed to commit.");
7970                         goto EXIT;
7971                 }
7972         }
7973
7974         //gst_pad_set_blocked_async(src-srcpad, TRUE)
7975         MMPLAYER_SUBTITLE_INFO_LOCK(player);
7976         player->subtitle_language_list = NULL;
7977         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7978
7979         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7980         if (ret != GST_STATE_CHANGE_SUCCESS) {
7981                 LOGE("failed to change state of textbin to READY");
7982                 result = MM_ERROR_PLAYER_INTERNAL;
7983                 goto EXIT;
7984         }
7985
7986         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7987         if (ret != GST_STATE_CHANGE_SUCCESS) {
7988                 LOGE("failed to change state of subparse to READY");
7989                 result = MM_ERROR_PLAYER_INTERNAL;
7990                 goto EXIT;
7991         }
7992
7993         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7994         if (ret != GST_STATE_CHANGE_SUCCESS) {
7995                 LOGE("failed to change state of filesrc to READY");
7996                 result = MM_ERROR_PLAYER_INTERNAL;
7997                 goto EXIT;
7998         }
7999
8000         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8001
8002         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8003
8004         charset = _mmplayer_get_charset(filepath);
8005         if (charset) {
8006                 LOGD("detected charset is %s", charset);
8007                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8008         }
8009
8010         result = _mmplayer_sync_subtitle_pipeline(player);
8011
8012 EXIT:
8013         MMPLAYER_FLEAVE();
8014         return result;
8015 }
8016
8017 /* API to switch between external subtitles */
8018 int
8019 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8020 {
8021         int result = MM_ERROR_NONE;
8022         mmplayer_t *player = (mmplayer_t *)hplayer;
8023         char *path = NULL;
8024
8025         MMPLAYER_FENTER();
8026
8027         /* check player handle */
8028         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8029
8030         /* filepath can be null in idle state */
8031         if (filepath) {
8032                 /* check file path */
8033                 if ((path = strstr(filepath, "file://")))
8034                         result = _mmplayer_exist_file_path(path + 7);
8035                 else
8036                         result = _mmplayer_exist_file_path(filepath);
8037
8038                 if (result != MM_ERROR_NONE) {
8039                         LOGE("invalid subtitle path 0x%X", result);
8040                         return result; /* file not found or permission denied */
8041                 }
8042         }
8043
8044         if (!player->pipeline) {
8045                 /* IDLE state */
8046                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8047                 if (mm_attrs_commit_all(player->attrs)) {
8048                         LOGE("failed to commit");       /* subtitle path will not be created */
8049                         return MM_ERROR_PLAYER_INTERNAL;
8050                 }
8051         } else {
8052                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8053                 /* check filepath */
8054                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8055
8056                 if (!__mmplayer_check_subtitle(player)) {
8057                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8058                         if (mm_attrs_commit_all(player->attrs)) {
8059                                 LOGE("failed to commit");
8060                                 return MM_ERROR_PLAYER_INTERNAL;
8061                         }
8062
8063                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8064                                 LOGE("fail to create text pipeline");
8065                                 return MM_ERROR_PLAYER_INTERNAL;
8066                         }
8067
8068                         result = _mmplayer_sync_subtitle_pipeline(player);
8069                 } else {
8070                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8071                 }
8072
8073                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8074                 player->is_external_subtitle_added_now = TRUE;
8075
8076                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8077                 if (!player->subtitle_language_list) {
8078                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8079                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8080                                 LOGW("subtitle language list is not updated yet");
8081                 }
8082                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8083         }
8084
8085         MMPLAYER_FLEAVE();
8086         return result;
8087 }
8088
8089 static int
8090 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8091 {
8092         int result = MM_ERROR_NONE;
8093         gchar *change_pad_name = NULL;
8094         GstPad *sinkpad = NULL;
8095         mmplayer_gst_element_t *mainbin = NULL;
8096         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8097         GstCaps *caps = NULL;
8098         gint total_track_num = 0;
8099
8100         MMPLAYER_FENTER();
8101
8102         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8103                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8104
8105         LOGD("Change Track(%d) to %d", type, index);
8106
8107         mainbin = player->pipeline->mainbin;
8108
8109         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8110                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8111         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8112                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8113         } else {
8114                 /* Changing Video Track is not supported. */
8115                 LOGE("Track Type Error");
8116                 goto EXIT;
8117         }
8118
8119         if (mainbin[elem_idx].gst == NULL) {
8120                 result = MM_ERROR_PLAYER_NO_OP;
8121                 LOGD("Req track doesn't exist");
8122                 goto EXIT;
8123         }
8124
8125         total_track_num = player->selector[type].total_track_num;
8126         if (total_track_num <= 0) {
8127                 result = MM_ERROR_PLAYER_NO_OP;
8128                 LOGD("Language list is not available");
8129                 goto EXIT;
8130         }
8131
8132         if ((index < 0) || (index >= total_track_num)) {
8133                 result = MM_ERROR_INVALID_ARGUMENT;
8134                 LOGD("Not a proper index : %d", index);
8135                 goto EXIT;
8136         }
8137
8138         /*To get the new pad from the selector*/
8139         change_pad_name = g_strdup_printf("sink_%u", index);
8140         if (change_pad_name == NULL) {
8141                 result = MM_ERROR_PLAYER_INTERNAL;
8142                 LOGD("Pad does not exists");
8143                 goto EXIT;
8144         }
8145
8146         LOGD("new active pad name: %s", change_pad_name);
8147
8148         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8149         if (sinkpad == NULL) {
8150                 LOGD("sinkpad is NULL");
8151                 result = MM_ERROR_PLAYER_INTERNAL;
8152                 goto EXIT;
8153         }
8154
8155         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8156         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8157
8158         caps = gst_pad_get_current_caps(sinkpad);
8159         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8160
8161         if (sinkpad)
8162                 gst_object_unref(sinkpad);
8163
8164         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8165                 __mmplayer_set_audio_attrs(player, caps);
8166
8167 EXIT:
8168         MMPLAYER_FREEIF(change_pad_name);
8169         return result;
8170 }
8171
8172 int
8173 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8174 {
8175         int result = MM_ERROR_NONE;
8176         mmplayer_t *player = NULL;
8177         mmplayer_gst_element_t *mainbin = NULL;
8178
8179         gint current_active_index = 0;
8180
8181         GstState current_state = GST_STATE_VOID_PENDING;
8182         GstEvent *event = NULL;
8183         gint64 time = 0;
8184
8185         MMPLAYER_FENTER();
8186
8187         player = (mmplayer_t *)hplayer;
8188         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8189
8190         if (!player->pipeline) {
8191                 LOGE("Track %d pre setting -> %d", type, index);
8192
8193                 player->selector[type].active_pad_index = index;
8194                 goto EXIT;
8195         }
8196
8197         mainbin = player->pipeline->mainbin;
8198
8199         current_active_index = player->selector[type].active_pad_index;
8200
8201         /*If index is same as running index no need to change the pad*/
8202         if (current_active_index == index)
8203                 goto EXIT;
8204
8205         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8206                 result = MM_ERROR_PLAYER_INVALID_STATE;
8207                 goto EXIT;
8208         }
8209
8210         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8211         if (current_state < GST_STATE_PAUSED) {
8212                 result = MM_ERROR_PLAYER_INVALID_STATE;
8213                 LOGW("Pipeline not in porper state");
8214                 goto EXIT;
8215         }
8216
8217         result = __mmplayer_change_selector_pad(player, type, index);
8218         if (result != MM_ERROR_NONE) {
8219                 LOGE("change selector pad error");
8220                 goto EXIT;
8221         }
8222
8223         player->selector[type].active_pad_index = index;
8224
8225         if (current_state == GST_STATE_PLAYING) {
8226                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8227                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8228                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8229                 if (event) {
8230                         _mmplayer_gst_send_event_to_sink(player, event);
8231                 } else {
8232                         result = MM_ERROR_PLAYER_INTERNAL;
8233                         goto EXIT;
8234                 }
8235         }
8236
8237 EXIT:
8238         return result;
8239 }
8240
8241 int
8242 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8243 {
8244         mmplayer_t *player = (mmplayer_t *)hplayer;
8245
8246         MMPLAYER_FENTER();
8247
8248         /* check player handle */
8249         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8250
8251         *silent = player->set_mode.subtitle_off;
8252
8253         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8254
8255         MMPLAYER_FLEAVE();
8256
8257         return MM_ERROR_NONE;
8258 }
8259
8260 static gboolean
8261 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8262 {
8263         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8264         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8265
8266         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8267         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8268
8269         int idx = 0;
8270
8271         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8272                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8273                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8274                         mmplayer_dump_t *dump_s;
8275                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8276                         if (dump_s == NULL) {
8277                                 LOGE("malloc fail");
8278                                 return FALSE;
8279                         }
8280
8281                         dump_s->dump_element_file = NULL;
8282                         dump_s->dump_pad = NULL;
8283                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8284
8285                         if (dump_s->dump_pad) {
8286                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8287                                 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN * 2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
8288                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8289                                 dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL);
8290                                 /* add list for removed buffer probe and close FILE */
8291                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8292                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8293                                 return TRUE;
8294                         } else {
8295                                 MMPLAYER_FREEIF(dump_s);
8296                                 LOGE("failed to get %s sink pad added", factory_name);
8297                         }
8298                 }
8299         }
8300         return FALSE;
8301 }
8302
8303 static GstPadProbeReturn
8304 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8305 {
8306         FILE *dump_data = (FILE *)u_data;
8307 //      int written = 0;
8308         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8309         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8310
8311         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8312
8313         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8314
8315 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8316
8317         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8318
8319         gst_buffer_unmap(buffer, &probe_info);
8320
8321         return GST_PAD_PROBE_OK;
8322 }
8323
8324 static void
8325 __mmplayer_release_dump_list(GList *dump_list)
8326 {
8327         GList *d_list = dump_list;
8328
8329         if (!d_list)
8330                 return;
8331
8332         for (; d_list; d_list = g_list_next(d_list)) {
8333                 mmplayer_dump_t *dump_s = d_list->data;
8334                 if (dump_s->dump_pad) {
8335                         if (dump_s->probe_handle_id)
8336                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8337                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8338                 }
8339                 if (dump_s->dump_element_file) {
8340                         fclose(dump_s->dump_element_file);
8341                         dump_s->dump_element_file = NULL;
8342                 }
8343                 MMPLAYER_FREEIF(dump_s);
8344         }
8345         g_list_free(dump_list);
8346         dump_list = NULL;
8347 }
8348
8349 int
8350 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8351 {
8352         mmplayer_t *player = (mmplayer_t *)hplayer;
8353
8354         MMPLAYER_FENTER();
8355
8356         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8357         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8358
8359         *exist = (bool)player->has_closed_caption;
8360
8361         MMPLAYER_FLEAVE();
8362
8363         return MM_ERROR_NONE;
8364 }
8365
8366 void
8367 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8368 {
8369         MMPLAYER_FENTER();
8370         if (buffer) {
8371                 // LOGD("unref internal gst buffer %p", buffer);
8372                 gst_buffer_unref((GstBuffer *)buffer);
8373                 buffer = NULL;
8374         }
8375         MMPLAYER_FLEAVE();
8376 }
8377
8378 int
8379 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8380 {
8381         mmplayer_t *player = (mmplayer_t *)hplayer;
8382
8383         MMPLAYER_FENTER();
8384
8385         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8386         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8387
8388         if (MMPLAYER_IS_STREAMING(player))
8389                 *timeout = (int)player->ini.live_state_change_timeout;
8390         else
8391                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8392
8393         LOGD("timeout = %d", *timeout);
8394
8395         MMPLAYER_FLEAVE();
8396         return MM_ERROR_NONE;
8397 }
8398
8399 static void
8400 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8401 {
8402         int i = 0;
8403         MMPLAYER_FENTER();
8404         MMPLAYER_RETURN_IF_FAIL(player);
8405
8406         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8407
8408                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8409                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8410                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8411                         player->storage_info[i].id = -1;
8412                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8413
8414                         if (path_type != MMPLAYER_PATH_MAX)
8415                                 break;
8416                 }
8417         }
8418
8419         MMPLAYER_FLEAVE();
8420 }
8421
8422 int
8423 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8424 {
8425         int ret = MM_ERROR_NONE;
8426         mmplayer_t *player = (mmplayer_t *)hplayer;
8427         MMMessageParamType msg_param = {0, };
8428
8429         MMPLAYER_FENTER();
8430         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8431
8432         LOGW("state changed storage %d:%d", id, state);
8433
8434         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8435                 return MM_ERROR_NONE;
8436
8437         /* FIXME: text path should be handled seperately. */
8438         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8439                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8440                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8441                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8442                 LOGW("external storage is removed");
8443
8444                 if (player->msg_posted == FALSE) {
8445                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8446                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8447                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8448                         player->msg_posted = TRUE;
8449                 }
8450
8451                 /* unrealize the player */
8452                 ret = _mmplayer_unrealize(hplayer);
8453                 if (ret != MM_ERROR_NONE)
8454                         LOGE("failed to unrealize");
8455         }
8456
8457         MMPLAYER_FLEAVE();
8458         return ret;
8459 }
8460
8461 int
8462 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8463 {
8464         int ret = MM_ERROR_NONE;
8465         mmplayer_t *player = (mmplayer_t *)hplayer;
8466         int idx = 0, total = 0;
8467         gchar *result = NULL, *tmp = NULL;
8468
8469         MMPLAYER_FENTER();
8470         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8471         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8472
8473         total = *num = g_list_length(player->adaptive_info.var_list);
8474         if (total <= 0) {
8475                 LOGW("There is no stream variant info.");
8476                 return ret;
8477         }
8478
8479         result = g_strdup("");
8480         for (idx = 0 ; idx < total ; idx++) {
8481                 stream_variant_t *v_data = NULL;
8482                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8483
8484                 if (v_data) {
8485                         gchar data[64] = {0};
8486                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8487
8488                         tmp = g_strconcat(result, data, NULL);
8489                         g_free(result);
8490                         result = tmp;
8491                 } else {
8492                         LOGW("There is no variant data in %d", idx);
8493                         (*num)--;
8494                 }
8495         }
8496
8497         *var_info = (char *)result;
8498
8499         LOGD("variant info %d:%s", *num, *var_info);
8500         MMPLAYER_FLEAVE();
8501         return ret;
8502 }
8503
8504 int
8505 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8506 {
8507         int ret = MM_ERROR_NONE;
8508         mmplayer_t *player = (mmplayer_t *)hplayer;
8509
8510         MMPLAYER_FENTER();
8511         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8512
8513         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8514
8515         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8516         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8517         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8518
8519         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8520                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8521                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8522                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8523
8524                 /* FIXME: seek to current position for applying new variant limitation */
8525         }
8526
8527         MMPLAYER_FLEAVE();
8528         return ret;
8529
8530 }
8531
8532 int
8533 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8534 {
8535         int ret = MM_ERROR_NONE;
8536         mmplayer_t *player = (mmplayer_t *)hplayer;
8537
8538         MMPLAYER_FENTER();
8539         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8540         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8541
8542         *bandwidth = player->adaptive_info.limit.bandwidth;
8543         *width = player->adaptive_info.limit.width;
8544         *height = player->adaptive_info.limit.height;
8545
8546         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8547
8548         MMPLAYER_FLEAVE();
8549         return ret;
8550 }
8551
8552 int
8553 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8554 {
8555         int ret = MM_ERROR_NONE;
8556         mmplayer_t *player = (mmplayer_t *)hplayer;
8557
8558         MMPLAYER_FENTER();
8559         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8560         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8561         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8562
8563         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8564
8565         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8566                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8567         else /* live case */
8568                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8569
8570         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8571
8572         MMPLAYER_FLEAVE();
8573         return ret;
8574 }
8575
8576 int
8577 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8578 {
8579 #define IDX_FIRST_SW_CODEC 0
8580         mmplayer_t *player = (mmplayer_t *)hplayer;
8581         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8582         MMHandleType attrs = 0;
8583
8584         MMPLAYER_FENTER();
8585         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8586
8587         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8588                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8589                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8590
8591         switch (stream_type) {
8592         case MM_PLAYER_STREAM_TYPE_AUDIO:
8593         /* to support audio codec selection, codec info have to be added in ini file as below.
8594            audio codec element hw = xxxx
8595            audio codec element sw = avdec */
8596                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8597                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8598                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8599                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8600                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8601                         return MM_ERROR_PLAYER_NO_OP;
8602                 }
8603         break;
8604         case MM_PLAYER_STREAM_TYPE_VIDEO:
8605         /* to support video codec selection, codec info have to be added in ini file as below.
8606            video codec element hw = omx
8607            video codec element sw = avdec */
8608                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8609                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8610                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8611                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8612                         LOGE("There is no video codec info for codec_type %d", codec_type);
8613                         return MM_ERROR_PLAYER_NO_OP;
8614                 }
8615         break;
8616         default:
8617                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8618                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8619         break;
8620         }
8621
8622         LOGD("update %s codec_type to %d", attr_name, codec_type);
8623
8624         attrs = MMPLAYER_GET_ATTRS(player);
8625         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8626
8627         if (mm_attrs_commit_all(player->attrs)) {
8628                 LOGE("failed to commit codec_type attributes");
8629                 return MM_ERROR_PLAYER_INTERNAL;
8630         }
8631
8632         MMPLAYER_FLEAVE();
8633         return MM_ERROR_NONE;
8634 }
8635
8636 int
8637 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8638 {
8639         mmplayer_t *player = (mmplayer_t *)hplayer;
8640         GstElement *rg_vol_element = NULL;
8641
8642         MMPLAYER_FENTER();
8643
8644         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8645
8646         player->sound.rg_enable = enabled;
8647
8648         /* just hold rgvolume enable value if pipeline is not ready */
8649         if (!player->pipeline || !player->pipeline->audiobin) {
8650                 LOGD("pipeline is not ready. holding rgvolume enable value");
8651                 return MM_ERROR_NONE;
8652         }
8653
8654         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8655
8656         if (!rg_vol_element) {
8657                 LOGD("rgvolume element is not created");
8658                 return MM_ERROR_PLAYER_INTERNAL;
8659         }
8660
8661         if (enabled)
8662                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8663         else
8664                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8665
8666         MMPLAYER_FLEAVE();
8667
8668         return MM_ERROR_NONE;
8669 }
8670
8671 int
8672 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8673 {
8674         mmplayer_t *player = (mmplayer_t *)hplayer;
8675         GstElement *rg_vol_element = NULL;
8676         gboolean enable = FALSE;
8677
8678         MMPLAYER_FENTER();
8679
8680         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8681         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8682
8683         /* just hold enable_rg value if pipeline is not ready */
8684         if (!player->pipeline || !player->pipeline->audiobin) {
8685                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8686                 *enabled = player->sound.rg_enable;
8687                 return MM_ERROR_NONE;
8688         }
8689
8690         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8691
8692         if (!rg_vol_element) {
8693                 LOGD("rgvolume element is not created");
8694                 return MM_ERROR_PLAYER_INTERNAL;
8695         }
8696
8697         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8698         *enabled = (bool)enable;
8699
8700         MMPLAYER_FLEAVE();
8701
8702         return MM_ERROR_NONE;
8703 }
8704
8705 int
8706 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8707 {
8708         mmplayer_t *player = (mmplayer_t *)hplayer;
8709         MMHandleType attrs = 0;
8710         void *handle = NULL;
8711         int ret = MM_ERROR_NONE;
8712
8713         MMPLAYER_FENTER();
8714
8715         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8716
8717         attrs = MMPLAYER_GET_ATTRS(player);
8718         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8719
8720         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8721         if (!handle) {
8722                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8723                 return MM_ERROR_PLAYER_INTERNAL;
8724         }
8725
8726         player->video_roi.scale_x = scale_x;
8727         player->video_roi.scale_y = scale_y;
8728         player->video_roi.scale_width = scale_width;
8729         player->video_roi.scale_height = scale_height;
8730
8731         /* check video sinkbin is created */
8732         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8733                 return MM_ERROR_NONE;
8734
8735         if (!gst_video_overlay_set_video_roi_area(
8736                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8737                 scale_x, scale_y, scale_width, scale_height))
8738                 ret = MM_ERROR_PLAYER_INTERNAL;
8739         else
8740                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8741                         scale_x, scale_y, scale_width, scale_height);
8742
8743         MMPLAYER_FLEAVE();
8744
8745         return ret;
8746 }
8747
8748 int
8749 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8750 {
8751         mmplayer_t *player = (mmplayer_t *)hplayer;
8752         int ret = MM_ERROR_NONE;
8753
8754         MMPLAYER_FENTER();
8755
8756         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8757         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8758
8759         *scale_x = player->video_roi.scale_x;
8760         *scale_y = player->video_roi.scale_y;
8761         *scale_width = player->video_roi.scale_width;
8762         *scale_height = player->video_roi.scale_height;
8763
8764         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8765                 *scale_x, *scale_y, *scale_width, *scale_height);
8766
8767         return ret;
8768 }
8769
8770 int
8771 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8772 {
8773         mmplayer_t* player = (mmplayer_t*)hplayer;
8774
8775         MMPLAYER_FENTER();
8776
8777         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8778
8779         player->client_pid = pid;
8780
8781         LOGD("client pid[%d] %p", pid, player);
8782
8783         MMPLAYER_FLEAVE();
8784
8785         return MM_ERROR_NONE;
8786 }
8787
8788 static gboolean
8789 __mmplayer_update_duration_value(mmplayer_t *player)
8790 {
8791         gboolean ret = FALSE;
8792         gint64 dur_nsec = 0;
8793         LOGD("try to update duration");
8794
8795         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8796                 player->duration = dur_nsec;
8797                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8798                 ret = TRUE;
8799         }
8800
8801         if (player->duration < 0) {
8802                 LOGW("duration is Non-Initialized !!!");
8803                 player->duration = 0;
8804         }
8805
8806         /* update streaming service type */
8807         player->streaming_type =  _mmplayer_get_stream_service_type(player);
8808
8809         /* check duration is OK */
8810         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8811                 /* FIXIT : find another way to get duration here. */
8812                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8813
8814         return ret;
8815 }
8816
8817 static gboolean
8818 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8819 {
8820         /* update audio params
8821         NOTE : We need original audio params and it can be only obtained from src pad of audio
8822         decoder. Below code only valid when we are not using 'resampler' just before
8823         'audioconverter'. */
8824         GstCaps *caps_a = NULL;
8825         GstPad *pad = NULL;
8826         gint samplerate = 0, channels = 0;
8827         GstStructure *p = NULL;
8828         GstElement *aconv = NULL;
8829
8830         LOGD("try to update audio attrs");
8831
8832         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8833
8834         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8835                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8836         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8837                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8838         } else {
8839                 LOGE("there is no audio converter");
8840                 return FALSE;
8841         }
8842
8843         pad = gst_element_get_static_pad(aconv, "sink");
8844
8845         if (!pad) {
8846                 LOGW("failed to get pad from audio converter");
8847                 return FALSE;
8848         }
8849
8850         caps_a = gst_pad_get_current_caps(pad);
8851         if (!caps_a) {
8852                 LOGW("not ready to get audio caps");
8853                 gst_object_unref(pad);
8854                 return FALSE;
8855         }
8856
8857         p = gst_caps_get_structure(caps_a, 0);
8858
8859         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8860
8861         gst_structure_get_int(p, "rate", &samplerate);
8862         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8863
8864         gst_structure_get_int(p, "channels", &channels);
8865         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8866
8867         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8868
8869         gst_caps_unref(caps_a);
8870         gst_object_unref(pad);
8871
8872         return TRUE;
8873 }
8874
8875 static gboolean
8876 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8877 {
8878         LOGD("try to update video attrs");
8879
8880         GstCaps *caps_v = NULL;
8881         GstPad *pad = NULL;
8882         gint tmpNu, tmpDe;
8883         gint width, height;
8884         GstStructure *p = NULL;
8885
8886         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8887         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8888
8889         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8890         if (!pad) {
8891                 LOGD("no videosink sink pad");
8892                 return FALSE;
8893         }
8894
8895         caps_v = gst_pad_get_current_caps(pad);
8896         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8897         if (!caps_v && player->v_stream_caps) {
8898                 caps_v = player->v_stream_caps;
8899                 gst_caps_ref(caps_v);
8900         }
8901
8902         if (!caps_v) {
8903                 LOGD("no negitiated caps from videosink");
8904                 gst_object_unref(pad);
8905                 return FALSE;
8906         }
8907
8908         p = gst_caps_get_structure(caps_v, 0);
8909         gst_structure_get_int(p, "width", &width);
8910         mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8911
8912         gst_structure_get_int(p, "height", &height);
8913         mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8914
8915         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8916
8917         SECURE_LOGD("width : %d     height : %d", width, height);
8918
8919         gst_caps_unref(caps_v);
8920         gst_object_unref(pad);
8921
8922         if (tmpDe > 0) {
8923                 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8924                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8925         }
8926
8927         return TRUE;
8928 }
8929
8930 static gboolean
8931 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8932 {
8933         gboolean ret = FALSE;
8934         guint64 data_size = 0;
8935         gchar *path = NULL;
8936         struct stat sb;
8937
8938         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8939         if (!player->duration)
8940                 return FALSE;
8941
8942         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8943                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8944                 if (stat(path, &sb) == 0)
8945                         data_size = (guint64)sb.st_size;
8946
8947         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8948                 data_size = player->http_content_size;
8949         }
8950
8951         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8952
8953         if (data_size) {
8954                 guint64 bitrate = 0;
8955                 guint64 msec_dur = 0;
8956
8957                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8958                 if (msec_dur > 0) {
8959                         bitrate = data_size * 8 * 1000 / msec_dur;
8960                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8961                         mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8962
8963                         ret = TRUE;
8964                 } else {
8965                         LOGD("player duration is less than 0");
8966                 }
8967         }
8968
8969         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8970                 if (player->total_bitrate) {
8971                         mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8972                         ret = TRUE;
8973                 }
8974         }
8975
8976         return ret;
8977 }
8978
8979 static void
8980 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8981 {
8982         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8983         data->uri_type = uri_type;
8984 }
8985
8986 static int
8987 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8988 {
8989         int ret = MM_ERROR_PLAYER_INVALID_URI;
8990         int mem_size = 0;
8991         char *buffer = NULL;
8992         char *seperator = strchr(path, ',');
8993         char ext[100] = {0,}, size[100] = {0,};
8994
8995         if (seperator) {
8996                 if ((buffer = strstr(path, "ext="))) {
8997                         buffer += strlen("ext=");
8998
8999                         if (strlen(buffer)) {
9000                                 strncpy(ext, buffer, 99);
9001
9002                                 if ((seperator = strchr(ext, ','))
9003                                         || (seperator = strchr(ext, ' '))
9004                                         || (seperator = strchr(ext, '\0'))) {
9005                                         seperator[0] = '\0';
9006                                 }
9007                         }
9008                 }
9009
9010                 if ((buffer = strstr(path, "size="))) {
9011                         buffer += strlen("size=");
9012
9013                         if (strlen(buffer) > 0) {
9014                                 strncpy(size, buffer, 99);
9015
9016                                 if ((seperator = strchr(size, ','))
9017                                         || (seperator = strchr(size, ' '))
9018                                         || (seperator = strchr(size, '\0'))) {
9019                                         seperator[0] = '\0';
9020                                 }
9021
9022                                 mem_size = atoi(size);
9023                         }
9024                 }
9025         }
9026
9027         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9028
9029         if (mem_size && param) {
9030                 if (data->input_mem.buf)
9031                         free(data->input_mem.buf);
9032                 data->input_mem.buf = malloc(mem_size);
9033
9034                 if (data->input_mem.buf) {
9035                         memcpy(data->input_mem.buf, param, mem_size);
9036                         data->input_mem.len = mem_size;
9037                         ret = MM_ERROR_NONE;
9038                 } else {
9039                         LOGE("failed to alloc mem %d", mem_size);
9040                         ret = MM_ERROR_PLAYER_INTERNAL;
9041                 }
9042
9043                 data->input_mem.offset = 0;
9044                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9045         }
9046
9047         return ret;
9048 }
9049
9050 static int
9051 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9052 {
9053         gchar *location = NULL;
9054         GError *err = NULL;
9055         char *path = NULL;
9056         int ret = MM_ERROR_NONE;
9057
9058         if ((path = strstr(uri, "file://"))) {
9059                 location = g_filename_from_uri(uri, NULL, &err);
9060                 if (!location || (err != NULL)) {
9061                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9062                                 (err != NULL) ? err->message : "unknown error");
9063                         if (err)
9064                                 g_error_free(err);
9065
9066                         MMPLAYER_FREEIF(location);
9067
9068                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9069                         return MM_ERROR_PLAYER_INVALID_URI;
9070                 }
9071                 LOGD("path from uri: %s", location);
9072         }
9073
9074         path = (location != NULL) ? (location) : ((char *)uri);
9075
9076
9077         ret = _mmplayer_exist_file_path(path);
9078
9079         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9080         if (ret == MM_ERROR_NONE) {
9081                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9082                 if (_mmplayer_is_sdp_file(path)) {
9083                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9084                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9085                 } else {
9086                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9087                 }
9088         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9089                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9090         } else {
9091                 LOGE("invalid uri, could not play..");
9092                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9093         }
9094
9095         MMPLAYER_FREEIF(location);
9096
9097         return ret;
9098 }
9099
9100 static mmplayer_video_decoded_data_info_t *
9101 __mmplayer_create_stream_from_pad(GstPad *pad)
9102 {
9103         GstCaps *caps = NULL;
9104         GstStructure *structure = NULL;
9105         unsigned int fourcc = 0;
9106         const gchar *string_format = NULL;
9107         mmplayer_video_decoded_data_info_t *stream = NULL;
9108         gint width, height;
9109         MMPixelFormatType format;
9110         GstVideoInfo info;
9111
9112         caps = gst_pad_get_current_caps(pad);
9113         if (!caps) {
9114                 LOGE("Caps is NULL.");
9115                 return NULL;
9116         }
9117
9118         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9119         structure = gst_caps_get_structure(caps, 0);
9120         gst_structure_get_int(structure, "width", &width);
9121         gst_structure_get_int(structure, "height", &height);
9122         string_format = gst_structure_get_string(structure, "format");
9123
9124         if (string_format)
9125                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9126         format = _mmplayer_get_pixtype(fourcc);
9127         gst_video_info_from_caps(&info, caps);
9128         gst_caps_unref(caps);
9129
9130         /* moved here */
9131         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9132                 LOGE("Wrong condition!!");
9133                 return NULL;
9134         }
9135
9136         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9137         if (!stream) {
9138                 LOGE("failed to alloc mem for video data");
9139                 return NULL;
9140         }
9141
9142         stream->width = width;
9143         stream->height = height;
9144         stream->format = format;
9145         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9146
9147         return stream;
9148 }
9149
9150 static void
9151 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9152 {
9153         unsigned int pitch = 0;
9154         unsigned int size = 0;
9155         int index = 0;
9156         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9157         tbm_bo bo = NULL;
9158
9159         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9160                 bo = gst_tizen_memory_get_bos(mem, index);
9161                 if (bo)
9162                         stream->bo[index] = tbm_bo_ref(bo);
9163                 else
9164                         LOGE("failed to get bo for index %d", index);
9165         }
9166
9167         for (index = 0; index < stream->plane_num; index++) {
9168                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9169                 stream->stride[index] = pitch;
9170                 if (pitch)
9171                         stream->elevation[index] = size / pitch;
9172                 else
9173                         stream->elevation[index] = stream->height;
9174         }
9175 }
9176
9177 static gboolean
9178 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9179 {
9180         if (stream->format == MM_PIXEL_FORMAT_I420) {
9181                 int ret = TBM_SURFACE_ERROR_NONE;
9182                 tbm_surface_h surface;
9183                 tbm_surface_info_s info;
9184
9185                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9186
9187                 ret = tbm_surface_get_info(surface, &info);
9188                 if (ret != TBM_SURFACE_ERROR_NONE) {
9189                         tbm_surface_destroy(surface);
9190                         return FALSE;
9191                 }
9192
9193                 tbm_surface_destroy(surface);
9194                 stream->stride[0] = info.planes[0].stride;
9195                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9196                 stream->stride[1] = info.planes[1].stride;
9197                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9198                 stream->stride[2] = info.planes[2].stride;
9199                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9200                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9201         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9202                 stream->stride[0] = stream->width * 4;
9203                 stream->elevation[0] = stream->height;
9204                 stream->bo_size = stream->stride[0] * stream->height;
9205         } else {
9206                 LOGE("Not support format %d", stream->format);
9207                 return FALSE;
9208         }
9209
9210         return TRUE;
9211 }
9212
9213 static gboolean
9214 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9215 {
9216         tbm_bo_handle thandle;
9217         gboolean is_mapped;
9218         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9219         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9220         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9221         int i = 0;
9222         int j = 0;
9223         int k = 0;
9224         unsigned char *src = NULL;
9225         unsigned char *dest = NULL;
9226         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9227
9228         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9229         if (!is_mapped) {
9230                 LOGE("fail to gst_memory_map");
9231                 return FALSE;
9232         }
9233
9234         if (!mapinfo.data) {
9235                 LOGE("data pointer is wrong");
9236                 goto ERROR;
9237         }
9238
9239         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9240         if (!stream->bo[0]) {
9241                 LOGE("Fail to tbm_bo_alloc!!");
9242                 goto ERROR;
9243         }
9244
9245         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9246         if (!thandle.ptr) {
9247                 LOGE("thandle pointer is wrong");
9248                 goto ERROR;
9249         }
9250
9251         if (stream->format == MM_PIXEL_FORMAT_I420) {
9252                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9253                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9254                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9255                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9256
9257                 dest_offset[0] = 0;
9258                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9259                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9260
9261                 for (i = 0; i < 3; i++) {
9262                         src = mapinfo.data + src_offset[i];
9263                         dest = thandle.ptr + dest_offset[i];
9264
9265                         if (i > 0)
9266                                 k = 1;
9267
9268                         for (j = 0; j < stream->height >> k; j++) {
9269                                 memcpy(dest, src, stream->width>>k);
9270                                 src += src_stride[i];
9271                                 dest += stream->stride[i];
9272                         }
9273                 }
9274         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9275                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9276         } else {
9277                 LOGE("Not support format %d", stream->format);
9278                 goto ERROR;
9279         }
9280
9281         tbm_bo_unmap(stream->bo[0]);
9282         gst_memory_unmap(mem, &mapinfo);
9283
9284         return TRUE;
9285
9286 ERROR:
9287         if (stream->bo[0])
9288                 tbm_bo_unmap(stream->bo[0]);
9289
9290         if (is_mapped)
9291                 gst_memory_unmap(mem, &mapinfo);
9292
9293         return FALSE;
9294 }
9295
9296 static void
9297 __mmplayer_set_pause_state(mmplayer_t *player)
9298 {
9299         if (player->sent_bos)
9300                 return;
9301
9302         /* rtsp case, get content attrs by GstMessage */
9303         if (MMPLAYER_IS_RTSP_STREAMING(player))
9304                 return;
9305
9306         /* it's first time to update all content attrs. */
9307         _mmplayer_update_content_attrs(player, ATTR_ALL);
9308 }
9309
9310 static void
9311 __mmplayer_set_playing_state(mmplayer_t *player)
9312 {
9313         gchar *audio_codec = NULL;
9314
9315         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9316                 /* initialize because auto resume is done well. */
9317                 player->resumed_by_rewind = FALSE;
9318                 player->playback_rate = 1.0;
9319         }
9320
9321         if (player->sent_bos)
9322                 return;
9323
9324         /* try to get content metadata */
9325
9326         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9327          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9328          * legacy mmfw-player api
9329          */
9330         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9331
9332         if ((player->cmd == MMPLAYER_COMMAND_START)
9333                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9334                 __mmplayer_handle_missed_plugin(player);
9335         }
9336
9337         /* check audio codec field is set or not
9338          * we can get it from typefinder or codec's caps.
9339          */
9340         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9341
9342         /* The codec format can't be sent for audio only case like amr, mid etc.
9343          * Because, parser don't make related TAG.
9344          * So, if it's not set yet, fill it with found data.
9345          */
9346         if (!audio_codec) {
9347                 if (g_strrstr(player->type, "audio/midi"))
9348                         audio_codec = "MIDI";
9349                 else if (g_strrstr(player->type, "audio/x-amr"))
9350                         audio_codec = "AMR";
9351                 else if (g_strrstr(player->type, "audio/mpeg")
9352                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9353                         audio_codec = "AAC";
9354                 else
9355                         audio_codec = "unknown";
9356
9357                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9358
9359                 if (mm_attrs_commit_all(player->attrs))
9360                         LOGE("failed to update attributes");
9361
9362                 LOGD("set audio codec type with caps");
9363         }
9364
9365         return;
9366 }