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