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