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