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