[0.6.178] rebuild pipeline for offload
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <sys/time.h>
36 #include <stdlib.h>
37 #include <dlog.h>
38 #include <gio/gio.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_sound.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
52
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
57
58 /*===========================================================================================
59 |                                                                                                                                                                                       |
60 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
61 |                                                                                                                                                                                       |
62 ========================================================================================== */
63
64 /*---------------------------------------------------------------------------
65 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
66 ---------------------------------------------------------------------------*/
67
68 /*---------------------------------------------------------------------------
69 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
70 ---------------------------------------------------------------------------*/
71
72 /*---------------------------------------------------------------------------
73 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
74 ---------------------------------------------------------------------------*/
75
76 /*---------------------------------------------------------------------------
77 |    LOCAL #defines:                                                                                                            |
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
81
82 #define MM_VOLUME_FACTOR_DEFAULT                1.0
83 #define MM_VOLUME_FACTOR_MIN                    0
84 #define MM_VOLUME_FACTOR_MAX                    1.0
85
86 /* Don't need to sleep for sound fadeout
87  * fadeout related fucntion will be deleted(Deprecated)
88  */
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
90
91 #define DEFAULT_PLAYBACK_RATE                   1.0
92 #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(mm_player_t *player);
136 static int              __mmplayer_gst_destroy_pipeline(mm_player_t *player);
137 static int              __mmplayer_gst_create_text_pipeline(mm_player_t *player);
138 static int              __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
139 static int              __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
140 static int              __mmplayer_gst_create_text_sink_bin(mm_player_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(mm_player_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(mm_player_t *player);
156 static void             __mmplayer_release_misc_post(mm_player_t *player);
157 static gboolean __mmplayer_init_gstreamer(mm_player_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(mm_player_t *player, MMPlayerTrackType type, int index);
162
163 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
164 static int              __mmplayer_handle_missed_plugin(mm_player_t *player);
165 static int              __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
166 static void             __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
167 static void             __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
168 static void             __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
169 static gpointer __mmplayer_gapless_play_thread(gpointer data);
170 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_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(mm_player_t *player);
174 static int              __mmplayer_gst_unrealize(mm_player_t *player);
175 static int              __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
176 static int              __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177
178 /* util */
179 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
180 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
181 static void __mmplayer_check_pipeline(mm_player_t *player);
182 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
183 static void __mmplayer_deactivate_old_path(mm_player_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mm_player_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(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
188 static void             __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType 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(mm_player_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
194
195 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
198
199 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
203
204 static void __mmplayer_set_pause_state(mm_player_t *player);
205 static void __mmplayer_set_playing_state(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_t *player, enum PlayerCommandState command)
430 {
431         MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
432         MMPlayerStateType 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         mm_player_t *player = (mm_player_t *)data;
601         MMPlayerGstElement *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         mm_player_t *player = (mm_player_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(mm_player_t *player, MMPlayerGstElement *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(mm_player_t *player, MMPlayerTrackType 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         mm_player_t *player = (mm_player_t *)data;
831         GstCaps *caps = NULL;
832         GstStructure *str = NULL;
833         const gchar *name = NULL;
834         MMPlayerTrackType 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(mm_player_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(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType 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         mm_player_t *player = (mm_player_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         enum MainElementID elem_idx = MMPLAYER_M_NUM;
1083         MMPlayerTrackType 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(mm_player_t *player, GstElement *selector, MMPlayerTrackType 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(mm_player_t *player, MMPlayerTrackType 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(mm_player_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(mm_player_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(mm_player_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         mm_player_t *player = NULL;
1377         GstElement *video_selector = NULL;
1378         GstElement *audio_selector = NULL;
1379         GstElement *text_selector = NULL;
1380
1381         MMPLAYER_FENTER();
1382         player = (mm_player_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(mm_player_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         mm_player_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 = (mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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(mm_player_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         mm_player_t *player = (mm_player_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         mm_player_t *player = (mm_player_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         MMPlayerGstElement *element = NULL;
2105         MMPlayerGstElement *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 = (MMPlayerGstElement *)bucket->data;
2113         bucket = bucket->next;
2114
2115         for (; bucket; bucket = bucket->next) {
2116                 element = (MMPlayerGstElement *)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         MMPlayerGstElement *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 = (MMPlayerGstElement *)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         mm_player_t *player = (mm_player_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(mm_player_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                         mm_player_audio_stream_buff_t *tmp = (mm_player_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(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2282 {
2283         MMPlayerAudioStreamDataType 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         mm_player_t *player = (mm_player_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         mm_player_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                         mm_player_audio_stream_buff_t *tmp = (mm_player_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 = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_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         mm_player_t *player = (mm_player_t *)data;
2413         MMPlayerGstElement *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(mm_player_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                 if (player->sound.focus_id)
2508                         snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2509                                         stream_type, stream_id, player->sound.focus_id);
2510                 else
2511                         snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2512                                         stream_type, stream_id);
2513                 props = gst_structure_from_string(stream_props, NULL);
2514                 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2515                 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2516                         stream_type, stream_id, player->sound.focus_id, stream_props);
2517                 gst_structure_free(props);
2518         }
2519
2520         mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2521
2522         switch (latency_mode) {
2523         case AUDIO_LATENCY_MODE_LOW:
2524                 latency = g_strndup("low", 3);
2525                 break;
2526         case AUDIO_LATENCY_MODE_MID:
2527                 latency = g_strndup("mid", 3);
2528                 break;
2529         case AUDIO_LATENCY_MODE_HIGH:
2530                 latency = g_strndup("high", 4);
2531                 break;
2532         };
2533
2534         g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2535                         "latency", latency,
2536                         NULL);
2537
2538         LOGD("audiosink property - latency=%s", latency);
2539
2540         MMPLAYER_FREEIF(latency);
2541
2542         MMPLAYER_FLEAVE();
2543 }
2544
2545 void
2546 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2547 {
2548         MMPlayerGstElement *audiobin = NULL;
2549
2550         MMPLAYER_FENTER();
2551         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2552
2553         audiobin = player->pipeline->audiobin;
2554
2555         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2556         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2557         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2558
2559         if (player->video360_yaw_radians <= M_PI &&
2560                         player->video360_yaw_radians >= -M_PI &&
2561                         player->video360_pitch_radians <= M_PI_2 &&
2562                         player->video360_pitch_radians >= -M_PI_2) {
2563                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564                                 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2565                                 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2566         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2567                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2568                                 "source-orientation-y", player->video360_metadata.init_view_heading,
2569                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2570         }
2571
2572         MMPLAYER_FLEAVE();
2573 }
2574
2575 static int
2576 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2577 {
2578         MMPlayerGstElement *audiobin = NULL;
2579         MMHandleType attrs = 0;
2580         GList *element_bucket = NULL;
2581         GstCaps *acaps = NULL;
2582         GstPad *sink_pad = NULL;
2583         int pitch_control = 0;
2584         double pitch_value = 1.0;
2585
2586         MMPLAYER_FENTER();
2587         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2588                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2589
2590         audiobin = player->pipeline->audiobin;
2591         attrs = MMPLAYER_GET_ATTRS(player);
2592
2593         if (player->build_audio_offload) { /* skip all the audio filters */
2594                 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2595                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2596                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2597                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2598                 goto DONE;
2599         }
2600
2601         /* pitch */
2602         mm_attrs_multiple_get(player->attrs, NULL,
2603                                 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2604                                 MM_PLAYER_PITCH_VALUE, &pitch_value,
2605                                 NULL);
2606
2607         LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2608         if (pitch_control && (player->videodec_linked == 0)) {
2609                 GstElementFactory *factory;
2610
2611                 factory = gst_element_factory_find("pitch");
2612                 if (factory) {
2613                         gst_object_unref(factory);
2614
2615                         /* converter */
2616                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2617
2618                         /* pitch */
2619                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2620                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2621                 } else {
2622                         LOGW("there is no pitch element");
2623                 }
2624         }
2625
2626         /* converter */
2627         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2628
2629         /* replaygain volume */
2630         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2631         if (player->sound.rg_enable)
2632                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2633         else
2634                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2635
2636         /* resampler */
2637         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", TRUE, player);
2638
2639         if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2640                 gchar *dst_format = NULL;
2641                 int dst_len = 0;
2642                 int dst_samplerate = 0;
2643                 int dst_channels = 0;
2644                 GstCaps *caps = NULL;
2645                 char *caps_str = NULL;
2646
2647                 /* get conf. values */
2648                 mm_attrs_multiple_get(player->attrs, NULL,
2649                                         "pcm_audioformat", &dst_format, &dst_len,
2650                                         "pcm_extraction_samplerate", &dst_samplerate,
2651                                         "pcm_extraction_channels", &dst_channels,
2652                                         NULL);
2653
2654                 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2655
2656                 /* capsfilter */
2657                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2658                 caps = gst_caps_new_simple("audio/x-raw",
2659                                 "format", G_TYPE_STRING, dst_format,
2660                                 "rate", G_TYPE_INT, dst_samplerate,
2661                                 "channels", G_TYPE_INT, dst_channels,
2662                                 NULL);
2663
2664                 caps_str = gst_caps_to_string(caps);
2665                 LOGD("new caps : %s", caps_str);
2666
2667                 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2668
2669                 /* clean */
2670                 gst_caps_unref(caps);
2671                 MMPLAYER_FREEIF(caps_str);
2672
2673                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2674
2675                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2676
2677                 /* raw pad handling signal, audiosink will be added after getting signal */
2678                 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2679                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2680
2681         } else {
2682
2683                 /* normal playback */
2684                 gint channels = 0;
2685
2686                 /* for logical volume control */
2687                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2688                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2689
2690                 if (player->sound.mute) {
2691                         LOGD("mute enabled");
2692                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2693                 }
2694
2695                 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2696
2697                 /* audio effect element. if audio effect is enabled */
2698                 if ((strcmp(player->ini.audioeffect_element, ""))
2699                         && (channels <= 2)
2700                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2701                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2702
2703                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2704
2705                         if ((!player->bypass_audio_effect)
2706                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2707                                 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2708                                         if (!_mmplayer_audio_effect_custom_apply(player))
2709                                                 LOGI("apply audio effect(custom) setting success");
2710                                 }
2711                         }
2712
2713                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
2714                                 && (player->set_mode.rich_audio))
2715                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2716                 }
2717
2718                 /* create audio sink */
2719                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2720                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2721                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2722
2723                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2724                 if (player->is_360_feature_enabled &&
2725                         player->is_content_spherical &&
2726                         channels == 4 &&
2727                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2728                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2729                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2730
2731                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2732
2733                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2734
2735                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2736                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2737                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2738                         gst_caps_unref(acaps);
2739
2740                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2741
2742                         player->is_openal_plugin_used = TRUE;
2743                 } else {
2744                         if (player->is_360_feature_enabled && player->is_content_spherical)
2745                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2746                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2747                 }
2748
2749                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2750                         (player->videodec_linked && player->ini.use_system_clock)) {
2751                         LOGD("system clock will be used.");
2752                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2753                 }
2754
2755                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2756                         __mmplayer_gst_set_pulsesink_property(player, attrs);
2757                 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2758                         __mmplayer_gst_set_openalsink_property(player);
2759
2760                 /* qos on */
2761                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2762                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2763
2764                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2765                 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2766                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2767                 gst_object_unref(GST_OBJECT(sink_pad));
2768
2769                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2770         }
2771
2772 DONE:
2773         *bucket = element_bucket;
2774
2775         MMPLAYER_FLEAVE();
2776         return MM_ERROR_NONE;
2777
2778 ERROR:
2779         g_list_free(element_bucket);
2780
2781         *bucket = NULL;
2782         MMPLAYER_FLEAVE();
2783         return MM_ERROR_PLAYER_INTERNAL;
2784 }
2785
2786 static int
2787 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2788 {
2789         MMPlayerGstElement *first_element = NULL;
2790         MMPlayerGstElement *audiobin = NULL;
2791         GstPad *pad = NULL;
2792         GstPad *ghostpad = NULL;
2793         GList *element_bucket = NULL;
2794         int i = 0;
2795
2796         MMPLAYER_FENTER();
2797         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2798
2799         /* alloc handles */
2800         audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2801         if (!audiobin) {
2802                 LOGE("failed to allocate memory for audiobin");
2803                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2804         }
2805
2806         /* create bin */
2807         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2808         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2809         if (!audiobin[MMPLAYER_A_BIN].gst) {
2810                 LOGE("failed to create audiobin");
2811                 goto ERROR;
2812         }
2813
2814         /* take it */
2815         player->pipeline->audiobin = audiobin;
2816
2817         /* create audio filters and audiosink */
2818         if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2819                 goto ERROR;
2820
2821         /* adding created elements to bin */
2822         LOGD("adding created elements to bin");
2823         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2824                 goto ERROR;
2825
2826         /* linking elements in the bucket by added order. */
2827         LOGD("Linking elements in the bucket by added order.");
2828         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2829                 goto ERROR;
2830
2831         /* get first element's sinkpad for creating ghostpad */
2832         first_element = (MMPlayerGstElement *)element_bucket->data;
2833         if (!first_element) {
2834                 LOGE("failed to get first elem");
2835                 goto ERROR;
2836         }
2837
2838         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2839         if (!pad) {
2840                 LOGE("failed to get pad from first element of audiobin");
2841                 goto ERROR;
2842         }
2843
2844         ghostpad = gst_ghost_pad_new("sink", pad);
2845         if (!ghostpad) {
2846                 LOGE("failed to create ghostpad");
2847                 goto ERROR;
2848         }
2849
2850         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2851                 LOGE("failed to add ghostpad to audiobin");
2852                 goto ERROR;
2853         }
2854
2855         gst_object_unref(pad);
2856
2857         g_list_free(element_bucket);
2858         MMPLAYER_FLEAVE();
2859
2860         return MM_ERROR_NONE;
2861
2862 ERROR:
2863         LOGD("ERROR : releasing audiobin");
2864
2865         if (pad)
2866                 gst_object_unref(GST_OBJECT(pad));
2867
2868         if (ghostpad)
2869                 gst_object_unref(GST_OBJECT(ghostpad));
2870
2871         if (element_bucket)
2872                 g_list_free(element_bucket);
2873
2874         /* release element which are not added to bin */
2875         for (i = 1; i < MMPLAYER_A_NUM; i++) {
2876                 /* NOTE : skip bin */
2877                 if (audiobin[i].gst) {
2878                         GstObject *parent = NULL;
2879                         parent = gst_element_get_parent(audiobin[i].gst);
2880
2881                         if (!parent) {
2882                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2883                                 audiobin[i].gst = NULL;
2884                         } else
2885                                 gst_object_unref(GST_OBJECT(parent));
2886                 }
2887         }
2888
2889         /* release audiobin with it's childs */
2890         if (audiobin[MMPLAYER_A_BIN].gst)
2891                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2892
2893         MMPLAYER_FREEIF(audiobin);
2894
2895         player->pipeline->audiobin = NULL;
2896
2897         return MM_ERROR_PLAYER_INTERNAL;
2898 }
2899
2900 static guint32
2901 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2902 {
2903         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2904 }
2905
2906 int
2907 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2908 {
2909         int ret = MM_ERROR_NONE;
2910         GList *l = NULL;
2911         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2912         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2913
2914         MMPLAYER_VIDEO_BO_LOCK(player);
2915
2916         if (player->video_bo_list) {
2917                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2918                         mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2919                         if (tmp && tmp->bo == bo) {
2920                                 tmp->used = FALSE;
2921                                 LOGD("release bo %p", bo);
2922                                 tbm_bo_unref(tmp->bo);
2923                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
2924                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
2925                                 return ret;
2926                         }
2927                 }
2928         } else {
2929                 /* hw codec is running or the list was reset for DRC. */
2930                 LOGW("there is no bo list.");
2931         }
2932         MMPLAYER_VIDEO_BO_UNLOCK(player);
2933
2934         LOGW("failed to find bo %p", bo);
2935         return ret;
2936 }
2937
2938 static void
2939 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2940 {
2941         GList *l = NULL;
2942
2943         MMPLAYER_FENTER();
2944         MMPLAYER_RETURN_IF_FAIL(player);
2945
2946         MMPLAYER_VIDEO_BO_LOCK(player);
2947         if (player->video_bo_list) {
2948                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2949                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2950                         mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2951                         if (tmp) {
2952                                 if (tmp->bo)
2953                                         tbm_bo_unref(tmp->bo);
2954                                 g_free(tmp);
2955                         }
2956                 }
2957                 g_list_free(player->video_bo_list);
2958                 player->video_bo_list = NULL;
2959         }
2960         player->video_bo_size = 0;
2961         MMPLAYER_VIDEO_BO_UNLOCK(player);
2962
2963         MMPLAYER_FLEAVE();
2964         return;
2965 }
2966
2967 static void *
2968 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2969 {
2970         GList *l = NULL;
2971         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2972         gboolean ret = TRUE;
2973
2974         /* check DRC, if it is, destroy the prev bo list to create again */
2975         if (player->video_bo_size != size) {
2976                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2977                 __mmplayer_video_stream_destroy_bo_list(player);
2978                 player->video_bo_size = size;
2979         }
2980
2981         MMPLAYER_VIDEO_BO_LOCK(player);
2982
2983         if ((!player->video_bo_list) ||
2984                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2985
2986                 /* create bo list */
2987                 int idx = 0;
2988                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2989
2990                 if (player->video_bo_list) {
2991                         /* if bo list did not created all, try it again. */
2992                         idx = g_list_length(player->video_bo_list);
2993                         LOGD("bo list exist(len: %d)", idx);
2994                 }
2995
2996                 for (; idx < player->ini.num_of_video_bo; idx++) {
2997                         mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2998                         if (!bo_info) {
2999                                 LOGE("Fail to alloc bo_info.");
3000                                 break;
3001                         }
3002                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3003                         if (!bo_info->bo) {
3004                                 LOGE("Fail to tbm_bo_alloc.");
3005                                 MMPLAYER_FREEIF(bo_info);
3006                                 break;
3007                         }
3008                         bo_info->used = FALSE;
3009                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3010                 }
3011
3012                 /* update video num buffers */
3013                 player->video_num_buffers = idx;
3014                 if (idx == player->ini.num_of_video_bo)
3015                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3016
3017                 if (idx == 0) {
3018                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3019                         return NULL;
3020                 }
3021
3022                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3023         }
3024
3025         while (TRUE) {
3026                 /* get bo from list*/
3027                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3028                         mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3029                         if (tmp && (tmp->used == FALSE)) {
3030                                 LOGD("found bo %p to use", tmp->bo);
3031                                 tmp->used = TRUE;
3032                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3033                                 return tbm_bo_ref(tmp->bo);
3034                         }
3035                 }
3036                 if (!ret) {
3037                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3038                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3039                         return NULL;
3040                 }
3041
3042                 if (player->ini.video_bo_timeout <= 0) {
3043                         MMPLAYER_VIDEO_BO_WAIT(player);
3044                 } else {
3045                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3046                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3047                 }
3048                 continue;
3049         }
3050 }
3051
3052 static void
3053 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3054 {
3055         mm_player_t *player = (mm_player_t *)data;
3056         MMPLAYER_FENTER();
3057         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3058
3059         /* send prerolled pkt */
3060         player->video_stream_prerolled = false;
3061
3062         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3063
3064         /* not to send prerolled pkt again */
3065         player->video_stream_prerolled = true;
3066 }
3067
3068 static void
3069 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3070 {
3071         mm_player_t *player = (mm_player_t *)data;
3072         MMPlayerVideoStreamDataType *stream = NULL;
3073         GstMemory *mem = NULL;
3074
3075         MMPLAYER_FENTER();
3076         MMPLAYER_RETURN_IF_FAIL(player);
3077         MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3078
3079         if (player->video_stream_prerolled) {
3080                 player->video_stream_prerolled = false;
3081                 LOGD("skip the prerolled pkt not to send it again");
3082                 return;
3083         }
3084
3085         /* clear stream data structure */
3086         stream = __mmplayer_create_stream_from_pad(pad);
3087         if (!stream) {
3088                 LOGE("failed to alloc stream");
3089                 return;
3090         }
3091
3092         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3093
3094         /* set size and timestamp */
3095         mem = gst_buffer_peek_memory(buffer, 0);
3096         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3097         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3098
3099         /* check zero-copy */
3100         if (player->set_mode.video_zc &&
3101                 player->set_mode.media_packet_video_stream &&
3102                 gst_is_tizen_memory(mem)) {
3103                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3104                 stream->internal_buffer = gst_buffer_ref(buffer);
3105         } else { /* sw codec */
3106                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3107                         goto ERROR;
3108
3109                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3110                         goto ERROR;
3111         }
3112
3113         if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3114                 LOGE("failed to send video stream data.");
3115                 goto ERROR;
3116         }
3117
3118         return;
3119
3120 ERROR:
3121         LOGE("release video stream resource.");
3122         if (gst_is_tizen_memory(mem)) {
3123                 int i = 0;
3124                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3125                         if (stream->bo[i])
3126                                 tbm_bo_unref(stream->bo[i]);
3127                 }
3128
3129                 /* unref gst buffer */
3130                 if (stream->internal_buffer)
3131                         gst_buffer_unref(stream->internal_buffer);
3132         } else {
3133                 if (stream->bo[0])
3134                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3135         }
3136         MMPLAYER_FREEIF(stream);
3137         return;
3138 }
3139
3140 static void
3141 __mmplayer_gst_set_video360_property(mm_player_t *player)
3142 {
3143         MMPlayerGstElement *videobin = NULL;
3144
3145         MMPLAYER_FENTER();
3146         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3147
3148         videobin = player->pipeline->videobin;
3149
3150         /* Set spatial media metadata and/or user settings to the element.
3151          * */
3152         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153                         "projection-type", player->video360_metadata.projection_type, NULL);
3154
3155         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3156                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3157
3158         if (player->video360_metadata.full_pano_width_pixels &&
3159                         player->video360_metadata.full_pano_height_pixels &&
3160                         player->video360_metadata.cropped_area_image_width &&
3161                         player->video360_metadata.cropped_area_image_height) {
3162                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3163                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3164                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3165                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3166                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3167                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3168                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3169                                 NULL);
3170         }
3171
3172         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3173                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3174                                 "horizontal-fov", player->video360_horizontal_fov,
3175                                 "vertical-fov", player->video360_vertical_fov, NULL);
3176         }
3177
3178         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3179                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3180                                 "zoom", 1.0f / player->video360_zoom, NULL);
3181         }
3182
3183         if (player->video360_yaw_radians <= M_PI &&
3184                         player->video360_yaw_radians >= -M_PI &&
3185                         player->video360_pitch_radians <= M_PI_2 &&
3186                         player->video360_pitch_radians >= -M_PI_2) {
3187                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3189                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3190         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3191                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3192                                 "pose-yaw", player->video360_metadata.init_view_heading,
3193                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3194         }
3195
3196         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3197                         "passthrough", !player->is_video360_enabled, NULL);
3198
3199
3200         MMPLAYER_FLEAVE();
3201 }
3202
3203 static int
3204 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3205 {
3206         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3207         GList *element_bucket = NULL;
3208
3209         MMPLAYER_FENTER();
3210         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3211
3212         /* create video360 filter */
3213         if (player->is_360_feature_enabled && player->is_content_spherical) {
3214                 LOGD("create video360 element");
3215                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3216                 __mmplayer_gst_set_video360_property(player);
3217                 goto EXIT;
3218         }
3219
3220         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3221                 LOGD("skip creating the videoconv and rotator");
3222                 return MM_ERROR_NONE;
3223         }
3224
3225         /* in case of sw codec & overlay surface type, except 360 playback.
3226          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3227         LOGD("create video converter: %s", video_csc);
3228         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3229
3230 EXIT:
3231         *bucket = element_bucket;
3232         MMPLAYER_FLEAVE();
3233         return MM_ERROR_NONE;
3234
3235 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3236         g_list_free(element_bucket);
3237
3238         *bucket = NULL;
3239         MMPLAYER_FLEAVE();
3240         return MM_ERROR_PLAYER_INTERNAL;
3241 }
3242
3243 static gchar *
3244 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3245 {
3246         gchar *factory_name = NULL;
3247
3248         switch (surface_type) {
3249         case MM_DISPLAY_SURFACE_OVERLAY:
3250                 if (strlen(player->ini.videosink_element_overlay) > 0)
3251                         factory_name = player->ini.videosink_element_overlay;
3252                 break;
3253         case MM_DISPLAY_SURFACE_REMOTE:
3254         case MM_DISPLAY_SURFACE_NULL:
3255                 if (strlen(player->ini.videosink_element_fake) > 0)
3256                         factory_name = player->ini.videosink_element_fake;
3257                 break;
3258         default:
3259                 LOGE("unidentified surface type");
3260                 break;
3261         }
3262
3263         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3264         return factory_name;
3265 }
3266
3267 static int
3268 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3269 {
3270         gchar *factory_name = NULL;
3271         MMPlayerGstElement *videobin = NULL;
3272         MMHandleType attrs;
3273         int gapless = 0;
3274
3275         MMPLAYER_FENTER();
3276         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3277
3278         videobin = player->pipeline->videobin;
3279         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3280
3281         attrs = MMPLAYER_GET_ATTRS(player);
3282         if (!attrs) {
3283                 LOGE("cannot get content attribute");
3284                 return MM_ERROR_PLAYER_INTERNAL;
3285         }
3286
3287         LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3288         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3289                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3290                 if (!use_tbm) {
3291                         /* support shard memory with S/W codec on HawkP */
3292                         if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3293                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3294                                         "use-tbm", use_tbm, NULL);
3295                         }
3296                 }
3297         } else {
3298                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3299                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3300         }
3301
3302         mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3303         if (gapless > 0) {
3304                 LOGD("disable last-sample");
3305                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3306         }
3307
3308         if (player->set_mode.media_packet_video_stream) {
3309                 int enable = 0;
3310                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3311                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3312                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3313
3314                 __mmplayer_add_signal_connection(player,
3315                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3316                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3317                                                                 "handoff",
3318                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3319                                                                 (gpointer)player);
3320
3321                 __mmplayer_add_signal_connection(player,
3322                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3323                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3324                                                                 "preroll-handoff",
3325                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3326                                                                 (gpointer)player);
3327         }
3328
3329         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3330                 return MM_ERROR_PLAYER_INTERNAL;
3331
3332         if (videobin[MMPLAYER_V_SINK].gst) {
3333                 GstPad *sink_pad = NULL;
3334                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3335                 if (sink_pad) {
3336                         __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3337                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3338                         gst_object_unref(GST_OBJECT(sink_pad));
3339                 } else {
3340                         LOGE("failed to get sink pad from videosink");
3341                 }
3342         }
3343
3344         return MM_ERROR_NONE;
3345 }
3346
3347 /**
3348  * VIDEO BIN
3349  * - video overlay surface(arm/x86) : tizenwlsink
3350  */
3351 static int
3352 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3353 {
3354         GstPad *pad = NULL;
3355         GList *element_bucket = NULL;
3356         MMPlayerGstElement *first_element = NULL;
3357         MMPlayerGstElement *videobin = NULL;
3358         gchar *videosink_factory_name = NULL;
3359
3360         MMPLAYER_FENTER();
3361         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3362
3363         /* alloc handles */
3364         videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3365         if (!videobin)
3366                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3367
3368         player->pipeline->videobin = videobin;
3369
3370         /* create bin */
3371         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3372         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3373         if (!videobin[MMPLAYER_V_BIN].gst) {
3374                 LOGE("failed to create videobin");
3375                 goto ERROR;
3376         }
3377
3378         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3379                 goto ERROR;
3380
3381         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3382         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3383
3384         /* additional setting for sink plug-in */
3385         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3386                 LOGE("failed to set video property");
3387                 goto ERROR;
3388         }
3389
3390         /* store it as it's sink element */
3391         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3392
3393         /* adding created elements to bin */
3394         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3395                 LOGE("failed to add elements");
3396                 goto ERROR;
3397         }
3398
3399         /* Linking elements in the bucket by added order */
3400         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3401                 LOGE("failed to link elements");
3402                 goto ERROR;
3403         }
3404
3405         /* get first element's sinkpad for creating ghostpad */
3406         first_element = (MMPlayerGstElement *)element_bucket->data;
3407         if (!first_element) {
3408                 LOGE("failed to get first element from bucket");
3409                 goto ERROR;
3410         }
3411
3412         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3413         if (!pad) {
3414                 LOGE("failed to get pad from first element");
3415                 goto ERROR;
3416         }
3417
3418         /* create ghostpad */
3419         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3420         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3421                 LOGE("failed to add ghostpad to videobin");
3422                 goto ERROR;
3423         }
3424         gst_object_unref(pad);
3425
3426         /* done. free allocated variables */
3427         g_list_free(element_bucket);
3428
3429         MMPLAYER_FLEAVE();
3430
3431         return MM_ERROR_NONE;
3432
3433 ERROR:
3434         LOGE("ERROR : releasing videobin");
3435         g_list_free(element_bucket);
3436
3437         if (pad)
3438                 gst_object_unref(GST_OBJECT(pad));
3439
3440         /* release videobin with it's childs */
3441         if (videobin[MMPLAYER_V_BIN].gst)
3442                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3443
3444         MMPLAYER_FREEIF(videobin);
3445         player->pipeline->videobin = NULL;
3446
3447         return MM_ERROR_PLAYER_INTERNAL;
3448 }
3449
3450 static int
3451 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3452 {
3453         GList *element_bucket = NULL;
3454         MMPlayerGstElement *textbin = player->pipeline->textbin;
3455
3456         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3457         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3458         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3459                                                         "signal-handoffs", FALSE,
3460                                                         NULL);
3461
3462         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3463         __mmplayer_add_signal_connection(player,
3464                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3465                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3466                                                         "handoff",
3467                                                         G_CALLBACK(__mmplayer_update_subtitle),
3468                                                         (gpointer)player);
3469
3470         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3471                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472
3473         if (!player->play_subtitle) {
3474                 LOGD("add textbin sink as sink element of whole pipeline.");
3475                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3476         }
3477
3478         /* adding created elements to bin */
3479         LOGD("adding created elements to bin");
3480         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3481                 LOGE("failed to add elements");
3482                 goto ERROR;
3483         }
3484
3485         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3486         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3487         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3488
3489         /* linking elements in the bucket by added order. */
3490         LOGD("Linking elements in the bucket by added order.");
3491         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3492                 LOGE("failed to link elements");
3493                 goto ERROR;
3494         }
3495
3496         /* done. free allocated variables */
3497         g_list_free(element_bucket);
3498
3499         if (textbin[MMPLAYER_T_QUEUE].gst) {
3500                 GstPad *pad = NULL;
3501                 GstPad *ghostpad = NULL;
3502
3503                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3504                 if (!pad) {
3505                         LOGE("failed to get sink pad of text queue");
3506                         goto ERROR;
3507                 }
3508
3509                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3510                 gst_object_unref(pad);
3511
3512                 if (!ghostpad) {
3513                         LOGE("failed to create ghostpad of textbin");
3514                         goto ERROR;
3515                 }
3516
3517                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3518                         LOGE("failed to add ghostpad to textbin");
3519                         gst_object_unref(ghostpad);
3520                         goto ERROR;
3521                 }
3522         }
3523
3524         return MM_ERROR_NONE;
3525
3526 ERROR:
3527         g_list_free(element_bucket);
3528
3529         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3530                 LOGE("remove textbin sink from sink list");
3531                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3532         }
3533
3534         /* release element at __mmplayer_gst_create_text_sink_bin */
3535         return MM_ERROR_PLAYER_INTERNAL;
3536 }
3537
3538 static int
3539 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3540 {
3541         MMPlayerGstElement *textbin = NULL;
3542         GList *element_bucket = NULL;
3543         int surface_type = 0;
3544         gint i = 0;
3545
3546         MMPLAYER_FENTER();
3547
3548         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3549
3550         /* alloc handles */
3551         textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3552         if (!textbin) {
3553                 LOGE("failed to allocate memory for textbin");
3554                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3555         }
3556
3557         /* create bin */
3558         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3559         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3560         if (!textbin[MMPLAYER_T_BIN].gst) {
3561                 LOGE("failed to create textbin");
3562                 goto ERROR;
3563         }
3564
3565         /* take it */
3566         player->pipeline->textbin = textbin;
3567
3568         /* fakesink */
3569         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3570         LOGD("surface type for subtitle : %d", surface_type);
3571         switch (surface_type) {
3572         case MM_DISPLAY_SURFACE_OVERLAY:
3573         case MM_DISPLAY_SURFACE_NULL:
3574         case MM_DISPLAY_SURFACE_REMOTE:
3575                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3576                         LOGE("failed to make plain text elements");
3577                         goto ERROR;
3578                 }
3579                 break;
3580         default:
3581                 goto ERROR;
3582                 break;
3583         }
3584
3585         MMPLAYER_FLEAVE();
3586
3587         return MM_ERROR_NONE;
3588
3589 ERROR:
3590
3591         LOGD("ERROR : releasing textbin");
3592
3593         g_list_free(element_bucket);
3594
3595         /* release signal */
3596         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3597
3598         /* release element which are not added to bin */
3599         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3600                 /* NOTE : skip bin */
3601                 if (textbin[i].gst) {
3602                         GstObject *parent = NULL;
3603                         parent = gst_element_get_parent(textbin[i].gst);
3604
3605                         if (!parent) {
3606                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3607                                 textbin[i].gst = NULL;
3608                         } else {
3609                                 gst_object_unref(GST_OBJECT(parent));
3610                         }
3611                 }
3612         }
3613
3614         /* release textbin with it's childs */
3615         if (textbin[MMPLAYER_T_BIN].gst)
3616                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3617
3618         MMPLAYER_FREEIF(player->pipeline->textbin);
3619         player->pipeline->textbin = NULL;
3620
3621         MMPLAYER_FLEAVE();
3622         return MM_ERROR_PLAYER_INTERNAL;
3623 }
3624
3625 static int
3626 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3627 {
3628         MMPlayerGstElement *mainbin = NULL;
3629         MMPlayerGstElement *textbin = NULL;
3630         MMHandleType attrs = 0;
3631         GstElement *subsrc = NULL;
3632         GstElement *subparse = NULL;
3633         gchar *subtitle_uri = NULL;
3634         const gchar *charset = NULL;
3635         GstPad *pad = NULL;
3636
3637         MMPLAYER_FENTER();
3638
3639         /* get mainbin */
3640         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3641                                                                 player->pipeline &&
3642                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3643
3644         mainbin = player->pipeline->mainbin;
3645
3646         attrs = MMPLAYER_GET_ATTRS(player);
3647         if (!attrs) {
3648                 LOGE("cannot get content attribute");
3649                 return MM_ERROR_PLAYER_INTERNAL;
3650         }
3651
3652         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3653         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3654                 LOGE("subtitle uri is not proper filepath.");
3655                 return MM_ERROR_PLAYER_INVALID_URI;
3656         }
3657
3658         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3659                 LOGE("failed to get storage info of subtitle path");
3660                 return MM_ERROR_PLAYER_INVALID_URI;
3661         }
3662
3663         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3664
3665         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3666         player->subtitle_language_list = NULL;
3667         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3668
3669         /* create the subtitle source */
3670         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3671         if (!subsrc) {
3672                 LOGE("failed to create filesrc element");
3673                 goto ERROR;
3674         }
3675         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3676
3677         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3678         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3679
3680         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3681                 LOGW("failed to add queue");
3682                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3683                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3684                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3685                 goto ERROR;
3686         }
3687
3688         /* subparse */
3689         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3690         if (!subparse) {
3691                 LOGE("failed to create subparse element");
3692                 goto ERROR;
3693         }
3694
3695         charset = util_get_charset(subtitle_uri);
3696         if (charset) {
3697                 LOGD("detected charset is %s", charset);
3698                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3699         }
3700
3701         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3702         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3703
3704         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3705                 LOGW("failed to add subparse");
3706                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3707                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3708                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3709                 goto ERROR;
3710         }
3711
3712         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3713                 LOGW("failed to link subsrc and subparse");
3714                 goto ERROR;
3715         }
3716
3717         player->play_subtitle = TRUE;
3718         player->adjust_subtitle_pos = 0;
3719
3720         LOGD("play subtitle using subtitle file");
3721
3722         if (player->pipeline->textbin == NULL) {
3723                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3724                         LOGE("failed to create text sink bin. continuing without text");
3725                         goto ERROR;
3726                 }
3727
3728                 textbin = player->pipeline->textbin;
3729
3730                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3731                         LOGW("failed to add textbin");
3732
3733                         /* release signal */
3734                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3735
3736                         /* release textbin with it's childs */
3737                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3738                         MMPLAYER_FREEIF(player->pipeline->textbin);
3739                         player->pipeline->textbin = textbin = NULL;
3740                         goto ERROR;
3741                 }
3742
3743                 LOGD("link text input selector and textbin ghost pad");
3744
3745                 player->textsink_linked = 1;
3746                 player->external_text_idx = 0;
3747                 LOGI("textsink is linked");
3748         } else {
3749                 textbin = player->pipeline->textbin;
3750                 LOGD("text bin has been created. reuse it.");
3751                 player->external_text_idx = 1;
3752         }
3753
3754         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3755                 LOGW("failed to link subparse and textbin");
3756                 goto ERROR;
3757         }
3758
3759         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3760         if (!pad) {
3761                 LOGE("failed to get sink pad from textsink to probe data");
3762                 goto ERROR;
3763         }
3764
3765         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3766                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3767
3768         gst_object_unref(pad);
3769         pad = NULL;
3770
3771         /* create dot. for debugging */
3772         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3773         MMPLAYER_FLEAVE();
3774
3775         return MM_ERROR_NONE;
3776
3777 ERROR:
3778         /* release text pipeline resource */
3779         player->textsink_linked = 0;
3780
3781         /* release signal */
3782         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3783
3784         if (player->pipeline->textbin) {
3785                 LOGE("remove textbin");
3786
3787                 /* release textbin with it's childs */
3788                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3789                 MMPLAYER_FREEIF(player->pipeline->textbin);
3790                 player->pipeline->textbin = NULL;
3791
3792         }
3793
3794         /* release subtitle elem */
3795         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3796         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3797
3798         return MM_ERROR_PLAYER_INTERNAL;
3799 }
3800
3801 gboolean
3802 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3803 {
3804         mm_player_t *player = (mm_player_t *)data;
3805         MMMessageParamType msg = {0, };
3806         GstClockTime duration = 0;
3807         gpointer text = NULL;
3808         guint text_size = 0;
3809         gboolean ret = TRUE;
3810         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3811
3812         MMPLAYER_FENTER();
3813
3814         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3815         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3816
3817         if (player->is_subtitle_force_drop) {
3818                 LOGW("subtitle is dropped forcedly.");
3819                 return ret;
3820         }
3821
3822         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3823         text = mapinfo.data;
3824         text_size = mapinfo.size;
3825
3826         if (player->set_mode.subtitle_off) {
3827                 LOGD("subtitle is OFF.");
3828                 return TRUE;
3829         }
3830
3831         if (!text || (text_size == 0)) {
3832                 LOGD("There is no subtitle to be displayed.");
3833                 return TRUE;
3834         }
3835
3836         msg.data = (void *)text;
3837
3838         duration = GST_BUFFER_DURATION(buffer);
3839
3840         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3841                 if (player->duration > GST_BUFFER_PTS(buffer))
3842                         duration = player->duration - GST_BUFFER_PTS(buffer);
3843                 else
3844                         duration = 0;
3845                 LOGI("subtitle duration is invalid, subtitle duration change "
3846                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3847         }
3848         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3849
3850         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3851
3852         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3853         gst_buffer_unmap(buffer, &mapinfo);
3854
3855         MMPLAYER_FLEAVE();
3856
3857         return ret;
3858 }
3859
3860 static GstPadProbeReturn
3861 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3862 {
3863         mm_player_t *player = (mm_player_t *)u_data;
3864         GstClockTime cur_timestamp = 0;
3865         gint64 adjusted_timestamp = 0;
3866         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3867
3868         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3869
3870         if (player->set_mode.subtitle_off) {
3871                 LOGD("subtitle is OFF.");
3872                 return TRUE;
3873         }
3874
3875         if (player->adjust_subtitle_pos == 0) {
3876                 LOGD("nothing to do");
3877                 return TRUE;
3878         }
3879
3880         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3881         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3882
3883         if (adjusted_timestamp < 0) {
3884                 LOGD("adjusted_timestamp under zero");
3885                 MMPLAYER_FLEAVE();
3886                 return FALSE;
3887         }
3888
3889         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3890         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3891                                 GST_TIME_ARGS(cur_timestamp),
3892                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3893
3894         return GST_PAD_PROBE_OK;
3895 }
3896
3897 static int
3898 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3899 {
3900         MMPLAYER_FENTER();
3901
3902         /* check player and subtitlebin are created */
3903         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3904         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3905
3906         if (position == 0) {
3907                 LOGD("nothing to do");
3908                 MMPLAYER_FLEAVE();
3909                 return MM_ERROR_NONE;
3910         }
3911
3912         switch (format) {
3913         case MM_PLAYER_POS_FORMAT_TIME:
3914                 {
3915                         /* check current postion */
3916                         player->adjust_subtitle_pos = position;
3917
3918                         LOGD("save adjust_subtitle_pos in player") ;
3919                 }
3920                 break;
3921
3922         default:
3923                 {
3924                         LOGW("invalid format.");
3925                         MMPLAYER_FLEAVE();
3926                         return MM_ERROR_INVALID_ARGUMENT;
3927                 }
3928         }
3929
3930         MMPLAYER_FLEAVE();
3931
3932         return MM_ERROR_NONE;
3933 }
3934
3935 /**
3936  * This function is to create  audio or video pipeline for playing.
3937  *
3938  * @param       player          [in]    handle of player
3939  *
3940  * @return      This function returns zero on success.
3941  * @remark
3942  * @see
3943  */
3944 static int
3945 __mmplayer_gst_create_pipeline(mm_player_t *player)
3946 {
3947         int ret = MM_ERROR_NONE;
3948         MMPlayerGstElement *mainbin = NULL;
3949         MMHandleType attrs = 0;
3950
3951         MMPLAYER_FENTER();
3952         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3953
3954         /* get profile attribute */
3955         attrs = MMPLAYER_GET_ATTRS(player);
3956         if (!attrs) {
3957                 LOGE("failed to get content attribute");
3958                 goto INIT_ERROR;
3959         }
3960
3961         /* create pipeline handles */
3962         if (player->pipeline) {
3963                 LOGE("pipeline should be released before create new one");
3964                 goto INIT_ERROR;
3965         }
3966
3967         player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3968         if (player->pipeline == NULL)
3969                 goto INIT_ERROR;
3970
3971         /* create mainbin */
3972         mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3973         if (mainbin == NULL)
3974                 goto INIT_ERROR;
3975
3976         /* create pipeline */
3977         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3978         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3979         if (!mainbin[MMPLAYER_M_PIPE].gst) {
3980                 LOGE("failed to create pipeline");
3981                 g_free(mainbin);
3982                 goto INIT_ERROR;
3983         }
3984
3985         player->pipeline->mainbin = mainbin;
3986
3987         /* create the source and decoder elements */
3988         if (MMPLAYER_IS_MS_BUFF_SRC(player))
3989                 ret = __mmplayer_gst_build_es_pipeline(player);
3990         else
3991                 ret = __mmplayer_gst_build_pipeline(player);
3992
3993         if (ret != MM_ERROR_NONE) {
3994                 LOGE("failed to create some elements");
3995                 goto INIT_ERROR;
3996         }
3997
3998         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3999         if (__mmplayer_check_subtitle(player)
4000                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4001                 LOGE("failed to create text pipeline");
4002
4003         /* add bus watch */
4004         ret = __mmplayer_gst_add_bus_watch(player);
4005         if (ret != MM_ERROR_NONE) {
4006                 LOGE("failed to add bus watch");
4007                 goto INIT_ERROR;
4008         }
4009
4010         MMPLAYER_FLEAVE();
4011         return MM_ERROR_NONE;
4012
4013 INIT_ERROR:
4014         __mmplayer_gst_destroy_pipeline(player);
4015         return MM_ERROR_PLAYER_INTERNAL;
4016 }
4017
4018 static void
4019 __mmplayer_reset_gapless_state(mm_player_t *player)
4020 {
4021         MMPLAYER_FENTER();
4022         MMPLAYER_RETURN_IF_FAIL(player
4023                 && player->pipeline
4024                 && player->pipeline->audiobin
4025                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4026
4027         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4028
4029         MMPLAYER_FLEAVE();
4030         return;
4031 }
4032
4033 static int
4034 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4035 {
4036         gint timeout = 0;
4037         int ret = MM_ERROR_NONE;
4038
4039         MMPLAYER_FENTER();
4040
4041         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4042
4043         /* cleanup stuffs */
4044         MMPLAYER_FREEIF(player->type);
4045         player->no_more_pad = FALSE;
4046         player->num_dynamic_pad = 0;
4047         player->demux_pad_index = 0;
4048
4049         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4050         player->subtitle_language_list = NULL;
4051         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4052
4053         __mmplayer_reset_gapless_state(player);
4054
4055         if (player->streamer) {
4056                 __mm_player_streaming_initialize(player->streamer, FALSE);
4057                 __mm_player_streaming_destroy(player->streamer);
4058                 player->streamer = NULL;
4059         }
4060
4061         /* cleanup unlinked mime type */
4062         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4063         MMPLAYER_FREEIF(player->unlinked_video_mime);
4064         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4065
4066         /* cleanup running stuffs */
4067         __mmplayer_cancel_eos_timer(player);
4068
4069         /* cleanup gst stuffs */
4070         if (player->pipeline) {
4071                 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4072                 GstTagList *tag_list = player->pipeline->tag_list;
4073
4074                 /* first we need to disconnect all signal hander */
4075                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4076
4077                 if (mainbin) {
4078                         MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4079                         MMPlayerGstElement *videobin = player->pipeline->videobin;
4080                         MMPlayerGstElement *textbin = player->pipeline->textbin;
4081                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4082                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4083                         gst_object_unref(bus);
4084
4085                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4086                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4087                         if (ret != MM_ERROR_NONE) {
4088                                 LOGE("fail to change state to NULL");
4089                                 return MM_ERROR_PLAYER_INTERNAL;
4090                         }
4091
4092                         LOGW("succeeded in changing state to NULL");
4093
4094                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4095
4096                         /* free fakesink */
4097                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4098                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4099
4100                         /* free avsysaudiosink
4101                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4102                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4103                         */
4104                         MMPLAYER_FREEIF(audiobin);
4105                         MMPLAYER_FREEIF(videobin);
4106                         MMPLAYER_FREEIF(textbin);
4107                         MMPLAYER_FREEIF(mainbin);
4108                 }
4109
4110                 if (tag_list)
4111                         gst_tag_list_unref(tag_list);
4112
4113                 MMPLAYER_FREEIF(player->pipeline);
4114         }
4115         MMPLAYER_FREEIF(player->album_art);
4116
4117         if (player->v_stream_caps) {
4118                 gst_caps_unref(player->v_stream_caps);
4119                 player->v_stream_caps = NULL;
4120         }
4121
4122         if (player->a_stream_caps) {
4123                 gst_caps_unref(player->a_stream_caps);
4124                 player->a_stream_caps = NULL;
4125         }
4126
4127         if (player->s_stream_caps) {
4128                 gst_caps_unref(player->s_stream_caps);
4129                 player->s_stream_caps = NULL;
4130         }
4131         __mmplayer_track_destroy(player);
4132
4133         if (player->sink_elements)
4134                 g_list_free(player->sink_elements);
4135         player->sink_elements = NULL;
4136
4137         if (player->bufmgr) {
4138                 tbm_bufmgr_deinit(player->bufmgr);
4139                 player->bufmgr = NULL;
4140         }
4141
4142         LOGW("finished destroy pipeline");
4143
4144         MMPLAYER_FLEAVE();
4145
4146         return ret;
4147 }
4148
4149 static int
4150 __mmplayer_gst_realize(mm_player_t *player)
4151 {
4152         gint timeout = 0;
4153         int ret = MM_ERROR_NONE;
4154
4155         MMPLAYER_FENTER();
4156
4157         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4158
4159         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4160
4161         ret = __mmplayer_gst_create_pipeline(player);
4162         if (ret) {
4163                 LOGE("failed to create pipeline");
4164                 return ret;
4165         }
4166
4167         /* set pipeline state to READY */
4168         /* NOTE : state change to READY must be performed sync. */
4169         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4170         ret = __mmplayer_gst_set_state(player,
4171                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4172
4173         if (ret != MM_ERROR_NONE) {
4174                 /* return error if failed to set state */
4175                 LOGE("failed to set READY state");
4176                 return ret;
4177         }
4178
4179         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4180
4181         /* create dot before error-return. for debugging */
4182         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4183
4184         MMPLAYER_FLEAVE();
4185
4186         return ret;
4187 }
4188
4189 static int
4190 __mmplayer_gst_unrealize(mm_player_t *player)
4191 {
4192         int ret = MM_ERROR_NONE;
4193
4194         MMPLAYER_FENTER();
4195
4196         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4197
4198         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4199         MMPLAYER_PRINT_STATE(player);
4200
4201         /* release miscellaneous information */
4202         __mmplayer_release_misc(player);
4203
4204         /* destroy pipeline */
4205         ret = __mmplayer_gst_destroy_pipeline(player);
4206         if (ret != MM_ERROR_NONE) {
4207                 LOGE("failed to destory pipeline");
4208                 return ret;
4209         }
4210
4211         /* release miscellaneous information.
4212            these info needs to be released after pipeline is destroyed. */
4213         __mmplayer_release_misc_post(player);
4214
4215         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4216
4217         MMPLAYER_FLEAVE();
4218
4219         return ret;
4220 }
4221
4222 static int
4223 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4224 {
4225         MMPLAYER_FENTER();
4226
4227         if (!player) {
4228                 LOGW("set_message_callback is called with invalid player handle");
4229                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4230         }
4231
4232         player->msg_cb = callback;
4233         player->msg_cb_param = user_param;
4234
4235         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4236
4237         MMPLAYER_FLEAVE();
4238
4239         return MM_ERROR_NONE;
4240 }
4241
4242 int
4243 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4244 {
4245         int ret = MM_ERROR_NONE;
4246         char *path = NULL;
4247
4248         MMPLAYER_FENTER();
4249
4250         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4251         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4252         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4253
4254         memset(data, 0, sizeof(MMPlayerParseProfile));
4255
4256         if (strstr(uri, "es_buff://")) {
4257                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4258         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4259                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4260         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4261                 gchar *tmp = NULL;
4262                 tmp = g_ascii_strdown(uri, strlen(uri));
4263                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4264                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4265                 else
4266                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4267                 g_free(tmp);
4268         } else if (strstr(uri, "mms://")) {
4269                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4270         } else if ((path = strstr(uri, "mem://"))) {
4271                 ret = __mmplayer_set_mem_uri(data, path, param);
4272         } else {
4273                 ret = __mmplayer_set_file_uri(data, uri);
4274         }
4275
4276         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4277                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4278         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4279                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4280
4281         /* dump parse result */
4282         SECURE_LOGW("incoming uri : %s", uri);
4283         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4284                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4285
4286         MMPLAYER_FLEAVE();
4287
4288         return ret;
4289 }
4290
4291 static gboolean
4292 __mmplayer_can_do_interrupt(mm_player_t *player)
4293 {
4294         if (!player || !player->pipeline || !player->attrs) {
4295                 LOGW("not initialized");
4296                 goto FAILED;
4297         }
4298
4299         if (player->audio_stream_render_cb) {
4300                 LOGW("not support in pcm extraction mode");
4301                 goto FAILED;
4302         }
4303
4304         /* check if seeking */
4305         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4306                 MMMessageParamType msg_param;
4307                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4308                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4309                 player->seek_state = MMPLAYER_SEEK_NONE;
4310                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4311                 goto FAILED;
4312         }
4313
4314         /* check other thread */
4315         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4316                 LOGW("locked already, cmd state : %d", player->cmd);
4317
4318                 /* check application command */
4319                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4320                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4321
4322                         /* lock will be released at mrp_resource_release_cb() */
4323                         MMPLAYER_CMD_LOCK(player);
4324                         goto INTERRUPT;
4325                 }
4326                 LOGW("nothing to do");
4327                 goto FAILED;
4328         } else {
4329                 LOGW("can interrupt immediately");
4330                 goto INTERRUPT;
4331         }
4332
4333 FAILED:    /* with CMD UNLOCKED */
4334         return FALSE;
4335
4336 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4337         return TRUE;
4338 }
4339
4340 static int
4341 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4342                 void *user_data)
4343 {
4344         mm_player_t *player = NULL;
4345
4346         MMPLAYER_FENTER();
4347
4348         if (user_data == NULL) {
4349                 LOGE("- user_data is null");
4350                 return FALSE;
4351         }
4352         player = (mm_player_t *)user_data;
4353
4354         /* do something to release resource here.
4355          * player stop and interrupt forwarding */
4356         if (!__mmplayer_can_do_interrupt(player)) {
4357                 LOGW("no need to interrupt, so leave");
4358         } else {
4359                 MMMessageParamType msg = {0, };
4360                 gint64 pos = 0;
4361
4362                 player->interrupted_by_resource = TRUE;
4363
4364                 /* get last play position */
4365                 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4366                         LOGW("failed to get play position.");
4367                 } else {
4368                         msg.union_type = MM_MSG_UNION_TIME;
4369                         msg.time.elapsed = pos;
4370                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4371                 }
4372                 LOGD("video resource conflict so, resource will be freed by unrealizing");
4373                 if (_mmplayer_unrealize((MMHandleType)player))
4374                         LOGW("failed to unrealize");
4375
4376                 /* lock is called in __mmplayer_can_do_interrupt() */
4377                 MMPLAYER_CMD_UNLOCK(player);
4378         }
4379
4380         if (res == player->video_overlay_resource)
4381                 player->video_overlay_resource = FALSE;
4382         else
4383                 player->video_decoder_resource = FALSE;
4384
4385         MMPLAYER_FLEAVE();
4386
4387         return FALSE;
4388 }
4389
4390 static void
4391 __mmplayer_initialize_video_roi(mm_player_t *player)
4392 {
4393         player->video_roi.scale_x = 0.0;
4394         player->video_roi.scale_y = 0.0;
4395         player->video_roi.scale_width = 1.0;
4396         player->video_roi.scale_height = 1.0;
4397 }
4398
4399 int
4400 _mmplayer_create_player(MMHandleType handle)
4401 {
4402         int ret = MM_ERROR_PLAYER_INTERNAL;
4403         bool enabled = false;
4404
4405         mm_player_t *player = MM_PLAYER_CAST(handle);
4406
4407         MMPLAYER_FENTER();
4408
4409         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4410
4411         /* initialize player state */
4412         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4413         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4414         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4415         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4416
4417         /* check current state */
4418         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4419
4420         /* construct attributes */
4421         player->attrs = _mmplayer_construct_attribute(handle);
4422
4423         if (!player->attrs) {
4424                 LOGE("Failed to construct attributes");
4425                 return ret;
4426         }
4427
4428         /* initialize gstreamer with configured parameter */
4429         if (!__mmplayer_init_gstreamer(player)) {
4430                 LOGE("Initializing gstreamer failed");
4431                 _mmplayer_deconstruct_attribute(handle);
4432                 return ret;
4433         }
4434
4435         /* create lock. note that g_tread_init() has already called in gst_init() */
4436         g_mutex_init(&player->fsink_lock);
4437
4438         /* create update tag lock */
4439         g_mutex_init(&player->update_tag_lock);
4440
4441         /* create gapless play mutex */
4442         g_mutex_init(&player->gapless_play_thread_mutex);
4443
4444         /* create gapless play cond */
4445         g_cond_init(&player->gapless_play_thread_cond);
4446
4447         /* create gapless play thread */
4448         player->gapless_play_thread =
4449                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4450         if (!player->gapless_play_thread) {
4451                 LOGE("failed to create gapless play thread");
4452                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4453                 g_mutex_clear(&player->gapless_play_thread_mutex);
4454                 g_cond_clear(&player->gapless_play_thread_cond);
4455                 goto ERROR;
4456         }
4457
4458         player->bus_msg_q = g_queue_new();
4459         if (!player->bus_msg_q) {
4460                 LOGE("failed to create queue for bus_msg");
4461                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4462                 goto ERROR;
4463         }
4464
4465         ret = _mmplayer_initialize_video_capture(player);
4466         if (ret != MM_ERROR_NONE) {
4467                 LOGE("failed to initialize video capture");
4468                 goto ERROR;
4469         }
4470
4471         /* initialize resource manager */
4472         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4473                 __resource_release_cb, player, &player->resource_manager)
4474                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4475                 LOGE("failed to initialize resource manager");
4476                 ret = MM_ERROR_PLAYER_INTERNAL;
4477                 goto ERROR;
4478         }
4479
4480         /* create video bo lock and cond */
4481         g_mutex_init(&player->video_bo_mutex);
4482         g_cond_init(&player->video_bo_cond);
4483
4484         /* create media stream callback mutex */
4485         g_mutex_init(&player->media_stream_cb_lock);
4486
4487         /* create subtitle info lock and cond */
4488         g_mutex_init(&player->subtitle_info_mutex);
4489         g_cond_init(&player->subtitle_info_cond);
4490
4491         player->streaming_type = STREAMING_SERVICE_NONE;
4492
4493         /* give default value of audio effect setting */
4494         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4495         player->sound.rg_enable = false;
4496         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4497
4498         player->play_subtitle = FALSE;
4499         player->has_closed_caption = FALSE;
4500         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4501         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4502         player->pending_resume = FALSE;
4503         if (player->ini.dump_element_keyword[0][0] == '\0')
4504                 player->ini.set_dump_element_flag = FALSE;
4505         else
4506                 player->ini.set_dump_element_flag = TRUE;
4507
4508         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4509         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4510         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4511
4512         /* Set video360 settings to their defaults for just-created player.
4513          * */
4514
4515         player->is_360_feature_enabled = FALSE;
4516         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4517                 LOGI("spherical feature info: %d", enabled);
4518                 if (enabled)
4519                         player->is_360_feature_enabled = TRUE;
4520         } else {
4521                 LOGE("failed to get spherical feature info");
4522         }
4523
4524         player->is_content_spherical = FALSE;
4525         player->is_video360_enabled = TRUE;
4526         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4527         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4528         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4529         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4530         player->video360_zoom = 1.0f;
4531         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4532         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4533
4534         __mmplayer_initialize_video_roi(player);
4535
4536         /* set player state to null */
4537         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4538         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4539
4540         MMPLAYER_FLEAVE();
4541
4542         return MM_ERROR_NONE;
4543
4544 ERROR:
4545         /* free lock */
4546         g_mutex_clear(&player->fsink_lock);
4547         /* free update tag lock */
4548         g_mutex_clear(&player->update_tag_lock);
4549         g_queue_free(player->bus_msg_q);
4550         /* free gapless play thread */
4551         if (player->gapless_play_thread) {
4552                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4553                 player->gapless_play_thread_exit = TRUE;
4554                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4555                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4556
4557                 g_thread_join(player->gapless_play_thread);
4558                 player->gapless_play_thread = NULL;
4559
4560                 g_mutex_clear(&player->gapless_play_thread_mutex);
4561                 g_cond_clear(&player->gapless_play_thread_cond);
4562         }
4563
4564         /* release attributes */
4565         _mmplayer_deconstruct_attribute(handle);
4566
4567         MMPLAYER_FLEAVE();
4568
4569         return ret;
4570 }
4571
4572 static gboolean
4573 __mmplayer_init_gstreamer(mm_player_t *player)
4574 {
4575         static gboolean initialized = FALSE;
4576         static const int max_argc = 50;
4577         gint *argc = NULL;
4578         gchar **argv = NULL;
4579         gchar **argv2 = NULL;
4580         GError *err = NULL;
4581         int i = 0;
4582         int arg_count = 0;
4583
4584         if (initialized) {
4585                 LOGD("gstreamer already initialized.");
4586                 return TRUE;
4587         }
4588
4589         /* alloc */
4590         argc = malloc(sizeof(int));
4591         argv = malloc(sizeof(gchar *) * max_argc);
4592         argv2 = malloc(sizeof(gchar *) * max_argc);
4593
4594         if (!argc || !argv || !argv2)
4595                 goto ERROR;
4596
4597         memset(argv, 0, sizeof(gchar *) * max_argc);
4598         memset(argv2, 0, sizeof(gchar *) * max_argc);
4599
4600         /* add initial */
4601         *argc = 1;
4602         argv[0] = g_strdup("mmplayer");
4603
4604         /* add gst_param */
4605         for (i = 0; i < 5; i++) {
4606                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4607                 if (strlen(player->ini.gst_param[i]) > 0) {
4608                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4609                         (*argc)++;
4610                 }
4611         }
4612
4613         /* we would not do fork for scanning plugins */
4614         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4615         (*argc)++;
4616
4617         /* check disable registry scan */
4618         if (player->ini.skip_rescan) {
4619                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4620                 (*argc)++;
4621         }
4622
4623         /* check disable segtrap */
4624         if (player->ini.disable_segtrap) {
4625                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4626                 (*argc)++;
4627         }
4628
4629         LOGD("initializing gstreamer with following parameter");
4630         LOGD("argc : %d", *argc);
4631         arg_count = *argc;
4632
4633         for (i = 0; i < arg_count; i++) {
4634                 argv2[i] = argv[i];
4635                 LOGD("argv[%d] : %s", i, argv2[i]);
4636         }
4637
4638         /* initializing gstreamer */
4639         if (!gst_init_check(argc, &argv, &err)) {
4640                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4641                 if (err)
4642                         g_error_free(err);
4643
4644                 goto ERROR;
4645         }
4646         /* release */
4647         for (i = 0; i < arg_count; i++) {
4648                 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4649                 MMPLAYER_FREEIF(argv2[i]);
4650         }
4651
4652         MMPLAYER_FREEIF(argv);
4653         MMPLAYER_FREEIF(argv2);
4654         MMPLAYER_FREEIF(argc);
4655
4656         /* done */
4657         initialized = TRUE;
4658
4659         return TRUE;
4660
4661 ERROR:
4662
4663         /* release */
4664         for (i = 0; i < arg_count; i++) {
4665                 LOGD("free[%d] : %s", i, argv2[i]);
4666                 MMPLAYER_FREEIF(argv2[i]);
4667         }
4668
4669         MMPLAYER_FREEIF(argv);
4670         MMPLAYER_FREEIF(argv2);
4671         MMPLAYER_FREEIF(argc);
4672
4673         return FALSE;
4674 }
4675
4676 static void
4677 __mmplayer_check_async_state_transition(mm_player_t *player)
4678 {
4679         GstState element_state = GST_STATE_VOID_PENDING;
4680         GstState element_pending_state = GST_STATE_VOID_PENDING;
4681         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4682         GstElement *element = NULL;
4683         gboolean async = FALSE;
4684
4685         /* check player handle */
4686         MMPLAYER_RETURN_IF_FAIL(player &&
4687                                                 player->pipeline &&
4688                                                 player->pipeline->mainbin &&
4689                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4690
4691         if (player->attrs)
4692                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4693
4694         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4695                 LOGD("don't need to check the pipeline state");
4696                 return;
4697         }
4698
4699         MMPLAYER_PRINT_STATE(player);
4700
4701         /* wait for state transition */
4702         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4703         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4704
4705         if (ret == GST_STATE_CHANGE_FAILURE) {
4706                 LOGE(" [%s] state : %s   pending : %s",
4707                         GST_ELEMENT_NAME(element),
4708                         gst_element_state_get_name(element_state),
4709                         gst_element_state_get_name(element_pending_state));
4710
4711                 /* dump state of all element */
4712                 __mmplayer_dump_pipeline_state(player);
4713
4714                 return;
4715         }
4716
4717         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4718         return;
4719 }
4720
4721 int
4722 _mmplayer_destroy(MMHandleType handle)
4723 {
4724         mm_player_t *player = MM_PLAYER_CAST(handle);
4725
4726         MMPLAYER_FENTER();
4727
4728         /* check player handle */
4729         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4730
4731         /* destroy can called at anytime */
4732         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4733
4734         /* check async state transition */
4735         __mmplayer_check_async_state_transition(player);
4736
4737         /* release gapless play thread */
4738         if (player->gapless_play_thread) {
4739                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4740                 player->gapless_play_thread_exit = TRUE;
4741                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4742                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4743
4744                 LOGD("waitting for gapless play thread exit");
4745                 g_thread_join(player->gapless_play_thread);
4746                 g_mutex_clear(&player->gapless_play_thread_mutex);
4747                 g_cond_clear(&player->gapless_play_thread_cond);
4748                 LOGD("gapless play thread released");
4749         }
4750
4751         _mmplayer_release_video_capture(player);
4752
4753         /* de-initialize resource manager */
4754         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4755                         player->resource_manager))
4756                 LOGE("failed to deinitialize resource manager");
4757
4758         /* release pipeline */
4759         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4760                 LOGE("failed to destory pipeline");
4761                 return MM_ERROR_PLAYER_INTERNAL;
4762         }
4763
4764         g_queue_free(player->bus_msg_q);
4765
4766         /* release subtitle info lock and cond */
4767         g_mutex_clear(&player->subtitle_info_mutex);
4768         g_cond_clear(&player->subtitle_info_cond);
4769
4770         __mmplayer_release_dump_list(player->dump_list);
4771
4772         /* release miscellaneous information */
4773         __mmplayer_release_misc(player);
4774
4775         /* release miscellaneous information.
4776            these info needs to be released after pipeline is destroyed. */
4777         __mmplayer_release_misc_post(player);
4778
4779         /* release attributes */
4780         _mmplayer_deconstruct_attribute(handle);
4781
4782         /* release lock */
4783         g_mutex_clear(&player->fsink_lock);
4784
4785         /* release lock */
4786         g_mutex_clear(&player->update_tag_lock);
4787
4788         /* release video bo lock and cond */
4789         g_mutex_clear(&player->video_bo_mutex);
4790         g_cond_clear(&player->video_bo_cond);
4791
4792         /* release media stream callback lock */
4793         g_mutex_clear(&player->media_stream_cb_lock);
4794
4795         MMPLAYER_FLEAVE();
4796
4797         return MM_ERROR_NONE;
4798 }
4799
4800 int
4801 _mmplayer_realize(MMHandleType hplayer)
4802 {
4803         mm_player_t *player = (mm_player_t *)hplayer;
4804         char *uri = NULL;
4805         void *param = NULL;
4806         MMHandleType attrs = 0;
4807         int ret = MM_ERROR_NONE;
4808
4809         MMPLAYER_FENTER();
4810
4811         /* check player handle */
4812         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4813
4814         /* check current state */
4815         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4816
4817         attrs = MMPLAYER_GET_ATTRS(player);
4818         if (!attrs) {
4819                 LOGE("fail to get attributes.");
4820                 return MM_ERROR_PLAYER_INTERNAL;
4821         }
4822         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4823         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
4824
4825         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4826                 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4827
4828                 if (ret != MM_ERROR_NONE) {
4829                         LOGE("failed to parse profile");
4830                         return ret;
4831                 }
4832         }
4833
4834         if (uri && (strstr(uri, "es_buff://"))) {
4835                 if (strstr(uri, "es_buff://push_mode"))
4836                         player->es_player_push_mode = TRUE;
4837                 else
4838                         player->es_player_push_mode = FALSE;
4839         }
4840
4841         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4842                 LOGW("mms protocol is not supported format.");
4843                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4844         }
4845
4846         if (MMPLAYER_IS_STREAMING(player))
4847                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4848         else
4849                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4850
4851         player->smooth_streaming = FALSE;
4852         player->videodec_linked  = 0;
4853         player->audiodec_linked  = 0;
4854         player->textsink_linked = 0;
4855         player->is_external_subtitle_present = FALSE;
4856         player->is_external_subtitle_added_now = FALSE;
4857         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4858         player->video360_metadata.is_spherical = -1;
4859         player->is_openal_plugin_used = FALSE;
4860         player->demux_pad_index = 0;
4861         player->subtitle_language_list = NULL;
4862         player->is_subtitle_force_drop = FALSE;
4863
4864         __mmplayer_track_initialize(player);
4865         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4866
4867         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4868                 gint prebuffer_ms = 0, rebuffer_ms = 0;
4869
4870                 player->streamer = __mm_player_streaming_create();
4871                 __mm_player_streaming_initialize(player->streamer, TRUE);
4872
4873                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4874                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4875
4876                 if (prebuffer_ms > 0) {
4877                         prebuffer_ms = MAX(prebuffer_ms, 1000);
4878                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4879                 }
4880
4881                 if (rebuffer_ms > 0) {
4882                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4883                         rebuffer_ms = MAX(rebuffer_ms, 1000);
4884                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4885                 }
4886
4887                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4888                                                                 player->streamer->buffering_req.rebuffer_time);
4889         }
4890
4891         /* realize pipeline */
4892         ret = __mmplayer_gst_realize(player);
4893         if (ret != MM_ERROR_NONE)
4894                 LOGE("fail to realize the player.");
4895
4896         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4897
4898         MMPLAYER_FLEAVE();
4899
4900         return ret;
4901 }
4902
4903 int
4904 _mmplayer_unrealize(MMHandleType hplayer)
4905 {
4906         mm_player_t *player = (mm_player_t *)hplayer;
4907         int ret = MM_ERROR_NONE;
4908
4909         MMPLAYER_FENTER();
4910
4911         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4912
4913         MMPLAYER_CMD_UNLOCK(player);
4914         /* destroy the gst bus msg thread which is created during realize.
4915            this funct have to be called before getting cmd lock. */
4916         __mmplayer_bus_msg_thread_destroy(player);
4917         MMPLAYER_CMD_LOCK(player);
4918
4919         /* check current state */
4920         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4921
4922         /* check async state transition */
4923         __mmplayer_check_async_state_transition(player);
4924
4925         /* unrealize pipeline */
4926         ret = __mmplayer_gst_unrealize(player);
4927
4928         /* set asm stop if success */
4929         if (MM_ERROR_NONE == ret) {
4930                 if (!player->interrupted_by_resource) {
4931                         if (player->video_decoder_resource != NULL) {
4932                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4933                                                 player->video_decoder_resource);
4934                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4935                                         LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4936                                 else
4937                                         player->video_decoder_resource = NULL;
4938                         }
4939
4940                         if (player->video_overlay_resource != NULL) {
4941                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4942                                                 player->video_overlay_resource);
4943                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4944                                         LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4945                                 else
4946                                         player->video_overlay_resource = NULL;
4947                         }
4948
4949                         ret = mm_resource_manager_commit(player->resource_manager);
4950                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4951                                 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4952                 }
4953         } else
4954                 LOGE("failed and don't change asm state to stop");
4955
4956         MMPLAYER_FLEAVE();
4957
4958         return ret;
4959 }
4960
4961 int
4962 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4963 {
4964         mm_player_t *player = (mm_player_t *)hplayer;
4965
4966         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4967
4968         return __mmplayer_gst_set_message_callback(player, callback, user_param);
4969 }
4970
4971 int
4972 _mmplayer_get_state(MMHandleType hplayer, int *state)
4973 {
4974         mm_player_t *player = (mm_player_t *)hplayer;
4975
4976         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4977
4978         *state = MMPLAYER_CURRENT_STATE(player);
4979
4980         return MM_ERROR_NONE;
4981 }
4982
4983
4984 int
4985 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4986 {
4987         mm_player_t *player = (mm_player_t *)hplayer;
4988         GstElement *vol_element = NULL;
4989         int i = 0;
4990
4991         MMPLAYER_FENTER();
4992
4993         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4994
4995         LOGD("volume [L]=%f:[R]=%f",
4996                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4997
4998         /* invalid factor range or not */
4999         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5000                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5001                         LOGE("Invalid factor!(valid factor:0~1.0)");
5002                         return MM_ERROR_INVALID_ARGUMENT;
5003                 }
5004         }
5005
5006         /* not support to set other value into each channel */
5007         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5008                 return MM_ERROR_INVALID_ARGUMENT;
5009
5010         /* Save volume to handle. Currently the first array element will be saved. */
5011         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5012
5013         /* check pipeline handle */
5014         if (!player->pipeline || !player->pipeline->audiobin) {
5015                 LOGD("audiobin is not created yet");
5016                 LOGD("but, current stored volume will be set when it's created.");
5017
5018                 /* NOTE : stored volume will be used in create_audiobin
5019                  * returning MM_ERROR_NONE here makes application to able to
5020                  * set volume at anytime.
5021                  */
5022                 return MM_ERROR_NONE;
5023         }
5024
5025         /* setting volume to volume element */
5026         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5027
5028         if (vol_element) {
5029                 LOGD("volume is set [%f]", player->sound.volume);
5030                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5031         }
5032
5033         MMPLAYER_FLEAVE();
5034
5035         return MM_ERROR_NONE;
5036 }
5037
5038 int
5039 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5040 {
5041         mm_player_t *player = (mm_player_t *)hplayer;
5042         int i = 0;
5043
5044         MMPLAYER_FENTER();
5045
5046         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5048
5049         /* returning stored volume */
5050         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5051                 volume->level[i] = player->sound.volume;
5052
5053         MMPLAYER_FLEAVE();
5054
5055         return MM_ERROR_NONE;
5056 }
5057
5058 int
5059 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5060 {
5061         mm_player_t *player = (mm_player_t *)hplayer;
5062         GstElement *vol_element = NULL;
5063
5064         MMPLAYER_FENTER();
5065
5066         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067
5068         /* mute value shoud 0 or 1 */
5069         if (mute != 0 && mute != 1) {
5070                 LOGE("bad mute value");
5071
5072                 /* FIXIT : definitly, we need _BAD_PARAM error code */
5073                 return MM_ERROR_INVALID_ARGUMENT;
5074         }
5075
5076         player->sound.mute = mute;
5077
5078         /* just hold mute value if pipeline is not ready */
5079         if (!player->pipeline || !player->pipeline->audiobin) {
5080                 LOGD("pipeline is not ready. holding mute value");
5081                 return MM_ERROR_NONE;
5082         }
5083
5084         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5085
5086         /* NOTE : volume will only created when the bt is enabled */
5087         if (vol_element) {
5088                 LOGD("mute : %d", mute);
5089                 g_object_set(vol_element, "mute", mute, NULL);
5090         } else
5091                 LOGD("volume elemnet is not created. using volume in audiosink");
5092
5093         MMPLAYER_FLEAVE();
5094
5095         return MM_ERROR_NONE;
5096 }
5097
5098 int
5099 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5100 {
5101         mm_player_t *player = (mm_player_t *)hplayer;
5102
5103         MMPLAYER_FENTER();
5104
5105         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5107
5108         /* just hold mute value if pipeline is not ready */
5109         if (!player->pipeline || !player->pipeline->audiobin) {
5110                 LOGD("pipeline is not ready. returning stored value");
5111                 *pmute = player->sound.mute;
5112                 return MM_ERROR_NONE;
5113         }
5114
5115         *pmute = player->sound.mute;
5116
5117         MMPLAYER_FLEAVE();
5118
5119         return MM_ERROR_NONE;
5120 }
5121
5122 int
5123 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5124 {
5125         mm_player_t *player = (mm_player_t *)hplayer;
5126
5127         MMPLAYER_FENTER();
5128
5129         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5130
5131         player->video_stream_changed_cb = callback;
5132         player->video_stream_changed_cb_user_param = user_param;
5133         LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5134
5135         MMPLAYER_FLEAVE();
5136
5137         return MM_ERROR_NONE;
5138 }
5139
5140 int
5141 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5142 {
5143         mm_player_t *player = (mm_player_t *)hplayer;
5144
5145         MMPLAYER_FENTER();
5146
5147         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5148
5149         player->audio_stream_changed_cb = callback;
5150         player->audio_stream_changed_cb_user_param = user_param;
5151         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5152
5153         MMPLAYER_FLEAVE();
5154
5155         return MM_ERROR_NONE;
5156 }
5157
5158 int
5159 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5160 {
5161         mm_player_t *player = (mm_player_t *)hplayer;
5162
5163         MMPLAYER_FENTER();
5164
5165         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5166
5167         player->audio_stream_render_cb = callback;
5168         player->audio_stream_cb_user_param = user_param;
5169         player->audio_stream_sink_sync = sync;
5170         LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5171
5172         MMPLAYER_FLEAVE();
5173
5174         return MM_ERROR_NONE;
5175 }
5176
5177 int
5178 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5179 {
5180         mm_player_t *player = (mm_player_t *)hplayer;
5181
5182         MMPLAYER_FENTER();
5183
5184         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5185
5186         if (callback && !player->bufmgr)
5187                 player->bufmgr = tbm_bufmgr_init(-1);
5188
5189         player->set_mode.media_packet_video_stream = (callback) ? true : false;
5190         player->video_stream_cb = callback;
5191         player->video_stream_cb_user_param = user_param;
5192
5193         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5194
5195         MMPLAYER_FLEAVE();
5196
5197         return MM_ERROR_NONE;
5198 }
5199
5200 int
5201 _mmplayer_start(MMHandleType hplayer)
5202 {
5203         mm_player_t *player = (mm_player_t *)hplayer;
5204         gint ret = MM_ERROR_NONE;
5205
5206         MMPLAYER_FENTER();
5207
5208         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209
5210         /* check current state */
5211         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5212
5213         /* start pipeline */
5214         ret = __mmplayer_gst_start(player);
5215         if (ret != MM_ERROR_NONE)
5216                 LOGE("failed to start player.");
5217
5218         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5219                 LOGD("force playing start even during buffering");
5220                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5221         }
5222
5223         MMPLAYER_FLEAVE();
5224
5225         return ret;
5226 }
5227
5228 /* NOTE: post "not supported codec message" to application
5229  * when one codec is not found during AUTOPLUGGING in MSL.
5230  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5231  * And, if any codec is not found, don't send message here.
5232  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5233  */
5234 int
5235 __mmplayer_handle_missed_plugin(mm_player_t *player)
5236 {
5237         MMMessageParamType msg_param;
5238         memset(&msg_param, 0, sizeof(MMMessageParamType));
5239         gboolean post_msg_direct = FALSE;
5240
5241         MMPLAYER_FENTER();
5242
5243         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244
5245         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5246                         player->not_supported_codec, player->can_support_codec);
5247
5248         if (player->not_found_demuxer) {
5249                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5250                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5251
5252                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5253                 MMPLAYER_FREEIF(msg_param.data);
5254
5255                 return MM_ERROR_NONE;
5256         }
5257
5258         if (player->not_supported_codec) {
5259                 if (player->can_support_codec) {
5260                         // There is one codec to play
5261                         post_msg_direct = TRUE;
5262                 } else {
5263                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5264                                 post_msg_direct = TRUE;
5265                 }
5266
5267                 if (post_msg_direct) {
5268                         MMMessageParamType msg_param;
5269                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5270
5271                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5272                                 LOGW("not found AUDIO codec, posting error code to application.");
5273
5274                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5275                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5276                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5277                                 LOGW("not found VIDEO codec, posting error code to application.");
5278
5279                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5280                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5281                         }
5282
5283                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5284
5285                         MMPLAYER_FREEIF(msg_param.data);
5286
5287                         return MM_ERROR_NONE;
5288                 } else {
5289                         // no any supported codec case
5290                         LOGW("not found any codec, posting error code to application.");
5291
5292                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5293                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5294                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5295                         } else {
5296                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5297                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5298                         }
5299
5300                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5301
5302                         MMPLAYER_FREEIF(msg_param.data);
5303                 }
5304         }
5305
5306         MMPLAYER_FLEAVE();
5307
5308         return MM_ERROR_NONE;
5309 }
5310
5311 static void
5312 __mmplayer_check_pipeline(mm_player_t *player)
5313 {
5314         GstState element_state = GST_STATE_VOID_PENDING;
5315         GstState element_pending_state = GST_STATE_VOID_PENDING;
5316         gint timeout = 0;
5317         int ret = MM_ERROR_NONE;
5318
5319         if (!player->gapless.reconfigure)
5320                 return;
5321
5322         LOGW("pipeline is under construction.");
5323
5324         MMPLAYER_PLAYBACK_LOCK(player);
5325         MMPLAYER_PLAYBACK_UNLOCK(player);
5326
5327         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5328
5329         /* wait for state transition */
5330         ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5331         if (ret == GST_STATE_CHANGE_FAILURE)
5332                 LOGE("failed to change pipeline state within %d sec", timeout);
5333 }
5334
5335 /* NOTE : it should be able to call 'stop' anytime*/
5336 int
5337 _mmplayer_stop(MMHandleType hplayer)
5338 {
5339         mm_player_t *player = (mm_player_t *)hplayer;
5340         int ret = MM_ERROR_NONE;
5341
5342         MMPLAYER_FENTER();
5343
5344         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5345
5346         /* check current state */
5347         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5348
5349         /* check pipline building state */
5350         __mmplayer_check_pipeline(player);
5351         __mmplayer_reset_gapless_state(player);
5352
5353         /* NOTE : application should not wait for EOS after calling STOP */
5354         __mmplayer_cancel_eos_timer(player);
5355
5356         /* reset */
5357         player->seek_state = MMPLAYER_SEEK_NONE;
5358
5359         /* stop pipeline */
5360         ret = __mmplayer_gst_stop(player);
5361
5362         if (ret != MM_ERROR_NONE)
5363                 LOGE("failed to stop player.");
5364
5365         MMPLAYER_FLEAVE();
5366
5367         return ret;
5368 }
5369
5370 int
5371 _mmplayer_pause(MMHandleType hplayer)
5372 {
5373         mm_player_t *player = (mm_player_t *)hplayer;
5374         gint64 pos_nsec = 0;
5375         gboolean async = FALSE;
5376         gint ret = MM_ERROR_NONE;
5377
5378         MMPLAYER_FENTER();
5379
5380         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5381
5382         /* check current state */
5383         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5384
5385         /* check pipline building state */
5386         __mmplayer_check_pipeline(player);
5387
5388         switch (MMPLAYER_CURRENT_STATE(player)) {
5389         case MM_PLAYER_STATE_READY:
5390                 {
5391                         /* check prepare async or not.
5392                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5393                          */
5394                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5395                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5396
5397                         /* Changing back sync of rtspsrc to async */
5398                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5399                                 LOGD("async prepare working mode for rtsp");
5400                                 async = TRUE;
5401                         }
5402                 }
5403                 break;
5404
5405         case MM_PLAYER_STATE_PLAYING:
5406                 {
5407                         /* NOTE : store current point to overcome some bad operation
5408                         *(returning zero when getting current position in paused state) of some
5409                         * elements
5410                         */
5411                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5412                                 LOGW("getting current position failed in paused");
5413
5414                         player->last_position = pos_nsec;
5415
5416                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5417                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5418                            This causes problem is position calculation during normal pause resume scenarios also.
5419                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5420                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5421                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5422                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5423                         }
5424                 }
5425                 break;
5426         }
5427
5428         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5429                 LOGD("doing async pause in case of ms buff src");
5430                 async = TRUE;
5431         }
5432
5433         /* pause pipeline */
5434         ret = __mmplayer_gst_pause(player, async);
5435
5436         if (ret != MM_ERROR_NONE)
5437                 LOGE("failed to pause player. ret : 0x%x", ret);
5438
5439         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5440                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5441                         LOGE("failed to update display_rotation");
5442         }
5443
5444         MMPLAYER_FLEAVE();
5445
5446         return ret;
5447 }
5448
5449 /* in case of streaming, pause could take long time.*/
5450 int
5451 _mmplayer_abort_pause(MMHandleType hplayer)
5452 {
5453         mm_player_t *player = (mm_player_t *)hplayer;
5454         int ret = MM_ERROR_NONE;
5455
5456         MMPLAYER_FENTER();
5457
5458         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5459                                                 player->pipeline &&
5460                                                 player->pipeline->mainbin,
5461                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5462
5463         LOGD("set the pipeline state to READY");
5464
5465         /* set state to READY */
5466         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5467                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5468         if (ret != MM_ERROR_NONE) {
5469                 LOGE("fail to change state to READY");
5470                 return MM_ERROR_PLAYER_INTERNAL;
5471         }
5472
5473         LOGD("succeeded in changing state to READY");
5474         return ret;
5475 }
5476
5477 int
5478 _mmplayer_resume(MMHandleType hplayer)
5479 {
5480         mm_player_t *player = (mm_player_t *)hplayer;
5481         int ret = MM_ERROR_NONE;
5482         gboolean async = FALSE;
5483
5484         MMPLAYER_FENTER();
5485
5486         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5487
5488         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5489                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5490                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5491                         return ret;
5492                 }
5493
5494                 /* Changing back sync mode rtspsrc to async */
5495                 LOGD("async resume for rtsp case");
5496                 async = TRUE;
5497         }
5498
5499         /* check current state */
5500         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5501
5502         ret = __mmplayer_gst_resume(player, async);
5503         if (ret != MM_ERROR_NONE)
5504                 LOGE("failed to resume player.");
5505
5506         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5507                 LOGD("force resume even during buffering");
5508                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5509         }
5510
5511         MMPLAYER_FLEAVE();
5512
5513         return ret;
5514 }
5515
5516 int
5517 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5518 {
5519         mm_player_t *player = (mm_player_t *)hplayer;
5520         gint64 pos_nsec = 0;
5521         int ret = MM_ERROR_NONE;
5522         int mute = FALSE;
5523         signed long long start = 0, stop = 0;
5524         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5525         MMPLAYER_FENTER();
5526
5527         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5529
5530         /* The sound of video is not supported under 0.0 and over 2.0. */
5531         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5532                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5533                         mute = TRUE;
5534         }
5535         _mmplayer_set_mute(hplayer, mute);
5536
5537         if (player->playback_rate == rate)
5538                 return MM_ERROR_NONE;
5539
5540         /* If the position is reached at start potion during fast backward, EOS is posted.
5541          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5542          */
5543         player->playback_rate = rate;
5544
5545         current_state = MMPLAYER_CURRENT_STATE(player);
5546
5547         if (current_state != MM_PLAYER_STATE_PAUSED)
5548                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5549
5550         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5551
5552         if ((current_state == MM_PLAYER_STATE_PAUSED)
5553                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5554                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5555                 pos_nsec = player->last_position;
5556         }
5557
5558         if (rate >= 0) {
5559                 start = pos_nsec;
5560                 stop = GST_CLOCK_TIME_NONE;
5561         } else {
5562                 start = GST_CLOCK_TIME_NONE;
5563                 stop = pos_nsec;
5564         }
5565
5566         if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5567                                 player->playback_rate,
5568                                 GST_FORMAT_TIME,
5569                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5570                                 GST_SEEK_TYPE_SET, start,
5571                                 GST_SEEK_TYPE_SET, stop)) {
5572                 LOGE("failed to set speed playback");
5573                 return MM_ERROR_PLAYER_SEEK;
5574         }
5575
5576         LOGD("succeeded to set speed playback as %0.1f", rate);
5577
5578         MMPLAYER_FLEAVE();
5579
5580         return MM_ERROR_NONE;;
5581 }
5582
5583 int
5584 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5585 {
5586         mm_player_t *player = (mm_player_t *)hplayer;
5587         int ret = MM_ERROR_NONE;
5588
5589         MMPLAYER_FENTER();
5590
5591         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5592
5593         /* check pipline building state */
5594         __mmplayer_check_pipeline(player);
5595
5596         ret = __mmplayer_gst_set_position(player, position, FALSE);
5597
5598         MMPLAYER_FLEAVE();
5599
5600         return ret;
5601 }
5602
5603 int
5604 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5605 {
5606         mm_player_t *player = (mm_player_t *)hplayer;
5607         int ret = MM_ERROR_NONE;
5608
5609         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5610
5611         ret = __mmplayer_gst_get_position(player, position);
5612
5613         return ret;
5614 }
5615
5616 int
5617 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5618 {
5619         mm_player_t *player = (mm_player_t *)hplayer;
5620         int ret = MM_ERROR_NONE;
5621
5622         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5623         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5624
5625         if (g_strrstr(player->type, "video/mpegts"))
5626                 __mmplayer_update_duration_value(player);
5627
5628         *duration = player->duration;
5629         return ret;
5630 }
5631
5632 int
5633 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5634 {
5635         mm_player_t *player = (mm_player_t *)hplayer;
5636         int ret = MM_ERROR_NONE;
5637
5638         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5639
5640         ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5641
5642         return ret;
5643 }
5644
5645 int
5646 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5647 {
5648         mm_player_t *player = (mm_player_t *)hplayer;
5649         int ret = MM_ERROR_NONE;
5650
5651         MMPLAYER_FENTER();
5652
5653         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5654
5655         ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5656
5657         MMPLAYER_FLEAVE();
5658
5659         return ret;
5660 }
5661
5662 static gboolean
5663 __mmplayer_is_midi_type(gchar *str_caps)
5664 {
5665         if ((g_strrstr(str_caps, "audio/midi")) ||
5666                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5667                 (g_strrstr(str_caps, "application/x-smaf")) ||
5668                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5669                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5670                 (g_strrstr(str_caps, "audio/xmf")) ||
5671                 (g_strrstr(str_caps, "audio/mxmf"))) {
5672                 LOGD("midi");
5673                 return TRUE;
5674         }
5675
5676         return FALSE;
5677 }
5678
5679 static gboolean
5680 __mmplayer_is_only_mp3_type(gchar *str_caps)
5681 {
5682         if (g_strrstr(str_caps, "application/x-id3") ||
5683                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5684                 return TRUE;
5685         return FALSE;
5686 }
5687
5688 static void
5689 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5690 {
5691         GstStructure *caps_structure = NULL;
5692         gint samplerate = 0;
5693         gint channels = 0;
5694
5695         MMPLAYER_FENTER();
5696         MMPLAYER_RETURN_IF_FAIL(player && caps);
5697
5698         caps_structure = gst_caps_get_structure(caps, 0);
5699
5700         /* set stream information */
5701         gst_structure_get_int(caps_structure, "rate", &samplerate);
5702         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5703
5704         gst_structure_get_int(caps_structure, "channels", &channels);
5705         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5706
5707         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5708 }
5709
5710 static void
5711 __mmplayer_update_content_type_info(mm_player_t *player)
5712 {
5713         MMPLAYER_FENTER();
5714         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5715
5716         if (__mmplayer_is_midi_type(player->type)) {
5717                 player->bypass_audio_effect = TRUE;
5718                 return;
5719         }
5720
5721         if (!player->streamer) {
5722                 LOGD("no need to check streaming type");
5723                 return;
5724         }
5725
5726         if (g_strrstr(player->type, "application/x-hls")) {
5727                 /* If it can't know exact type when it parses uri because of redirection case,
5728                  * it will be fixed by typefinder or when doing autoplugging.
5729                  */
5730                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5731                 player->streamer->is_adaptive_streaming = TRUE;
5732         } else if (g_strrstr(player->type, "application/dash+xml")) {
5733                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5734                 player->streamer->is_adaptive_streaming = TRUE;
5735         }
5736
5737         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5738         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5739                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5740
5741                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5742                         if (player->streamer->is_adaptive_streaming)
5743                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5744                         else
5745                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5746                 }
5747         }
5748
5749         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5750         MMPLAYER_FLEAVE();
5751 }
5752
5753 void
5754 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5755         GstCaps *caps, gpointer data)
5756 {
5757         mm_player_t *player = (mm_player_t *)data;
5758         GstPad *pad = NULL;
5759
5760         MMPLAYER_FENTER();
5761
5762         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5763
5764         /* store type string */
5765         MMPLAYER_FREEIF(player->type);
5766         player->type = gst_caps_to_string(caps);
5767         if (player->type)
5768                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5769                                 player, player->type, probability, gst_caps_get_size(caps));
5770
5771         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5772                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5773                 LOGE("not support media format");
5774
5775                 if (player->msg_posted == FALSE) {
5776                         MMMessageParamType msg_param;
5777                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5778
5779                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5780                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5781
5782                         /* don't post more if one was sent already */
5783                         player->msg_posted = TRUE;
5784                 }
5785                 return;
5786         }
5787
5788         __mmplayer_update_content_type_info(player);
5789
5790         pad = gst_element_get_static_pad(tf, "src");
5791         if (!pad) {
5792                 LOGE("fail to get typefind src pad.");
5793                 return;
5794         }
5795
5796         if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5797                 gboolean async = FALSE;
5798                 LOGE("failed to autoplug %s", player->type);
5799
5800                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5801
5802                 if (async && player->msg_posted == FALSE)
5803                         __mmplayer_handle_missed_plugin(player);
5804
5805         }
5806
5807         gst_object_unref(GST_OBJECT(pad));
5808
5809         MMPLAYER_FLEAVE();
5810
5811         return;
5812 }
5813
5814 GstElement *
5815 __mmplayer_gst_make_decodebin(mm_player_t *player)
5816 {
5817         GstElement *decodebin = NULL;
5818
5819         MMPLAYER_FENTER();
5820
5821         /* create decodebin */
5822         decodebin = gst_element_factory_make("decodebin", NULL);
5823
5824         if (!decodebin) {
5825                 LOGE("fail to create decodebin");
5826                 goto ERROR;
5827         }
5828
5829         /* raw pad handling signal */
5830         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5831                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5832
5833         /* no-more-pad pad handling signal */
5834         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5835                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5836
5837         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5838                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5839
5840         /* This signal is emitted when a pad for which there is no further possible
5841            decoding is added to the decodebin.*/
5842         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5843                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5844
5845         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5846            before looking for any elements that can handle that stream.*/
5847         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5848                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5849
5850         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5851            before looking for any elements that can handle that stream.*/
5852         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5853                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5854
5855         /* This signal is emitted once decodebin has finished decoding all the data.*/
5856         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5857                                                 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5858
5859         /* This signal is emitted when a element is added to the bin.*/
5860         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5861                                                 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5862
5863 ERROR:
5864         return decodebin;
5865 }
5866
5867 static GstElement *
5868 __mmplayer_gst_make_queue2(mm_player_t *player)
5869 {
5870         GstElement *queue2 = NULL;
5871         gint64 dur_bytes = 0L;
5872         MMPlayerGstElement *mainbin = NULL;
5873         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5874
5875         MMPLAYER_FENTER();
5876         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5877
5878         mainbin = player->pipeline->mainbin;
5879
5880         queue2 = gst_element_factory_make("queue2", "queue2");
5881         if (!queue2) {
5882                 LOGE("failed to create buffering queue element");
5883                 return NULL;
5884         }
5885
5886         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5887                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5888
5889         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5890
5891         /* NOTE : in case of ts streaming, player could not get the correct duration info *
5892          *                skip the pull mode(file or ring buffering) setting. */
5893         if (dur_bytes > 0) {
5894                 if (!g_strrstr(player->type, "video/mpegts")) {
5895                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5896                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5897                 }
5898         } else {
5899                 dur_bytes = 0;
5900         }
5901
5902         __mm_player_streaming_set_queue2(player->streamer,
5903                                                                         queue2,
5904                                                                         FALSE,
5905                                                                         type,
5906                                                                         (guint64)dur_bytes); /* no meaning at the moment */
5907
5908         return queue2;
5909 }
5910
5911 gboolean
5912 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5913 {
5914         MMPlayerGstElement *mainbin = NULL;
5915         GstElement *decodebin = NULL;
5916         GstElement *queue2 = NULL;
5917         GstPad *sinkpad = NULL;
5918         GstPad *qsrcpad = NULL;
5919
5920         MMPLAYER_FENTER();
5921         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5922
5923         mainbin = player->pipeline->mainbin;
5924
5925         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5926
5927                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5928                         LOGW("need to check: muxed buffer is not null");
5929                 }
5930
5931                 queue2 = __mmplayer_gst_make_queue2(player);
5932                 if (!queue2) {
5933                         LOGE("failed to make queue2");
5934                         goto ERROR;
5935                 }
5936
5937                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5938                         LOGE("failed to add buffering queue");
5939                         goto ERROR;
5940                 }
5941
5942                 sinkpad = gst_element_get_static_pad(queue2, "sink");
5943                 qsrcpad = gst_element_get_static_pad(queue2, "src");
5944
5945                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5946                         LOGE("failed to link [%s:%s]-[%s:%s]",
5947                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5948                         goto ERROR;
5949                 }
5950
5951                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5952                         LOGE("failed to sync queue2 state with parent");
5953                         goto ERROR;
5954                 }
5955
5956                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5957                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5958
5959                 srcpad = qsrcpad;
5960
5961                 gst_object_unref(GST_OBJECT(sinkpad));
5962                 sinkpad = NULL;
5963         }
5964
5965         /* create decodebin */
5966         decodebin = __mmplayer_gst_make_decodebin(player);
5967         if (!decodebin) {
5968                 LOGE("failed to make decodebin");
5969                 goto ERROR;
5970         }
5971
5972         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5973                 LOGE("failed to add decodebin");
5974                 goto ERROR;
5975         }
5976
5977         /* to force caps on the decodebin element and avoid reparsing stuff by
5978         * typefind. It also avoids a deadlock in the way typefind activates pads in
5979         * the state change */
5980         g_object_set(decodebin, "sink-caps", caps, NULL);
5981
5982         sinkpad = gst_element_get_static_pad(decodebin, "sink");
5983
5984         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5985                 LOGE("failed to link [%s:%s]-[%s:%s]",
5986                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5987                 goto ERROR;
5988         }
5989
5990         gst_object_unref(GST_OBJECT(sinkpad));
5991         sinkpad = NULL;
5992         gst_object_unref(GST_OBJECT(qsrcpad));
5993         qsrcpad = NULL;
5994
5995         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5996         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5997
5998         /* set decodebin property about buffer in streaming playback. *
5999          * in case of HLS/DASH, it does not need to have big buffer   *
6000          * because it is kind of adaptive streaming.                  */
6001         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6002                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6003                 gint high_percent = 0;
6004
6005                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6006                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6007
6008                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6009
6010                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6011
6012                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6013                                                                                         "high-percent", high_percent,
6014                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6015                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6016                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6017         }
6018
6019         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6020                 LOGE("failed to sync decodebin state with parent");
6021                 goto ERROR;
6022         }
6023
6024         MMPLAYER_FLEAVE();
6025
6026         return TRUE;
6027
6028 ERROR:
6029
6030         if (sinkpad)
6031                 gst_object_unref(GST_OBJECT(sinkpad));
6032
6033         if (qsrcpad)
6034                 gst_object_unref(GST_OBJECT(qsrcpad));
6035
6036         if (queue2) {
6037                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6038                  * You need to explicitly set elements to the NULL state before
6039                  * dropping the final reference, to allow them to clean up.
6040                  */
6041                 gst_element_set_state(queue2, GST_STATE_NULL);
6042
6043                 /* And, it still has a parent "player".
6044                  * You need to let the parent manage the object instead of unreffing the object directly.
6045                  */
6046                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6047                 gst_object_unref(queue2);
6048                 queue2 = NULL;
6049         }
6050
6051         if (decodebin) {
6052                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6053                  * You need to explicitly set elements to the NULL state before
6054                  * dropping the final reference, to allow them to clean up.
6055                  */
6056                 gst_element_set_state(decodebin, GST_STATE_NULL);
6057
6058                 /* And, it still has a parent "player".
6059                  * You need to let the parent manage the object instead of unreffing the object directly.
6060                  */
6061
6062                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6063                 gst_object_unref(decodebin);
6064                 decodebin = NULL;
6065         }
6066
6067         return FALSE;
6068 }
6069
6070 static int
6071 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6072 {
6073         MMPLAYER_FENTER();
6074
6075         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6076         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6077
6078         LOGD("class : %s, mime : %s", factory_class, mime);
6079
6080         /* add missing plugin */
6081         /* NOTE : msl should check missing plugin for image mime type.
6082          * Some motion jpeg clips can have playable audio track.
6083          * So, msl have to play audio after displaying popup written video format not supported.
6084          */
6085         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6086                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6087                         LOGD("not found demuxer");
6088                         player->not_found_demuxer = TRUE;
6089                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6090
6091                         goto DONE;
6092                 }
6093         }
6094
6095         if (!g_strrstr(factory_class, "Demuxer")) {
6096                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6097                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6098                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6099
6100                         /* check that clip have multi tracks or not */
6101                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6102                                 LOGD("video plugin is already linked");
6103                         } else {
6104                                 LOGW("add VIDEO to missing plugin");
6105                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6106                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6107                         }
6108                 } else if (g_str_has_prefix(mime, "audio")) {
6109                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6110                                 LOGD("audio plugin is already linked");
6111                         } else {
6112                                 LOGW("add AUDIO to missing plugin");
6113                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6114                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6115                         }
6116                 }
6117         }
6118
6119 DONE:
6120         MMPLAYER_FLEAVE();
6121
6122         return MM_ERROR_NONE;
6123 }
6124
6125 static void
6126 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
6127 {
6128         mm_player_t *player = (mm_player_t *)data;
6129
6130         MMPLAYER_FENTER();
6131
6132         MMPLAYER_RETURN_IF_FAIL(player);
6133
6134         /* remove fakesink. */
6135         if (!__mmplayer_gst_remove_fakesink(player,
6136                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6137                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6138                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6139                  * source element are not same. To overcome this situation, this function will called
6140                  * several places and several times. Therefore, this is not an error case.
6141                  */
6142                 return;
6143         }
6144
6145         LOGD("[handle: %p] pipeline has completely constructed", player);
6146
6147         if ((player->ini.async_start) &&
6148                 (player->msg_posted == FALSE) &&
6149                 (player->cmd >= MMPLAYER_COMMAND_START))
6150                 __mmplayer_handle_missed_plugin(player);
6151
6152         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6153 }
6154
6155 static int
6156 __mmplayer_check_profile(void)
6157 {
6158         char *profileName;
6159         static int profile_tv = -1;
6160
6161         if (__builtin_expect(profile_tv != -1, 1))
6162                 return profile_tv;
6163
6164         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6165         switch (*profileName) {
6166         case 't':
6167         case 'T':
6168                 profile_tv = 1;
6169                 break;
6170         default:
6171                 profile_tv = 0;
6172                 break;
6173         }
6174         free(profileName);
6175
6176         return profile_tv;
6177 }
6178
6179 static gboolean
6180 __mmplayer_get_next_uri(mm_player_t *player)
6181 {
6182         MMPlayerParseProfile profile;
6183         gint uri_idx = 0;
6184         guint num_of_list = 0;
6185         char *uri = NULL;
6186
6187         num_of_list = g_list_length(player->uri_info.uri_list);
6188         uri_idx = player->uri_info.uri_idx;
6189
6190         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6191         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6192                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6193                 if (!uri) {
6194                         LOGW("next uri does not exist");
6195                         continue;
6196                 }
6197
6198                 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6199                         LOGE("failed to parse profile");
6200                         continue;
6201                 }
6202
6203                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6204                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6205                         LOGW("uri type is not supported(%d)", profile.uri_type);
6206                         continue;
6207                 }
6208
6209                 LOGD("success to find next uri %d", uri_idx);
6210                 break;
6211         }
6212
6213         if (uri_idx == num_of_list) {
6214                 LOGE("failed to find next uri");
6215                 return FALSE;
6216         }
6217
6218         player->uri_info.uri_idx = uri_idx;
6219         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6220
6221         if (mm_attrs_commit_all(player->attrs)) {
6222                 LOGE("failed to commit");
6223                 return FALSE;
6224         }
6225
6226         SECURE_LOGD("next playback uri: %s", uri);
6227         return TRUE;
6228 }
6229
6230 static gboolean
6231 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6232 {
6233 #define REPEAT_COUNT_INFINITELY -1
6234 #define REPEAT_COUNT_MIN 2
6235
6236         MMHandleType attrs = 0;
6237         gint video = 0;
6238         gint count = 0;
6239         gint gapless = 0;
6240         guint num_of_list = 0;
6241         int profile_tv = -1;
6242
6243         MMPLAYER_FENTER();
6244
6245         LOGD("checking for gapless play option");
6246
6247         if (player->pipeline->textbin) {
6248                 LOGE("subtitle path is enabled. gapless play is not supported.");
6249                 goto ERROR;
6250         }
6251
6252         attrs = MMPLAYER_GET_ATTRS(player);
6253         if (!attrs) {
6254                 LOGE("fail to get attributes.");
6255                 goto ERROR;
6256         }
6257
6258         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6259
6260         /* gapless playback is not supported in case of video at TV profile. */
6261         profile_tv = __mmplayer_check_profile();
6262         if (profile_tv && video) {
6263                 LOGW("not support video gapless playback");
6264                 goto ERROR;
6265         }
6266
6267         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6268                 LOGE("failed to get play count");
6269
6270         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6271                 LOGE("failed to get gapless mode");
6272
6273         /* check repeat count in case of audio */
6274         if (!gapless &&
6275                 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6276                 LOGW("gapless is disabled");
6277                 goto ERROR;
6278         }
6279
6280         num_of_list = g_list_length(player->uri_info.uri_list);
6281
6282         LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6283
6284         if (num_of_list == 0) {
6285                 /* audio looping path */
6286                 if (count >= REPEAT_COUNT_MIN) {
6287                         /* decrease play count */
6288                         /* we succeeded to rewind. update play count and then wait for next EOS */
6289                         count--;
6290                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6291                         /* commit attribute */
6292                         if (mm_attrs_commit_all(attrs))
6293                                 LOGE("failed to commit attribute");
6294
6295                 } else if (count != REPEAT_COUNT_INFINITELY) {
6296                         LOGD("there is no next uri and no repeat");
6297                         goto ERROR;
6298                 }
6299                 LOGD("looping cnt %d", count);
6300         } else {
6301                 /* gapless playback path */
6302                 if (!__mmplayer_get_next_uri(player)) {
6303                         LOGE("failed to get next uri");
6304                         goto ERROR;
6305                 }
6306         }
6307         return TRUE;
6308
6309 ERROR:
6310         LOGE("unable to play gapless path. EOS will be posted soon");
6311         return FALSE;
6312 }
6313
6314 static void
6315 __mmplayer_initialize_gapless_play(mm_player_t *player)
6316 {
6317         int i;
6318
6319         MMPLAYER_FENTER();
6320
6321         player->smooth_streaming = FALSE;
6322         player->videodec_linked = 0;
6323         player->audiodec_linked = 0;
6324         player->textsink_linked = 0;
6325         player->is_external_subtitle_present = FALSE;
6326         player->is_external_subtitle_added_now = FALSE;
6327         player->not_supported_codec = MISSING_PLUGIN_NONE;
6328         player->can_support_codec = FOUND_PLUGIN_NONE;
6329         player->pending_seek.is_pending = false;
6330         player->pending_seek.pos = 0;
6331         player->msg_posted = FALSE;
6332         player->has_many_types = FALSE;
6333         player->no_more_pad = FALSE;
6334         player->not_found_demuxer = 0;
6335         player->seek_state = MMPLAYER_SEEK_NONE;
6336         player->is_subtitle_force_drop = FALSE;
6337         player->play_subtitle = FALSE;
6338         player->adjust_subtitle_pos = 0;
6339
6340         player->total_bitrate = 0;
6341         player->total_maximum_bitrate = 0;
6342
6343         __mmplayer_track_initialize(player);
6344         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6345
6346         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6347                 player->bitrate[i] = 0;
6348                 player->maximum_bitrate[i] = 0;
6349         }
6350
6351         if (player->v_stream_caps) {
6352                 gst_caps_unref(player->v_stream_caps);
6353                 player->v_stream_caps = NULL;
6354         }
6355
6356         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6357
6358         /* clean found parsers */
6359         if (player->parsers) {
6360                 GList *parsers = player->parsers;
6361                 for (; parsers; parsers = g_list_next(parsers)) {
6362                         gchar *name = parsers->data;
6363                         MMPLAYER_FREEIF(name);
6364                 }
6365                 g_list_free(player->parsers);
6366                 player->parsers = NULL;
6367         }
6368
6369         /* clean found audio decoders */
6370         if (player->audio_decoders) {
6371                 GList *a_dec = player->audio_decoders;
6372                 for (; a_dec; a_dec = g_list_next(a_dec)) {
6373                         gchar *name = a_dec->data;
6374                         MMPLAYER_FREEIF(name);
6375                 }
6376                 g_list_free(player->audio_decoders);
6377                 player->audio_decoders = NULL;
6378         }
6379
6380         MMPLAYER_FLEAVE();
6381 }
6382
6383 static void
6384 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6385 {
6386         MMPlayerGstElement *mainbin = NULL;
6387         MMMessageParamType msg_param = {0,};
6388         GstElement *element = NULL;
6389         MMHandleType attrs = 0;
6390         char *uri = NULL;
6391         enum MainElementID elem_idx = MMPLAYER_M_NUM;
6392
6393         MMPLAYER_FENTER();
6394
6395         if (!player || !player->pipeline || !player->pipeline->mainbin) {
6396                 LOGE("player is not initialized");
6397                 goto ERROR;
6398         }
6399
6400         mainbin = player->pipeline->mainbin;
6401         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6402
6403         attrs = MMPLAYER_GET_ATTRS(player);
6404         if (!attrs) {
6405                 LOGE("fail to get attributes");
6406                 goto ERROR;
6407         }
6408
6409         /* Initialize Player values */
6410         __mmplayer_initialize_gapless_play(player);
6411
6412         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6413
6414         if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6415                 LOGE("failed to parse profile");
6416                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6417                 goto ERROR;
6418         }
6419
6420         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6421                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6422                 LOGE("dash or hls is not supportable");
6423                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6424                 goto ERROR;
6425         }
6426
6427         element = __mmplayer_gst_create_source(player);
6428         if (!element) {
6429                 LOGE("no source element was created");
6430                 goto ERROR;
6431         }
6432
6433         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6434                 LOGE("failed to add source element to pipeline");
6435                 gst_object_unref(GST_OBJECT(element));
6436                 element = NULL;
6437                 goto ERROR;
6438         }
6439
6440         /* take source element */
6441         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6442         mainbin[MMPLAYER_M_SRC].gst = element;
6443
6444         element = NULL;
6445
6446         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6447                 if (player->streamer == NULL) {
6448                         player->streamer = __mm_player_streaming_create();
6449                         __mm_player_streaming_initialize(player->streamer, TRUE);
6450                 }
6451
6452                 elem_idx = MMPLAYER_M_TYPEFIND;
6453                 element = gst_element_factory_make("typefind", "typefinder");
6454                 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6455                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6456         } else {
6457                 elem_idx = MMPLAYER_M_AUTOPLUG;
6458                 element = __mmplayer_gst_make_decodebin(player);
6459         }
6460
6461         /* check autoplug element is OK */
6462         if (!element) {
6463                 LOGE("can not create element(%d)", elem_idx);
6464                 goto ERROR;
6465         }
6466
6467         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6468                 LOGE("failed to add sinkbin to pipeline");
6469                 gst_object_unref(GST_OBJECT(element));
6470                 element = NULL;
6471                 goto ERROR;
6472         }
6473
6474         mainbin[elem_idx].id = elem_idx;
6475         mainbin[elem_idx].gst = element;
6476
6477         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6478                 LOGE("Failed to link src - autoplug(or typefind)");
6479                 goto ERROR;
6480         }
6481
6482         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6483                 LOGE("Failed to change state of src element");
6484                 goto ERROR;
6485         }
6486
6487         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6488                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6489                         LOGE("Failed to change state of decodebin");
6490                         goto ERROR;
6491                 }
6492         } else {
6493                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6494                         LOGE("Failed to change state of src element");
6495                         goto ERROR;
6496                 }
6497         }
6498
6499         player->gapless.stream_changed = TRUE;
6500         player->gapless.running = TRUE;
6501         MMPLAYER_FLEAVE();
6502         return;
6503
6504 ERROR:
6505         if (player) {
6506                 MMPLAYER_PLAYBACK_UNLOCK(player);
6507
6508                 if (!player->msg_posted) {
6509                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6510                         player->msg_posted = TRUE;
6511                 }
6512         }
6513         return;
6514 }
6515
6516 static gboolean
6517 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6518 {
6519         mm_player_selector_t *selector = &player->selector[type];
6520         MMPlayerGstElement *sinkbin = NULL;
6521         enum MainElementID selectorId = MMPLAYER_M_NUM;
6522         enum MainElementID sinkId = MMPLAYER_M_NUM;
6523         GstPad *srcpad = NULL;
6524         GstPad *sinkpad = NULL;
6525         gboolean send_notice = FALSE;
6526
6527         MMPLAYER_FENTER();
6528         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6529
6530         LOGD("type %d", type);
6531
6532         switch (type) {
6533         case MM_PLAYER_TRACK_TYPE_AUDIO:
6534                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6535                 sinkId = MMPLAYER_A_BIN;
6536                 sinkbin = player->pipeline->audiobin;
6537                 break;
6538         case MM_PLAYER_TRACK_TYPE_VIDEO:
6539                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6540                 sinkId = MMPLAYER_V_BIN;
6541                 sinkbin = player->pipeline->videobin;
6542                 send_notice = TRUE;
6543                 break;
6544         case MM_PLAYER_TRACK_TYPE_TEXT:
6545                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6546                 sinkId = MMPLAYER_T_BIN;
6547                 sinkbin = player->pipeline->textbin;
6548                 break;
6549         default:
6550                 LOGE("requested type is not supportable");
6551                 return FALSE;
6552                 break;
6553         }
6554
6555         if (player->pipeline->mainbin[selectorId].gst) {
6556                 gint n;
6557
6558                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6559
6560                 if (selector->event_probe_id != 0)
6561                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6562                 selector->event_probe_id = 0;
6563
6564                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6565                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6566
6567                         if (srcpad && sinkpad) {
6568                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6569                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6570                                 gst_pad_unlink(srcpad, sinkpad);
6571
6572                                 /* send custom event to sink pad to handle it at video sink */
6573                                 if (send_notice) {
6574                                         LOGD("send custom event to sinkpad");
6575                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6576                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6577                                         gst_pad_send_event(sinkpad, event);
6578                                 }
6579                         }
6580
6581                         gst_object_unref(sinkpad);
6582                         sinkpad = NULL;
6583                 }
6584                 gst_object_unref(srcpad);
6585                 srcpad = NULL;
6586
6587                 LOGD("selector release");
6588
6589                 /* release and unref requests pad from the selector */
6590                 for (n = 0; n < selector->channels->len; n++) {
6591                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6592                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6593                 }
6594                 g_ptr_array_set_size(selector->channels, 0);
6595
6596                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6597                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6598
6599                 player->pipeline->mainbin[selectorId].gst = NULL;
6600                 selector = NULL;
6601         }
6602
6603         return TRUE;
6604 }
6605
6606 static void
6607 __mmplayer_deactivate_old_path(mm_player_t *player)
6608 {
6609         MMPLAYER_FENTER();
6610         MMPLAYER_RETURN_IF_FAIL(player);
6611
6612         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6613                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6614                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6615                 LOGE("deactivate selector error");
6616                 goto ERROR;
6617         }
6618
6619         __mmplayer_track_destroy(player);
6620         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6621
6622         if (player->streamer) {
6623                 __mm_player_streaming_initialize(player->streamer, FALSE);
6624                 __mm_player_streaming_destroy(player->streamer);
6625                 player->streamer = NULL;
6626         }
6627
6628         MMPLAYER_PLAYBACK_LOCK(player);
6629         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6630
6631         MMPLAYER_FLEAVE();
6632         return;
6633
6634 ERROR:
6635
6636         if (!player->msg_posted) {
6637                 MMMessageParamType msg = {0,};
6638
6639                 /*post error*/
6640                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6641                 LOGE("gapless_uri_play> deactivate error");
6642
6643                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6644                 player->msg_posted = TRUE;
6645         }
6646         return;
6647 }
6648
6649 int
6650 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6651 {
6652         int result = MM_ERROR_NONE;
6653         mm_player_t *player = (mm_player_t *)hplayer;
6654         MMPLAYER_FENTER();
6655
6656         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6657
6658         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6659         if (mm_attrs_commit_all(player->attrs)) {
6660                 LOGE("failed to commit the original uri.");
6661                 result = MM_ERROR_PLAYER_INTERNAL;
6662         } else {
6663                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6664                         LOGE("failed to add the original uri in the uri list.");
6665         }
6666
6667         MMPLAYER_FLEAVE();
6668         return result;
6669 }
6670
6671 int
6672 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6673 {
6674         mm_player_t *player = (mm_player_t *)hplayer;
6675         guint num_of_list = 0;
6676
6677         MMPLAYER_FENTER();
6678
6679         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6680         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6681
6682         if (player->pipeline && player->pipeline->textbin) {
6683                 LOGE("subtitle path is enabled.");
6684                 return MM_ERROR_PLAYER_INVALID_STATE;
6685         }
6686
6687         num_of_list = g_list_length(player->uri_info.uri_list);
6688
6689         if (is_first_path) {
6690                 if (num_of_list == 0) {
6691                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6692                         LOGD("add original path : %s", uri);
6693                 } else {
6694                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6695                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6696
6697                         LOGD("change original path : %s", uri);
6698                 }
6699         } else {
6700                 MMHandleType attrs = 0;
6701                 attrs = MMPLAYER_GET_ATTRS(player);
6702
6703                 if (num_of_list == 0) {
6704                         char *original_uri = NULL;
6705
6706                         if (attrs) {
6707                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6708
6709                                 if (!original_uri) {
6710                                         LOGE("there is no original uri.");
6711                                         return MM_ERROR_PLAYER_INVALID_STATE;
6712                                 }
6713
6714                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6715                                 player->uri_info.uri_idx = 0;
6716
6717                                 LOGD("add original path at first : %s", original_uri);
6718                         }
6719                 }
6720
6721                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6722                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6723         }
6724
6725         MMPLAYER_FLEAVE();
6726         return MM_ERROR_NONE;
6727 }
6728
6729 int
6730 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6731 {
6732         mm_player_t *player = (mm_player_t *)hplayer;
6733         char *next_uri = NULL;
6734         guint num_of_list = 0;
6735
6736         MMPLAYER_FENTER();
6737         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6738
6739         num_of_list = g_list_length(player->uri_info.uri_list);
6740
6741         if (num_of_list > 0) {
6742                 gint uri_idx = player->uri_info.uri_idx;
6743
6744                 if (uri_idx < num_of_list-1)
6745                         uri_idx++;
6746                 else
6747                         uri_idx = 0;
6748
6749                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6750                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6751
6752                 *uri = g_strdup(next_uri);
6753         }
6754
6755         MMPLAYER_FLEAVE();
6756         return MM_ERROR_NONE;
6757 }
6758
6759 static void
6760 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad,
6761         GstCaps *caps, gpointer data)
6762 {
6763         mm_player_t *player = (mm_player_t *)data;
6764         const gchar *klass = NULL;
6765         const gchar *mime = NULL;
6766         gchar *caps_str = NULL;
6767
6768         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6769         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6770         caps_str = gst_caps_to_string(caps);
6771
6772         LOGW("unknown type of caps : %s from %s",
6773                                         caps_str, GST_ELEMENT_NAME(elem));
6774
6775         MMPLAYER_FREEIF(caps_str);
6776
6777         /* There is no available codec. */
6778         __mmplayer_check_not_supported_codec(player, klass, mime);
6779 }
6780
6781 static gboolean
6782 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
6783         GstCaps *caps,  gpointer data)
6784 {
6785         mm_player_t *player = (mm_player_t *)data;
6786         const char *mime = NULL;
6787         gboolean ret = TRUE;
6788
6789         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6790         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6791
6792         if (g_str_has_prefix(mime, "audio")) {
6793                 GstStructure *caps_structure = NULL;
6794                 gint samplerate = 0;
6795                 gint channels = 0;
6796                 gchar *caps_str = NULL;
6797
6798                 caps_structure = gst_caps_get_structure(caps, 0);
6799                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6800                 gst_structure_get_int(caps_structure, "channels", &channels);
6801
6802                 if ((channels > 0 && samplerate == 0)) {
6803                         LOGD("exclude audio...");
6804                         ret = FALSE;
6805                 }
6806
6807                 caps_str = gst_caps_to_string(caps);
6808                 /* set it directly because not sent by TAG */
6809                 if (g_strrstr(caps_str, "mobile-xmf"))
6810                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6811                 MMPLAYER_FREEIF(caps_str);
6812         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6813                 MMMessageParamType msg_param;
6814                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6815                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6816                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6817                 LOGD("video file is not supported on this device");
6818                 ret = FALSE;
6819         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6820                 LOGD("already video linked");
6821                 ret = FALSE;
6822         } else {
6823                 LOGD("found new stream");
6824         }
6825
6826         return ret;
6827 }
6828
6829 static gboolean
6830 __mmplayer_is_audio_offload_device_type(mm_player_t *player)
6831 {
6832         gboolean ret = TRUE;
6833         GDBusConnection *conn = NULL;
6834         GError *err = NULL;
6835         GVariant *result = NULL;
6836         const gchar *dbus_device_type = NULL;
6837         const gchar *dbus_ret = NULL;
6838         gint idx = 0;
6839
6840         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6841         if (!conn || err) {
6842                 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6843                 g_error_free(err);
6844                 ret = FALSE;
6845                 goto DONE;
6846         }
6847
6848         result = g_dbus_connection_call_sync(conn,
6849                                         "org.pulseaudio.Server",
6850                                         "/org/pulseaudio/StreamManager",
6851                                         "org.pulseaudio.StreamManager",
6852                                         "GetCurrentMediaRoutingPath",
6853                                         g_variant_new("(s)", "out"),
6854                                         G_VARIANT_TYPE("(ss)"),
6855                                         G_DBUS_CALL_FLAGS_NONE,
6856                                         2000,
6857                                         NULL,
6858                                         &err);
6859         if (!result || err) {
6860                 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6861                 g_error_free(err);
6862                 ret = FALSE;
6863                 goto DONE;
6864         }
6865
6866         /* device type is listed in stream-map.json at mmfw-sysconf */
6867         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6868
6869         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6870         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6871                 ret = FALSE;
6872                 goto DONE;
6873         }
6874
6875         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6876         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6877                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6878                         LOGD("audio offload is supportable");
6879                         ret = TRUE;
6880                         goto DONE;
6881                 }
6882         }
6883
6884         LOGD("audio offload is not supportable");
6885         ret = FALSE;
6886
6887 DONE:
6888         g_variant_unref(result);
6889         g_object_unref(conn);
6890
6891         return ret;
6892 }
6893
6894 static void __mmplayer_rebuild_audio_pipeline(mm_player_t *player)
6895 {
6896         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6897         gint64 position = 0;
6898
6899         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6900                 player->pipeline && player->pipeline->mainbin);
6901
6902         MMPLAYER_CMD_LOCK(player);
6903         current_state = MMPLAYER_CURRENT_STATE(player);
6904
6905         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6906                 LOGW("getting current position failed in paused");
6907
6908         _mmplayer_unrealize((MMHandleType)player);
6909         _mmplayer_realize((MMHandleType)player);
6910
6911         _mmplayer_set_position((MMHandleType)player, position);
6912
6913         /* async not to be blocked in streaming case */
6914         mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6915         if (mm_attrs_commit_all(player->attrs))
6916                 LOGE("failed to commit");
6917
6918         _mmplayer_pause((MMHandleType)player);
6919
6920         if (current_state == MM_PLAYER_STATE_PLAYING)
6921                 _mmplayer_start((MMHandleType)player);
6922         MMPLAYER_CMD_UNLOCK(player);
6923
6924         LOGD("rebuilding audio pipeline is completed.");
6925 }
6926
6927 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6928 {
6929         mm_player_t *player = (mm_player_t *)user_data;
6930         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6931         gboolean is_supportable = FALSE;
6932
6933         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6934                 LOGW("failed to get device type");
6935         else
6936                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6937
6938         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6939                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6940                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6941                 LOGD("ignore this dev connected info");
6942                 return;
6943         }
6944
6945         is_supportable = __mmplayer_is_audio_offload_device_type(player);
6946         if (player->build_audio_offload == is_supportable) {
6947                 LOGD("keep current pipeline without re-building");
6948                 return;
6949         }
6950
6951         /* rebuild pipeline */
6952         LOGD("re-build pipeline - offload: %d", is_supportable);
6953         player->build_audio_offload = FALSE;
6954         __mmplayer_rebuild_audio_pipeline(player);
6955
6956         return;
6957 }
6958
6959 static gboolean
6960 __mmplayer_add_audio_device_connected_cb(mm_player_t *player)
6961 {
6962         unsigned int id = 0;
6963
6964         if (player->audio_device_cb_id != 0) {
6965                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6966                 return TRUE;
6967         }
6968
6969         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6970                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6971                 LOGD("added device connected cb (%u)", id);
6972                 player->audio_device_cb_id = id;
6973         } else {
6974                 LOGW("failed to add device connected cb");
6975                 return FALSE;
6976         }
6977
6978         return TRUE;
6979 }
6980
6981 static gboolean
6982 __mmplayer_can_build_audio_offload_path(mm_player_t *player)
6983 {
6984         gboolean ret = FALSE;
6985         GstElementFactory *factory = NULL;
6986
6987         MMPLAYER_FENTER();
6988         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6989
6990         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6991         if (!__mmplayer_is_only_mp3_type(player->type))
6992                 goto DONE;
6993
6994         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6995                 LOGD("there is no audio offload sink");
6996                 goto DONE;
6997         }
6998
6999         if (player->ini.audio_offload_device_type[0][0] == '\0') {
7000                 LOGW("there is no audio device type to support offload");
7001                 goto DONE;
7002         }
7003
7004         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7005         if (!factory) {
7006                 LOGW("there is no installed audio offload sink element");
7007                 goto DONE;
7008         }
7009         gst_object_unref(factory);
7010
7011         if (!__mmplayer_add_audio_device_connected_cb(player))
7012                 goto DONE;
7013
7014         if (!__mmplayer_is_audio_offload_device_type(player))
7015                 goto DONE;
7016
7017         LOGD("audio offload can be built");
7018         ret = TRUE;
7019
7020 DONE:
7021         MMPLAYER_FLEAVE();
7022         return ret;
7023 }
7024
7025 static GstAutoplugSelectResult
7026 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
7027 {
7028         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7029         int idx = 0;
7030         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7031         int audio_offload = 0;
7032
7033         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7034                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7035
7036                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7037                         LOGD("expose audio path to build offload output path");
7038                         player->build_audio_offload = TRUE;
7039                         /* update codec info */
7040                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7041                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7042                         player->audiodec_linked = 1;
7043
7044                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7045                         goto DONE;
7046                 }
7047
7048                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7049
7050                 LOGD("audio codec type: %d", codec_type);
7051                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7052                         /* sw codec will be skipped */
7053                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7054                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7055                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7056                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7057                                         goto DONE;
7058                                 }
7059                         }
7060                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7061                         /* hw codec will be skipped */
7062                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
7063                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7064                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7065                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7066                                 goto DONE;
7067                         }
7068                 }
7069
7070                 /* set stream information */
7071                 if (!player->audiodec_linked)
7072                         __mmplayer_set_audio_attrs(player, caps);
7073
7074                 /* update codec info */
7075                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7076                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7077                 player->audiodec_linked = 1;
7078
7079         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7080
7081                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7082
7083                 LOGD("video codec type: %d", codec_type);
7084                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7085                         /* sw codec is skipped */
7086                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7087                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7088                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7089                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7090                                         goto DONE;
7091                                 }
7092                         }
7093                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7094                         /* hw codec is skipped */
7095                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7096                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7097                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7098                                 goto DONE;
7099                         }
7100                 }
7101
7102                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7103                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7104
7105                         /* mark video decoder for acquire */
7106                         if (player->video_decoder_resource == NULL) {
7107                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7108                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7109                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7110                                                 &player->video_decoder_resource)
7111                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7112                                         LOGE("could not mark video_decoder resource for acquire");
7113                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7114                                         goto DONE;
7115                                 }
7116                         } else {
7117                                 LOGW("video decoder resource is already acquired, skip it.");
7118                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7119                                 goto DONE;
7120                         }
7121
7122                         player->interrupted_by_resource = FALSE;
7123                         /* acquire resources for video playing */
7124                         if (mm_resource_manager_commit(player->resource_manager)
7125                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7126                                 LOGE("could not acquire resources for video decoding");
7127                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7128                                 goto DONE;
7129                         }
7130                 }
7131
7132                 /* update codec info */
7133                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7134                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7135                 player->videodec_linked = 1;
7136         }
7137
7138 DONE:
7139         return ret;
7140 }
7141
7142 gint
7143 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7144         GstCaps *caps, GstElementFactory *factory, gpointer data)
7145 {
7146         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7147         mm_player_t *player = (mm_player_t *)data;
7148
7149         gchar *factory_name = NULL;
7150         gchar *caps_str = NULL;
7151         const gchar *klass = NULL;
7152         gint idx = 0;
7153
7154         factory_name = GST_OBJECT_NAME(factory);
7155         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7156         caps_str = gst_caps_to_string(caps);
7157
7158         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7159
7160         /* store type string */
7161         if (player->type == NULL) {
7162                 player->type = gst_caps_to_string(caps);
7163                 __mmplayer_update_content_type_info(player);
7164         }
7165
7166         /* filtering exclude keyword */
7167         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7168                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7169                         LOGW("skipping [%s] by exculde keyword [%s]",
7170                                         factory_name, player->ini.exclude_element_keyword[idx]);
7171
7172                         result = GST_AUTOPLUG_SELECT_SKIP;
7173                         goto DONE;
7174                 }
7175         }
7176
7177         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7178                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7179                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7180                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7181                         result = GST_AUTOPLUG_SELECT_SKIP;
7182                         goto DONE;
7183                 }
7184         }
7185
7186         /* exclude webm format */
7187         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7188          * because webm format is not supportable.
7189          * If webm is disabled in "autoplug-continue", there is no state change
7190          * failure or error because the decodebin will expose the pad directly.
7191          * It make MSL invoke _prepare_async_callback.
7192          * So, we need to disable webm format in "autoplug-select" */
7193         if (caps_str && strstr(caps_str, "webm")) {
7194                 LOGW("webm is not supported");
7195                 result = GST_AUTOPLUG_SELECT_SKIP;
7196                 goto DONE;
7197         }
7198
7199         /* check factory class for filtering */
7200         /* NOTE : msl don't need to use image plugins.
7201          * So, those plugins should be skipped for error handling.
7202          */
7203         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7204                 LOGD("skipping [%s] by not required", factory_name);
7205                 result = GST_AUTOPLUG_SELECT_SKIP;
7206                 goto DONE;
7207         }
7208
7209         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7210                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7211                 // TO CHECK : subtitle if needed, add subparse exception.
7212                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7213                 result = GST_AUTOPLUG_SELECT_SKIP;
7214                 goto DONE;
7215         }
7216
7217         if (g_strrstr(factory_name, "mpegpsdemux")) {
7218                 LOGD("skipping PS container - not support");
7219                 result = GST_AUTOPLUG_SELECT_SKIP;
7220                 goto DONE;
7221         }
7222
7223         if (g_strrstr(factory_name, "mssdemux"))
7224                 player->smooth_streaming = TRUE;
7225
7226         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7227                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7228                 gint stype = 0;
7229                 gint width = 0;
7230                 GstStructure *str = NULL;
7231                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7232
7233                 /* don't make video because of not required */
7234                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7235                         (!player->set_mode.media_packet_video_stream)) {
7236                         LOGD("no need video decoding, expose pad");
7237                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7238                         goto DONE;
7239                 }
7240
7241                 /* get w/h for omx state-tune */
7242                 /* FIXME: deprecated? */
7243                 str = gst_caps_get_structure(caps, 0);
7244                 gst_structure_get_int(str, "width", &width);
7245
7246                 if (width != 0) {
7247                         if (player->v_stream_caps) {
7248                                 gst_caps_unref(player->v_stream_caps);
7249                                 player->v_stream_caps = NULL;
7250                         }
7251
7252                         player->v_stream_caps = gst_caps_copy(caps);
7253                         LOGD("take caps for video state tune");
7254                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7255                 }
7256         }
7257
7258         if (g_strrstr(klass, "Codec/Decoder")) {
7259                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7260                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7261                         LOGW("skip add decoder");
7262                         goto DONE;
7263                 }
7264         }
7265
7266 DONE:
7267         MMPLAYER_FREEIF(caps_str);
7268
7269         return result;
7270 }
7271
7272 static void
7273 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad,
7274         gpointer data)
7275 {
7276         //mm_player_t *player = (mm_player_t *)data;
7277         GstCaps *caps = NULL;
7278
7279         LOGD("[Decodebin2] pad-removed signal");
7280
7281         caps = gst_pad_query_caps(new_pad, NULL);
7282         if (!caps) {
7283                 LOGW("query caps is NULL");
7284                 return;
7285         }
7286
7287         gchar *caps_str = NULL;
7288         caps_str = gst_caps_to_string(caps);
7289
7290         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7291
7292         MMPLAYER_FREEIF(caps_str);
7293         gst_caps_unref(caps);
7294 }
7295
7296 static void
7297 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7298 {
7299         mm_player_t *player = (mm_player_t *)data;
7300         GstIterator *iter = NULL;
7301         GValue item = { 0, };
7302         GstPad *pad = NULL;
7303         gboolean done = FALSE;
7304         gboolean is_all_drained = TRUE;
7305
7306         MMPLAYER_FENTER();
7307         MMPLAYER_RETURN_IF_FAIL(player);
7308
7309         LOGD("__mmplayer_gst_decode_drained");
7310
7311         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7312                 LOGW("Fail to get cmd lock");
7313                 return;
7314         }
7315
7316         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7317                 !__mmplayer_verify_gapless_play_path(player)) {
7318                 LOGD("decoding is finished.");
7319                 __mmplayer_reset_gapless_state(player);
7320                 MMPLAYER_CMD_UNLOCK(player);
7321                 return;
7322         }
7323
7324         player->gapless.reconfigure = TRUE;
7325
7326         /* check decodebin src pads whether they received EOS or not */
7327         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7328
7329         while (!done) {
7330                 switch (gst_iterator_next(iter, &item)) {
7331                 case GST_ITERATOR_OK:
7332                         pad = g_value_get_object(&item);
7333                         if (pad && !GST_PAD_IS_EOS(pad)) {
7334                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7335                                 is_all_drained = FALSE;
7336                                 break;
7337                         }
7338                         g_value_reset(&item);
7339                         break;
7340                 case GST_ITERATOR_RESYNC:
7341                         gst_iterator_resync(iter);
7342                         break;
7343                 case GST_ITERATOR_ERROR:
7344                 case GST_ITERATOR_DONE:
7345                         done = TRUE;
7346                         break;
7347                 }
7348         }
7349         g_value_unset(&item);
7350         gst_iterator_free(iter);
7351
7352         if (!is_all_drained) {
7353                 LOGD("Wait util the all pads get EOS.");
7354                 MMPLAYER_CMD_UNLOCK(player);
7355                 MMPLAYER_FLEAVE();
7356                 return;
7357         }
7358
7359         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7360         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7361
7362         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7363         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7364         __mmplayer_deactivate_old_path(player);
7365         MMPLAYER_CMD_UNLOCK(player);
7366
7367         MMPLAYER_FLEAVE();
7368 }
7369
7370 void
7371 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7372 {
7373         mm_player_t *player = (mm_player_t *)data;
7374         const gchar *klass = NULL;
7375         gchar *factory_name = NULL;
7376
7377         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7378         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7379
7380         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7381
7382         if (__mmplayer_add_dump_buffer_probe(player, element))
7383                 LOGD("add buffer probe");
7384
7385         //<-
7386         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7387                 gchar *selected = NULL;
7388                 selected = g_strdup(GST_ELEMENT_NAME(element));
7389                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7390         }
7391         //-> temp code
7392
7393         if (g_strrstr(klass, "Parser")) {
7394                 gchar *selected = NULL;
7395
7396                 selected = g_strdup(factory_name);
7397                 player->parsers = g_list_append(player->parsers, selected);
7398         }
7399
7400         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7401                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7402                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7403
7404                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7405                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7406
7407                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7408                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7409                                                 "max-video-width", player->adaptive_info.limit.width,
7410                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7411
7412         } else if (g_strrstr(klass, "Demuxer")) {
7413                 //LOGD("plugged element is demuxer. take it");
7414                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7415                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7416         }
7417
7418         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7419                 int surface_type = 0;
7420
7421                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7422         }
7423
7424         // to support trust-zone only
7425         if (g_strrstr(factory_name, "asfdemux")) {
7426                 LOGD("set file-location %s", player->profile.uri);
7427                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7428         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7429                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7430                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7431         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7432                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7433                         (__mmplayer_is_only_mp3_type(player->type))) {
7434                         LOGD("[mpegaudioparse] set streaming pull mode.");
7435                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7436                 }
7437         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7438                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7439         }
7440
7441         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7442                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7443                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7444
7445                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7446                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7447
7448                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7449                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7450                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7451                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7452                         __mm_player_streaming_set_multiqueue(player->streamer, element);
7453                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7454                 }
7455
7456         }
7457
7458         return;
7459 }
7460
7461 static void
7462 __mmplayer_release_misc(mm_player_t *player)
7463 {
7464         int i;
7465         bool cur_mode = player->set_mode.rich_audio;
7466         MMPLAYER_FENTER();
7467
7468         MMPLAYER_RETURN_IF_FAIL(player);
7469
7470         player->video_stream_cb = NULL;
7471         player->video_stream_cb_user_param = NULL;
7472         player->video_stream_prerolled = false;
7473
7474         player->audio_stream_render_cb = NULL;
7475         player->audio_stream_cb_user_param = NULL;
7476         player->audio_stream_sink_sync = false;
7477
7478         player->video_stream_changed_cb = NULL;
7479         player->video_stream_changed_cb_user_param = NULL;
7480
7481         player->audio_stream_changed_cb = NULL;
7482         player->audio_stream_changed_cb_user_param = NULL;
7483
7484         player->sent_bos = FALSE;
7485         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7486
7487         player->seek_state = MMPLAYER_SEEK_NONE;
7488
7489         player->total_bitrate = 0;
7490         player->total_maximum_bitrate = 0;
7491
7492         player->not_found_demuxer = 0;
7493
7494         player->last_position = 0;
7495         player->duration = 0;
7496         player->http_content_size = 0;
7497         player->not_supported_codec = MISSING_PLUGIN_NONE;
7498         player->can_support_codec = FOUND_PLUGIN_NONE;
7499         player->pending_seek.is_pending = false;
7500         player->pending_seek.pos = 0;
7501         player->msg_posted = FALSE;
7502         player->has_many_types = FALSE;
7503         player->is_subtitle_force_drop = FALSE;
7504         player->play_subtitle = FALSE;
7505         player->adjust_subtitle_pos = 0;
7506         player->has_closed_caption = FALSE;
7507         player->set_mode.media_packet_video_stream = false;
7508         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7509         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7510         /* recover mode */
7511         player->set_mode.rich_audio = cur_mode;
7512
7513         if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7514                 LOGW("failed to remove audio device_connected_callback");
7515         player->audio_device_cb_id = 0;
7516
7517         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7518                 player->bitrate[i] = 0;
7519                 player->maximum_bitrate[i] = 0;
7520         }
7521
7522         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7523
7524         /* remove media stream cb(appsrc cb) */
7525         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7526                 player->media_stream_buffer_status_cb[i] = NULL;
7527                 player->media_stream_seek_data_cb[i] = NULL;
7528                 player->buffer_cb_user_param[i] = NULL;
7529                 player->seek_cb_user_param[i] = NULL;
7530         }
7531         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7532
7533         /* free memory related to audio effect */
7534         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7535
7536         if (player->adaptive_info.var_list) {
7537                 g_list_free_full(player->adaptive_info.var_list, g_free);
7538                 player->adaptive_info.var_list = NULL;
7539         }
7540
7541         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7542         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7543         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7544
7545         /* Reset video360 settings to their defaults in case if the pipeline is to be
7546          * re-created.
7547          * */
7548         player->video360_metadata.is_spherical = -1;
7549         player->is_openal_plugin_used = FALSE;
7550
7551         player->is_content_spherical = FALSE;
7552         player->is_video360_enabled = TRUE;
7553         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7554         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7555         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7556         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7557         player->video360_zoom = 1.0f;
7558         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7559         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7560
7561         player->sound.rg_enable = false;
7562
7563         __mmplayer_initialize_video_roi(player);
7564         MMPLAYER_FLEAVE();
7565 }
7566
7567 static void
7568 __mmplayer_release_misc_post(mm_player_t *player)
7569 {
7570         char *original_uri = NULL;
7571         MMPLAYER_FENTER();
7572
7573         /* player->pipeline is already released before. */
7574
7575         MMPLAYER_RETURN_IF_FAIL(player);
7576
7577         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7578
7579         /* clean found parsers */
7580         if (player->parsers) {
7581                 GList *parsers = player->parsers;
7582                 for (; parsers; parsers = g_list_next(parsers)) {
7583                         gchar *name = parsers->data;
7584                         MMPLAYER_FREEIF(name);
7585                 }
7586                 g_list_free(player->parsers);
7587                 player->parsers = NULL;
7588         }
7589
7590         /* clean found audio decoders */
7591         if (player->audio_decoders) {
7592                 GList *a_dec = player->audio_decoders;
7593                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7594                         gchar *name = a_dec->data;
7595                         MMPLAYER_FREEIF(name);
7596                 }
7597                 g_list_free(player->audio_decoders);
7598                 player->audio_decoders = NULL;
7599         }
7600
7601         /* clean the uri list except original uri */
7602         if (player->uri_info.uri_list) {
7603                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7604
7605                 if (player->attrs) {
7606                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7607                         LOGD("restore original uri = %s", original_uri);
7608
7609                         if (mm_attrs_commit_all(player->attrs))
7610                                 LOGE("failed to commit the original uri.");
7611                 }
7612
7613                 GList *uri_list = player->uri_info.uri_list;
7614                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7615                         gchar *uri = uri_list->data;
7616                         MMPLAYER_FREEIF(uri);
7617                 }
7618                 g_list_free(player->uri_info.uri_list);
7619                 player->uri_info.uri_list = NULL;
7620         }
7621
7622         /* clear the audio stream buffer list */
7623         __mmplayer_audio_stream_clear_buffer(player, FALSE);
7624
7625         /* clear the video stream bo list */
7626         __mmplayer_video_stream_destroy_bo_list(player);
7627         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7628
7629         if (player->profile.input_mem.buf) {
7630                 free(player->profile.input_mem.buf);
7631                 player->profile.input_mem.buf = NULL;
7632         }
7633         player->profile.input_mem.len = 0;
7634         player->profile.input_mem.offset = 0;
7635
7636         player->uri_info.uri_idx = 0;
7637         MMPLAYER_FLEAVE();
7638 }
7639
7640 gboolean
7641 __mmplayer_check_subtitle(mm_player_t *player)
7642 {
7643         MMHandleType attrs = 0;
7644         char *subtitle_uri = NULL;
7645
7646         MMPLAYER_FENTER();
7647
7648         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7649
7650         /* get subtitle attribute */
7651         attrs = MMPLAYER_GET_ATTRS(player);
7652         if (!attrs)
7653                 return FALSE;
7654
7655         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7656         if (!subtitle_uri || !strlen(subtitle_uri))
7657                 return FALSE;
7658
7659         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7660         player->is_external_subtitle_present = TRUE;
7661
7662         MMPLAYER_FLEAVE();
7663
7664         return TRUE;
7665 }
7666
7667 void
7668 __mmplayer_cancel_eos_timer(mm_player_t *player)
7669 {
7670         MMPLAYER_RETURN_IF_FAIL(player);
7671
7672         if (player->eos_timer) {
7673                 LOGD("cancel eos timer");
7674                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7675                 player->eos_timer = 0;
7676         }
7677
7678         return;
7679 }
7680
7681 static void
7682 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7683 {
7684         MMPLAYER_FENTER();
7685
7686         MMPLAYER_RETURN_IF_FAIL(player);
7687         MMPLAYER_RETURN_IF_FAIL(sink);
7688
7689         player->sink_elements = g_list_append(player->sink_elements, sink);
7690
7691         MMPLAYER_FLEAVE();
7692 }
7693
7694 static void
7695 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7696 {
7697         MMPLAYER_FENTER();
7698
7699         MMPLAYER_RETURN_IF_FAIL(player);
7700         MMPLAYER_RETURN_IF_FAIL(sink);
7701
7702         player->sink_elements = g_list_remove(player->sink_elements, sink);
7703
7704         MMPLAYER_FLEAVE();
7705 }
7706
7707 void
7708 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7709         MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7710 {
7711         MMPlayerSignalItem *item = NULL;
7712
7713         MMPLAYER_FENTER();
7714         MMPLAYER_RETURN_IF_FAIL(player);
7715
7716         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7717                 LOGE("invalid signal type [%d]", type);
7718                 return;
7719         }
7720
7721         item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7722         if (!item) {
7723                 LOGE("cannot connect signal [%s]", signal);
7724                 return;
7725         }
7726
7727         item->obj = object;
7728         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7729         player->signals[type] = g_list_append(player->signals[type], item);
7730
7731         MMPLAYER_FLEAVE();
7732         return;
7733 }
7734
7735 /* NOTE : be careful with calling this api. please refer to below glib comment
7736  * glib comment : Note that there is a bug in GObject that makes this function much
7737  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7738  * will no longer be called, but, the signal handler is not currently disconnected.
7739  * If the instance is itself being freed at the same time than this doesn't matter,
7740  * since the signal will automatically be removed, but if instance persists,
7741  * then the signal handler will leak. You should not remove the signal yourself
7742  * because in a future versions of GObject, the handler will automatically be
7743  * disconnected.
7744  *
7745  * It's possible to work around this problem in a way that will continue to work
7746  * with future versions of GObject by checking that the signal handler is still
7747  * connected before disconnected it:
7748  *
7749  *  if (g_signal_handler_is_connected(instance, id))
7750  *    g_signal_handler_disconnect(instance, id);
7751  */
7752 static void
7753 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7754 {
7755         GList *sig_list = NULL;
7756         MMPlayerSignalItem *item = NULL;
7757
7758         MMPLAYER_FENTER();
7759
7760         MMPLAYER_RETURN_IF_FAIL(player);
7761
7762         LOGD("release signals type : %d", type);
7763
7764         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7765                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7766                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7767                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7768                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7769                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7770                 return;
7771         }
7772
7773         sig_list = player->signals[type];
7774
7775         for (; sig_list; sig_list = sig_list->next) {
7776                 item = sig_list->data;
7777
7778                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7779                         if (g_signal_handler_is_connected(item->obj, item->sig))
7780                                 g_signal_handler_disconnect(item->obj, item->sig);
7781                 }
7782
7783                 MMPLAYER_FREEIF(item);
7784         }
7785
7786         g_list_free(player->signals[type]);
7787         player->signals[type] = NULL;
7788
7789         MMPLAYER_FLEAVE();
7790
7791         return;
7792 }
7793
7794 int
7795 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7796 {
7797         mm_player_t *player = 0;
7798         int prev_display_surface_type = 0;
7799         void *prev_display_overlay = NULL;
7800
7801         MMPLAYER_FENTER();
7802
7803         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7804         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7805
7806         player = MM_PLAYER_CAST(handle);
7807
7808         /* check video sinkbin is created */
7809         if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7810                 LOGE("Videosink is already created");
7811                 return MM_ERROR_NONE;
7812         }
7813
7814         LOGD("videosink element is not yet ready");
7815
7816         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7817                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7818                 MMPLAYER_FLEAVE();
7819                 return MM_ERROR_INVALID_ARGUMENT;
7820         }
7821
7822         /* load previous attributes */
7823         if (player->attrs) {
7824                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7825                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7826                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7827                 if (prev_display_surface_type == surface_type) {
7828                         LOGD("incoming display surface type is same as previous one, do nothing..");
7829                         MMPLAYER_FLEAVE();
7830                         return MM_ERROR_NONE;
7831                 }
7832         } else {
7833                 LOGE("failed to load attributes");
7834                 MMPLAYER_FLEAVE();
7835                 return MM_ERROR_PLAYER_INTERNAL;
7836         }
7837
7838         /* videobin is not created yet, so we just set attributes related to display surface */
7839         LOGD("store display attribute for given surface type(%d)", surface_type);
7840         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7841         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7842         if (mm_attrs_commit_all(player->attrs)) {
7843                 LOGE("failed to commit attribute");
7844                 MMPLAYER_FLEAVE();
7845                 return MM_ERROR_PLAYER_INTERNAL;
7846         }
7847
7848         MMPLAYER_FLEAVE();
7849         return MM_ERROR_NONE;
7850 }
7851
7852 /* Note : if silent is true, then subtitle would not be displayed. :*/
7853 int
7854 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7855 {
7856         mm_player_t *player = (mm_player_t *)hplayer;
7857
7858         MMPLAYER_FENTER();
7859
7860         /* check player handle */
7861         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7862
7863         player->set_mode.subtitle_off = silent;
7864
7865         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7866
7867         MMPLAYER_FLEAVE();
7868
7869         return MM_ERROR_NONE;
7870 }
7871
7872 int
7873 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7874 {
7875         MMPlayerGstElement *mainbin = NULL;
7876         MMPlayerGstElement *textbin = NULL;
7877         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7878         GstState current_state = GST_STATE_VOID_PENDING;
7879         GstState element_state = GST_STATE_VOID_PENDING;
7880         GstState element_pending_state = GST_STATE_VOID_PENDING;
7881         gint64 time = 0;
7882         GstEvent *event = NULL;
7883         int result = MM_ERROR_NONE;
7884
7885         GstClock *curr_clock = NULL;
7886         GstClockTime base_time, start_time, curr_time;
7887
7888
7889         MMPLAYER_FENTER();
7890
7891         /* check player handle */
7892         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7893                                                                 player->pipeline &&
7894                                                                 player->pipeline->mainbin &&
7895                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7896
7897         mainbin = player->pipeline->mainbin;
7898         textbin = player->pipeline->textbin;
7899
7900         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7901
7902         // sync clock with current pipeline
7903         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7904         curr_time = gst_clock_get_time(curr_clock);
7905
7906         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7907         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7908
7909         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7910                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7911
7912         if (current_state > GST_STATE_READY) {
7913                 // sync state with current pipeline
7914                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7915                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7916                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7917
7918                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7919                 if (GST_STATE_CHANGE_FAILURE == ret) {
7920                         LOGE("fail to state change.");
7921                         result = MM_ERROR_PLAYER_INTERNAL;
7922                         goto ERROR;
7923                 }
7924         }
7925         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7926         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7927
7928         if (curr_clock) {
7929                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7930                 gst_object_unref(curr_clock);
7931         }
7932
7933         // seek to current position
7934         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7935                 result = MM_ERROR_PLAYER_INVALID_STATE;
7936                 LOGE("gst_element_query_position failed, invalid state");
7937                 goto ERROR;
7938         }
7939
7940         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7941         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);
7942         if (event) {
7943                 __mmplayer_gst_send_event_to_sink(player, event);
7944         } else {
7945                 result = MM_ERROR_PLAYER_INTERNAL;
7946                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7947                 goto ERROR;
7948         }
7949
7950         /* sync state with current pipeline */
7951         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7952         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7953         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7954
7955         return MM_ERROR_NONE;
7956
7957 ERROR:
7958         /* release text pipeline resource */
7959         player->textsink_linked = 0;
7960
7961         /* release signal */
7962         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7963
7964         /* release textbin with it's childs */
7965         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7966         MMPLAYER_FREEIF(player->pipeline->textbin);
7967         player->pipeline->textbin = NULL;
7968
7969         /* release subtitle elem */
7970         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7971         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7972
7973         return result;
7974 }
7975
7976 static int
7977 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7978 {
7979         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7980         GstState current_state = GST_STATE_VOID_PENDING;
7981
7982         MMHandleType attrs = 0;
7983         MMPlayerGstElement *mainbin = NULL;
7984         MMPlayerGstElement *textbin = NULL;
7985
7986         gchar *subtitle_uri = NULL;
7987         int result = MM_ERROR_NONE;
7988         const gchar *charset = NULL;
7989
7990         MMPLAYER_FENTER();
7991
7992         /* check player handle */
7993         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7994                                                                 player->pipeline &&
7995                                                                 player->pipeline->mainbin &&
7996                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7997         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7998
7999         mainbin = player->pipeline->mainbin;
8000         textbin = player->pipeline->textbin;
8001
8002         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8003         if (current_state < GST_STATE_READY) {
8004                 result = MM_ERROR_PLAYER_INVALID_STATE;
8005                 LOGE("Pipeline is not in proper state");
8006                 goto EXIT;
8007         }
8008
8009         attrs = MMPLAYER_GET_ATTRS(player);
8010         if (!attrs) {
8011                 LOGE("cannot get content attribute");
8012                 result = MM_ERROR_PLAYER_INTERNAL;
8013                 goto EXIT;
8014         }
8015
8016         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8017         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8018                 LOGE("subtitle uri is not proper filepath");
8019                 result = MM_ERROR_PLAYER_INVALID_URI;
8020                 goto EXIT;
8021         }
8022
8023         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8024                 LOGE("failed to get storage info of subtitle path");
8025                 result = MM_ERROR_PLAYER_INVALID_URI;
8026                 goto EXIT;
8027         }
8028
8029         LOGD("old subtitle file path is [%s]", subtitle_uri);
8030         LOGD("new subtitle file path is [%s]", filepath);
8031
8032         if (!strcmp(filepath, subtitle_uri)) {
8033                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8034                 goto EXIT;
8035         } else {
8036                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8037                 if (mm_attrs_commit_all(player->attrs)) {
8038                         LOGE("failed to commit.");
8039                         goto EXIT;
8040                 }
8041         }
8042
8043         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8044         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8045         player->subtitle_language_list = NULL;
8046         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8047
8048         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8049         if (ret != GST_STATE_CHANGE_SUCCESS) {
8050                 LOGE("failed to change state of textbin to READY");
8051                 result = MM_ERROR_PLAYER_INTERNAL;
8052                 goto EXIT;
8053         }
8054
8055         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8056         if (ret != GST_STATE_CHANGE_SUCCESS) {
8057                 LOGE("failed to change state of subparse to READY");
8058                 result = MM_ERROR_PLAYER_INTERNAL;
8059                 goto EXIT;
8060         }
8061
8062         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8063         if (ret != GST_STATE_CHANGE_SUCCESS) {
8064                 LOGE("failed to change state of filesrc to READY");
8065                 result = MM_ERROR_PLAYER_INTERNAL;
8066                 goto EXIT;
8067         }
8068
8069         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8070
8071         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8072
8073         charset = util_get_charset(filepath);
8074         if (charset) {
8075                 LOGD("detected charset is %s", charset);
8076                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8077         }
8078
8079         result = _mmplayer_sync_subtitle_pipeline(player);
8080
8081 EXIT:
8082         MMPLAYER_FLEAVE();
8083         return result;
8084 }
8085
8086 /* API to switch between external subtitles */
8087 int
8088 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8089 {
8090         int result = MM_ERROR_NONE;
8091         mm_player_t *player = (mm_player_t *)hplayer;
8092         char *path = NULL;
8093
8094         MMPLAYER_FENTER();
8095
8096         /* check player handle */
8097         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8098
8099         /* filepath can be null in idle state */
8100         if (filepath) {
8101                 /* check file path */
8102                 if ((path = strstr(filepath, "file://")))
8103                         result = util_exist_file_path(path + 7);
8104                 else
8105                         result = util_exist_file_path(filepath);
8106
8107                 if (result != MM_ERROR_NONE) {
8108                         LOGE("invalid subtitle path 0x%X", result);
8109                         return result; /* file not found or permission denied */
8110                 }
8111         }
8112
8113         if (!player->pipeline) {
8114                 /* IDLE state */
8115                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8116                 if (mm_attrs_commit_all(player->attrs)) {
8117                         LOGE("failed to commit");       /* subtitle path will not be created */
8118                         return MM_ERROR_PLAYER_INTERNAL;
8119                 }
8120         } else {
8121                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8122                 /* check filepath */
8123                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8124
8125                 if (!__mmplayer_check_subtitle(player)) {
8126                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8127                         if (mm_attrs_commit_all(player->attrs)) {
8128                                 LOGE("failed to commit");
8129                                 return MM_ERROR_PLAYER_INTERNAL;
8130                         }
8131
8132                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8133                                 LOGE("fail to create text pipeline");
8134                                 return MM_ERROR_PLAYER_INTERNAL;
8135                         }
8136
8137                         result = _mmplayer_sync_subtitle_pipeline(player);
8138                 } else {
8139                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8140                 }
8141
8142                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8143                 player->is_external_subtitle_added_now = TRUE;
8144
8145                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8146                 if (!player->subtitle_language_list) {
8147                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8148                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8149                                 LOGW("subtitle language list is not updated yet");
8150                 }
8151                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8152         }
8153
8154         MMPLAYER_FLEAVE();
8155         return result;
8156 }
8157
8158 static int
8159 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
8160 {
8161         int result = MM_ERROR_NONE;
8162         gchar *change_pad_name = NULL;
8163         GstPad *sinkpad = NULL;
8164         MMPlayerGstElement *mainbin = NULL;
8165         enum MainElementID elem_idx = MMPLAYER_M_NUM;
8166         GstCaps *caps = NULL;
8167         gint total_track_num = 0;
8168
8169         MMPLAYER_FENTER();
8170
8171         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8172                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8173
8174         LOGD("Change Track(%d) to %d", type, index);
8175
8176         mainbin = player->pipeline->mainbin;
8177
8178         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8179                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8180         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8181                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8182         } else {
8183                 /* Changing Video Track is not supported. */
8184                 LOGE("Track Type Error");
8185                 goto EXIT;
8186         }
8187
8188         if (mainbin[elem_idx].gst == NULL) {
8189                 result = MM_ERROR_PLAYER_NO_OP;
8190                 LOGD("Req track doesn't exist");
8191                 goto EXIT;
8192         }
8193
8194         total_track_num = player->selector[type].total_track_num;
8195         if (total_track_num <= 0) {
8196                 result = MM_ERROR_PLAYER_NO_OP;
8197                 LOGD("Language list is not available");
8198                 goto EXIT;
8199         }
8200
8201         if ((index < 0) || (index >= total_track_num)) {
8202                 result = MM_ERROR_INVALID_ARGUMENT;
8203                 LOGD("Not a proper index : %d", index);
8204                 goto EXIT;
8205         }
8206
8207         /*To get the new pad from the selector*/
8208         change_pad_name = g_strdup_printf("sink_%u", index);
8209         if (change_pad_name == NULL) {
8210                 result = MM_ERROR_PLAYER_INTERNAL;
8211                 LOGD("Pad does not exists");
8212                 goto EXIT;
8213         }
8214
8215         LOGD("new active pad name: %s", change_pad_name);
8216
8217         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8218         if (sinkpad == NULL) {
8219                 LOGD("sinkpad is NULL");
8220                 result = MM_ERROR_PLAYER_INTERNAL;
8221                 goto EXIT;
8222         }
8223
8224         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8225         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8226
8227         caps = gst_pad_get_current_caps(sinkpad);
8228         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8229
8230         if (sinkpad)
8231                 gst_object_unref(sinkpad);
8232
8233         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8234                 __mmplayer_set_audio_attrs(player, caps);
8235
8236 EXIT:
8237         MMPLAYER_FREEIF(change_pad_name);
8238         return result;
8239 }
8240
8241 int
8242 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8243 {
8244         int result = MM_ERROR_NONE;
8245         mm_player_t *player = NULL;
8246         MMPlayerGstElement *mainbin = NULL;
8247
8248         gint current_active_index = 0;
8249
8250         GstState current_state = GST_STATE_VOID_PENDING;
8251         GstEvent *event = NULL;
8252         gint64 time = 0;
8253
8254         MMPLAYER_FENTER();
8255
8256         player = (mm_player_t *)hplayer;
8257         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8258
8259         if (!player->pipeline) {
8260                 LOGE("Track %d pre setting -> %d", type, index);
8261
8262                 player->selector[type].active_pad_index = index;
8263                 goto EXIT;
8264         }
8265
8266         mainbin = player->pipeline->mainbin;
8267
8268         current_active_index = player->selector[type].active_pad_index;
8269
8270         /*If index is same as running index no need to change the pad*/
8271         if (current_active_index == index)
8272                 goto EXIT;
8273
8274         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8275                 result = MM_ERROR_PLAYER_INVALID_STATE;
8276                 goto EXIT;
8277         }
8278
8279         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8280         if (current_state < GST_STATE_PAUSED) {
8281                 result = MM_ERROR_PLAYER_INVALID_STATE;
8282                 LOGW("Pipeline not in porper state");
8283                 goto EXIT;
8284         }
8285
8286         result = __mmplayer_change_selector_pad(player, type, index);
8287         if (result != MM_ERROR_NONE) {
8288                 LOGE("change selector pad error");
8289                 goto EXIT;
8290         }
8291
8292         player->selector[type].active_pad_index = index;
8293
8294         if (current_state == GST_STATE_PLAYING) {
8295                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8296                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8297                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8298                 if (event) {
8299                         __mmplayer_gst_send_event_to_sink(player, event);
8300                 } else {
8301                         result = MM_ERROR_PLAYER_INTERNAL;
8302                         goto EXIT;
8303                 }
8304         }
8305
8306 EXIT:
8307         return result;
8308 }
8309
8310 int
8311 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8312 {
8313         mm_player_t *player = (mm_player_t *)hplayer;
8314
8315         MMPLAYER_FENTER();
8316
8317         /* check player handle */
8318         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8319
8320         *silent = player->set_mode.subtitle_off;
8321
8322         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8323
8324         MMPLAYER_FLEAVE();
8325
8326         return MM_ERROR_NONE;
8327 }
8328
8329 static gboolean
8330 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8331 {
8332         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8333         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8334
8335         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8336         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8337
8338         int idx = 0;
8339
8340         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8341                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8342                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8343                         mm_player_dump_t *dump_s;
8344                         dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8345                         if (dump_s == NULL) {
8346                                 LOGE("malloc fail");
8347                                 return FALSE;
8348                         }
8349
8350                         dump_s->dump_element_file = NULL;
8351                         dump_s->dump_pad = NULL;
8352                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8353
8354                         if (dump_s->dump_pad) {
8355                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8356                                 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]);
8357                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8358                                 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);
8359                                 /* add list for removed buffer probe and close FILE */
8360                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8361                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8362                                 return TRUE;
8363                         } else {
8364                                 MMPLAYER_FREEIF(dump_s);
8365                                 LOGE("failed to get %s sink pad added", factory_name);
8366                         }
8367                 }
8368         }
8369         return FALSE;
8370 }
8371
8372 static GstPadProbeReturn
8373 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8374 {
8375         FILE *dump_data = (FILE *)u_data;
8376 //      int written = 0;
8377         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8378         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8379
8380         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8381
8382         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8383
8384 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8385
8386         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8387
8388         return GST_PAD_PROBE_OK;
8389 }
8390
8391 static void
8392 __mmplayer_release_dump_list(GList *dump_list)
8393 {
8394         GList *d_list = dump_list;
8395
8396         if (!d_list)
8397                 return;
8398
8399         for (; d_list; d_list = g_list_next(d_list)) {
8400                 mm_player_dump_t *dump_s = d_list->data;
8401                 if (dump_s->dump_pad) {
8402                         if (dump_s->probe_handle_id)
8403                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8404                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8405                 }
8406                 if (dump_s->dump_element_file) {
8407                         fclose(dump_s->dump_element_file);
8408                         dump_s->dump_element_file = NULL;
8409                 }
8410                 MMPLAYER_FREEIF(dump_s);
8411         }
8412         g_list_free(dump_list);
8413         dump_list = NULL;
8414 }
8415
8416 int
8417 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8418 {
8419         mm_player_t *player = (mm_player_t *)hplayer;
8420
8421         MMPLAYER_FENTER();
8422
8423         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8424         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8425
8426         *exist = (bool)player->has_closed_caption;
8427
8428         MMPLAYER_FLEAVE();
8429
8430         return MM_ERROR_NONE;
8431 }
8432
8433 void
8434 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8435 {
8436         MMPLAYER_FENTER();
8437         if (buffer) {
8438                 // LOGD("unref internal gst buffer %p", buffer);
8439                 gst_buffer_unref((GstBuffer *)buffer);
8440                 buffer = NULL;
8441         }
8442         MMPLAYER_FLEAVE();
8443 }
8444
8445 int
8446 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8447 {
8448         mm_player_t *player = (mm_player_t *)hplayer;
8449
8450         MMPLAYER_FENTER();
8451
8452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8453         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8454
8455         if (MMPLAYER_IS_STREAMING(player))
8456                 *timeout = (int)player->ini.live_state_change_timeout;
8457         else
8458                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8459
8460         LOGD("timeout = %d", *timeout);
8461
8462         MMPLAYER_FLEAVE();
8463         return MM_ERROR_NONE;
8464 }
8465
8466 int
8467 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8468 {
8469         mm_player_t *player = (mm_player_t *)hplayer;
8470
8471         MMPLAYER_FENTER();
8472
8473         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8475
8476         *num = player->video_num_buffers;
8477         *extra_num = player->video_extra_num_buffers;
8478
8479         LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8480
8481         MMPLAYER_FLEAVE();
8482         return MM_ERROR_NONE;
8483 }
8484
8485 static void
8486 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8487 {
8488         int i = 0;
8489         MMPLAYER_FENTER();
8490         MMPLAYER_RETURN_IF_FAIL(player);
8491
8492         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8493
8494                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8495                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8496                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8497                         player->storage_info[i].id = -1;
8498                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8499
8500                         if (path_type != MMPLAYER_PATH_MAX)
8501                                 break;
8502                 }
8503         }
8504
8505         MMPLAYER_FLEAVE();
8506 }
8507
8508 int
8509 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8510 {
8511         int ret = MM_ERROR_NONE;
8512         mm_player_t *player = (mm_player_t *)hplayer;
8513         MMMessageParamType msg_param = {0, };
8514
8515         MMPLAYER_FENTER();
8516         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8517
8518         LOGW("state changed storage %d:%d", id, state);
8519
8520         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8521                 return MM_ERROR_NONE;
8522
8523         /* FIXME: text path should be handled seperately. */
8524         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8525                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8526                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8527                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8528                 LOGW("external storage is removed");
8529
8530                 if (player->msg_posted == FALSE) {
8531                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8532                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8533                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8534                         player->msg_posted = TRUE;
8535                 }
8536
8537                 /* unrealize the player */
8538                 ret = _mmplayer_unrealize(hplayer);
8539                 if (ret != MM_ERROR_NONE)
8540                         LOGE("failed to unrealize");
8541         }
8542
8543         MMPLAYER_FLEAVE();
8544         return ret;
8545 }
8546
8547 int
8548 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8549 {
8550         int ret = MM_ERROR_NONE;
8551         mm_player_t *player = (mm_player_t *)hplayer;
8552         int idx = 0, total = 0;
8553         gchar *result = NULL, *tmp = NULL;
8554
8555         MMPLAYER_FENTER();
8556         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8557         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8558
8559         total = *num = g_list_length(player->adaptive_info.var_list);
8560         if (total <= 0) {
8561                 LOGW("There is no stream variant info.");
8562                 return ret;
8563         }
8564
8565         result = g_strdup("");
8566         for (idx = 0 ; idx < total ; idx++) {
8567                 VariantData *v_data = NULL;
8568                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8569
8570                 if (v_data) {
8571                         gchar data[64] = {0};
8572                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8573
8574                         tmp = g_strconcat(result, data, NULL);
8575                         g_free(result);
8576                         result = tmp;
8577                 } else {
8578                         LOGW("There is no variant data in %d", idx);
8579                         (*num)--;
8580                 }
8581         }
8582
8583         *var_info = (char *)result;
8584
8585         LOGD("variant info %d:%s", *num, *var_info);
8586         MMPLAYER_FLEAVE();
8587         return ret;
8588 }
8589
8590 int
8591 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8592 {
8593         int ret = MM_ERROR_NONE;
8594         mm_player_t *player = (mm_player_t *)hplayer;
8595
8596         MMPLAYER_FENTER();
8597         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8598
8599         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8600
8601         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8602         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8603         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8604
8605         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8606                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8607                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8608                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8609
8610                 /* FIXME: seek to current position for applying new variant limitation */
8611         }
8612
8613         MMPLAYER_FLEAVE();
8614         return ret;
8615
8616 }
8617
8618 int
8619 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8620 {
8621         int ret = MM_ERROR_NONE;
8622         mm_player_t *player = (mm_player_t *)hplayer;
8623
8624         MMPLAYER_FENTER();
8625         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8626         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8627
8628         *bandwidth = player->adaptive_info.limit.bandwidth;
8629         *width = player->adaptive_info.limit.width;
8630         *height = player->adaptive_info.limit.height;
8631
8632         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8633
8634         MMPLAYER_FLEAVE();
8635         return ret;
8636 }
8637
8638 int
8639 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8640 {
8641         int ret = MM_ERROR_NONE;
8642         mm_player_t *player = (mm_player_t *)hplayer;
8643
8644         MMPLAYER_FENTER();
8645         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8646         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8647         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8648
8649         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8650
8651         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8652                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8653         else /* live case */
8654                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8655
8656         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8657
8658         MMPLAYER_FLEAVE();
8659         return ret;
8660 }
8661
8662 int
8663 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8664 {
8665 #define IDX_FIRST_SW_CODEC 0
8666         mm_player_t *player = (mm_player_t *)hplayer;
8667         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8668         MMHandleType attrs = 0;
8669
8670         MMPLAYER_FENTER();
8671         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8672
8673         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8674                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8675                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8676
8677         switch (stream_type) {
8678         case MM_PLAYER_STREAM_TYPE_AUDIO:
8679         /* to support audio codec selection, codec info have to be added in ini file as below.
8680            audio codec element hw = xxxx
8681            audio codec element sw = avdec */
8682                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8683                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8684                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8685                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8686                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8687                         return MM_ERROR_PLAYER_NO_OP;
8688                 }
8689         break;
8690         case MM_PLAYER_STREAM_TYPE_VIDEO:
8691         /* to support video codec selection, codec info have to be added in ini file as below.
8692            video codec element hw = omx
8693            video codec element sw = avdec */
8694                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8695                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8696                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8697                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8698                         LOGE("There is no video codec info for codec_type %d", codec_type);
8699                         return MM_ERROR_PLAYER_NO_OP;
8700                 }
8701         break;
8702         default:
8703                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8704                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8705         break;
8706         }
8707
8708         LOGD("update %s codec_type to %d", attr_name, codec_type);
8709
8710         attrs = MMPLAYER_GET_ATTRS(player);
8711         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8712
8713         if (mm_attrs_commit_all(player->attrs)) {
8714                 LOGE("failed to commit codec_type attributes");
8715                 return MM_ERROR_PLAYER_INTERNAL;
8716         }
8717
8718         MMPLAYER_FLEAVE();
8719         return MM_ERROR_NONE;
8720 }
8721
8722 int
8723 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8724 {
8725         mm_player_t *player = (mm_player_t *)hplayer;
8726         GstElement *rg_vol_element = NULL;
8727
8728         MMPLAYER_FENTER();
8729
8730         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731
8732         player->sound.rg_enable = enabled;
8733
8734         /* just hold rgvolume enable value if pipeline is not ready */
8735         if (!player->pipeline || !player->pipeline->audiobin) {
8736                 LOGD("pipeline is not ready. holding rgvolume enable value");
8737                 return MM_ERROR_NONE;
8738         }
8739
8740         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8741
8742         if (!rg_vol_element) {
8743                 LOGD("rgvolume element is not created");
8744                 return MM_ERROR_PLAYER_INTERNAL;
8745         }
8746
8747         if (enabled)
8748                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8749         else
8750                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8751
8752         MMPLAYER_FLEAVE();
8753
8754         return MM_ERROR_NONE;
8755 }
8756
8757 int
8758 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8759 {
8760         mm_player_t *player = (mm_player_t *)hplayer;
8761         GstElement *rg_vol_element = NULL;
8762         gboolean enable = FALSE;
8763
8764         MMPLAYER_FENTER();
8765
8766         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8767         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8768
8769         /* just hold enable_rg value if pipeline is not ready */
8770         if (!player->pipeline || !player->pipeline->audiobin) {
8771                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8772                 *enabled = player->sound.rg_enable;
8773                 return MM_ERROR_NONE;
8774         }
8775
8776         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8777
8778         if (!rg_vol_element) {
8779                 LOGD("rgvolume element is not created");
8780                 return MM_ERROR_PLAYER_INTERNAL;
8781         }
8782
8783         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8784         *enabled = (bool)enable;
8785
8786         MMPLAYER_FLEAVE();
8787
8788         return MM_ERROR_NONE;
8789 }
8790
8791 int
8792 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8793 {
8794         mm_player_t *player = (mm_player_t *)hplayer;
8795         MMHandleType attrs = 0;
8796         void *handle = NULL;
8797         int ret = MM_ERROR_NONE;
8798
8799         MMPLAYER_FENTER();
8800
8801         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8802
8803         attrs = MMPLAYER_GET_ATTRS(player);
8804         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8805
8806         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8807         if (!handle) {
8808                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8809                 return MM_ERROR_PLAYER_INTERNAL;
8810         }
8811
8812         player->video_roi.scale_x = scale_x;
8813         player->video_roi.scale_y = scale_y;
8814         player->video_roi.scale_width = scale_width;
8815         player->video_roi.scale_height = scale_height;
8816
8817         /* check video sinkbin is created */
8818         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8819                 return MM_ERROR_NONE;
8820
8821         if (!gst_video_overlay_set_video_roi_area(
8822                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8823                 scale_x, scale_y, scale_width, scale_height))
8824                 ret = MM_ERROR_PLAYER_INTERNAL;
8825         else
8826                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8827                         scale_x, scale_y, scale_width, scale_height);
8828
8829         MMPLAYER_FLEAVE();
8830
8831         return ret;
8832 }
8833
8834 int
8835 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8836 {
8837         mm_player_t *player = (mm_player_t *)hplayer;
8838         int ret = MM_ERROR_NONE;
8839
8840         MMPLAYER_FENTER();
8841
8842         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8844
8845         *scale_x = player->video_roi.scale_x;
8846         *scale_y = player->video_roi.scale_y;
8847         *scale_width = player->video_roi.scale_width;
8848         *scale_height = player->video_roi.scale_height;
8849
8850         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8851                 *scale_x, *scale_y, *scale_width, *scale_height);
8852
8853         return ret;
8854 }
8855
8856 static gboolean
8857 __mmplayer_update_duration_value(mm_player_t *player)
8858 {
8859         gboolean ret = FALSE;
8860         gint64 dur_nsec = 0;
8861         LOGD("try to update duration");
8862
8863         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8864                 player->duration = dur_nsec;
8865                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8866                 ret = TRUE;
8867         }
8868
8869         if (player->duration < 0) {
8870                 LOGW("duration is Non-Initialized !!!");
8871                 player->duration = 0;
8872         }
8873
8874         /* update streaming service type */
8875         player->streaming_type =  __mmplayer_get_stream_service_type(player);
8876
8877         /* check duration is OK */
8878         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8879                 /* FIXIT : find another way to get duration here. */
8880                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8881
8882         return ret;
8883 }
8884
8885 static gboolean
8886 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8887 {
8888         /* update audio params
8889         NOTE : We need original audio params and it can be only obtained from src pad of audio
8890         decoder. Below code only valid when we are not using 'resampler' just before
8891         'audioconverter'. */
8892         GstCaps *caps_a = NULL;
8893         GstPad *pad = NULL;
8894         gint samplerate = 0, channels = 0;
8895         GstStructure *p = NULL;
8896
8897         LOGD("try to update audio attrs");
8898
8899         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8900         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8901
8902         pad = gst_element_get_static_pad(
8903                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8904
8905         if (!pad) {
8906                 LOGW("failed to get pad from audiosink");
8907                 return FALSE;
8908         }
8909
8910         caps_a = gst_pad_get_current_caps(pad);
8911         if (!caps_a) {
8912                 LOGW("not ready to get audio caps");
8913                 gst_object_unref(pad);
8914                 return FALSE;
8915         }
8916
8917         p = gst_caps_get_structure(caps_a, 0);
8918
8919         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8920
8921         gst_structure_get_int(p, "rate", &samplerate);
8922         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8923
8924         gst_structure_get_int(p, "channels", &channels);
8925         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8926
8927         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8928
8929         gst_caps_unref(caps_a);
8930         gst_object_unref(pad);
8931
8932         return TRUE;
8933 }
8934
8935 static gboolean
8936 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8937 {
8938         LOGD("try to update video attrs");
8939
8940         GstCaps *caps_v = NULL;
8941         GstPad *pad = NULL;
8942         gint tmpNu, tmpDe;
8943         gint width, height;
8944         GstStructure *p = NULL;
8945
8946         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8947         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8948
8949         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8950         if (!pad) {
8951                 LOGD("no videosink sink pad");
8952                 return FALSE;
8953         }
8954
8955         caps_v = gst_pad_get_current_caps(pad);
8956         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8957         if (!caps_v && player->v_stream_caps) {
8958                 caps_v = player->v_stream_caps;
8959                 gst_caps_ref(caps_v);
8960         }
8961
8962         if (!caps_v) {
8963                 LOGD("no negitiated caps from videosink");
8964                 gst_object_unref(pad);
8965                 return FALSE;
8966         }
8967
8968         p = gst_caps_get_structure(caps_v, 0);
8969         gst_structure_get_int(p, "width", &width);
8970         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8971
8972         gst_structure_get_int(p, "height", &height);
8973         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8974
8975         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8976
8977         SECURE_LOGD("width : %d     height : %d", width, height);
8978
8979         gst_caps_unref(caps_v);
8980         gst_object_unref(pad);
8981
8982         if (tmpDe > 0) {
8983                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8984                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8985         }
8986
8987         return TRUE;
8988 }
8989
8990 static gboolean
8991 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8992 {
8993         gboolean ret = FALSE;
8994         guint64 data_size = 0;
8995         gchar *path = NULL;
8996         struct stat sb;
8997
8998         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8999         if (!player->duration)
9000                 return FALSE;
9001
9002         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9003                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9004                 if (stat(path, &sb) == 0)
9005                         data_size = (guint64)sb.st_size;
9006
9007         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9008                 data_size = player->http_content_size;
9009         }
9010
9011         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9012
9013         if (data_size) {
9014                 guint64 bitrate = 0;
9015                 guint64 msec_dur = 0;
9016
9017                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9018                 if (msec_dur > 0) {
9019                         bitrate = data_size * 8 * 1000 / msec_dur;
9020                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9021                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9022
9023                         ret = TRUE;
9024                 } else {
9025                         LOGD("player duration is less than 0");
9026                 }
9027         }
9028
9029         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9030                 if (player->total_bitrate) {
9031                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9032                         ret = TRUE;
9033                 }
9034         }
9035
9036         return ret;
9037 }
9038
9039 static void
9040 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
9041 {
9042         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9043         data->uri_type = uri_type;
9044 }
9045
9046 static int
9047 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
9048 {
9049         int ret = MM_ERROR_PLAYER_INVALID_URI;
9050         int mem_size = 0;
9051         char *buffer = NULL;
9052         char *seperator = strchr(path, ',');
9053         char ext[100] = {0,}, size[100] = {0,};
9054
9055         if (seperator) {
9056                 if ((buffer = strstr(path, "ext="))) {
9057                         buffer += strlen("ext=");
9058
9059                         if (strlen(buffer)) {
9060                                 strncpy(ext, buffer, 99);
9061
9062                                 if ((seperator = strchr(ext, ','))
9063                                         || (seperator = strchr(ext, ' '))
9064                                         || (seperator = strchr(ext, '\0'))) {
9065                                         seperator[0] = '\0';
9066                                 }
9067                         }
9068                 }
9069
9070                 if ((buffer = strstr(path, "size="))) {
9071                         buffer += strlen("size=");
9072
9073                         if (strlen(buffer) > 0) {
9074                                 strncpy(size, buffer, 99);
9075
9076                                 if ((seperator = strchr(size, ','))
9077                                         || (seperator = strchr(size, ' '))
9078                                         || (seperator = strchr(size, '\0'))) {
9079                                         seperator[0] = '\0';
9080                                 }
9081
9082                                 mem_size = atoi(size);
9083                         }
9084                 }
9085         }
9086
9087         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9088
9089         if (mem_size && param) {
9090                 if (data->input_mem.buf)
9091                         free(data->input_mem.buf);
9092                 data->input_mem.buf = malloc(mem_size);
9093
9094                 if (data->input_mem.buf) {
9095                         memcpy(data->input_mem.buf, param, mem_size);
9096                         data->input_mem.len = mem_size;
9097                         ret = MM_ERROR_NONE;
9098                 } else {
9099                         LOGE("failed to alloc mem %d", mem_size);
9100                         ret = MM_ERROR_PLAYER_INTERNAL;
9101                 }
9102
9103                 data->input_mem.offset = 0;
9104                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9105         }
9106
9107         return ret;
9108 }
9109
9110 static int
9111 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
9112 {
9113         gchar *location = NULL;
9114         GError *err = NULL;
9115         char *path = NULL;
9116         int ret = MM_ERROR_NONE;
9117
9118         if ((path = strstr(uri, "file://"))) {
9119                 location = g_filename_from_uri(uri, NULL, &err);
9120                 if (!location || (err != NULL)) {
9121                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9122                                 (err != NULL) ? err->message : "unknown error");
9123                         if (err)
9124                                 g_error_free(err);
9125
9126                         MMPLAYER_FREEIF(location);
9127
9128                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9129                         return MM_ERROR_PLAYER_INVALID_URI;
9130                 }
9131                 LOGD("path from uri: %s", location);
9132         }
9133
9134         path = (location != NULL) ? (location) : ((char *)uri);
9135
9136
9137         ret = util_exist_file_path(path);
9138
9139         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9140         if (ret == MM_ERROR_NONE) {
9141                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9142                 if (util_is_sdp_file(path)) {
9143                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9144                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9145                 } else {
9146                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9147                 }
9148         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9149                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9150         } else {
9151                 LOGE("invalid uri, could not play..");
9152                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9153         }
9154
9155         MMPLAYER_FREEIF(location);
9156
9157         return ret;
9158 }
9159
9160 static MMPlayerVideoStreamDataType *
9161 __mmplayer_create_stream_from_pad(GstPad *pad)
9162 {
9163         GstCaps *caps = NULL;
9164         GstStructure *structure = NULL;
9165         unsigned int fourcc = 0;
9166         const gchar *string_format = NULL;
9167         MMPlayerVideoStreamDataType *stream = NULL;
9168         gint width, height;
9169         MMPixelFormatType format;
9170
9171         caps = gst_pad_get_current_caps(pad);
9172         if (!caps) {
9173                 LOGE("Caps is NULL.");
9174                 return NULL;
9175         }
9176
9177         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9178         structure = gst_caps_get_structure(caps, 0);
9179         gst_structure_get_int(structure, "width", &width);
9180         gst_structure_get_int(structure, "height", &height);
9181         string_format = gst_structure_get_string(structure, "format");
9182         if (string_format)
9183                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9184         format = util_get_pixtype(fourcc);
9185         gst_caps_unref(caps);
9186
9187         /* moved here */
9188         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9189                 LOGE("Wrong condition!!");
9190                 return NULL;
9191         }
9192
9193         stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9194         if (!stream) {
9195                 LOGE("failed to alloc mem for video data");
9196                 return NULL;
9197         }
9198
9199         stream->width = width;
9200         stream->height = height;
9201         stream->format = format;
9202
9203         return stream;
9204 }
9205
9206 static void
9207 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9208 {
9209         unsigned int pitch = 0;
9210         int index = 0;
9211         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9212
9213         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9214                 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9215                 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9216                 stream->stride[index] = pitch;
9217                 stream->elevation[index] = stream->height;
9218         }
9219 }
9220
9221 static gboolean
9222 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9223 {
9224         if (stream->format == MM_PIXEL_FORMAT_I420) {
9225                 int ret = TBM_SURFACE_ERROR_NONE;
9226                 tbm_surface_h surface;
9227                 tbm_surface_info_s info;
9228
9229                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9230
9231                 ret = tbm_surface_get_info(surface, &info);
9232                 if (ret != TBM_SURFACE_ERROR_NONE) {
9233                         tbm_surface_destroy(surface);
9234                         return FALSE;
9235                 }
9236
9237                 tbm_surface_destroy(surface);
9238                 stream->stride[0] = info.planes[0].stride;
9239                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9240                 stream->stride[1] = info.planes[1].stride;
9241                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9242                 stream->stride[2] = info.planes[2].stride;
9243                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9244                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9245         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9246                 stream->stride[0] = stream->width * 4;
9247                 stream->elevation[0] = stream->height;
9248                 stream->bo_size = stream->stride[0] * stream->height;
9249         } else {
9250                 LOGE("Not support format %d", stream->format);
9251                 return FALSE;
9252         }
9253
9254         return TRUE;
9255 }
9256
9257 static gboolean
9258 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9259 {
9260         tbm_bo_handle thandle;
9261         gboolean is_mapped;
9262         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9263         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9264         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9265         int i = 0;
9266         int j = 0;
9267         int k = 0;
9268         unsigned char *src = NULL;
9269         unsigned char *dest = NULL;
9270         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9271
9272         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9273         if (!is_mapped) {
9274                 LOGE("fail to gst_memory_map");
9275                 return FALSE;
9276         }
9277
9278         if (!mapinfo.data) {
9279                 LOGE("data pointer is wrong");
9280                 goto ERROR;
9281         }
9282
9283         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9284         if (!stream->bo[0]) {
9285                 LOGE("Fail to tbm_bo_alloc!!");
9286                 goto ERROR;
9287         }
9288
9289         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9290         if (!thandle.ptr) {
9291                 LOGE("thandle pointer is wrong");
9292                 goto ERROR;
9293         }
9294
9295         if (stream->format == MM_PIXEL_FORMAT_I420) {
9296                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9297                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9298                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9299                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9300
9301                 dest_offset[0] = 0;
9302                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9303                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9304
9305                 for (i = 0; i < 3; i++) {
9306                         src = mapinfo.data + src_offset[i];
9307                         dest = thandle.ptr + dest_offset[i];
9308
9309                         if (i > 0)
9310                                 k = 1;
9311
9312                         for (j = 0; j < stream->height >> k; j++) {
9313                                 memcpy(dest, src, stream->width>>k);
9314                                 src += src_stride[i];
9315                                 dest += stream->stride[i];
9316                         }
9317                 }
9318         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9319                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9320         } else {
9321                 LOGE("Not support format %d", stream->format);
9322                 goto ERROR;
9323         }
9324
9325         tbm_bo_unmap(stream->bo[0]);
9326         gst_memory_unmap(mem, &mapinfo);
9327
9328         return TRUE;
9329
9330 ERROR:
9331         if (stream->bo[0])
9332                 tbm_bo_unmap(stream->bo[0]);
9333
9334         if (is_mapped)
9335                 gst_memory_unmap(mem, &mapinfo);
9336
9337         return FALSE;
9338 }
9339
9340 static void
9341 __mmplayer_set_pause_state(mm_player_t *player)
9342 {
9343         if (player->sent_bos)
9344                 return;
9345
9346         /* rtsp case, get content attrs by GstMessage */
9347         if (MMPLAYER_IS_RTSP_STREAMING(player))
9348                 return;
9349
9350         /* it's first time to update all content attrs. */
9351         __mmplayer_update_content_attrs(player, ATTR_ALL);
9352 }
9353
9354 static void
9355 __mmplayer_set_playing_state(mm_player_t *player)
9356 {
9357         gchar *audio_codec = NULL;
9358
9359         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9360                 /* initialize because auto resume is done well. */
9361                 player->resumed_by_rewind = FALSE;
9362                 player->playback_rate = 1.0;
9363         }
9364
9365         if (player->sent_bos)
9366                 return;
9367
9368         /* try to get content metadata */
9369
9370         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9371          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9372          * legacy mmfw-player api
9373          */
9374         __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9375
9376         if ((player->cmd == MMPLAYER_COMMAND_START)
9377                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9378                 __mmplayer_handle_missed_plugin(player);
9379         }
9380
9381         /* check audio codec field is set or not
9382          * we can get it from typefinder or codec's caps.
9383          */
9384         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9385
9386         /* The codec format can't be sent for audio only case like amr, mid etc.
9387          * Because, parser don't make related TAG.
9388          * So, if it's not set yet, fill it with found data.
9389          */
9390         if (!audio_codec) {
9391                 if (g_strrstr(player->type, "audio/midi"))
9392                         audio_codec = "MIDI";
9393                 else if (g_strrstr(player->type, "audio/x-amr"))
9394                         audio_codec = "AMR";
9395                 else if (g_strrstr(player->type, "audio/mpeg")
9396                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9397                         audio_codec = "AAC";
9398                 else
9399                         audio_codec = "unknown";
9400
9401                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9402
9403                 if (mm_attrs_commit_all(player->attrs))
9404                         LOGE("failed to update attributes");
9405
9406                 LOGD("set audio codec type with caps");
9407         }
9408
9409         return;
9410 }