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