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