[0.6.179] check uri suffix considering extra option
[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 audio decoders */
6359         if (player->audio_decoders) {
6360                 GList *a_dec = player->audio_decoders;
6361                 for (; a_dec; a_dec = g_list_next(a_dec)) {
6362                         gchar *name = a_dec->data;
6363                         MMPLAYER_FREEIF(name);
6364                 }
6365                 g_list_free(player->audio_decoders);
6366                 player->audio_decoders = NULL;
6367         }
6368
6369         MMPLAYER_FLEAVE();
6370 }
6371
6372 static void
6373 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6374 {
6375         MMPlayerGstElement *mainbin = NULL;
6376         MMMessageParamType msg_param = {0,};
6377         GstElement *element = NULL;
6378         MMHandleType attrs = 0;
6379         char *uri = NULL;
6380         enum MainElementID elem_idx = MMPLAYER_M_NUM;
6381
6382         MMPLAYER_FENTER();
6383
6384         if (!player || !player->pipeline || !player->pipeline->mainbin) {
6385                 LOGE("player is not initialized");
6386                 goto ERROR;
6387         }
6388
6389         mainbin = player->pipeline->mainbin;
6390         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6391
6392         attrs = MMPLAYER_GET_ATTRS(player);
6393         if (!attrs) {
6394                 LOGE("fail to get attributes");
6395                 goto ERROR;
6396         }
6397
6398         /* Initialize Player values */
6399         __mmplayer_initialize_gapless_play(player);
6400
6401         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6402
6403         if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6404                 LOGE("failed to parse profile");
6405                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6406                 goto ERROR;
6407         }
6408
6409         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6410                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6411                 LOGE("dash or hls is not supportable");
6412                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6413                 goto ERROR;
6414         }
6415
6416         element = __mmplayer_gst_create_source(player);
6417         if (!element) {
6418                 LOGE("no source element was created");
6419                 goto ERROR;
6420         }
6421
6422         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6423                 LOGE("failed to add source element to pipeline");
6424                 gst_object_unref(GST_OBJECT(element));
6425                 element = NULL;
6426                 goto ERROR;
6427         }
6428
6429         /* take source element */
6430         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6431         mainbin[MMPLAYER_M_SRC].gst = element;
6432
6433         element = NULL;
6434
6435         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6436                 if (player->streamer == NULL) {
6437                         player->streamer = __mm_player_streaming_create();
6438                         __mm_player_streaming_initialize(player->streamer, TRUE);
6439                 }
6440
6441                 elem_idx = MMPLAYER_M_TYPEFIND;
6442                 element = gst_element_factory_make("typefind", "typefinder");
6443                 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6444                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6445         } else {
6446                 elem_idx = MMPLAYER_M_AUTOPLUG;
6447                 element = __mmplayer_gst_make_decodebin(player);
6448         }
6449
6450         /* check autoplug element is OK */
6451         if (!element) {
6452                 LOGE("can not create element(%d)", elem_idx);
6453                 goto ERROR;
6454         }
6455
6456         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6457                 LOGE("failed to add sinkbin to pipeline");
6458                 gst_object_unref(GST_OBJECT(element));
6459                 element = NULL;
6460                 goto ERROR;
6461         }
6462
6463         mainbin[elem_idx].id = elem_idx;
6464         mainbin[elem_idx].gst = element;
6465
6466         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6467                 LOGE("Failed to link src - autoplug(or typefind)");
6468                 goto ERROR;
6469         }
6470
6471         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6472                 LOGE("Failed to change state of src element");
6473                 goto ERROR;
6474         }
6475
6476         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6477                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6478                         LOGE("Failed to change state of decodebin");
6479                         goto ERROR;
6480                 }
6481         } else {
6482                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6483                         LOGE("Failed to change state of src element");
6484                         goto ERROR;
6485                 }
6486         }
6487
6488         player->gapless.stream_changed = TRUE;
6489         player->gapless.running = TRUE;
6490         MMPLAYER_FLEAVE();
6491         return;
6492
6493 ERROR:
6494         if (player) {
6495                 MMPLAYER_PLAYBACK_UNLOCK(player);
6496
6497                 if (!player->msg_posted) {
6498                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6499                         player->msg_posted = TRUE;
6500                 }
6501         }
6502         return;
6503 }
6504
6505 static gboolean
6506 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6507 {
6508         mm_player_selector_t *selector = &player->selector[type];
6509         MMPlayerGstElement *sinkbin = NULL;
6510         enum MainElementID selectorId = MMPLAYER_M_NUM;
6511         enum MainElementID sinkId = MMPLAYER_M_NUM;
6512         GstPad *srcpad = NULL;
6513         GstPad *sinkpad = NULL;
6514         gboolean send_notice = FALSE;
6515
6516         MMPLAYER_FENTER();
6517         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6518
6519         LOGD("type %d", type);
6520
6521         switch (type) {
6522         case MM_PLAYER_TRACK_TYPE_AUDIO:
6523                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6524                 sinkId = MMPLAYER_A_BIN;
6525                 sinkbin = player->pipeline->audiobin;
6526                 break;
6527         case MM_PLAYER_TRACK_TYPE_VIDEO:
6528                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6529                 sinkId = MMPLAYER_V_BIN;
6530                 sinkbin = player->pipeline->videobin;
6531                 send_notice = TRUE;
6532                 break;
6533         case MM_PLAYER_TRACK_TYPE_TEXT:
6534                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6535                 sinkId = MMPLAYER_T_BIN;
6536                 sinkbin = player->pipeline->textbin;
6537                 break;
6538         default:
6539                 LOGE("requested type is not supportable");
6540                 return FALSE;
6541                 break;
6542         }
6543
6544         if (player->pipeline->mainbin[selectorId].gst) {
6545                 gint n;
6546
6547                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6548
6549                 if (selector->event_probe_id != 0)
6550                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6551                 selector->event_probe_id = 0;
6552
6553                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6554                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6555
6556                         if (srcpad && sinkpad) {
6557                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6558                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6559                                 gst_pad_unlink(srcpad, sinkpad);
6560
6561                                 /* send custom event to sink pad to handle it at video sink */
6562                                 if (send_notice) {
6563                                         LOGD("send custom event to sinkpad");
6564                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6565                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6566                                         gst_pad_send_event(sinkpad, event);
6567                                 }
6568                         }
6569
6570                         gst_object_unref(sinkpad);
6571                         sinkpad = NULL;
6572                 }
6573                 gst_object_unref(srcpad);
6574                 srcpad = NULL;
6575
6576                 LOGD("selector release");
6577
6578                 /* release and unref requests pad from the selector */
6579                 for (n = 0; n < selector->channels->len; n++) {
6580                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6581                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6582                 }
6583                 g_ptr_array_set_size(selector->channels, 0);
6584
6585                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6586                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6587
6588                 player->pipeline->mainbin[selectorId].gst = NULL;
6589                 selector = NULL;
6590         }
6591
6592         return TRUE;
6593 }
6594
6595 static void
6596 __mmplayer_deactivate_old_path(mm_player_t *player)
6597 {
6598         MMPLAYER_FENTER();
6599         MMPLAYER_RETURN_IF_FAIL(player);
6600
6601         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6602                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6603                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6604                 LOGE("deactivate selector error");
6605                 goto ERROR;
6606         }
6607
6608         __mmplayer_track_destroy(player);
6609         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6610
6611         if (player->streamer) {
6612                 __mm_player_streaming_initialize(player->streamer, FALSE);
6613                 __mm_player_streaming_destroy(player->streamer);
6614                 player->streamer = NULL;
6615         }
6616
6617         MMPLAYER_PLAYBACK_LOCK(player);
6618         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6619
6620         MMPLAYER_FLEAVE();
6621         return;
6622
6623 ERROR:
6624
6625         if (!player->msg_posted) {
6626                 MMMessageParamType msg = {0,};
6627
6628                 /*post error*/
6629                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6630                 LOGE("gapless_uri_play> deactivate error");
6631
6632                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6633                 player->msg_posted = TRUE;
6634         }
6635         return;
6636 }
6637
6638 int
6639 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6640 {
6641         int result = MM_ERROR_NONE;
6642         mm_player_t *player = (mm_player_t *)hplayer;
6643         MMPLAYER_FENTER();
6644
6645         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6646
6647         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6648         if (mm_attrs_commit_all(player->attrs)) {
6649                 LOGE("failed to commit the original uri.");
6650                 result = MM_ERROR_PLAYER_INTERNAL;
6651         } else {
6652                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6653                         LOGE("failed to add the original uri in the uri list.");
6654         }
6655
6656         MMPLAYER_FLEAVE();
6657         return result;
6658 }
6659
6660 int
6661 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6662 {
6663         mm_player_t *player = (mm_player_t *)hplayer;
6664         guint num_of_list = 0;
6665
6666         MMPLAYER_FENTER();
6667
6668         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6669         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6670
6671         if (player->pipeline && player->pipeline->textbin) {
6672                 LOGE("subtitle path is enabled.");
6673                 return MM_ERROR_PLAYER_INVALID_STATE;
6674         }
6675
6676         num_of_list = g_list_length(player->uri_info.uri_list);
6677
6678         if (is_first_path) {
6679                 if (num_of_list == 0) {
6680                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6681                         SECURE_LOGD("add original path : %s", uri);
6682                 } else {
6683                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6684                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6685
6686                         SECURE_LOGD("change original path : %s", uri);
6687                 }
6688         } else {
6689                 MMHandleType attrs = 0;
6690                 attrs = MMPLAYER_GET_ATTRS(player);
6691
6692                 if (num_of_list == 0) {
6693                         char *original_uri = NULL;
6694
6695                         if (attrs) {
6696                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6697
6698                                 if (!original_uri) {
6699                                         LOGE("there is no original uri.");
6700                                         return MM_ERROR_PLAYER_INVALID_STATE;
6701                                 }
6702
6703                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6704                                 player->uri_info.uri_idx = 0;
6705
6706                                 SECURE_LOGD("add original path at first : %s", original_uri);
6707                         }
6708                 }
6709
6710                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6711                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6712         }
6713
6714         MMPLAYER_FLEAVE();
6715         return MM_ERROR_NONE;
6716 }
6717
6718 int
6719 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6720 {
6721         mm_player_t *player = (mm_player_t *)hplayer;
6722         char *next_uri = NULL;
6723         guint num_of_list = 0;
6724
6725         MMPLAYER_FENTER();
6726         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6727
6728         num_of_list = g_list_length(player->uri_info.uri_list);
6729
6730         if (num_of_list > 0) {
6731                 gint uri_idx = player->uri_info.uri_idx;
6732
6733                 if (uri_idx < num_of_list-1)
6734                         uri_idx++;
6735                 else
6736                         uri_idx = 0;
6737
6738                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6739                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6740
6741                 *uri = g_strdup(next_uri);
6742         }
6743
6744         MMPLAYER_FLEAVE();
6745         return MM_ERROR_NONE;
6746 }
6747
6748 static void
6749 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad,
6750         GstCaps *caps, gpointer data)
6751 {
6752         mm_player_t *player = (mm_player_t *)data;
6753         const gchar *klass = NULL;
6754         const gchar *mime = NULL;
6755         gchar *caps_str = NULL;
6756
6757         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6758         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6759         caps_str = gst_caps_to_string(caps);
6760
6761         LOGW("unknown type of caps : %s from %s",
6762                                         caps_str, GST_ELEMENT_NAME(elem));
6763
6764         MMPLAYER_FREEIF(caps_str);
6765
6766         /* There is no available codec. */
6767         __mmplayer_check_not_supported_codec(player, klass, mime);
6768 }
6769
6770 static gboolean
6771 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
6772         GstCaps *caps,  gpointer data)
6773 {
6774         mm_player_t *player = (mm_player_t *)data;
6775         const char *mime = NULL;
6776         gboolean ret = TRUE;
6777
6778         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6779         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6780
6781         if (g_str_has_prefix(mime, "audio")) {
6782                 GstStructure *caps_structure = NULL;
6783                 gint samplerate = 0;
6784                 gint channels = 0;
6785                 gchar *caps_str = NULL;
6786
6787                 caps_structure = gst_caps_get_structure(caps, 0);
6788                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6789                 gst_structure_get_int(caps_structure, "channels", &channels);
6790
6791                 if ((channels > 0 && samplerate == 0)) {
6792                         LOGD("exclude audio...");
6793                         ret = FALSE;
6794                 }
6795
6796                 caps_str = gst_caps_to_string(caps);
6797                 /* set it directly because not sent by TAG */
6798                 if (g_strrstr(caps_str, "mobile-xmf"))
6799                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6800                 MMPLAYER_FREEIF(caps_str);
6801         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6802                 MMMessageParamType msg_param;
6803                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6804                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6805                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6806                 LOGD("video file is not supported on this device");
6807                 ret = FALSE;
6808         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6809                 LOGD("already video linked");
6810                 ret = FALSE;
6811         } else {
6812                 LOGD("found new stream");
6813         }
6814
6815         return ret;
6816 }
6817
6818 static gboolean
6819 __mmplayer_is_audio_offload_device_type(mm_player_t *player)
6820 {
6821         gboolean ret = TRUE;
6822         GDBusConnection *conn = NULL;
6823         GError *err = NULL;
6824         GVariant *result = NULL;
6825         const gchar *dbus_device_type = NULL;
6826         const gchar *dbus_ret = NULL;
6827         gint idx = 0;
6828
6829         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6830         if (!conn || err) {
6831                 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6832                 g_error_free(err);
6833                 ret = FALSE;
6834                 goto DONE;
6835         }
6836
6837         result = g_dbus_connection_call_sync(conn,
6838                                         "org.pulseaudio.Server",
6839                                         "/org/pulseaudio/StreamManager",
6840                                         "org.pulseaudio.StreamManager",
6841                                         "GetCurrentMediaRoutingPath",
6842                                         g_variant_new("(s)", "out"),
6843                                         G_VARIANT_TYPE("(ss)"),
6844                                         G_DBUS_CALL_FLAGS_NONE,
6845                                         2000,
6846                                         NULL,
6847                                         &err);
6848         if (!result || err) {
6849                 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6850                 g_error_free(err);
6851                 ret = FALSE;
6852                 goto DONE;
6853         }
6854
6855         /* device type is listed in stream-map.json at mmfw-sysconf */
6856         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6857
6858         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6859         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6860                 ret = FALSE;
6861                 goto DONE;
6862         }
6863
6864         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6865         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6866                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6867                         LOGD("audio offload is supportable");
6868                         ret = TRUE;
6869                         goto DONE;
6870                 }
6871         }
6872
6873         LOGD("audio offload is not supportable");
6874         ret = FALSE;
6875
6876 DONE:
6877         g_variant_unref(result);
6878         g_object_unref(conn);
6879
6880         return ret;
6881 }
6882
6883 static void __mmplayer_rebuild_audio_pipeline(mm_player_t *player)
6884 {
6885         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6886         gint64 position = 0;
6887
6888         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6889                 player->pipeline && player->pipeline->mainbin);
6890
6891         MMPLAYER_CMD_LOCK(player);
6892         current_state = MMPLAYER_CURRENT_STATE(player);
6893
6894         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6895                 LOGW("getting current position failed in paused");
6896
6897         _mmplayer_unrealize((MMHandleType)player);
6898         _mmplayer_realize((MMHandleType)player);
6899
6900         _mmplayer_set_position((MMHandleType)player, position);
6901
6902         /* async not to be blocked in streaming case */
6903         mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6904         if (mm_attrs_commit_all(player->attrs))
6905                 LOGE("failed to commit");
6906
6907         _mmplayer_pause((MMHandleType)player);
6908
6909         if (current_state == MM_PLAYER_STATE_PLAYING)
6910                 _mmplayer_start((MMHandleType)player);
6911         MMPLAYER_CMD_UNLOCK(player);
6912
6913         LOGD("rebuilding audio pipeline is completed.");
6914 }
6915
6916 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6917 {
6918         mm_player_t *player = (mm_player_t *)user_data;
6919         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6920         gboolean is_supportable = FALSE;
6921
6922         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6923                 LOGW("failed to get device type");
6924         else
6925                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6926
6927         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6928                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6929                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6930                 LOGD("ignore this dev connected info");
6931                 return;
6932         }
6933
6934         is_supportable = __mmplayer_is_audio_offload_device_type(player);
6935         if (player->build_audio_offload == is_supportable) {
6936                 LOGD("keep current pipeline without re-building");
6937                 return;
6938         }
6939
6940         /* rebuild pipeline */
6941         LOGD("re-build pipeline - offload: %d", is_supportable);
6942         player->build_audio_offload = FALSE;
6943         __mmplayer_rebuild_audio_pipeline(player);
6944
6945         return;
6946 }
6947
6948 static gboolean
6949 __mmplayer_add_audio_device_connected_cb(mm_player_t *player)
6950 {
6951         unsigned int id = 0;
6952
6953         if (player->audio_device_cb_id != 0) {
6954                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6955                 return TRUE;
6956         }
6957
6958         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6959                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6960                 LOGD("added device connected cb (%u)", id);
6961                 player->audio_device_cb_id = id;
6962         } else {
6963                 LOGW("failed to add device connected cb");
6964                 return FALSE;
6965         }
6966
6967         return TRUE;
6968 }
6969
6970 static gboolean
6971 __mmplayer_can_build_audio_offload_path(mm_player_t *player)
6972 {
6973         gboolean ret = FALSE;
6974         GstElementFactory *factory = NULL;
6975
6976         MMPLAYER_FENTER();
6977         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6978
6979         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6980         if (!__mmplayer_is_only_mp3_type(player->type))
6981                 goto DONE;
6982
6983         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6984                 LOGD("there is no audio offload sink");
6985                 goto DONE;
6986         }
6987
6988         if (player->ini.audio_offload_device_type[0][0] == '\0') {
6989                 LOGW("there is no audio device type to support offload");
6990                 goto DONE;
6991         }
6992
6993         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6994         if (!factory) {
6995                 LOGW("there is no installed audio offload sink element");
6996                 goto DONE;
6997         }
6998         gst_object_unref(factory);
6999
7000         if (!__mmplayer_add_audio_device_connected_cb(player))
7001                 goto DONE;
7002
7003         if (!__mmplayer_is_audio_offload_device_type(player))
7004                 goto DONE;
7005
7006         LOGD("audio offload can be built");
7007         ret = TRUE;
7008
7009 DONE:
7010         MMPLAYER_FLEAVE();
7011         return ret;
7012 }
7013
7014 static GstAutoplugSelectResult
7015 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
7016 {
7017         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7018         int idx = 0;
7019         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7020         int audio_offload = 0;
7021
7022         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7023                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7024
7025                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7026                         LOGD("expose audio path to build offload output path");
7027                         player->build_audio_offload = TRUE;
7028                         /* update codec info */
7029                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7030                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7031                         player->audiodec_linked = 1;
7032
7033                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7034                         goto DONE;
7035                 }
7036
7037                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7038
7039                 LOGD("audio codec type: %d", codec_type);
7040                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7041                         /* sw codec will be skipped */
7042                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7043                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7044                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7045                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7046                                         goto DONE;
7047                                 }
7048                         }
7049                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7050                         /* hw codec will be skipped */
7051                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
7052                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7053                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7054                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7055                                 goto DONE;
7056                         }
7057                 }
7058
7059                 /* set stream information */
7060                 if (!player->audiodec_linked)
7061                         __mmplayer_set_audio_attrs(player, caps);
7062
7063                 /* update codec info */
7064                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7065                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7066                 player->audiodec_linked = 1;
7067
7068         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7069
7070                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7071
7072                 LOGD("video codec type: %d", codec_type);
7073                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7074                         /* sw codec is skipped */
7075                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7076                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7077                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7078                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7079                                         goto DONE;
7080                                 }
7081                         }
7082                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7083                         /* hw codec is skipped */
7084                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7085                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7086                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7087                                 goto DONE;
7088                         }
7089                 }
7090
7091                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7092                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7093
7094                         /* mark video decoder for acquire */
7095                         if (player->video_decoder_resource == NULL) {
7096                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7097                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7098                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7099                                                 &player->video_decoder_resource)
7100                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7101                                         LOGE("could not mark video_decoder resource for acquire");
7102                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7103                                         goto DONE;
7104                                 }
7105                         } else {
7106                                 LOGW("video decoder resource is already acquired, skip it.");
7107                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7108                                 goto DONE;
7109                         }
7110
7111                         player->interrupted_by_resource = FALSE;
7112                         /* acquire resources for video playing */
7113                         if (mm_resource_manager_commit(player->resource_manager)
7114                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7115                                 LOGE("could not acquire resources for video decoding");
7116                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7117                                 goto DONE;
7118                         }
7119                 }
7120
7121                 /* update codec info */
7122                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7123                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7124                 player->videodec_linked = 1;
7125         }
7126
7127 DONE:
7128         return ret;
7129 }
7130
7131 gint
7132 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7133         GstCaps *caps, GstElementFactory *factory, gpointer data)
7134 {
7135         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7136         mm_player_t *player = (mm_player_t *)data;
7137
7138         gchar *factory_name = NULL;
7139         gchar *caps_str = NULL;
7140         const gchar *klass = NULL;
7141         gint idx = 0;
7142
7143         factory_name = GST_OBJECT_NAME(factory);
7144         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7145         caps_str = gst_caps_to_string(caps);
7146
7147         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7148
7149         /* store type string */
7150         if (player->type == NULL) {
7151                 player->type = gst_caps_to_string(caps);
7152                 __mmplayer_update_content_type_info(player);
7153         }
7154
7155         /* filtering exclude keyword */
7156         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7157                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7158                         LOGW("skipping [%s] by exculde keyword [%s]",
7159                                         factory_name, player->ini.exclude_element_keyword[idx]);
7160
7161                         result = GST_AUTOPLUG_SELECT_SKIP;
7162                         goto DONE;
7163                 }
7164         }
7165
7166         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7167                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7168                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7169                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7170                         result = GST_AUTOPLUG_SELECT_SKIP;
7171                         goto DONE;
7172                 }
7173         }
7174
7175         /* exclude webm format */
7176         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7177          * because webm format is not supportable.
7178          * If webm is disabled in "autoplug-continue", there is no state change
7179          * failure or error because the decodebin will expose the pad directly.
7180          * It make MSL invoke _prepare_async_callback.
7181          * So, we need to disable webm format in "autoplug-select" */
7182         if (caps_str && strstr(caps_str, "webm")) {
7183                 LOGW("webm is not supported");
7184                 result = GST_AUTOPLUG_SELECT_SKIP;
7185                 goto DONE;
7186         }
7187
7188         /* check factory class for filtering */
7189         /* NOTE : msl don't need to use image plugins.
7190          * So, those plugins should be skipped for error handling.
7191          */
7192         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7193                 LOGD("skipping [%s] by not required", factory_name);
7194                 result = GST_AUTOPLUG_SELECT_SKIP;
7195                 goto DONE;
7196         }
7197
7198         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7199                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7200                 // TO CHECK : subtitle if needed, add subparse exception.
7201                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7202                 result = GST_AUTOPLUG_SELECT_SKIP;
7203                 goto DONE;
7204         }
7205
7206         if (g_strrstr(factory_name, "mpegpsdemux")) {
7207                 LOGD("skipping PS container - not support");
7208                 result = GST_AUTOPLUG_SELECT_SKIP;
7209                 goto DONE;
7210         }
7211
7212         if (g_strrstr(factory_name, "mssdemux"))
7213                 player->smooth_streaming = TRUE;
7214
7215         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7216                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7217                 gint stype = 0;
7218                 gint width = 0;
7219                 GstStructure *str = NULL;
7220                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7221
7222                 /* don't make video because of not required */
7223                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7224                         (!player->set_mode.media_packet_video_stream)) {
7225                         LOGD("no need video decoding, expose pad");
7226                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7227                         goto DONE;
7228                 }
7229
7230                 /* get w/h for omx state-tune */
7231                 /* FIXME: deprecated? */
7232                 str = gst_caps_get_structure(caps, 0);
7233                 gst_structure_get_int(str, "width", &width);
7234
7235                 if (width != 0) {
7236                         if (player->v_stream_caps) {
7237                                 gst_caps_unref(player->v_stream_caps);
7238                                 player->v_stream_caps = NULL;
7239                         }
7240
7241                         player->v_stream_caps = gst_caps_copy(caps);
7242                         LOGD("take caps for video state tune");
7243                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7244                 }
7245         }
7246
7247         if (g_strrstr(klass, "Codec/Decoder")) {
7248                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7249                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7250                         LOGW("skip add decoder");
7251                         goto DONE;
7252                 }
7253         }
7254
7255 DONE:
7256         MMPLAYER_FREEIF(caps_str);
7257
7258         return result;
7259 }
7260
7261 static void
7262 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad,
7263         gpointer data)
7264 {
7265         //mm_player_t *player = (mm_player_t *)data;
7266         GstCaps *caps = NULL;
7267
7268         LOGD("[Decodebin2] pad-removed signal");
7269
7270         caps = gst_pad_query_caps(new_pad, NULL);
7271         if (!caps) {
7272                 LOGW("query caps is NULL");
7273                 return;
7274         }
7275
7276         gchar *caps_str = NULL;
7277         caps_str = gst_caps_to_string(caps);
7278
7279         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7280
7281         MMPLAYER_FREEIF(caps_str);
7282         gst_caps_unref(caps);
7283 }
7284
7285 static void
7286 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7287 {
7288         mm_player_t *player = (mm_player_t *)data;
7289         GstIterator *iter = NULL;
7290         GValue item = { 0, };
7291         GstPad *pad = NULL;
7292         gboolean done = FALSE;
7293         gboolean is_all_drained = TRUE;
7294
7295         MMPLAYER_FENTER();
7296         MMPLAYER_RETURN_IF_FAIL(player);
7297
7298         LOGD("__mmplayer_gst_decode_drained");
7299
7300         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7301                 LOGW("Fail to get cmd lock");
7302                 return;
7303         }
7304
7305         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7306                 !__mmplayer_verify_gapless_play_path(player)) {
7307                 LOGD("decoding is finished.");
7308                 __mmplayer_reset_gapless_state(player);
7309                 MMPLAYER_CMD_UNLOCK(player);
7310                 return;
7311         }
7312
7313         player->gapless.reconfigure = TRUE;
7314
7315         /* check decodebin src pads whether they received EOS or not */
7316         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7317
7318         while (!done) {
7319                 switch (gst_iterator_next(iter, &item)) {
7320                 case GST_ITERATOR_OK:
7321                         pad = g_value_get_object(&item);
7322                         if (pad && !GST_PAD_IS_EOS(pad)) {
7323                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7324                                 is_all_drained = FALSE;
7325                                 break;
7326                         }
7327                         g_value_reset(&item);
7328                         break;
7329                 case GST_ITERATOR_RESYNC:
7330                         gst_iterator_resync(iter);
7331                         break;
7332                 case GST_ITERATOR_ERROR:
7333                 case GST_ITERATOR_DONE:
7334                         done = TRUE;
7335                         break;
7336                 }
7337         }
7338         g_value_unset(&item);
7339         gst_iterator_free(iter);
7340
7341         if (!is_all_drained) {
7342                 LOGD("Wait util the all pads get EOS.");
7343                 MMPLAYER_CMD_UNLOCK(player);
7344                 MMPLAYER_FLEAVE();
7345                 return;
7346         }
7347
7348         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7349         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7350
7351         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7352         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7353         __mmplayer_deactivate_old_path(player);
7354         MMPLAYER_CMD_UNLOCK(player);
7355
7356         MMPLAYER_FLEAVE();
7357 }
7358
7359 void
7360 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7361 {
7362         mm_player_t *player = (mm_player_t *)data;
7363         const gchar *klass = NULL;
7364         gchar *factory_name = NULL;
7365
7366         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7367         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7368
7369         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7370
7371         if (__mmplayer_add_dump_buffer_probe(player, element))
7372                 LOGD("add buffer probe");
7373
7374         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7375                 gchar *selected = NULL;
7376                 selected = g_strdup(GST_ELEMENT_NAME(element));
7377                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7378         }
7379
7380         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7381                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7382                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7383
7384                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7385                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7386
7387                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7388                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7389                                                 "max-video-width", player->adaptive_info.limit.width,
7390                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7391
7392         } else if (g_strrstr(klass, "Demuxer")) {
7393                 //LOGD("plugged element is demuxer. take it");
7394                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7395                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7396         }
7397
7398         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7399                 int surface_type = 0;
7400
7401                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7402         }
7403
7404         // to support trust-zone only
7405         if (g_strrstr(factory_name, "asfdemux")) {
7406                 LOGD("set file-location %s", player->profile.uri);
7407                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7408         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7409                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7410                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7411         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7412                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7413                         (__mmplayer_is_only_mp3_type(player->type))) {
7414                         LOGD("[mpegaudioparse] set streaming pull mode.");
7415                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7416                 }
7417         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7418                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7419         }
7420
7421         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7422                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7423                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7424
7425                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7426                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7427
7428                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7429                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7430                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7431                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7432                         __mm_player_streaming_set_multiqueue(player->streamer, element);
7433                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7434                 }
7435
7436         }
7437
7438         return;
7439 }
7440
7441 static void
7442 __mmplayer_release_misc(mm_player_t *player)
7443 {
7444         int i;
7445         bool cur_mode = player->set_mode.rich_audio;
7446         MMPLAYER_FENTER();
7447
7448         MMPLAYER_RETURN_IF_FAIL(player);
7449
7450         player->video_stream_cb = NULL;
7451         player->video_stream_cb_user_param = NULL;
7452         player->video_stream_prerolled = false;
7453
7454         player->audio_stream_render_cb = NULL;
7455         player->audio_stream_cb_user_param = NULL;
7456         player->audio_stream_sink_sync = false;
7457
7458         player->video_stream_changed_cb = NULL;
7459         player->video_stream_changed_cb_user_param = NULL;
7460
7461         player->audio_stream_changed_cb = NULL;
7462         player->audio_stream_changed_cb_user_param = NULL;
7463
7464         player->sent_bos = FALSE;
7465         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7466
7467         player->seek_state = MMPLAYER_SEEK_NONE;
7468
7469         player->total_bitrate = 0;
7470         player->total_maximum_bitrate = 0;
7471
7472         player->not_found_demuxer = 0;
7473
7474         player->last_position = 0;
7475         player->duration = 0;
7476         player->http_content_size = 0;
7477         player->not_supported_codec = MISSING_PLUGIN_NONE;
7478         player->can_support_codec = FOUND_PLUGIN_NONE;
7479         player->pending_seek.is_pending = false;
7480         player->pending_seek.pos = 0;
7481         player->msg_posted = FALSE;
7482         player->has_many_types = FALSE;
7483         player->is_subtitle_force_drop = FALSE;
7484         player->play_subtitle = FALSE;
7485         player->adjust_subtitle_pos = 0;
7486         player->has_closed_caption = FALSE;
7487         player->set_mode.media_packet_video_stream = false;
7488         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7489         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7490         /* recover mode */
7491         player->set_mode.rich_audio = cur_mode;
7492
7493         if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7494                 LOGW("failed to remove audio device_connected_callback");
7495         player->audio_device_cb_id = 0;
7496
7497         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7498                 player->bitrate[i] = 0;
7499                 player->maximum_bitrate[i] = 0;
7500         }
7501
7502         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7503
7504         /* remove media stream cb(appsrc cb) */
7505         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7506                 player->media_stream_buffer_status_cb[i] = NULL;
7507                 player->media_stream_seek_data_cb[i] = NULL;
7508                 player->buffer_cb_user_param[i] = NULL;
7509                 player->seek_cb_user_param[i] = NULL;
7510         }
7511         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7512
7513         /* free memory related to audio effect */
7514         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7515
7516         if (player->adaptive_info.var_list) {
7517                 g_list_free_full(player->adaptive_info.var_list, g_free);
7518                 player->adaptive_info.var_list = NULL;
7519         }
7520
7521         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7522         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7523         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7524
7525         /* Reset video360 settings to their defaults in case if the pipeline is to be
7526          * re-created.
7527          * */
7528         player->video360_metadata.is_spherical = -1;
7529         player->is_openal_plugin_used = FALSE;
7530
7531         player->is_content_spherical = FALSE;
7532         player->is_video360_enabled = TRUE;
7533         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7534         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7535         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7536         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7537         player->video360_zoom = 1.0f;
7538         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7539         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7540
7541         player->sound.rg_enable = false;
7542
7543         __mmplayer_initialize_video_roi(player);
7544         MMPLAYER_FLEAVE();
7545 }
7546
7547 static void
7548 __mmplayer_release_misc_post(mm_player_t *player)
7549 {
7550         char *original_uri = NULL;
7551         MMPLAYER_FENTER();
7552
7553         /* player->pipeline is already released before. */
7554
7555         MMPLAYER_RETURN_IF_FAIL(player);
7556
7557         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7558
7559         /* clean found audio decoders */
7560         if (player->audio_decoders) {
7561                 GList *a_dec = player->audio_decoders;
7562                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7563                         gchar *name = a_dec->data;
7564                         MMPLAYER_FREEIF(name);
7565                 }
7566                 g_list_free(player->audio_decoders);
7567                 player->audio_decoders = NULL;
7568         }
7569
7570         /* clean the uri list except original uri */
7571         if (player->uri_info.uri_list) {
7572                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7573
7574                 if (player->attrs) {
7575                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7576                         LOGD("restore original uri = %s", original_uri);
7577
7578                         if (mm_attrs_commit_all(player->attrs))
7579                                 LOGE("failed to commit the original uri.");
7580                 }
7581
7582                 GList *uri_list = player->uri_info.uri_list;
7583                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7584                         gchar *uri = uri_list->data;
7585                         MMPLAYER_FREEIF(uri);
7586                 }
7587                 g_list_free(player->uri_info.uri_list);
7588                 player->uri_info.uri_list = NULL;
7589         }
7590
7591         /* clear the audio stream buffer list */
7592         __mmplayer_audio_stream_clear_buffer(player, FALSE);
7593
7594         /* clear the video stream bo list */
7595         __mmplayer_video_stream_destroy_bo_list(player);
7596         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7597
7598         if (player->profile.input_mem.buf) {
7599                 free(player->profile.input_mem.buf);
7600                 player->profile.input_mem.buf = NULL;
7601         }
7602         player->profile.input_mem.len = 0;
7603         player->profile.input_mem.offset = 0;
7604
7605         player->uri_info.uri_idx = 0;
7606         MMPLAYER_FLEAVE();
7607 }
7608
7609 gboolean
7610 __mmplayer_check_subtitle(mm_player_t *player)
7611 {
7612         MMHandleType attrs = 0;
7613         char *subtitle_uri = NULL;
7614
7615         MMPLAYER_FENTER();
7616
7617         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7618
7619         /* get subtitle attribute */
7620         attrs = MMPLAYER_GET_ATTRS(player);
7621         if (!attrs)
7622                 return FALSE;
7623
7624         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7625         if (!subtitle_uri || !strlen(subtitle_uri))
7626                 return FALSE;
7627
7628         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7629         player->is_external_subtitle_present = TRUE;
7630
7631         MMPLAYER_FLEAVE();
7632
7633         return TRUE;
7634 }
7635
7636 void
7637 __mmplayer_cancel_eos_timer(mm_player_t *player)
7638 {
7639         MMPLAYER_RETURN_IF_FAIL(player);
7640
7641         if (player->eos_timer) {
7642                 LOGD("cancel eos timer");
7643                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7644                 player->eos_timer = 0;
7645         }
7646
7647         return;
7648 }
7649
7650 static void
7651 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7652 {
7653         MMPLAYER_FENTER();
7654
7655         MMPLAYER_RETURN_IF_FAIL(player);
7656         MMPLAYER_RETURN_IF_FAIL(sink);
7657
7658         player->sink_elements = g_list_append(player->sink_elements, sink);
7659
7660         MMPLAYER_FLEAVE();
7661 }
7662
7663 static void
7664 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7665 {
7666         MMPLAYER_FENTER();
7667
7668         MMPLAYER_RETURN_IF_FAIL(player);
7669         MMPLAYER_RETURN_IF_FAIL(sink);
7670
7671         player->sink_elements = g_list_remove(player->sink_elements, sink);
7672
7673         MMPLAYER_FLEAVE();
7674 }
7675
7676 void
7677 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7678         MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7679 {
7680         MMPlayerSignalItem *item = NULL;
7681
7682         MMPLAYER_FENTER();
7683         MMPLAYER_RETURN_IF_FAIL(player);
7684
7685         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7686                 LOGE("invalid signal type [%d]", type);
7687                 return;
7688         }
7689
7690         item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7691         if (!item) {
7692                 LOGE("cannot connect signal [%s]", signal);
7693                 return;
7694         }
7695
7696         item->obj = object;
7697         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7698         player->signals[type] = g_list_append(player->signals[type], item);
7699
7700         MMPLAYER_FLEAVE();
7701         return;
7702 }
7703
7704 /* NOTE : be careful with calling this api. please refer to below glib comment
7705  * glib comment : Note that there is a bug in GObject that makes this function much
7706  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7707  * will no longer be called, but, the signal handler is not currently disconnected.
7708  * If the instance is itself being freed at the same time than this doesn't matter,
7709  * since the signal will automatically be removed, but if instance persists,
7710  * then the signal handler will leak. You should not remove the signal yourself
7711  * because in a future versions of GObject, the handler will automatically be
7712  * disconnected.
7713  *
7714  * It's possible to work around this problem in a way that will continue to work
7715  * with future versions of GObject by checking that the signal handler is still
7716  * connected before disconnected it:
7717  *
7718  *  if (g_signal_handler_is_connected(instance, id))
7719  *    g_signal_handler_disconnect(instance, id);
7720  */
7721 static void
7722 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7723 {
7724         GList *sig_list = NULL;
7725         MMPlayerSignalItem *item = NULL;
7726
7727         MMPLAYER_FENTER();
7728
7729         MMPLAYER_RETURN_IF_FAIL(player);
7730
7731         LOGD("release signals type : %d", type);
7732
7733         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7734                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7735                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7736                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7737                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7738                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7739                 return;
7740         }
7741
7742         sig_list = player->signals[type];
7743
7744         for (; sig_list; sig_list = sig_list->next) {
7745                 item = sig_list->data;
7746
7747                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7748                         if (g_signal_handler_is_connected(item->obj, item->sig))
7749                                 g_signal_handler_disconnect(item->obj, item->sig);
7750                 }
7751
7752                 MMPLAYER_FREEIF(item);
7753         }
7754
7755         g_list_free(player->signals[type]);
7756         player->signals[type] = NULL;
7757
7758         MMPLAYER_FLEAVE();
7759
7760         return;
7761 }
7762
7763 int
7764 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7765 {
7766         mm_player_t *player = 0;
7767         int prev_display_surface_type = 0;
7768         void *prev_display_overlay = NULL;
7769
7770         MMPLAYER_FENTER();
7771
7772         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7773         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7774
7775         player = MM_PLAYER_CAST(handle);
7776
7777         /* check video sinkbin is created */
7778         if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7779                 LOGE("Videosink is already created");
7780                 return MM_ERROR_NONE;
7781         }
7782
7783         LOGD("videosink element is not yet ready");
7784
7785         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7786                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7787                 MMPLAYER_FLEAVE();
7788                 return MM_ERROR_INVALID_ARGUMENT;
7789         }
7790
7791         /* load previous attributes */
7792         if (player->attrs) {
7793                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7794                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7795                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7796                 if (prev_display_surface_type == surface_type) {
7797                         LOGD("incoming display surface type is same as previous one, do nothing..");
7798                         MMPLAYER_FLEAVE();
7799                         return MM_ERROR_NONE;
7800                 }
7801         } else {
7802                 LOGE("failed to load attributes");
7803                 MMPLAYER_FLEAVE();
7804                 return MM_ERROR_PLAYER_INTERNAL;
7805         }
7806
7807         /* videobin is not created yet, so we just set attributes related to display surface */
7808         LOGD("store display attribute for given surface type(%d)", surface_type);
7809         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7810         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7811         if (mm_attrs_commit_all(player->attrs)) {
7812                 LOGE("failed to commit attribute");
7813                 MMPLAYER_FLEAVE();
7814                 return MM_ERROR_PLAYER_INTERNAL;
7815         }
7816
7817         MMPLAYER_FLEAVE();
7818         return MM_ERROR_NONE;
7819 }
7820
7821 /* Note : if silent is true, then subtitle would not be displayed. :*/
7822 int
7823 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7824 {
7825         mm_player_t *player = (mm_player_t *)hplayer;
7826
7827         MMPLAYER_FENTER();
7828
7829         /* check player handle */
7830         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7831
7832         player->set_mode.subtitle_off = silent;
7833
7834         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7835
7836         MMPLAYER_FLEAVE();
7837
7838         return MM_ERROR_NONE;
7839 }
7840
7841 int
7842 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7843 {
7844         MMPlayerGstElement *mainbin = NULL;
7845         MMPlayerGstElement *textbin = NULL;
7846         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7847         GstState current_state = GST_STATE_VOID_PENDING;
7848         GstState element_state = GST_STATE_VOID_PENDING;
7849         GstState element_pending_state = GST_STATE_VOID_PENDING;
7850         gint64 time = 0;
7851         GstEvent *event = NULL;
7852         int result = MM_ERROR_NONE;
7853
7854         GstClock *curr_clock = NULL;
7855         GstClockTime base_time, start_time, curr_time;
7856
7857
7858         MMPLAYER_FENTER();
7859
7860         /* check player handle */
7861         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7862                                                                 player->pipeline &&
7863                                                                 player->pipeline->mainbin &&
7864                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7865
7866         mainbin = player->pipeline->mainbin;
7867         textbin = player->pipeline->textbin;
7868
7869         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7870
7871         // sync clock with current pipeline
7872         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7873         curr_time = gst_clock_get_time(curr_clock);
7874
7875         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7876         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7877
7878         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7879                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7880
7881         if (current_state > GST_STATE_READY) {
7882                 // sync state with current pipeline
7883                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7884                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7885                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7886
7887                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7888                 if (GST_STATE_CHANGE_FAILURE == ret) {
7889                         LOGE("fail to state change.");
7890                         result = MM_ERROR_PLAYER_INTERNAL;
7891                         goto ERROR;
7892                 }
7893         }
7894         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7895         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7896
7897         if (curr_clock) {
7898                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7899                 gst_object_unref(curr_clock);
7900         }
7901
7902         // seek to current position
7903         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7904                 result = MM_ERROR_PLAYER_INVALID_STATE;
7905                 LOGE("gst_element_query_position failed, invalid state");
7906                 goto ERROR;
7907         }
7908
7909         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7910         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);
7911         if (event) {
7912                 __mmplayer_gst_send_event_to_sink(player, event);
7913         } else {
7914                 result = MM_ERROR_PLAYER_INTERNAL;
7915                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7916                 goto ERROR;
7917         }
7918
7919         /* sync state with current pipeline */
7920         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7921         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7922         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7923
7924         return MM_ERROR_NONE;
7925
7926 ERROR:
7927         /* release text pipeline resource */
7928         player->textsink_linked = 0;
7929
7930         /* release signal */
7931         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7932
7933         /* release textbin with it's childs */
7934         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7935         MMPLAYER_FREEIF(player->pipeline->textbin);
7936         player->pipeline->textbin = NULL;
7937
7938         /* release subtitle elem */
7939         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7940         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7941
7942         return result;
7943 }
7944
7945 static int
7946 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7947 {
7948         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7949         GstState current_state = GST_STATE_VOID_PENDING;
7950
7951         MMHandleType attrs = 0;
7952         MMPlayerGstElement *mainbin = NULL;
7953         MMPlayerGstElement *textbin = NULL;
7954
7955         gchar *subtitle_uri = NULL;
7956         int result = MM_ERROR_NONE;
7957         const gchar *charset = NULL;
7958
7959         MMPLAYER_FENTER();
7960
7961         /* check player handle */
7962         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7963                                                                 player->pipeline &&
7964                                                                 player->pipeline->mainbin &&
7965                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7966         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7967
7968         mainbin = player->pipeline->mainbin;
7969         textbin = player->pipeline->textbin;
7970
7971         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7972         if (current_state < GST_STATE_READY) {
7973                 result = MM_ERROR_PLAYER_INVALID_STATE;
7974                 LOGE("Pipeline is not in proper state");
7975                 goto EXIT;
7976         }
7977
7978         attrs = MMPLAYER_GET_ATTRS(player);
7979         if (!attrs) {
7980                 LOGE("cannot get content attribute");
7981                 result = MM_ERROR_PLAYER_INTERNAL;
7982                 goto EXIT;
7983         }
7984
7985         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7986         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7987                 LOGE("subtitle uri is not proper filepath");
7988                 result = MM_ERROR_PLAYER_INVALID_URI;
7989                 goto EXIT;
7990         }
7991
7992         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7993                 LOGE("failed to get storage info of subtitle path");
7994                 result = MM_ERROR_PLAYER_INVALID_URI;
7995                 goto EXIT;
7996         }
7997
7998         LOGD("old subtitle file path is [%s]", subtitle_uri);
7999         LOGD("new subtitle file path is [%s]", filepath);
8000
8001         if (!strcmp(filepath, subtitle_uri)) {
8002                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8003                 goto EXIT;
8004         } else {
8005                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8006                 if (mm_attrs_commit_all(player->attrs)) {
8007                         LOGE("failed to commit.");
8008                         goto EXIT;
8009                 }
8010         }
8011
8012         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8013         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8014         player->subtitle_language_list = NULL;
8015         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8016
8017         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8018         if (ret != GST_STATE_CHANGE_SUCCESS) {
8019                 LOGE("failed to change state of textbin to READY");
8020                 result = MM_ERROR_PLAYER_INTERNAL;
8021                 goto EXIT;
8022         }
8023
8024         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8025         if (ret != GST_STATE_CHANGE_SUCCESS) {
8026                 LOGE("failed to change state of subparse to READY");
8027                 result = MM_ERROR_PLAYER_INTERNAL;
8028                 goto EXIT;
8029         }
8030
8031         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8032         if (ret != GST_STATE_CHANGE_SUCCESS) {
8033                 LOGE("failed to change state of filesrc to READY");
8034                 result = MM_ERROR_PLAYER_INTERNAL;
8035                 goto EXIT;
8036         }
8037
8038         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8039
8040         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8041
8042         charset = util_get_charset(filepath);
8043         if (charset) {
8044                 LOGD("detected charset is %s", charset);
8045                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8046         }
8047
8048         result = _mmplayer_sync_subtitle_pipeline(player);
8049
8050 EXIT:
8051         MMPLAYER_FLEAVE();
8052         return result;
8053 }
8054
8055 /* API to switch between external subtitles */
8056 int
8057 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8058 {
8059         int result = MM_ERROR_NONE;
8060         mm_player_t *player = (mm_player_t *)hplayer;
8061         char *path = NULL;
8062
8063         MMPLAYER_FENTER();
8064
8065         /* check player handle */
8066         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8067
8068         /* filepath can be null in idle state */
8069         if (filepath) {
8070                 /* check file path */
8071                 if ((path = strstr(filepath, "file://")))
8072                         result = util_exist_file_path(path + 7);
8073                 else
8074                         result = util_exist_file_path(filepath);
8075
8076                 if (result != MM_ERROR_NONE) {
8077                         LOGE("invalid subtitle path 0x%X", result);
8078                         return result; /* file not found or permission denied */
8079                 }
8080         }
8081
8082         if (!player->pipeline) {
8083                 /* IDLE state */
8084                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8085                 if (mm_attrs_commit_all(player->attrs)) {
8086                         LOGE("failed to commit");       /* subtitle path will not be created */
8087                         return MM_ERROR_PLAYER_INTERNAL;
8088                 }
8089         } else {
8090                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8091                 /* check filepath */
8092                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8093
8094                 if (!__mmplayer_check_subtitle(player)) {
8095                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8096                         if (mm_attrs_commit_all(player->attrs)) {
8097                                 LOGE("failed to commit");
8098                                 return MM_ERROR_PLAYER_INTERNAL;
8099                         }
8100
8101                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8102                                 LOGE("fail to create text pipeline");
8103                                 return MM_ERROR_PLAYER_INTERNAL;
8104                         }
8105
8106                         result = _mmplayer_sync_subtitle_pipeline(player);
8107                 } else {
8108                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8109                 }
8110
8111                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8112                 player->is_external_subtitle_added_now = TRUE;
8113
8114                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8115                 if (!player->subtitle_language_list) {
8116                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8117                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8118                                 LOGW("subtitle language list is not updated yet");
8119                 }
8120                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8121         }
8122
8123         MMPLAYER_FLEAVE();
8124         return result;
8125 }
8126
8127 static int
8128 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
8129 {
8130         int result = MM_ERROR_NONE;
8131         gchar *change_pad_name = NULL;
8132         GstPad *sinkpad = NULL;
8133         MMPlayerGstElement *mainbin = NULL;
8134         enum MainElementID elem_idx = MMPLAYER_M_NUM;
8135         GstCaps *caps = NULL;
8136         gint total_track_num = 0;
8137
8138         MMPLAYER_FENTER();
8139
8140         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8141                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8142
8143         LOGD("Change Track(%d) to %d", type, index);
8144
8145         mainbin = player->pipeline->mainbin;
8146
8147         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8148                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8149         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8150                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8151         } else {
8152                 /* Changing Video Track is not supported. */
8153                 LOGE("Track Type Error");
8154                 goto EXIT;
8155         }
8156
8157         if (mainbin[elem_idx].gst == NULL) {
8158                 result = MM_ERROR_PLAYER_NO_OP;
8159                 LOGD("Req track doesn't exist");
8160                 goto EXIT;
8161         }
8162
8163         total_track_num = player->selector[type].total_track_num;
8164         if (total_track_num <= 0) {
8165                 result = MM_ERROR_PLAYER_NO_OP;
8166                 LOGD("Language list is not available");
8167                 goto EXIT;
8168         }
8169
8170         if ((index < 0) || (index >= total_track_num)) {
8171                 result = MM_ERROR_INVALID_ARGUMENT;
8172                 LOGD("Not a proper index : %d", index);
8173                 goto EXIT;
8174         }
8175
8176         /*To get the new pad from the selector*/
8177         change_pad_name = g_strdup_printf("sink_%u", index);
8178         if (change_pad_name == NULL) {
8179                 result = MM_ERROR_PLAYER_INTERNAL;
8180                 LOGD("Pad does not exists");
8181                 goto EXIT;
8182         }
8183
8184         LOGD("new active pad name: %s", change_pad_name);
8185
8186         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8187         if (sinkpad == NULL) {
8188                 LOGD("sinkpad is NULL");
8189                 result = MM_ERROR_PLAYER_INTERNAL;
8190                 goto EXIT;
8191         }
8192
8193         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8194         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8195
8196         caps = gst_pad_get_current_caps(sinkpad);
8197         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8198
8199         if (sinkpad)
8200                 gst_object_unref(sinkpad);
8201
8202         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8203                 __mmplayer_set_audio_attrs(player, caps);
8204
8205 EXIT:
8206         MMPLAYER_FREEIF(change_pad_name);
8207         return result;
8208 }
8209
8210 int
8211 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8212 {
8213         int result = MM_ERROR_NONE;
8214         mm_player_t *player = NULL;
8215         MMPlayerGstElement *mainbin = NULL;
8216
8217         gint current_active_index = 0;
8218
8219         GstState current_state = GST_STATE_VOID_PENDING;
8220         GstEvent *event = NULL;
8221         gint64 time = 0;
8222
8223         MMPLAYER_FENTER();
8224
8225         player = (mm_player_t *)hplayer;
8226         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8227
8228         if (!player->pipeline) {
8229                 LOGE("Track %d pre setting -> %d", type, index);
8230
8231                 player->selector[type].active_pad_index = index;
8232                 goto EXIT;
8233         }
8234
8235         mainbin = player->pipeline->mainbin;
8236
8237         current_active_index = player->selector[type].active_pad_index;
8238
8239         /*If index is same as running index no need to change the pad*/
8240         if (current_active_index == index)
8241                 goto EXIT;
8242
8243         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8244                 result = MM_ERROR_PLAYER_INVALID_STATE;
8245                 goto EXIT;
8246         }
8247
8248         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8249         if (current_state < GST_STATE_PAUSED) {
8250                 result = MM_ERROR_PLAYER_INVALID_STATE;
8251                 LOGW("Pipeline not in porper state");
8252                 goto EXIT;
8253         }
8254
8255         result = __mmplayer_change_selector_pad(player, type, index);
8256         if (result != MM_ERROR_NONE) {
8257                 LOGE("change selector pad error");
8258                 goto EXIT;
8259         }
8260
8261         player->selector[type].active_pad_index = index;
8262
8263         if (current_state == GST_STATE_PLAYING) {
8264                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8265                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8266                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8267                 if (event) {
8268                         __mmplayer_gst_send_event_to_sink(player, event);
8269                 } else {
8270                         result = MM_ERROR_PLAYER_INTERNAL;
8271                         goto EXIT;
8272                 }
8273         }
8274
8275 EXIT:
8276         return result;
8277 }
8278
8279 int
8280 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8281 {
8282         mm_player_t *player = (mm_player_t *)hplayer;
8283
8284         MMPLAYER_FENTER();
8285
8286         /* check player handle */
8287         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8288
8289         *silent = player->set_mode.subtitle_off;
8290
8291         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8292
8293         MMPLAYER_FLEAVE();
8294
8295         return MM_ERROR_NONE;
8296 }
8297
8298 static gboolean
8299 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8300 {
8301         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8302         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8303
8304         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8305         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8306
8307         int idx = 0;
8308
8309         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8310                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8311                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8312                         mm_player_dump_t *dump_s;
8313                         dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8314                         if (dump_s == NULL) {
8315                                 LOGE("malloc fail");
8316                                 return FALSE;
8317                         }
8318
8319                         dump_s->dump_element_file = NULL;
8320                         dump_s->dump_pad = NULL;
8321                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8322
8323                         if (dump_s->dump_pad) {
8324                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8325                                 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]);
8326                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8327                                 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);
8328                                 /* add list for removed buffer probe and close FILE */
8329                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8330                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8331                                 return TRUE;
8332                         } else {
8333                                 MMPLAYER_FREEIF(dump_s);
8334                                 LOGE("failed to get %s sink pad added", factory_name);
8335                         }
8336                 }
8337         }
8338         return FALSE;
8339 }
8340
8341 static GstPadProbeReturn
8342 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8343 {
8344         FILE *dump_data = (FILE *)u_data;
8345 //      int written = 0;
8346         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8347         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8348
8349         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8350
8351         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8352
8353 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8354
8355         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8356
8357         return GST_PAD_PROBE_OK;
8358 }
8359
8360 static void
8361 __mmplayer_release_dump_list(GList *dump_list)
8362 {
8363         GList *d_list = dump_list;
8364
8365         if (!d_list)
8366                 return;
8367
8368         for (; d_list; d_list = g_list_next(d_list)) {
8369                 mm_player_dump_t *dump_s = d_list->data;
8370                 if (dump_s->dump_pad) {
8371                         if (dump_s->probe_handle_id)
8372                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8373                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8374                 }
8375                 if (dump_s->dump_element_file) {
8376                         fclose(dump_s->dump_element_file);
8377                         dump_s->dump_element_file = NULL;
8378                 }
8379                 MMPLAYER_FREEIF(dump_s);
8380         }
8381         g_list_free(dump_list);
8382         dump_list = NULL;
8383 }
8384
8385 int
8386 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8387 {
8388         mm_player_t *player = (mm_player_t *)hplayer;
8389
8390         MMPLAYER_FENTER();
8391
8392         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8393         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8394
8395         *exist = (bool)player->has_closed_caption;
8396
8397         MMPLAYER_FLEAVE();
8398
8399         return MM_ERROR_NONE;
8400 }
8401
8402 void
8403 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8404 {
8405         MMPLAYER_FENTER();
8406         if (buffer) {
8407                 // LOGD("unref internal gst buffer %p", buffer);
8408                 gst_buffer_unref((GstBuffer *)buffer);
8409                 buffer = NULL;
8410         }
8411         MMPLAYER_FLEAVE();
8412 }
8413
8414 int
8415 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8416 {
8417         mm_player_t *player = (mm_player_t *)hplayer;
8418
8419         MMPLAYER_FENTER();
8420
8421         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8422         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8423
8424         if (MMPLAYER_IS_STREAMING(player))
8425                 *timeout = (int)player->ini.live_state_change_timeout;
8426         else
8427                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8428
8429         LOGD("timeout = %d", *timeout);
8430
8431         MMPLAYER_FLEAVE();
8432         return MM_ERROR_NONE;
8433 }
8434
8435 int
8436 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8437 {
8438         mm_player_t *player = (mm_player_t *)hplayer;
8439
8440         MMPLAYER_FENTER();
8441
8442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8443         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8444
8445         *num = player->video_num_buffers;
8446         *extra_num = player->video_extra_num_buffers;
8447
8448         LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8449
8450         MMPLAYER_FLEAVE();
8451         return MM_ERROR_NONE;
8452 }
8453
8454 static void
8455 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8456 {
8457         int i = 0;
8458         MMPLAYER_FENTER();
8459         MMPLAYER_RETURN_IF_FAIL(player);
8460
8461         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8462
8463                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8464                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8465                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8466                         player->storage_info[i].id = -1;
8467                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8468
8469                         if (path_type != MMPLAYER_PATH_MAX)
8470                                 break;
8471                 }
8472         }
8473
8474         MMPLAYER_FLEAVE();
8475 }
8476
8477 int
8478 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8479 {
8480         int ret = MM_ERROR_NONE;
8481         mm_player_t *player = (mm_player_t *)hplayer;
8482         MMMessageParamType msg_param = {0, };
8483
8484         MMPLAYER_FENTER();
8485         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486
8487         LOGW("state changed storage %d:%d", id, state);
8488
8489         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8490                 return MM_ERROR_NONE;
8491
8492         /* FIXME: text path should be handled seperately. */
8493         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8494                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8495                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8496                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8497                 LOGW("external storage is removed");
8498
8499                 if (player->msg_posted == FALSE) {
8500                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8501                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8502                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8503                         player->msg_posted = TRUE;
8504                 }
8505
8506                 /* unrealize the player */
8507                 ret = _mmplayer_unrealize(hplayer);
8508                 if (ret != MM_ERROR_NONE)
8509                         LOGE("failed to unrealize");
8510         }
8511
8512         MMPLAYER_FLEAVE();
8513         return ret;
8514 }
8515
8516 int
8517 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8518 {
8519         int ret = MM_ERROR_NONE;
8520         mm_player_t *player = (mm_player_t *)hplayer;
8521         int idx = 0, total = 0;
8522         gchar *result = NULL, *tmp = NULL;
8523
8524         MMPLAYER_FENTER();
8525         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8527
8528         total = *num = g_list_length(player->adaptive_info.var_list);
8529         if (total <= 0) {
8530                 LOGW("There is no stream variant info.");
8531                 return ret;
8532         }
8533
8534         result = g_strdup("");
8535         for (idx = 0 ; idx < total ; idx++) {
8536                 VariantData *v_data = NULL;
8537                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8538
8539                 if (v_data) {
8540                         gchar data[64] = {0};
8541                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8542
8543                         tmp = g_strconcat(result, data, NULL);
8544                         g_free(result);
8545                         result = tmp;
8546                 } else {
8547                         LOGW("There is no variant data in %d", idx);
8548                         (*num)--;
8549                 }
8550         }
8551
8552         *var_info = (char *)result;
8553
8554         LOGD("variant info %d:%s", *num, *var_info);
8555         MMPLAYER_FLEAVE();
8556         return ret;
8557 }
8558
8559 int
8560 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8561 {
8562         int ret = MM_ERROR_NONE;
8563         mm_player_t *player = (mm_player_t *)hplayer;
8564
8565         MMPLAYER_FENTER();
8566         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8567
8568         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8569
8570         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8571         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8572         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8573
8574         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8575                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8576                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8577                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8578
8579                 /* FIXME: seek to current position for applying new variant limitation */
8580         }
8581
8582         MMPLAYER_FLEAVE();
8583         return ret;
8584
8585 }
8586
8587 int
8588 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8589 {
8590         int ret = MM_ERROR_NONE;
8591         mm_player_t *player = (mm_player_t *)hplayer;
8592
8593         MMPLAYER_FENTER();
8594         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8596
8597         *bandwidth = player->adaptive_info.limit.bandwidth;
8598         *width = player->adaptive_info.limit.width;
8599         *height = player->adaptive_info.limit.height;
8600
8601         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8602
8603         MMPLAYER_FLEAVE();
8604         return ret;
8605 }
8606
8607 int
8608 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8609 {
8610         int ret = MM_ERROR_NONE;
8611         mm_player_t *player = (mm_player_t *)hplayer;
8612
8613         MMPLAYER_FENTER();
8614         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8615         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8616         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8617
8618         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8619
8620         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8621                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8622         else /* live case */
8623                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8624
8625         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8626
8627         MMPLAYER_FLEAVE();
8628         return ret;
8629 }
8630
8631 int
8632 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8633 {
8634 #define IDX_FIRST_SW_CODEC 0
8635         mm_player_t *player = (mm_player_t *)hplayer;
8636         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8637         MMHandleType attrs = 0;
8638
8639         MMPLAYER_FENTER();
8640         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8641
8642         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8643                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8644                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8645
8646         switch (stream_type) {
8647         case MM_PLAYER_STREAM_TYPE_AUDIO:
8648         /* to support audio codec selection, codec info have to be added in ini file as below.
8649            audio codec element hw = xxxx
8650            audio codec element sw = avdec */
8651                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8652                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8653                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8654                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8655                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8656                         return MM_ERROR_PLAYER_NO_OP;
8657                 }
8658         break;
8659         case MM_PLAYER_STREAM_TYPE_VIDEO:
8660         /* to support video codec selection, codec info have to be added in ini file as below.
8661            video codec element hw = omx
8662            video codec element sw = avdec */
8663                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8664                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8665                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8666                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8667                         LOGE("There is no video codec info for codec_type %d", codec_type);
8668                         return MM_ERROR_PLAYER_NO_OP;
8669                 }
8670         break;
8671         default:
8672                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8673                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8674         break;
8675         }
8676
8677         LOGD("update %s codec_type to %d", attr_name, codec_type);
8678
8679         attrs = MMPLAYER_GET_ATTRS(player);
8680         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8681
8682         if (mm_attrs_commit_all(player->attrs)) {
8683                 LOGE("failed to commit codec_type attributes");
8684                 return MM_ERROR_PLAYER_INTERNAL;
8685         }
8686
8687         MMPLAYER_FLEAVE();
8688         return MM_ERROR_NONE;
8689 }
8690
8691 int
8692 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8693 {
8694         mm_player_t *player = (mm_player_t *)hplayer;
8695         GstElement *rg_vol_element = NULL;
8696
8697         MMPLAYER_FENTER();
8698
8699         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8700
8701         player->sound.rg_enable = enabled;
8702
8703         /* just hold rgvolume enable value if pipeline is not ready */
8704         if (!player->pipeline || !player->pipeline->audiobin) {
8705                 LOGD("pipeline is not ready. holding rgvolume enable value");
8706                 return MM_ERROR_NONE;
8707         }
8708
8709         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8710
8711         if (!rg_vol_element) {
8712                 LOGD("rgvolume element is not created");
8713                 return MM_ERROR_PLAYER_INTERNAL;
8714         }
8715
8716         if (enabled)
8717                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8718         else
8719                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8720
8721         MMPLAYER_FLEAVE();
8722
8723         return MM_ERROR_NONE;
8724 }
8725
8726 int
8727 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8728 {
8729         mm_player_t *player = (mm_player_t *)hplayer;
8730         GstElement *rg_vol_element = NULL;
8731         gboolean enable = FALSE;
8732
8733         MMPLAYER_FENTER();
8734
8735         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8737
8738         /* just hold enable_rg value if pipeline is not ready */
8739         if (!player->pipeline || !player->pipeline->audiobin) {
8740                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8741                 *enabled = player->sound.rg_enable;
8742                 return MM_ERROR_NONE;
8743         }
8744
8745         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8746
8747         if (!rg_vol_element) {
8748                 LOGD("rgvolume element is not created");
8749                 return MM_ERROR_PLAYER_INTERNAL;
8750         }
8751
8752         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8753         *enabled = (bool)enable;
8754
8755         MMPLAYER_FLEAVE();
8756
8757         return MM_ERROR_NONE;
8758 }
8759
8760 int
8761 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8762 {
8763         mm_player_t *player = (mm_player_t *)hplayer;
8764         MMHandleType attrs = 0;
8765         void *handle = NULL;
8766         int ret = MM_ERROR_NONE;
8767
8768         MMPLAYER_FENTER();
8769
8770         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8771
8772         attrs = MMPLAYER_GET_ATTRS(player);
8773         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8774
8775         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8776         if (!handle) {
8777                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8778                 return MM_ERROR_PLAYER_INTERNAL;
8779         }
8780
8781         player->video_roi.scale_x = scale_x;
8782         player->video_roi.scale_y = scale_y;
8783         player->video_roi.scale_width = scale_width;
8784         player->video_roi.scale_height = scale_height;
8785
8786         /* check video sinkbin is created */
8787         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8788                 return MM_ERROR_NONE;
8789
8790         if (!gst_video_overlay_set_video_roi_area(
8791                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8792                 scale_x, scale_y, scale_width, scale_height))
8793                 ret = MM_ERROR_PLAYER_INTERNAL;
8794         else
8795                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8796                         scale_x, scale_y, scale_width, scale_height);
8797
8798         MMPLAYER_FLEAVE();
8799
8800         return ret;
8801 }
8802
8803 int
8804 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8805 {
8806         mm_player_t *player = (mm_player_t *)hplayer;
8807         int ret = MM_ERROR_NONE;
8808
8809         MMPLAYER_FENTER();
8810
8811         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8813
8814         *scale_x = player->video_roi.scale_x;
8815         *scale_y = player->video_roi.scale_y;
8816         *scale_width = player->video_roi.scale_width;
8817         *scale_height = player->video_roi.scale_height;
8818
8819         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8820                 *scale_x, *scale_y, *scale_width, *scale_height);
8821
8822         return ret;
8823 }
8824
8825 static gboolean
8826 __mmplayer_update_duration_value(mm_player_t *player)
8827 {
8828         gboolean ret = FALSE;
8829         gint64 dur_nsec = 0;
8830         LOGD("try to update duration");
8831
8832         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8833                 player->duration = dur_nsec;
8834                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8835                 ret = TRUE;
8836         }
8837
8838         if (player->duration < 0) {
8839                 LOGW("duration is Non-Initialized !!!");
8840                 player->duration = 0;
8841         }
8842
8843         /* update streaming service type */
8844         player->streaming_type =  __mmplayer_get_stream_service_type(player);
8845
8846         /* check duration is OK */
8847         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8848                 /* FIXIT : find another way to get duration here. */
8849                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8850
8851         return ret;
8852 }
8853
8854 static gboolean
8855 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8856 {
8857         /* update audio params
8858         NOTE : We need original audio params and it can be only obtained from src pad of audio
8859         decoder. Below code only valid when we are not using 'resampler' just before
8860         'audioconverter'. */
8861         GstCaps *caps_a = NULL;
8862         GstPad *pad = NULL;
8863         gint samplerate = 0, channels = 0;
8864         GstStructure *p = NULL;
8865
8866         LOGD("try to update audio attrs");
8867
8868         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8869         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8870
8871         pad = gst_element_get_static_pad(
8872                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8873
8874         if (!pad) {
8875                 LOGW("failed to get pad from audiosink");
8876                 return FALSE;
8877         }
8878
8879         caps_a = gst_pad_get_current_caps(pad);
8880         if (!caps_a) {
8881                 LOGW("not ready to get audio caps");
8882                 gst_object_unref(pad);
8883                 return FALSE;
8884         }
8885
8886         p = gst_caps_get_structure(caps_a, 0);
8887
8888         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8889
8890         gst_structure_get_int(p, "rate", &samplerate);
8891         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8892
8893         gst_structure_get_int(p, "channels", &channels);
8894         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8895
8896         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8897
8898         gst_caps_unref(caps_a);
8899         gst_object_unref(pad);
8900
8901         return TRUE;
8902 }
8903
8904 static gboolean
8905 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8906 {
8907         LOGD("try to update video attrs");
8908
8909         GstCaps *caps_v = NULL;
8910         GstPad *pad = NULL;
8911         gint tmpNu, tmpDe;
8912         gint width, height;
8913         GstStructure *p = NULL;
8914
8915         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8916         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8917
8918         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8919         if (!pad) {
8920                 LOGD("no videosink sink pad");
8921                 return FALSE;
8922         }
8923
8924         caps_v = gst_pad_get_current_caps(pad);
8925         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8926         if (!caps_v && player->v_stream_caps) {
8927                 caps_v = player->v_stream_caps;
8928                 gst_caps_ref(caps_v);
8929         }
8930
8931         if (!caps_v) {
8932                 LOGD("no negitiated caps from videosink");
8933                 gst_object_unref(pad);
8934                 return FALSE;
8935         }
8936
8937         p = gst_caps_get_structure(caps_v, 0);
8938         gst_structure_get_int(p, "width", &width);
8939         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8940
8941         gst_structure_get_int(p, "height", &height);
8942         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8943
8944         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8945
8946         SECURE_LOGD("width : %d     height : %d", width, height);
8947
8948         gst_caps_unref(caps_v);
8949         gst_object_unref(pad);
8950
8951         if (tmpDe > 0) {
8952                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8953                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8954         }
8955
8956         return TRUE;
8957 }
8958
8959 static gboolean
8960 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8961 {
8962         gboolean ret = FALSE;
8963         guint64 data_size = 0;
8964         gchar *path = NULL;
8965         struct stat sb;
8966
8967         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8968         if (!player->duration)
8969                 return FALSE;
8970
8971         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8972                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8973                 if (stat(path, &sb) == 0)
8974                         data_size = (guint64)sb.st_size;
8975
8976         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8977                 data_size = player->http_content_size;
8978         }
8979
8980         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8981
8982         if (data_size) {
8983                 guint64 bitrate = 0;
8984                 guint64 msec_dur = 0;
8985
8986                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8987                 if (msec_dur > 0) {
8988                         bitrate = data_size * 8 * 1000 / msec_dur;
8989                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8990                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8991
8992                         ret = TRUE;
8993                 } else {
8994                         LOGD("player duration is less than 0");
8995                 }
8996         }
8997
8998         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8999                 if (player->total_bitrate) {
9000                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9001                         ret = TRUE;
9002                 }
9003         }
9004
9005         return ret;
9006 }
9007
9008 static void
9009 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
9010 {
9011         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9012         data->uri_type = uri_type;
9013 }
9014
9015 static int
9016 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
9017 {
9018         int ret = MM_ERROR_PLAYER_INVALID_URI;
9019         int mem_size = 0;
9020         char *buffer = NULL;
9021         char *seperator = strchr(path, ',');
9022         char ext[100] = {0,}, size[100] = {0,};
9023
9024         if (seperator) {
9025                 if ((buffer = strstr(path, "ext="))) {
9026                         buffer += strlen("ext=");
9027
9028                         if (strlen(buffer)) {
9029                                 strncpy(ext, buffer, 99);
9030
9031                                 if ((seperator = strchr(ext, ','))
9032                                         || (seperator = strchr(ext, ' '))
9033                                         || (seperator = strchr(ext, '\0'))) {
9034                                         seperator[0] = '\0';
9035                                 }
9036                         }
9037                 }
9038
9039                 if ((buffer = strstr(path, "size="))) {
9040                         buffer += strlen("size=");
9041
9042                         if (strlen(buffer) > 0) {
9043                                 strncpy(size, buffer, 99);
9044
9045                                 if ((seperator = strchr(size, ','))
9046                                         || (seperator = strchr(size, ' '))
9047                                         || (seperator = strchr(size, '\0'))) {
9048                                         seperator[0] = '\0';
9049                                 }
9050
9051                                 mem_size = atoi(size);
9052                         }
9053                 }
9054         }
9055
9056         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9057
9058         if (mem_size && param) {
9059                 if (data->input_mem.buf)
9060                         free(data->input_mem.buf);
9061                 data->input_mem.buf = malloc(mem_size);
9062
9063                 if (data->input_mem.buf) {
9064                         memcpy(data->input_mem.buf, param, mem_size);
9065                         data->input_mem.len = mem_size;
9066                         ret = MM_ERROR_NONE;
9067                 } else {
9068                         LOGE("failed to alloc mem %d", mem_size);
9069                         ret = MM_ERROR_PLAYER_INTERNAL;
9070                 }
9071
9072                 data->input_mem.offset = 0;
9073                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9074         }
9075
9076         return ret;
9077 }
9078
9079 static int
9080 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
9081 {
9082         gchar *location = NULL;
9083         GError *err = NULL;
9084         char *path = NULL;
9085         int ret = MM_ERROR_NONE;
9086
9087         if ((path = strstr(uri, "file://"))) {
9088                 location = g_filename_from_uri(uri, NULL, &err);
9089                 if (!location || (err != NULL)) {
9090                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9091                                 (err != NULL) ? err->message : "unknown error");
9092                         if (err)
9093                                 g_error_free(err);
9094
9095                         MMPLAYER_FREEIF(location);
9096
9097                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9098                         return MM_ERROR_PLAYER_INVALID_URI;
9099                 }
9100                 LOGD("path from uri: %s", location);
9101         }
9102
9103         path = (location != NULL) ? (location) : ((char *)uri);
9104
9105
9106         ret = util_exist_file_path(path);
9107
9108         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9109         if (ret == MM_ERROR_NONE) {
9110                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9111                 if (util_is_sdp_file(path)) {
9112                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9113                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9114                 } else {
9115                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9116                 }
9117         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9118                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9119         } else {
9120                 LOGE("invalid uri, could not play..");
9121                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9122         }
9123
9124         MMPLAYER_FREEIF(location);
9125
9126         return ret;
9127 }
9128
9129 static MMPlayerVideoStreamDataType *
9130 __mmplayer_create_stream_from_pad(GstPad *pad)
9131 {
9132         GstCaps *caps = NULL;
9133         GstStructure *structure = NULL;
9134         unsigned int fourcc = 0;
9135         const gchar *string_format = NULL;
9136         MMPlayerVideoStreamDataType *stream = NULL;
9137         gint width, height;
9138         MMPixelFormatType format;
9139
9140         caps = gst_pad_get_current_caps(pad);
9141         if (!caps) {
9142                 LOGE("Caps is NULL.");
9143                 return NULL;
9144         }
9145
9146         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9147         structure = gst_caps_get_structure(caps, 0);
9148         gst_structure_get_int(structure, "width", &width);
9149         gst_structure_get_int(structure, "height", &height);
9150         string_format = gst_structure_get_string(structure, "format");
9151         if (string_format)
9152                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9153         format = util_get_pixtype(fourcc);
9154         gst_caps_unref(caps);
9155
9156         /* moved here */
9157         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9158                 LOGE("Wrong condition!!");
9159                 return NULL;
9160         }
9161
9162         stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9163         if (!stream) {
9164                 LOGE("failed to alloc mem for video data");
9165                 return NULL;
9166         }
9167
9168         stream->width = width;
9169         stream->height = height;
9170         stream->format = format;
9171
9172         return stream;
9173 }
9174
9175 static void
9176 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9177 {
9178         unsigned int pitch = 0;
9179         int index = 0;
9180         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9181
9182         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9183                 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9184                 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9185                 stream->stride[index] = pitch;
9186                 stream->elevation[index] = stream->height;
9187         }
9188 }
9189
9190 static gboolean
9191 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9192 {
9193         if (stream->format == MM_PIXEL_FORMAT_I420) {
9194                 int ret = TBM_SURFACE_ERROR_NONE;
9195                 tbm_surface_h surface;
9196                 tbm_surface_info_s info;
9197
9198                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9199
9200                 ret = tbm_surface_get_info(surface, &info);
9201                 if (ret != TBM_SURFACE_ERROR_NONE) {
9202                         tbm_surface_destroy(surface);
9203                         return FALSE;
9204                 }
9205
9206                 tbm_surface_destroy(surface);
9207                 stream->stride[0] = info.planes[0].stride;
9208                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9209                 stream->stride[1] = info.planes[1].stride;
9210                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9211                 stream->stride[2] = info.planes[2].stride;
9212                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9213                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9214         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9215                 stream->stride[0] = stream->width * 4;
9216                 stream->elevation[0] = stream->height;
9217                 stream->bo_size = stream->stride[0] * stream->height;
9218         } else {
9219                 LOGE("Not support format %d", stream->format);
9220                 return FALSE;
9221         }
9222
9223         return TRUE;
9224 }
9225
9226 static gboolean
9227 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9228 {
9229         tbm_bo_handle thandle;
9230         gboolean is_mapped;
9231         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9232         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9233         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9234         int i = 0;
9235         int j = 0;
9236         int k = 0;
9237         unsigned char *src = NULL;
9238         unsigned char *dest = NULL;
9239         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9240
9241         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9242         if (!is_mapped) {
9243                 LOGE("fail to gst_memory_map");
9244                 return FALSE;
9245         }
9246
9247         if (!mapinfo.data) {
9248                 LOGE("data pointer is wrong");
9249                 goto ERROR;
9250         }
9251
9252         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9253         if (!stream->bo[0]) {
9254                 LOGE("Fail to tbm_bo_alloc!!");
9255                 goto ERROR;
9256         }
9257
9258         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9259         if (!thandle.ptr) {
9260                 LOGE("thandle pointer is wrong");
9261                 goto ERROR;
9262         }
9263
9264         if (stream->format == MM_PIXEL_FORMAT_I420) {
9265                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9266                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9267                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9268                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9269
9270                 dest_offset[0] = 0;
9271                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9272                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9273
9274                 for (i = 0; i < 3; i++) {
9275                         src = mapinfo.data + src_offset[i];
9276                         dest = thandle.ptr + dest_offset[i];
9277
9278                         if (i > 0)
9279                                 k = 1;
9280
9281                         for (j = 0; j < stream->height >> k; j++) {
9282                                 memcpy(dest, src, stream->width>>k);
9283                                 src += src_stride[i];
9284                                 dest += stream->stride[i];
9285                         }
9286                 }
9287         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9288                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9289         } else {
9290                 LOGE("Not support format %d", stream->format);
9291                 goto ERROR;
9292         }
9293
9294         tbm_bo_unmap(stream->bo[0]);
9295         gst_memory_unmap(mem, &mapinfo);
9296
9297         return TRUE;
9298
9299 ERROR:
9300         if (stream->bo[0])
9301                 tbm_bo_unmap(stream->bo[0]);
9302
9303         if (is_mapped)
9304                 gst_memory_unmap(mem, &mapinfo);
9305
9306         return FALSE;
9307 }
9308
9309 static void
9310 __mmplayer_set_pause_state(mm_player_t *player)
9311 {
9312         if (player->sent_bos)
9313                 return;
9314
9315         /* rtsp case, get content attrs by GstMessage */
9316         if (MMPLAYER_IS_RTSP_STREAMING(player))
9317                 return;
9318
9319         /* it's first time to update all content attrs. */
9320         __mmplayer_update_content_attrs(player, ATTR_ALL);
9321 }
9322
9323 static void
9324 __mmplayer_set_playing_state(mm_player_t *player)
9325 {
9326         gchar *audio_codec = NULL;
9327
9328         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9329                 /* initialize because auto resume is done well. */
9330                 player->resumed_by_rewind = FALSE;
9331                 player->playback_rate = 1.0;
9332         }
9333
9334         if (player->sent_bos)
9335                 return;
9336
9337         /* try to get content metadata */
9338
9339         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9340          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9341          * legacy mmfw-player api
9342          */
9343         __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9344
9345         if ((player->cmd == MMPLAYER_COMMAND_START)
9346                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9347                 __mmplayer_handle_missed_plugin(player);
9348         }
9349
9350         /* check audio codec field is set or not
9351          * we can get it from typefinder or codec's caps.
9352          */
9353         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9354
9355         /* The codec format can't be sent for audio only case like amr, mid etc.
9356          * Because, parser don't make related TAG.
9357          * So, if it's not set yet, fill it with found data.
9358          */
9359         if (!audio_codec) {
9360                 if (g_strrstr(player->type, "audio/midi"))
9361                         audio_codec = "MIDI";
9362                 else if (g_strrstr(player->type, "audio/x-amr"))
9363                         audio_codec = "AMR";
9364                 else if (g_strrstr(player->type, "audio/mpeg")
9365                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9366                         audio_codec = "AAC";
9367                 else
9368                         audio_codec = "unknown";
9369
9370                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9371
9372                 if (mm_attrs_commit_all(player->attrs))
9373                         LOGE("failed to update attributes");
9374
9375                 LOGD("set audio codec type with caps");
9376         }
9377
9378         return;
9379 }