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