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