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