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