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