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