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