4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
94 #define PLAYER_DISPLAY_MODE_DST_ROI 5
96 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
98 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
99 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
100 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
101 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
103 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
104 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
106 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
108 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
109 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
110 #define DEFAULT_PCM_OUT_CHANNEL 2
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
146 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
147 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
148 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
149 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
150 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
151 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
152 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
153 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
158 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
159 static void __mmplayer_release_misc(mmplayer_t *player);
160 static void __mmplayer_release_misc_post(mmplayer_t *player);
161 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
162 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
164 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
167 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
168 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
169 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
170 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
171 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
172 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
173 static gpointer __mmplayer_gapless_play_thread(gpointer data);
174 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
175 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
176 static void __mmplayer_release_dump_list(GList *dump_list);
177 static int __mmplayer_gst_realize(mmplayer_t *player);
178 static int __mmplayer_gst_unrealize(mmplayer_t *player);
179 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
180 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
183 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
184 static void __mmplayer_activate_next_source(mmplayer_t *player, GstState target);
185 static void __mmplayer_check_pipeline(mmplayer_t *player);
186 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
187 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
188 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
189 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
190 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
191 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
192 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
193 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
194 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
195 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
196 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
197 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
199 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
200 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
201 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
203 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
204 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
205 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
206 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
208 static void __mmplayer_set_pause_state(mmplayer_t *player);
209 static void __mmplayer_set_playing_state(mmplayer_t *player);
210 /*===========================================================================================
212 | FUNCTION DEFINITIONS |
214 ========================================================================================== */
218 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
222 count = gst_tag_list_get_tag_size(list, tag);
224 LOGD("count = %d", count);
226 for (i = 0; i < count; i++) {
229 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
230 if (!gst_tag_list_get_string_index(list, tag, i, &str))
231 g_assert_not_reached();
233 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
237 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
239 g_print(" : %s", str);
246 /* This function should be called after the pipeline goes PAUSED or higher
249 __mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
251 static gboolean has_duration = FALSE;
252 static gboolean has_video_attrs = FALSE;
253 static gboolean has_audio_attrs = FALSE;
254 static gboolean has_bitrate = FALSE;
255 gboolean missing_only = FALSE;
256 gboolean all = FALSE;
257 MMHandleType attrs = 0;
261 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
263 /* check player state here */
264 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
265 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
266 /* give warning now only */
267 LOGW("be careful. content attributes may not available in this state ");
270 /* get content attribute first */
271 attrs = MMPLAYER_GET_ATTRS(player);
273 LOGE("cannot get content attribute");
277 /* get update flag */
279 if (flag & ATTR_MISSING_ONLY) {
281 LOGD("updating missed attr only");
284 if (flag & ATTR_ALL) {
286 has_duration = FALSE;
287 has_video_attrs = FALSE;
288 has_audio_attrs = FALSE;
291 LOGD("updating all attrs");
294 if (missing_only && all) {
295 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
296 missing_only = FALSE;
299 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
300 has_duration = __mmplayer_update_duration_value(player);
302 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
303 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
305 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
306 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
308 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
309 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
312 if (mm_attrs_commit_all(attrs)) {
313 LOGE("failed to update attributes");
323 __mmplayer_get_stream_service_type(mmplayer_t *player)
325 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
329 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
331 player->pipeline->mainbin &&
332 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
333 STREAMING_SERVICE_NONE);
335 /* streaming service type if streaming */
336 if (!MMPLAYER_IS_STREAMING(player))
337 return STREAMING_SERVICE_NONE;
339 streaming_type = (player->duration == 0) ?
340 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
342 switch (streaming_type) {
343 case STREAMING_SERVICE_LIVE:
344 LOGD("it's live streaming");
346 case STREAMING_SERVICE_VOD:
347 LOGD("it's vod streaming");
350 LOGE("should not get here");
356 return streaming_type;
359 /* this function sets the player state and also report
360 * it to applicaton by calling callback function
363 __mmplayer_set_state(mmplayer_t *player, int state)
365 MMMessageParamType msg = {0, };
367 MMPLAYER_RETURN_IF_FAIL(player);
369 if (MMPLAYER_CURRENT_STATE(player) == state) {
370 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
371 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
375 /* update player states */
376 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
377 MMPLAYER_CURRENT_STATE(player) = state;
379 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
380 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
383 MMPLAYER_PRINT_STATE(player);
385 switch (MMPLAYER_CURRENT_STATE(player)) {
386 case MM_PLAYER_STATE_NULL:
387 case MM_PLAYER_STATE_READY:
389 case MM_PLAYER_STATE_PAUSED:
390 __mmplayer_set_pause_state(player);
392 case MM_PLAYER_STATE_PLAYING:
393 __mmplayer_set_playing_state(player);
395 case MM_PLAYER_STATE_NONE:
397 LOGW("invalid target state, there is nothing to do.");
402 /* post message to application */
403 if (MMPLAYER_TARGET_STATE(player) == state) {
404 /* fill the message with state of player */
405 msg.union_type = MM_MSG_UNION_STATE;
406 msg.state.previous = MMPLAYER_PREV_STATE(player);
407 msg.state.current = MMPLAYER_CURRENT_STATE(player);
409 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
411 /* state changed by resource callback */
412 if (player->interrupted_by_resource)
413 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
414 else /* state changed by usecase */
415 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
418 LOGD("intermediate state, do nothing.");
419 MMPLAYER_PRINT_STATE(player);
423 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
424 && !player->sent_bos) {
425 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
426 player->sent_bos = TRUE;
433 __mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
435 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
436 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
440 //LOGD("incomming command : %d ", command);
442 current_state = MMPLAYER_CURRENT_STATE(player);
443 pending_state = MMPLAYER_PENDING_STATE(player);
445 MMPLAYER_PRINT_STATE(player);
448 case MMPLAYER_COMMAND_CREATE:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
452 if (current_state == MM_PLAYER_STATE_NULL ||
453 current_state == MM_PLAYER_STATE_READY ||
454 current_state == MM_PLAYER_STATE_PAUSED ||
455 current_state == MM_PLAYER_STATE_PLAYING)
460 case MMPLAYER_COMMAND_DESTROY:
462 /* destroy can called anytime */
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
468 case MMPLAYER_COMMAND_REALIZE:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (pending_state != MM_PLAYER_STATE_NONE) {
475 /* need ready state to realize */
476 if (current_state == MM_PLAYER_STATE_READY)
479 if (current_state != MM_PLAYER_STATE_NULL)
485 case MMPLAYER_COMMAND_UNREALIZE:
487 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
489 if (current_state == MM_PLAYER_STATE_NULL)
494 case MMPLAYER_COMMAND_START:
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PLAYING)
501 else if (current_state != MM_PLAYER_STATE_READY &&
502 current_state != MM_PLAYER_STATE_PAUSED)
504 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
507 LOGD("player is going to paused state, just change the pending state as playing");
514 case MMPLAYER_COMMAND_STOP:
516 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
518 if (current_state == MM_PLAYER_STATE_READY)
521 /* need playing/paused state to stop */
522 if (current_state != MM_PLAYER_STATE_PLAYING &&
523 current_state != MM_PLAYER_STATE_PAUSED)
528 case MMPLAYER_COMMAND_PAUSE:
530 if (MMPLAYER_IS_LIVE_STREAMING(player))
533 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
534 goto NOT_COMPLETED_SEEK;
536 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
538 if (pending_state == MM_PLAYER_STATE_NONE) {
539 if (current_state == MM_PLAYER_STATE_PAUSED)
541 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
543 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
545 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
546 if (current_state == MM_PLAYER_STATE_PAUSED)
547 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
554 case MMPLAYER_COMMAND_RESUME:
556 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
557 goto NOT_COMPLETED_SEEK;
559 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
561 if (pending_state == MM_PLAYER_STATE_NONE) {
562 if (current_state == MM_PLAYER_STATE_PLAYING)
564 else if (current_state != MM_PLAYER_STATE_PAUSED)
566 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
568 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
569 LOGD("player is going to paused state, just change the pending state as playing");
579 player->cmd = command;
581 return MM_ERROR_NONE;
584 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
585 MMPLAYER_STATE_GET_NAME(current_state), command);
586 return MM_ERROR_PLAYER_INVALID_STATE;
589 LOGW("not completed seek");
590 return MM_ERROR_PLAYER_DOING_SEEK;
593 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
598 return MM_ERROR_PLAYER_NO_OP;
602 __mmplayer_gapless_play_thread(gpointer data)
604 mmplayer_t *player = (mmplayer_t *)data;
605 mmplayer_gst_element_t *mainbin = NULL;
607 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
609 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
610 while (!player->gapless_play_thread_exit) {
611 LOGD("gapless play thread started. waiting for signal.");
612 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
614 LOGD("reconfigure pipeline for gapless play.");
616 if (player->gapless_play_thread_exit) {
617 if (player->gapless.reconfigure) {
618 player->gapless.reconfigure = false;
619 MMPLAYER_PLAYBACK_UNLOCK(player);
621 LOGD("exiting gapless play thread");
625 mainbin = player->pipeline->mainbin;
627 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
628 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
629 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
630 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
631 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
633 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
635 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
641 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
643 GSource *source = NULL;
647 source = g_main_context_find_source_by_id(context, source_id);
648 if (source != NULL) {
649 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
650 g_source_destroy(source);
657 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
659 mmplayer_t *player = (mmplayer_t *)hplayer;
660 GstMessage *msg = NULL;
661 GQueue *queue = NULL;
664 MMPLAYER_RETURN_IF_FAIL(player);
666 /* disconnecting bus watch */
667 if (player->bus_watcher)
668 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
669 player->bus_watcher = 0;
671 /* destroy the gst bus msg thread */
672 if (player->bus_msg_thread) {
673 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
674 player->bus_msg_thread_exit = TRUE;
675 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
676 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
678 LOGD("gst bus msg thread exit.");
679 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
680 player->bus_msg_thread = NULL;
682 g_mutex_clear(&player->bus_msg_thread_mutex);
683 g_cond_clear(&player->bus_msg_thread_cond);
686 g_mutex_lock(&player->bus_msg_q_lock);
687 queue = player->bus_msg_q;
688 while (!g_queue_is_empty(queue)) {
689 msg = (GstMessage *)g_queue_pop_head(queue);
694 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
695 gst_message_unref(msg);
697 g_mutex_unlock(&player->bus_msg_q_lock);
703 __mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
705 GstElement *parent = NULL;
707 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
708 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
711 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mmplayer_t *player = (mmplayer_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1062 gst_object_unref(GST_OBJECT(srcpad));
1069 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1071 mmplayer_t *player = (mmplayer_t *)data;
1072 GstElement *selector = NULL;
1073 GstCaps *caps = NULL;
1074 GstStructure *str = NULL;
1075 const gchar *name = NULL;
1076 GstPad *sinkpad = NULL;
1077 gboolean first_track = FALSE;
1078 gboolean caps_ret = TRUE;
1080 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1081 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1084 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1085 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1087 LOGD("pad-added signal handling");
1089 /* get mimetype from caps */
1090 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1094 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1095 /* LOGD("detected mimetype : %s", name); */
1097 if (strstr(name, "video")) {
1099 gchar *caps_str = NULL;
1101 caps_str = gst_caps_to_string(caps);
1102 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1103 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1104 player->set_mode.video_zc = true;
1106 MMPLAYER_FREEIF(caps_str);
1108 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1109 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1111 LOGD("surface type : %d", stype);
1113 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1114 __mmplayer_gst_create_sinkbin(elem, pad, player);
1118 /* in case of exporting video frame, it requires the 360 video filter.
1119 * it will be handled in _no_more_pads(). */
1120 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1121 __mmplayer_gst_make_fakesink(player, pad, name);
1125 LOGD("video selector is required");
1126 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1127 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1128 } else if (strstr(name, "audio")) {
1129 gint samplerate = 0;
1132 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1133 if (player->build_audio_offload)
1134 player->no_more_pad = TRUE; /* remove state holder */
1135 __mmplayer_gst_create_sinkbin(elem, pad, player);
1139 gst_structure_get_int(str, "rate", &samplerate);
1140 gst_structure_get_int(str, "channels", &channels);
1142 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1143 __mmplayer_gst_make_fakesink(player, pad, name);
1147 LOGD("audio selector is required");
1148 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1149 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1151 } else if (strstr(name, "text")) {
1152 LOGD("text selector is required");
1153 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1154 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1156 LOGE("invalid caps info");
1160 /* check selector and create it */
1161 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1162 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1167 LOGD("input-selector is already created.");
1171 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1173 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1175 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1176 LOGE("failed to link selector");
1177 gst_object_unref(GST_OBJECT(selector));
1182 LOGD("this track will be activated");
1183 g_object_set(selector, "active-pad", sinkpad, NULL);
1186 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1192 gst_caps_unref(caps);
1195 gst_object_unref(GST_OBJECT(sinkpad));
1203 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1205 GstPad *srcpad = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1210 LOGD("type %d", type);
1213 LOGD("there is no %d track", type);
1217 srcpad = gst_element_get_static_pad(selector, "src");
1219 LOGE("failed to get srcpad from selector");
1223 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1225 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1227 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1228 if (player->selector[type].block_id) {
1229 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1230 player->selector[type].block_id = 0;
1234 gst_object_unref(GST_OBJECT(srcpad));
1243 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1245 MMHandleType attrs = 0;
1246 gint active_index = 0;
1249 MMPLAYER_RETURN_IF_FAIL(player);
1251 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1253 /* change track to active pad */
1254 active_index = player->selector[type].active_pad_index;
1255 if ((active_index != DEFAULT_TRACK) &&
1256 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1257 LOGW("failed to change %d type track to %d", type, active_index);
1258 player->selector[type].active_pad_index = DEFAULT_TRACK;
1262 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1263 attrs = MMPLAYER_GET_ATTRS(player);
1265 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1266 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1268 if (mm_attrs_commit_all(attrs))
1269 LOGW("failed to commit attrs.");
1271 LOGW("cannot get content attribute");
1280 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1285 if (!audio_selector) {
1286 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1288 /* in case the source is changed, output can be changed. */
1289 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1290 LOGD("remove previous audiobin if it exist");
1292 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1293 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1295 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1296 MMPLAYER_FREEIF(player->pipeline->audiobin);
1299 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1300 __mmplayer_pipeline_complete(NULL, player);
1305 /* apply the audio track information */
1306 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1308 /* create audio sink path */
1309 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1310 LOGE("failed to create audio sink path");
1319 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1322 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1324 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1325 LOGD("text path is not supproted");
1329 /* apply the text track information */
1330 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1332 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1333 player->has_closed_caption = TRUE;
1335 /* create text decode path */
1336 player->no_more_pad = TRUE;
1338 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1339 LOGE("failed to create text sink path");
1348 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1350 gint64 dur_bytes = 0L;
1353 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1354 player->pipeline->mainbin && player->streamer, FALSE);
1356 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1357 LOGE("fail to get duration.");
1359 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1360 * use file information was already set on Q2 when it was created. */
1361 __mm_player_streaming_set_queue2(player->streamer,
1362 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1363 TRUE, /* use_buffering */
1364 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1365 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1372 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1374 mmplayer_t *player = NULL;
1375 GstElement *video_selector = NULL;
1376 GstElement *audio_selector = NULL;
1377 GstElement *text_selector = NULL;
1380 player = (mmplayer_t *)data;
1382 LOGD("no-more-pad signal handling");
1384 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1385 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1386 LOGW("player is shutting down");
1390 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1391 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1392 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1393 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1394 LOGE("failed to set queue2 buffering");
1399 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1400 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1401 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1403 if (!video_selector && !audio_selector && !text_selector) {
1404 LOGW("there is no selector");
1405 player->no_more_pad = TRUE;
1409 /* create video path followed by video-select */
1410 if (video_selector && !audio_selector && !text_selector)
1411 player->no_more_pad = TRUE;
1413 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1416 /* create audio path followed by audio-select */
1417 if (audio_selector && !text_selector)
1418 player->no_more_pad = TRUE;
1420 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1423 /* create text path followed by text-select */
1424 __mmplayer_create_text_sink_path(player, text_selector);
1427 if (player->gapless.reconfigure) {
1428 player->gapless.reconfigure = FALSE;
1429 MMPLAYER_PLAYBACK_UNLOCK(player);
1436 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1438 gboolean ret = FALSE;
1439 GstElement *pipeline = NULL;
1440 GstPad *sinkpad = NULL;
1443 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1446 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1448 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1450 LOGE("failed to get pad from sinkbin");
1456 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1457 LOGE("failed to link sinkbin for reusing");
1458 goto EXIT; /* exit either pass or fail */
1462 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1463 LOGE("failed to set state(READY) to sinkbin");
1468 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1469 LOGE("failed to add sinkbin to pipeline");
1474 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1475 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1480 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1481 LOGE("failed to set state(PAUSED) to sinkbin");
1490 gst_object_unref(GST_OBJECT(sinkpad));
1498 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1500 mmplayer_t *player = NULL;
1501 GstCaps *caps = NULL;
1502 gchar *caps_str = NULL;
1503 GstStructure *str = NULL;
1504 const gchar *name = NULL;
1505 GstElement *sinkbin = NULL;
1506 gboolean reusing = FALSE;
1507 gboolean caps_ret = TRUE;
1508 gchar *sink_pad_name = "sink";
1511 player = (mmplayer_t *)data;
1514 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1517 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1521 caps_str = gst_caps_to_string(caps);
1523 /* LOGD("detected mimetype : %s", name); */
1524 if (strstr(name, "audio")) {
1525 if (player->pipeline->audiobin == NULL) {
1526 const gchar *audio_format = gst_structure_get_string(str, "format");
1528 LOGD("original audio format %s", audio_format);
1529 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1532 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1533 LOGE("failed to create audiobin. continuing without audio");
1537 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1538 LOGD("creating audiobin success");
1541 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1542 LOGD("reusing audiobin");
1543 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1545 } else if (strstr(name, "video")) {
1546 /* 1. zero copy is updated at _decode_pad_added()
1547 * 2. NULL surface type is handled in _decode_pad_added() */
1548 LOGD("zero copy %d", player->set_mode.video_zc);
1549 if (player->pipeline->videobin == NULL) {
1550 int surface_type = 0;
1551 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1552 LOGD("display_surface_type (%d)", surface_type);
1554 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1555 LOGD("mark video overlay for acquire");
1556 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1557 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1558 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1559 &player->video_overlay_resource)
1560 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1561 LOGE("could not mark video_overlay resource for acquire");
1566 player->interrupted_by_resource = FALSE;
1568 if (mm_resource_manager_commit(player->resource_manager) !=
1569 MM_RESOURCE_MANAGER_ERROR_NONE) {
1570 LOGE("could not acquire resources for video playing");
1574 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1575 LOGE("failed to create videobin. continuing without video");
1579 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1580 LOGD("creating videosink bin success");
1583 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1584 LOGD("re-using videobin");
1585 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1587 } else if (strstr(name, "text")) {
1588 if (player->pipeline->textbin == NULL) {
1589 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1590 LOGE("failed to create text sink bin. continuing without text");
1594 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1595 player->textsink_linked = 1;
1596 LOGD("creating textsink bin success");
1598 if (!player->textsink_linked) {
1599 LOGD("re-using textbin");
1601 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1602 player->textsink_linked = 1;
1604 /* linked textbin exist which means that the external subtitle path exist already */
1605 LOGW("ignoring internal subtutle since external subtitle is available");
1608 sink_pad_name = "text_sink";
1610 LOGW("unknown mime type %s, ignoring it", name);
1614 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1617 LOGD("[handle: %p] success to create and link sink bin", player);
1619 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1620 * streaming task. if the task blocked, then buffer will not flow to the next element
1621 *(autoplugging element). so this is special hack for streaming. please try to remove it
1623 /* dec stream count. we can remove fakesink if it's zero */
1624 if (player->num_dynamic_pad)
1625 player->num_dynamic_pad--;
1627 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1629 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1630 __mmplayer_pipeline_complete(NULL, player);
1634 MMPLAYER_FREEIF(caps_str);
1637 gst_caps_unref(caps);
1643 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1645 int required_angle = 0; /* Angle required for straight view */
1646 int rotation_angle = 0;
1648 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1649 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1651 /* Counter clockwise */
1652 switch (orientation) {
1657 required_angle = 270;
1660 required_angle = 180;
1663 required_angle = 90;
1667 rotation_angle = display_angle + required_angle;
1668 if (rotation_angle >= 360)
1669 rotation_angle -= 360;
1671 /* chech if supported or not */
1672 if (rotation_angle % 90) {
1673 LOGD("not supported rotation angle = %d", rotation_angle);
1677 switch (rotation_angle) {
1679 *value = MM_DISPLAY_ROTATION_NONE;
1682 *value = MM_DISPLAY_ROTATION_90;
1685 *value = MM_DISPLAY_ROTATION_180;
1688 *value = MM_DISPLAY_ROTATION_270;
1692 LOGD("setting rotation property value : %d", *value);
1698 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1700 /* check video sinkbin is created */
1701 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1703 player->pipeline->videobin &&
1704 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1705 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1706 MM_ERROR_PLAYER_NOT_INITIALIZED);
1708 return MM_ERROR_NONE;
1712 __mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1714 int display_rotation = 0;
1715 gchar *org_orient = NULL;
1716 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1719 LOGE("cannot get content attribute");
1720 return MM_ERROR_PLAYER_INTERNAL;
1723 if (display_angle) {
1724 /* update user roation */
1725 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1727 /* Counter clockwise */
1728 switch (display_rotation) {
1729 case MM_DISPLAY_ROTATION_NONE:
1732 case MM_DISPLAY_ROTATION_90:
1733 *display_angle = 90;
1735 case MM_DISPLAY_ROTATION_180:
1736 *display_angle = 180;
1738 case MM_DISPLAY_ROTATION_270:
1739 *display_angle = 270;
1742 LOGW("wrong angle type : %d", display_rotation);
1745 LOGD("check user angle: %d", *display_angle);
1749 /* Counter clockwise */
1750 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1753 if (!strcmp(org_orient, "rotate-90"))
1755 else if (!strcmp(org_orient, "rotate-180"))
1757 else if (!strcmp(org_orient, "rotate-270"))
1760 LOGD("original rotation is %s", org_orient);
1762 LOGD("content_video_orientation get fail");
1765 LOGD("check orientation: %d", *orientation);
1768 return MM_ERROR_NONE;
1772 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1774 int rotation_value = 0;
1775 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1776 int display_angle = 0;
1779 /* check video sinkbin is created */
1780 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1783 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1785 /* get rotation value to set */
1786 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1787 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1788 LOGD("set video param : rotate %d", rotation_value);
1792 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1794 MMHandleType attrs = 0;
1798 /* check video sinkbin is created */
1799 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1802 attrs = MMPLAYER_GET_ATTRS(player);
1803 MMPLAYER_RETURN_IF_FAIL(attrs);
1805 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1806 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1807 LOGD("set video param : visible %d", visible);
1811 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1813 MMHandleType attrs = 0;
1814 int display_method = 0;
1817 /* check video sinkbin is created */
1818 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1821 attrs = MMPLAYER_GET_ATTRS(player);
1822 MMPLAYER_RETURN_IF_FAIL(attrs);
1824 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1825 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1826 LOGD("set video param : method %d", display_method);
1830 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1832 MMHandleType attrs = 0;
1833 void *handle = NULL;
1836 /* check video sinkbin is created */
1837 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1838 LOGW("There is no video sink");
1842 attrs = MMPLAYER_GET_ATTRS(player);
1843 MMPLAYER_RETURN_IF_FAIL(attrs);
1844 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1846 gst_video_overlay_set_video_roi_area(
1847 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1848 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1849 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1850 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1855 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1858 void *handle = NULL;
1862 int win_roi_width = 0;
1863 int win_roi_height = 0;
1866 /* check video sinkbin is created */
1867 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1868 LOGW("There is no video sink");
1872 attrs = MMPLAYER_GET_ATTRS(player);
1873 MMPLAYER_RETURN_IF_FAIL(attrs);
1875 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1878 /* It should be set after setting window */
1879 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1880 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1881 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1882 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1884 /* After setting window handle, set display roi area */
1885 gst_video_overlay_set_display_roi_area(
1886 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1887 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1888 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1889 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1894 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1896 MMHandleType attrs = 0;
1897 void *handle = NULL;
1899 /* check video sinkbin is created */
1900 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1903 attrs = MMPLAYER_GET_ATTRS(player);
1904 MMPLAYER_RETURN_IF_FAIL(attrs);
1906 /* common case if using overlay surface */
1907 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1910 /* default is using wl_surface_id */
1911 unsigned int wl_surface_id = 0;
1912 wl_surface_id = *(int *)handle;
1913 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1914 gst_video_overlay_set_wl_window_wl_surface_id(
1915 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1918 /* FIXIT : is it error case? */
1919 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1924 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
1926 gboolean update_all_param = FALSE;
1929 /* check video sinkbin is created */
1930 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1931 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1933 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1934 LOGE("can not find tizenwlsink");
1935 return MM_ERROR_PLAYER_INTERNAL;
1938 LOGD("param_name : %s", param_name);
1939 if (!g_strcmp0(param_name, "update_all_param"))
1940 update_all_param = TRUE;
1942 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1943 __mmplayer_video_param_set_display_overlay(player);
1944 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1945 __mmplayer_video_param_set_display_method(player);
1946 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1947 __mmplayer_video_param_set_display_visible(player);
1948 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1949 __mmplayer_video_param_set_display_rotation(player);
1950 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1951 __mmplayer_video_param_set_roi_area(player);
1952 if (update_all_param)
1953 __mmplayer_video_param_set_video_roi_area(player);
1955 return MM_ERROR_NONE;
1959 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
1961 MMHandleType attrs = 0;
1962 int surface_type = 0;
1963 int ret = MM_ERROR_NONE;
1967 /* check video sinkbin is created */
1968 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1969 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1971 attrs = MMPLAYER_GET_ATTRS(player);
1973 LOGE("cannot get content attribute");
1974 return MM_ERROR_PLAYER_INTERNAL;
1976 LOGD("param_name : %s", param_name);
1978 /* update display surface */
1979 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1980 LOGD("check display surface type attribute: %d", surface_type);
1982 /* configuring display */
1983 switch (surface_type) {
1984 case MM_DISPLAY_SURFACE_OVERLAY:
1986 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1987 if (ret != MM_ERROR_NONE)
1995 return MM_ERROR_NONE;
1999 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2001 gboolean disable_overlay = FALSE;
2002 mmplayer_t *player = (mmplayer_t *)hplayer;
2003 int ret = MM_ERROR_NONE;
2006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2007 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2008 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2009 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2011 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2012 LOGW("Display control is not supported");
2013 return MM_ERROR_PLAYER_INTERNAL;
2016 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2018 if (audio_only == (bool)disable_overlay) {
2019 LOGE("It's the same with current setting: (%d)", audio_only);
2020 return MM_ERROR_NONE;
2024 LOGE("disable overlay");
2025 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2027 /* release overlay resource */
2028 if (player->video_overlay_resource != NULL) {
2029 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2030 player->video_overlay_resource);
2031 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2032 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2035 player->video_overlay_resource = NULL;
2038 ret = mm_resource_manager_commit(player->resource_manager);
2039 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2040 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2044 /* mark video overlay for acquire */
2045 if (player->video_overlay_resource == NULL) {
2046 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2047 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2048 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2049 &player->video_overlay_resource);
2050 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2051 LOGE("could not prepare for video_overlay resource");
2056 player->interrupted_by_resource = FALSE;
2057 /* acquire resources for video overlay */
2058 ret = mm_resource_manager_commit(player->resource_manager);
2059 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2060 LOGE("could not acquire resources for video playing");
2064 LOGD("enable overlay");
2065 __mmplayer_video_param_set_display_overlay(player);
2066 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2071 return MM_ERROR_NONE;
2075 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2077 mmplayer_t *player = (mmplayer_t *)hplayer;
2078 gboolean disable_overlay = FALSE;
2082 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2083 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2084 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2085 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2086 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2088 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2089 LOGW("Display control is not supported");
2090 return MM_ERROR_PLAYER_INTERNAL;
2093 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2095 *paudio_only = (bool)disable_overlay;
2097 LOGD("audio_only : %d", *paudio_only);
2101 return MM_ERROR_NONE;
2105 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2107 GList *bucket = element_bucket;
2108 mmplayer_gst_element_t *element = NULL;
2109 mmplayer_gst_element_t *prv_element = NULL;
2110 GstElement *tee_element = NULL;
2111 gint successful_link_count = 0;
2115 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2117 prv_element = (mmplayer_gst_element_t *)bucket->data;
2118 bucket = bucket->next;
2120 for (; bucket; bucket = bucket->next) {
2121 element = (mmplayer_gst_element_t *)bucket->data;
2123 if (element && element->gst) {
2124 if (prv_element && prv_element->gst) {
2125 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2127 prv_element->gst = tee_element;
2129 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2130 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2131 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2135 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2136 LOGD("linking [%s] to [%s] success",
2137 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2138 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2139 successful_link_count++;
2140 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2141 LOGD("keep audio-tee element for next audio pipeline branch");
2142 tee_element = prv_element->gst;
2145 LOGD("linking [%s] to [%s] failed",
2146 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2147 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2153 prv_element = element;
2158 return successful_link_count;
2162 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2164 GList *bucket = element_bucket;
2165 mmplayer_gst_element_t *element = NULL;
2166 int successful_add_count = 0;
2170 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2171 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2173 for (; bucket; bucket = bucket->next) {
2174 element = (mmplayer_gst_element_t *)bucket->data;
2176 if (element && element->gst) {
2177 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2178 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2179 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2180 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2183 successful_add_count++;
2189 return successful_add_count;
2193 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2195 mmplayer_t *player = (mmplayer_t *)data;
2196 GstCaps *caps = NULL;
2197 GstStructure *str = NULL;
2199 gboolean caps_ret = TRUE;
2203 MMPLAYER_RETURN_IF_FAIL(pad);
2204 MMPLAYER_RETURN_IF_FAIL(unused);
2205 MMPLAYER_RETURN_IF_FAIL(data);
2207 caps = gst_pad_get_current_caps(pad);
2211 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2215 LOGD("name = %s", name);
2217 if (strstr(name, "audio")) {
2218 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2220 if (player->audio_stream_changed_cb) {
2221 LOGE("call the audio stream changed cb");
2222 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2224 } else if (strstr(name, "video")) {
2225 if ((name = gst_structure_get_string(str, "format")))
2226 player->set_mode.video_zc = name[0] == 'S';
2228 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2230 if (player->video_stream_changed_cb) {
2231 LOGE("call the video stream changed cb");
2232 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2235 LOGW("invalid caps info");
2240 gst_caps_unref(caps);
2248 __mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2253 MMPLAYER_RETURN_IF_FAIL(player);
2255 if (player->audio_stream_buff_list) {
2256 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2257 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2260 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2261 __mmplayer_audio_stream_send_data(player, tmp);
2263 MMPLAYER_FREEIF(tmp->pcm_data);
2264 MMPLAYER_FREEIF(tmp);
2267 g_list_free(player->audio_stream_buff_list);
2268 player->audio_stream_buff_list = NULL;
2275 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2277 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2280 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2282 audio_stream.bitrate = a_buffer->bitrate;
2283 audio_stream.channel = a_buffer->channel;
2284 audio_stream.depth = a_buffer->depth;
2285 audio_stream.is_little_endian = a_buffer->is_little_endian;
2286 audio_stream.channel_mask = a_buffer->channel_mask;
2287 audio_stream.data_size = a_buffer->data_size;
2288 audio_stream.data = a_buffer->pcm_data;
2289 audio_stream.pcm_format = a_buffer->pcm_format;
2291 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2292 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2298 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2300 mmplayer_t *player = (mmplayer_t *)data;
2301 const gchar *pcm_format = NULL;
2305 gint endianness = 0;
2306 guint64 channel_mask = 0;
2307 void *a_data = NULL;
2309 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2310 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2314 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2316 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2317 a_data = mapinfo.data;
2318 a_size = mapinfo.size;
2320 GstCaps *caps = gst_pad_get_current_caps(pad);
2321 GstStructure *structure = gst_caps_get_structure(caps, 0);
2323 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2324 pcm_format = gst_structure_get_string(structure, "format");
2325 gst_structure_get_int(structure, "rate", &rate);
2326 gst_structure_get_int(structure, "channels", &channel);
2327 gst_structure_get_int(structure, "depth", &depth);
2328 gst_structure_get_int(structure, "endianness", &endianness);
2329 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2330 gst_caps_unref(GST_CAPS(caps));
2332 /* In case of the sync is false, use buffer list. *
2333 * The num of buffer list depends on the num of audio channels */
2334 if (player->audio_stream_buff_list) {
2335 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2336 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2338 if (channel_mask == tmp->channel_mask) {
2339 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2340 if (tmp->data_size + a_size < tmp->buff_size) {
2341 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2342 tmp->data_size += a_size;
2344 /* send data to client */
2345 __mmplayer_audio_stream_send_data(player, tmp);
2347 if (a_size > tmp->buff_size) {
2348 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2349 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2350 if (tmp->pcm_data == NULL) {
2351 LOGE("failed to realloc data.");
2354 tmp->buff_size = a_size;
2356 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2357 memcpy(tmp->pcm_data, a_data, a_size);
2358 tmp->data_size = a_size;
2363 LOGE("data is empty in list.");
2369 /* create new audio stream data for newly found audio channel */
2370 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2371 if (a_buffer == NULL) {
2372 LOGE("failed to alloc data.");
2375 a_buffer->bitrate = rate;
2376 a_buffer->channel = channel;
2377 a_buffer->depth = depth;
2378 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2379 a_buffer->channel_mask = channel_mask;
2380 a_buffer->data_size = a_size;
2381 a_buffer->pcm_format = util_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2383 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2384 /* If sync is FALSE, use buffer list to reduce the IPC. */
2385 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2386 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2387 if (a_buffer->pcm_data == NULL) {
2388 LOGE("failed to alloc data.");
2389 MMPLAYER_FREEIF(a_buffer);
2392 memcpy(a_buffer->pcm_data, a_data, a_size);
2393 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2394 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2396 /* If sync is TRUE, send data directly. */
2397 a_buffer->pcm_data = a_data;
2398 __mmplayer_audio_stream_send_data(player, a_buffer);
2399 MMPLAYER_FREEIF(a_buffer);
2403 gst_buffer_unmap(buffer, &mapinfo);
2408 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2410 mmplayer_t *player = (mmplayer_t *)data;
2411 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2412 GstPad *sinkpad = NULL;
2413 GstElement *queue = NULL, *sink = NULL;
2416 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2418 queue = gst_element_factory_make("queue", NULL);
2419 if (queue == NULL) {
2420 LOGD("fail make queue");
2424 sink = gst_element_factory_make("fakesink", NULL);
2426 LOGD("fail make fakesink");
2430 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2432 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2433 LOGW("failed to link queue & sink");
2437 sinkpad = gst_element_get_static_pad(queue, "sink");
2439 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2440 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2444 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2446 gst_object_unref(sinkpad);
2447 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2448 g_object_set(sink, "sync", TRUE, NULL);
2449 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2451 /* keep the first sink reference only */
2452 if (!audiobin[MMPLAYER_A_SINK].gst) {
2453 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2454 audiobin[MMPLAYER_A_SINK].gst = sink;
2457 gst_element_set_state(sink, GST_STATE_PAUSED);
2458 gst_element_set_state(queue, GST_STATE_PAUSED);
2460 __mmplayer_add_signal_connection(player,
2462 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2464 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2467 __mmplayer_add_sink(player, sink);
2473 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2475 gst_object_unref(GST_OBJECT(queue));
2479 gst_object_unref(GST_OBJECT(sink));
2483 gst_object_unref(GST_OBJECT(sinkpad));
2491 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2493 #define MAX_PROPS_LEN 128
2494 gint latency_mode = 0;
2495 gchar *stream_type = NULL;
2496 gchar *latency = NULL;
2498 gchar stream_props[MAX_PROPS_LEN] = {0,};
2499 GstStructure *props = NULL;
2502 * It should be set after player creation through attribute.
2503 * But, it can not be changed during playing.
2506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2508 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2509 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2512 LOGE("stream_type is null.");
2514 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2515 stream_type, stream_id);
2516 props = gst_structure_from_string(stream_props, NULL);
2517 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2518 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2519 gst_structure_free(props);
2522 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2524 switch (latency_mode) {
2525 case AUDIO_LATENCY_MODE_LOW:
2526 latency = g_strndup("low", 3);
2528 case AUDIO_LATENCY_MODE_MID:
2529 latency = g_strndup("mid", 3);
2531 case AUDIO_LATENCY_MODE_HIGH:
2532 latency = g_strndup("high", 4);
2536 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2540 LOGD("audiosink property - latency=%s", latency);
2542 MMPLAYER_FREEIF(latency);
2548 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2550 mmplayer_gst_element_t *audiobin = NULL;
2553 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2555 audiobin = player->pipeline->audiobin;
2557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2558 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2561 if (player->video360_yaw_radians <= M_PI &&
2562 player->video360_yaw_radians >= -M_PI &&
2563 player->video360_pitch_radians <= M_PI_2 &&
2564 player->video360_pitch_radians >= -M_PI_2) {
2565 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2566 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2567 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2568 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2569 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2570 "source-orientation-y", player->video360_metadata.init_view_heading,
2571 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2578 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2580 mmplayer_gst_element_t *audiobin = NULL;
2581 GstPad *sink_pad = NULL;
2582 GstCaps *acaps = NULL;
2584 int pitch_control = 0;
2585 double pitch_value = 1.0;
2588 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2589 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2591 audiobin = player->pipeline->audiobin;
2593 LOGD("make element for normal audio playback");
2595 /* audio bin structure for playback. {} means optional.
2596 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2598 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2599 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2602 /* for pitch control */
2603 mm_attrs_multiple_get(player->attrs, NULL,
2604 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2605 MM_PLAYER_PITCH_VALUE, &pitch_value,
2608 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2609 if (pitch_control && (player->videodec_linked == 0)) {
2610 GstElementFactory *factory;
2612 factory = gst_element_factory_find("pitch");
2614 gst_object_unref(factory);
2617 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2620 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2621 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2623 LOGW("there is no pitch element");
2628 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2630 /* replaygain volume */
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2632 if (player->sound.rg_enable)
2633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2638 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2640 /* for logical volume control */
2641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2644 if (player->sound.mute) {
2645 LOGD("mute enabled");
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2649 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2651 /* audio effect element. if audio effect is enabled */
2652 if ((strcmp(player->ini.audioeffect_element, ""))
2654 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2657 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2659 if ((!player->bypass_audio_effect)
2660 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2661 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2662 if (!_mmplayer_audio_effect_custom_apply(player))
2663 LOGI("apply audio effect(custom) setting success");
2667 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2668 && (player->set_mode.rich_audio)) {
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2673 /* create audio sink */
2674 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2675 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2676 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2678 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2679 if (player->is_360_feature_enabled &&
2680 player->is_content_spherical &&
2682 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2683 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2684 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2686 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2688 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2690 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2691 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2692 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2693 gst_caps_unref(acaps);
2695 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2697 player->is_openal_plugin_used = TRUE;
2699 if (player->is_360_feature_enabled && player->is_content_spherical)
2700 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2701 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2704 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2705 (player->videodec_linked && player->ini.use_system_clock)) {
2706 LOGD("system clock will be used.");
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2710 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2711 __mmplayer_gst_set_pulsesink_property(player);
2712 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2713 __mmplayer_gst_set_openalsink_property(player);
2716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2719 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2720 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2721 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2722 gst_object_unref(GST_OBJECT(sink_pad));
2724 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2727 return MM_ERROR_NONE;
2729 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2731 return MM_ERROR_PLAYER_INTERNAL;
2735 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2737 mmplayer_gst_element_t *audiobin = NULL;
2738 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2740 gchar *dst_format = NULL;
2742 int dst_samplerate = 0;
2743 int dst_channels = 0;
2744 GstCaps *caps = NULL;
2745 char *caps_str = NULL;
2748 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2749 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2751 audiobin = player->pipeline->audiobin;
2753 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2755 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2757 [case 1] extract interleave audio pcm without playback
2758 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2759 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2761 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2763 [case 2] deinterleave for each channel without playback
2764 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2765 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2767 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2768 - fakesink (sync or not)
2771 [case 3] [case 1(sync only)] + playback
2772 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2774 * src - ... - tee - queue1 - playback path
2775 - queue2 - [case1 pipeline with sync]
2777 [case 4] [case 2(sync only)] + playback
2778 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2780 * src - ... - tee - queue1 - playback path
2781 - queue2 - [case2 pipeline with sync]
2785 /* 1. create tee and playback path
2786 'tee' should be added at first to copy the decoded stream
2788 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2789 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2790 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2792 /* tee - path 1 : for playback path */
2793 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2794 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2796 /* tee - path 2 : for extract path */
2797 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2798 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2801 /* if there is tee, 'tee - path 2' is linked here */
2803 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2806 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2808 /* 2. decide the extract pcm format */
2809 mm_attrs_multiple_get(player->attrs, NULL,
2810 "pcm_audioformat", &dst_format, &dst_len,
2811 "pcm_extraction_samplerate", &dst_samplerate,
2812 "pcm_extraction_channels", &dst_channels,
2815 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2816 dst_format, dst_len, dst_samplerate, dst_channels);
2818 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2819 mm_attrs_multiple_get(player->attrs, NULL,
2820 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2821 "content_audio_samplerate", &dst_samplerate,
2822 "content_audio_channels", &dst_channels,
2825 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2826 dst_format, dst_len, dst_samplerate, dst_channels);
2828 /* If there is no enough information, set it to platform default value. */
2829 if (dst_format == NULL || util_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2830 LOGD("set platform default format");
2831 dst_format = DEFAULT_PCM_OUT_FORMAT;
2833 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2834 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2837 /* 3. create capsfilter */
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2839 caps = gst_caps_new_simple("audio/x-raw",
2840 "format", G_TYPE_STRING, dst_format,
2841 "rate", G_TYPE_INT, dst_samplerate,
2842 "channels", G_TYPE_INT, dst_channels,
2845 caps_str = gst_caps_to_string(caps);
2846 LOGD("new caps : %s", caps_str);
2848 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2851 gst_caps_unref(caps);
2852 MMPLAYER_FREEIF(caps_str);
2854 /* 4-1. create deinterleave to extract pcm for each channel */
2855 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2857 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2859 /* audiosink will be added after getting signal for each channel */
2860 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2861 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2863 /* 4-2. create fakesink to extract interlevaed pcm */
2864 LOGD("add audio fakesink for interleaved audio");
2865 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2866 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2867 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2868 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2870 __mmplayer_add_signal_connection(player,
2871 G_OBJECT(audiobin[extract_sink_id].gst),
2872 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2874 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2877 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2881 return MM_ERROR_NONE;
2883 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2885 return MM_ERROR_PLAYER_INTERNAL;
2889 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2891 int ret = MM_ERROR_NONE;
2892 mmplayer_gst_element_t *audiobin = NULL;
2893 GList *element_bucket = NULL;
2896 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2897 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2899 audiobin = player->pipeline->audiobin;
2901 if (player->build_audio_offload) { /* skip all the audio filters */
2902 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2904 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2905 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2906 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2908 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2912 /* FIXME: need to mention the supportable condition at API reference */
2913 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2914 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2916 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2918 if (ret != MM_ERROR_NONE)
2921 LOGD("success to make audio bin element");
2922 *bucket = element_bucket;
2925 return MM_ERROR_NONE;
2928 LOGE("failed to make audio bin element");
2929 g_list_free(element_bucket);
2933 return MM_ERROR_PLAYER_INTERNAL;
2937 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2939 mmplayer_gst_element_t *first_element = NULL;
2940 mmplayer_gst_element_t *audiobin = NULL;
2942 GstPad *ghostpad = NULL;
2943 GList *element_bucket = NULL;
2947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2950 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2952 LOGE("failed to allocate memory for audiobin");
2953 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2957 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2958 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2959 if (!audiobin[MMPLAYER_A_BIN].gst) {
2960 LOGE("failed to create audiobin");
2965 player->pipeline->audiobin = audiobin;
2967 /* create audio filters and audiosink */
2968 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2971 /* adding created elements to bin */
2972 LOGD("adding created elements to bin");
2973 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2976 /* linking elements in the bucket by added order. */
2977 LOGD("Linking elements in the bucket by added order.");
2978 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2981 /* get first element's sinkpad for creating ghostpad */
2982 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2983 if (!first_element) {
2984 LOGE("failed to get first elem");
2988 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2990 LOGE("failed to get pad from first element of audiobin");
2994 ghostpad = gst_ghost_pad_new("sink", pad);
2996 LOGE("failed to create ghostpad");
3000 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3001 LOGE("failed to add ghostpad to audiobin");
3005 gst_object_unref(pad);
3007 g_list_free(element_bucket);
3010 return MM_ERROR_NONE;
3013 LOGD("ERROR : releasing audiobin");
3016 gst_object_unref(GST_OBJECT(pad));
3019 gst_object_unref(GST_OBJECT(ghostpad));
3022 g_list_free(element_bucket);
3024 /* release element which are not added to bin */
3025 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3026 /* NOTE : skip bin */
3027 if (audiobin[i].gst) {
3028 GstObject *parent = NULL;
3029 parent = gst_element_get_parent(audiobin[i].gst);
3032 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3033 audiobin[i].gst = NULL;
3035 gst_object_unref(GST_OBJECT(parent));
3039 /* release audiobin with it's childs */
3040 if (audiobin[MMPLAYER_A_BIN].gst)
3041 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3043 MMPLAYER_FREEIF(audiobin);
3045 player->pipeline->audiobin = NULL;
3047 return MM_ERROR_PLAYER_INTERNAL;
3051 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3053 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3057 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3059 int ret = MM_ERROR_NONE;
3061 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3062 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3064 MMPLAYER_VIDEO_BO_LOCK(player);
3066 if (player->video_bo_list) {
3067 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3068 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3069 if (tmp && tmp->bo == bo) {
3071 LOGD("release bo %p", bo);
3072 tbm_bo_unref(tmp->bo);
3073 MMPLAYER_VIDEO_BO_UNLOCK(player);
3074 MMPLAYER_VIDEO_BO_SIGNAL(player);
3079 /* hw codec is running or the list was reset for DRC. */
3080 LOGW("there is no bo list.");
3082 MMPLAYER_VIDEO_BO_UNLOCK(player);
3084 LOGW("failed to find bo %p", bo);
3089 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3094 MMPLAYER_RETURN_IF_FAIL(player);
3096 MMPLAYER_VIDEO_BO_LOCK(player);
3097 if (player->video_bo_list) {
3098 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3099 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3100 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3103 tbm_bo_unref(tmp->bo);
3107 g_list_free(player->video_bo_list);
3108 player->video_bo_list = NULL;
3110 player->video_bo_size = 0;
3111 MMPLAYER_VIDEO_BO_UNLOCK(player);
3118 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3121 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3122 gboolean ret = TRUE;
3124 /* check DRC, if it is, destroy the prev bo list to create again */
3125 if (player->video_bo_size != size) {
3126 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3127 __mmplayer_video_stream_destroy_bo_list(player);
3128 player->video_bo_size = size;
3131 MMPLAYER_VIDEO_BO_LOCK(player);
3133 if ((!player->video_bo_list) ||
3134 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3136 /* create bo list */
3138 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3140 if (player->video_bo_list) {
3141 /* if bo list did not created all, try it again. */
3142 idx = g_list_length(player->video_bo_list);
3143 LOGD("bo list exist(len: %d)", idx);
3146 for (; idx < player->ini.num_of_video_bo; idx++) {
3147 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3149 LOGE("Fail to alloc bo_info.");
3152 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3154 LOGE("Fail to tbm_bo_alloc.");
3155 MMPLAYER_FREEIF(bo_info);
3158 bo_info->used = FALSE;
3159 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3162 /* update video num buffers */
3163 player->video_num_buffers = idx;
3164 if (idx == player->ini.num_of_video_bo)
3165 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3168 MMPLAYER_VIDEO_BO_UNLOCK(player);
3172 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3176 /* get bo from list*/
3177 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3178 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3179 if (tmp && (tmp->used == FALSE)) {
3180 LOGD("found bo %p to use", tmp->bo);
3182 MMPLAYER_VIDEO_BO_UNLOCK(player);
3183 return tbm_bo_ref(tmp->bo);
3187 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3188 MMPLAYER_VIDEO_BO_UNLOCK(player);
3192 if (player->ini.video_bo_timeout <= 0) {
3193 MMPLAYER_VIDEO_BO_WAIT(player);
3195 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3196 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3203 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3205 mmplayer_t *player = (mmplayer_t *)data;
3207 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3209 /* send prerolled pkt */
3210 player->video_stream_prerolled = false;
3212 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3214 /* not to send prerolled pkt again */
3215 player->video_stream_prerolled = true;
3219 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3221 mmplayer_t *player = (mmplayer_t *)data;
3222 mmplayer_video_decoded_data_info_t *stream = NULL;
3223 GstMemory *mem = NULL;
3226 MMPLAYER_RETURN_IF_FAIL(player);
3227 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3229 if (player->video_stream_prerolled) {
3230 player->video_stream_prerolled = false;
3231 LOGD("skip the prerolled pkt not to send it again");
3235 /* clear stream data structure */
3236 stream = __mmplayer_create_stream_from_pad(pad);
3238 LOGE("failed to alloc stream");
3242 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3244 /* set size and timestamp */
3245 mem = gst_buffer_peek_memory(buffer, 0);
3246 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3247 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3249 /* check zero-copy */
3250 if (player->set_mode.video_zc &&
3251 player->set_mode.video_export &&
3252 gst_is_tizen_memory(mem)) {
3253 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3254 stream->internal_buffer = gst_buffer_ref(buffer);
3255 } else { /* sw codec */
3256 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3259 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3263 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3264 LOGE("failed to send video decoded data.");
3271 LOGE("release video stream resource.");
3272 if (gst_is_tizen_memory(mem)) {
3274 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3276 tbm_bo_unref(stream->bo[i]);
3279 /* unref gst buffer */
3280 if (stream->internal_buffer)
3281 gst_buffer_unref(stream->internal_buffer);
3284 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3286 MMPLAYER_FREEIF(stream);
3291 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3293 mmplayer_gst_element_t *videobin = NULL;
3296 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3298 videobin = player->pipeline->videobin;
3300 /* Set spatial media metadata and/or user settings to the element.
3302 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3303 "projection-type", player->video360_metadata.projection_type, NULL);
3305 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3306 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3308 if (player->video360_metadata.full_pano_width_pixels &&
3309 player->video360_metadata.full_pano_height_pixels &&
3310 player->video360_metadata.cropped_area_image_width &&
3311 player->video360_metadata.cropped_area_image_height) {
3312 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3313 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3314 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3315 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3316 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3317 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3318 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3322 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3323 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3324 "horizontal-fov", player->video360_horizontal_fov,
3325 "vertical-fov", player->video360_vertical_fov, NULL);
3328 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3329 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3330 "zoom", 1.0f / player->video360_zoom, NULL);
3333 if (player->video360_yaw_radians <= M_PI &&
3334 player->video360_yaw_radians >= -M_PI &&
3335 player->video360_pitch_radians <= M_PI_2 &&
3336 player->video360_pitch_radians >= -M_PI_2) {
3337 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3338 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3339 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3340 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3342 "pose-yaw", player->video360_metadata.init_view_heading,
3343 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3346 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3347 "passthrough", !player->is_video360_enabled, NULL);
3354 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3356 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3357 GList *element_bucket = NULL;
3360 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3362 /* create video360 filter */
3363 if (player->is_360_feature_enabled && player->is_content_spherical) {
3364 LOGD("create video360 element");
3365 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3366 __mmplayer_gst_set_video360_property(player);
3370 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3371 LOGD("skip creating the videoconv and rotator");
3372 return MM_ERROR_NONE;
3375 /* in case of sw codec & overlay surface type, except 360 playback.
3376 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3377 LOGD("create video converter: %s", video_csc);
3378 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3381 *bucket = element_bucket;
3383 return MM_ERROR_NONE;
3385 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3386 g_list_free(element_bucket);
3390 return MM_ERROR_PLAYER_INTERNAL;
3394 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3396 gchar *factory_name = NULL;
3398 switch (surface_type) {
3399 case MM_DISPLAY_SURFACE_OVERLAY:
3400 if (strlen(player->ini.videosink_element_overlay) > 0)
3401 factory_name = player->ini.videosink_element_overlay;
3403 case MM_DISPLAY_SURFACE_REMOTE:
3404 case MM_DISPLAY_SURFACE_NULL:
3405 if (strlen(player->ini.videosink_element_fake) > 0)
3406 factory_name = player->ini.videosink_element_fake;
3409 LOGE("unidentified surface type");
3413 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3414 return factory_name;
3418 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3420 gchar *factory_name = NULL;
3421 mmplayer_gst_element_t *videobin = NULL;
3426 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3428 videobin = player->pipeline->videobin;
3429 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3431 attrs = MMPLAYER_GET_ATTRS(player);
3433 LOGE("cannot get content attribute");
3434 return MM_ERROR_PLAYER_INTERNAL;
3437 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3438 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3439 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3441 /* support shard memory with S/W codec on HawkP */
3442 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3443 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3444 "use-tbm", use_tbm, NULL);
3448 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3449 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3452 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3454 LOGD("disable last-sample");
3455 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3458 if (player->set_mode.video_export) {
3460 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3461 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3462 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3464 __mmplayer_add_signal_connection(player,
3465 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3466 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3468 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3471 __mmplayer_add_signal_connection(player,
3472 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3473 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3475 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3479 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3480 return MM_ERROR_PLAYER_INTERNAL;
3482 if (videobin[MMPLAYER_V_SINK].gst) {
3483 GstPad *sink_pad = NULL;
3484 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3486 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3487 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3488 gst_object_unref(GST_OBJECT(sink_pad));
3490 LOGE("failed to get sink pad from videosink");
3494 return MM_ERROR_NONE;
3499 * - video overlay surface(arm/x86) : tizenwlsink
3502 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3505 GList *element_bucket = NULL;
3506 mmplayer_gst_element_t *first_element = NULL;
3507 mmplayer_gst_element_t *videobin = NULL;
3508 gchar *videosink_factory_name = NULL;
3511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3514 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3516 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3518 player->pipeline->videobin = videobin;
3521 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3522 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3523 if (!videobin[MMPLAYER_V_BIN].gst) {
3524 LOGE("failed to create videobin");
3528 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3531 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3532 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3534 /* additional setting for sink plug-in */
3535 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3536 LOGE("failed to set video property");
3540 /* store it as it's sink element */
3541 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3543 /* adding created elements to bin */
3544 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3545 LOGE("failed to add elements");
3549 /* Linking elements in the bucket by added order */
3550 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3551 LOGE("failed to link elements");
3555 /* get first element's sinkpad for creating ghostpad */
3556 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3557 if (!first_element) {
3558 LOGE("failed to get first element from bucket");
3562 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3564 LOGE("failed to get pad from first element");
3568 /* create ghostpad */
3569 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3570 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3571 LOGE("failed to add ghostpad to videobin");
3574 gst_object_unref(pad);
3576 /* done. free allocated variables */
3577 g_list_free(element_bucket);
3581 return MM_ERROR_NONE;
3584 LOGE("ERROR : releasing videobin");
3585 g_list_free(element_bucket);
3588 gst_object_unref(GST_OBJECT(pad));
3590 /* release videobin with it's childs */
3591 if (videobin[MMPLAYER_V_BIN].gst)
3592 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3594 MMPLAYER_FREEIF(videobin);
3595 player->pipeline->videobin = NULL;
3597 return MM_ERROR_PLAYER_INTERNAL;
3601 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3603 GList *element_bucket = NULL;
3604 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3606 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3607 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3608 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3609 "signal-handoffs", FALSE,
3612 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3613 __mmplayer_add_signal_connection(player,
3614 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3615 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3617 G_CALLBACK(__mmplayer_update_subtitle),
3620 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3621 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3623 if (!player->play_subtitle) {
3624 LOGD("add textbin sink as sink element of whole pipeline.");
3625 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3628 /* adding created elements to bin */
3629 LOGD("adding created elements to bin");
3630 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3631 LOGE("failed to add elements");
3635 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3636 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3637 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3639 /* linking elements in the bucket by added order. */
3640 LOGD("Linking elements in the bucket by added order.");
3641 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3642 LOGE("failed to link elements");
3646 /* done. free allocated variables */
3647 g_list_free(element_bucket);
3649 if (textbin[MMPLAYER_T_QUEUE].gst) {
3651 GstPad *ghostpad = NULL;
3653 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3655 LOGE("failed to get sink pad of text queue");
3659 ghostpad = gst_ghost_pad_new("text_sink", pad);
3660 gst_object_unref(pad);
3663 LOGE("failed to create ghostpad of textbin");
3667 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3668 LOGE("failed to add ghostpad to textbin");
3669 gst_object_unref(ghostpad);
3674 return MM_ERROR_NONE;
3677 g_list_free(element_bucket);
3679 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3680 LOGE("remove textbin sink from sink list");
3681 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3684 /* release element at __mmplayer_gst_create_text_sink_bin */
3685 return MM_ERROR_PLAYER_INTERNAL;
3689 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3691 mmplayer_gst_element_t *textbin = NULL;
3692 GList *element_bucket = NULL;
3693 int surface_type = 0;
3698 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3701 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3703 LOGE("failed to allocate memory for textbin");
3704 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3708 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3709 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3710 if (!textbin[MMPLAYER_T_BIN].gst) {
3711 LOGE("failed to create textbin");
3716 player->pipeline->textbin = textbin;
3719 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3720 LOGD("surface type for subtitle : %d", surface_type);
3721 switch (surface_type) {
3722 case MM_DISPLAY_SURFACE_OVERLAY:
3723 case MM_DISPLAY_SURFACE_NULL:
3724 case MM_DISPLAY_SURFACE_REMOTE:
3725 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3726 LOGE("failed to make plain text elements");
3737 return MM_ERROR_NONE;
3741 LOGD("ERROR : releasing textbin");
3743 g_list_free(element_bucket);
3745 /* release signal */
3746 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3748 /* release element which are not added to bin */
3749 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3750 /* NOTE : skip bin */
3751 if (textbin[i].gst) {
3752 GstObject *parent = NULL;
3753 parent = gst_element_get_parent(textbin[i].gst);
3756 gst_object_unref(GST_OBJECT(textbin[i].gst));
3757 textbin[i].gst = NULL;
3759 gst_object_unref(GST_OBJECT(parent));
3764 /* release textbin with it's childs */
3765 if (textbin[MMPLAYER_T_BIN].gst)
3766 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3768 MMPLAYER_FREEIF(player->pipeline->textbin);
3769 player->pipeline->textbin = NULL;
3772 return MM_ERROR_PLAYER_INTERNAL;
3776 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3778 mmplayer_gst_element_t *mainbin = NULL;
3779 mmplayer_gst_element_t *textbin = NULL;
3780 MMHandleType attrs = 0;
3781 GstElement *subsrc = NULL;
3782 GstElement *subparse = NULL;
3783 gchar *subtitle_uri = NULL;
3784 const gchar *charset = NULL;
3790 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3792 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3794 mainbin = player->pipeline->mainbin;
3796 attrs = MMPLAYER_GET_ATTRS(player);
3798 LOGE("cannot get content attribute");
3799 return MM_ERROR_PLAYER_INTERNAL;
3802 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3803 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3804 LOGE("subtitle uri is not proper filepath.");
3805 return MM_ERROR_PLAYER_INVALID_URI;
3808 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3809 LOGE("failed to get storage info of subtitle path");
3810 return MM_ERROR_PLAYER_INVALID_URI;
3813 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3815 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3816 player->subtitle_language_list = NULL;
3817 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3819 /* create the subtitle source */
3820 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3822 LOGE("failed to create filesrc element");
3825 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3827 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3828 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3830 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3831 LOGW("failed to add queue");
3832 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3833 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3834 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3839 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3841 LOGE("failed to create subparse element");
3845 charset = util_get_charset(subtitle_uri);
3847 LOGD("detected charset is %s", charset);
3848 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3851 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3852 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3854 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3855 LOGW("failed to add subparse");
3856 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3857 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3858 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3862 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3863 LOGW("failed to link subsrc and subparse");
3867 player->play_subtitle = TRUE;
3868 player->adjust_subtitle_pos = 0;
3870 LOGD("play subtitle using subtitle file");
3872 if (player->pipeline->textbin == NULL) {
3873 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3874 LOGE("failed to create text sink bin. continuing without text");
3878 textbin = player->pipeline->textbin;
3880 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3881 LOGW("failed to add textbin");
3883 /* release signal */
3884 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3886 /* release textbin with it's childs */
3887 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3888 MMPLAYER_FREEIF(player->pipeline->textbin);
3889 player->pipeline->textbin = textbin = NULL;
3893 LOGD("link text input selector and textbin ghost pad");
3895 player->textsink_linked = 1;
3896 player->external_text_idx = 0;
3897 LOGI("textsink is linked");
3899 textbin = player->pipeline->textbin;
3900 LOGD("text bin has been created. reuse it.");
3901 player->external_text_idx = 1;
3904 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3905 LOGW("failed to link subparse and textbin");
3909 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3911 LOGE("failed to get sink pad from textsink to probe data");
3915 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3916 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3918 gst_object_unref(pad);
3921 /* create dot. for debugging */
3922 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3925 return MM_ERROR_NONE;
3928 /* release text pipeline resource */
3929 player->textsink_linked = 0;
3931 /* release signal */
3932 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3934 if (player->pipeline->textbin) {
3935 LOGE("remove textbin");
3937 /* release textbin with it's childs */
3938 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3939 MMPLAYER_FREEIF(player->pipeline->textbin);
3940 player->pipeline->textbin = NULL;
3944 /* release subtitle elem */
3945 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3946 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3948 return MM_ERROR_PLAYER_INTERNAL;
3952 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3954 mmplayer_t *player = (mmplayer_t *)data;
3955 MMMessageParamType msg = {0, };
3956 GstClockTime duration = 0;
3957 gpointer text = NULL;
3958 guint text_size = 0;
3959 gboolean ret = TRUE;
3960 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3964 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3965 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3967 if (player->is_subtitle_force_drop) {
3968 LOGW("subtitle is dropped forcedly.");
3972 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3973 text = mapinfo.data;
3974 text_size = mapinfo.size;
3976 if (player->set_mode.subtitle_off) {
3977 LOGD("subtitle is OFF.");
3981 if (!text || (text_size == 0)) {
3982 LOGD("There is no subtitle to be displayed.");
3986 msg.data = (void *)text;
3988 duration = GST_BUFFER_DURATION(buffer);
3990 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3991 if (player->duration > GST_BUFFER_PTS(buffer))
3992 duration = player->duration - GST_BUFFER_PTS(buffer);
3995 LOGI("subtitle duration is invalid, subtitle duration change "
3996 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3998 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4000 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4002 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4003 gst_buffer_unmap(buffer, &mapinfo);
4010 static GstPadProbeReturn
4011 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4013 mmplayer_t *player = (mmplayer_t *)u_data;
4014 GstClockTime cur_timestamp = 0;
4015 gint64 adjusted_timestamp = 0;
4016 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4018 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4020 if (player->set_mode.subtitle_off) {
4021 LOGD("subtitle is OFF.");
4025 if (player->adjust_subtitle_pos == 0) {
4026 LOGD("nothing to do");
4030 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4031 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4033 if (adjusted_timestamp < 0) {
4034 LOGD("adjusted_timestamp under zero");
4039 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4040 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4041 GST_TIME_ARGS(cur_timestamp),
4042 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4044 return GST_PAD_PROBE_OK;
4048 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4052 /* check player and subtitlebin are created */
4053 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4054 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4056 if (position == 0) {
4057 LOGD("nothing to do");
4059 return MM_ERROR_NONE;
4062 /* check current postion */
4063 player->adjust_subtitle_pos = position;
4065 LOGD("save adjust_subtitle_pos in player");
4069 return MM_ERROR_NONE;
4073 * This function is to create audio or video pipeline for playing.
4075 * @param player [in] handle of player
4077 * @return This function returns zero on success.
4082 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4084 int ret = MM_ERROR_NONE;
4085 mmplayer_gst_element_t *mainbin = NULL;
4086 MMHandleType attrs = 0;
4089 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4091 /* get profile attribute */
4092 attrs = MMPLAYER_GET_ATTRS(player);
4094 LOGE("failed to get content attribute");
4098 /* create pipeline handles */
4099 if (player->pipeline) {
4100 LOGE("pipeline should be released before create new one");
4104 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4105 if (player->pipeline == NULL)
4108 /* create mainbin */
4109 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4110 if (mainbin == NULL)
4113 /* create pipeline */
4114 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4115 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4116 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4117 LOGE("failed to create pipeline");
4122 player->pipeline->mainbin = mainbin;
4124 /* create the source and decoder elements */
4125 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4126 ret = __mmplayer_gst_build_es_pipeline(player);
4128 ret = __mmplayer_gst_build_pipeline(player);
4130 if (ret != MM_ERROR_NONE) {
4131 LOGE("failed to create some elements");
4135 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4136 if (__mmplayer_check_subtitle(player)
4137 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4138 LOGE("failed to create text pipeline");
4141 ret = __mmplayer_gst_add_bus_watch(player);
4142 if (ret != MM_ERROR_NONE) {
4143 LOGE("failed to add bus watch");
4148 return MM_ERROR_NONE;
4151 __mmplayer_gst_destroy_pipeline(player);
4152 return MM_ERROR_PLAYER_INTERNAL;
4156 __mmplayer_reset_gapless_state(mmplayer_t *player)
4159 MMPLAYER_RETURN_IF_FAIL(player
4161 && player->pipeline->audiobin
4162 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4164 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4171 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4174 int ret = MM_ERROR_NONE;
4178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4180 /* cleanup stuffs */
4181 MMPLAYER_FREEIF(player->type);
4182 player->no_more_pad = FALSE;
4183 player->num_dynamic_pad = 0;
4184 player->demux_pad_index = 0;
4186 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4187 player->subtitle_language_list = NULL;
4188 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4190 __mmplayer_reset_gapless_state(player);
4192 if (player->streamer) {
4193 __mm_player_streaming_initialize(player->streamer, FALSE);
4194 __mm_player_streaming_destroy(player->streamer);
4195 player->streamer = NULL;
4198 /* cleanup unlinked mime type */
4199 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4200 MMPLAYER_FREEIF(player->unlinked_video_mime);
4201 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4203 /* cleanup running stuffs */
4204 __mmplayer_cancel_eos_timer(player);
4206 /* cleanup gst stuffs */
4207 if (player->pipeline) {
4208 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4209 GstTagList *tag_list = player->pipeline->tag_list;
4211 /* first we need to disconnect all signal hander */
4212 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4215 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4216 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4217 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4218 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4219 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4220 gst_object_unref(bus);
4222 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4223 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4224 if (ret != MM_ERROR_NONE) {
4225 LOGE("fail to change state to NULL");
4226 return MM_ERROR_PLAYER_INTERNAL;
4229 LOGW("succeeded in changing state to NULL");
4231 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4234 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4235 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4237 /* free avsysaudiosink
4238 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4239 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4241 MMPLAYER_FREEIF(audiobin);
4242 MMPLAYER_FREEIF(videobin);
4243 MMPLAYER_FREEIF(textbin);
4244 MMPLAYER_FREEIF(mainbin);
4248 gst_tag_list_unref(tag_list);
4250 MMPLAYER_FREEIF(player->pipeline);
4252 MMPLAYER_FREEIF(player->album_art);
4254 if (player->v_stream_caps) {
4255 gst_caps_unref(player->v_stream_caps);
4256 player->v_stream_caps = NULL;
4259 if (player->a_stream_caps) {
4260 gst_caps_unref(player->a_stream_caps);
4261 player->a_stream_caps = NULL;
4264 if (player->s_stream_caps) {
4265 gst_caps_unref(player->s_stream_caps);
4266 player->s_stream_caps = NULL;
4268 __mmplayer_track_destroy(player);
4270 if (player->sink_elements)
4271 g_list_free(player->sink_elements);
4272 player->sink_elements = NULL;
4274 if (player->bufmgr) {
4275 tbm_bufmgr_deinit(player->bufmgr);
4276 player->bufmgr = NULL;
4279 LOGW("finished destroy pipeline");
4287 __mmplayer_gst_realize(mmplayer_t *player)
4290 int ret = MM_ERROR_NONE;
4294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4296 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4298 ret = __mmplayer_gst_create_pipeline(player);
4300 LOGE("failed to create pipeline");
4304 /* set pipeline state to READY */
4305 /* NOTE : state change to READY must be performed sync. */
4306 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4307 ret = __mmplayer_gst_set_state(player,
4308 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4310 if (ret != MM_ERROR_NONE) {
4311 /* return error if failed to set state */
4312 LOGE("failed to set READY state");
4316 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4318 /* create dot before error-return. for debugging */
4319 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4327 __mmplayer_gst_unrealize(mmplayer_t *player)
4329 int ret = MM_ERROR_NONE;
4333 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4335 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4336 MMPLAYER_PRINT_STATE(player);
4338 /* release miscellaneous information */
4339 __mmplayer_release_misc(player);
4341 /* destroy pipeline */
4342 ret = __mmplayer_gst_destroy_pipeline(player);
4343 if (ret != MM_ERROR_NONE) {
4344 LOGE("failed to destory pipeline");
4348 /* release miscellaneous information.
4349 these info needs to be released after pipeline is destroyed. */
4350 __mmplayer_release_misc_post(player);
4352 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4360 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4365 LOGW("set_message_callback is called with invalid player handle");
4366 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4369 player->msg_cb = callback;
4370 player->msg_cb_param = user_param;
4372 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4376 return MM_ERROR_NONE;
4380 __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4382 int ret = MM_ERROR_NONE;
4387 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4388 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4389 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4391 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4393 if (strstr(uri, "es_buff://")) {
4394 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4395 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4396 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4397 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4399 tmp = g_ascii_strdown(uri, strlen(uri));
4400 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4401 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4403 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4405 } else if (strstr(uri, "mms://")) {
4406 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4407 } else if ((path = strstr(uri, "mem://"))) {
4408 ret = __mmplayer_set_mem_uri(data, path, param);
4410 ret = __mmplayer_set_file_uri(data, uri);
4413 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4414 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4415 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4416 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4418 /* dump parse result */
4419 SECURE_LOGW("incoming uri : %s", uri);
4420 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4421 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4429 __mmplayer_can_do_interrupt(mmplayer_t *player)
4431 if (!player || !player->pipeline || !player->attrs) {
4432 LOGW("not initialized");
4436 if (player->audio_decoded_cb) {
4437 LOGW("not support in pcm extraction mode");
4441 /* check if seeking */
4442 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4443 MMMessageParamType msg_param;
4444 memset(&msg_param, 0, sizeof(MMMessageParamType));
4445 msg_param.code = MM_ERROR_PLAYER_SEEK;
4446 player->seek_state = MMPLAYER_SEEK_NONE;
4447 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4451 /* check other thread */
4452 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4453 LOGW("locked already, cmd state : %d", player->cmd);
4455 /* check application command */
4456 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4457 LOGW("playing.. should wait cmd lock then, will be interrupted");
4459 /* lock will be released at mrp_resource_release_cb() */
4460 MMPLAYER_CMD_LOCK(player);
4463 LOGW("nothing to do");
4466 LOGW("can interrupt immediately");
4470 FAILED: /* with CMD UNLOCKED */
4473 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4478 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4481 mmplayer_t *player = NULL;
4485 if (user_data == NULL) {
4486 LOGE("- user_data is null");
4489 player = (mmplayer_t *)user_data;
4491 /* do something to release resource here.
4492 * player stop and interrupt forwarding */
4493 if (!__mmplayer_can_do_interrupt(player)) {
4494 LOGW("no need to interrupt, so leave");
4496 MMMessageParamType msg = {0, };
4499 player->interrupted_by_resource = TRUE;
4501 /* get last play position */
4502 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4503 LOGW("failed to get play position.");
4505 msg.union_type = MM_MSG_UNION_TIME;
4506 msg.time.elapsed = pos;
4507 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4509 LOGD("video resource conflict so, resource will be freed by unrealizing");
4510 if (_mmplayer_unrealize((MMHandleType)player))
4511 LOGW("failed to unrealize");
4513 /* lock is called in __mmplayer_can_do_interrupt() */
4514 MMPLAYER_CMD_UNLOCK(player);
4517 if (res == player->video_overlay_resource)
4518 player->video_overlay_resource = FALSE;
4520 player->video_decoder_resource = FALSE;
4528 __mmplayer_initialize_video_roi(mmplayer_t *player)
4530 player->video_roi.scale_x = 0.0;
4531 player->video_roi.scale_y = 0.0;
4532 player->video_roi.scale_width = 1.0;
4533 player->video_roi.scale_height = 1.0;
4537 _mmplayer_create_player(MMHandleType handle)
4539 int ret = MM_ERROR_PLAYER_INTERNAL;
4540 bool enabled = false;
4542 mmplayer_t *player = MM_PLAYER_CAST(handle);
4546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4548 /* initialize player state */
4549 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4550 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4551 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4552 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4554 /* check current state */
4555 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4557 /* construct attributes */
4558 player->attrs = _mmplayer_construct_attribute(handle);
4560 if (!player->attrs) {
4561 LOGE("Failed to construct attributes");
4565 /* initialize gstreamer with configured parameter */
4566 if (!__mmplayer_init_gstreamer(player)) {
4567 LOGE("Initializing gstreamer failed");
4568 _mmplayer_deconstruct_attribute(handle);
4572 /* create lock. note that g_tread_init() has already called in gst_init() */
4573 g_mutex_init(&player->fsink_lock);
4575 /* create update tag lock */
4576 g_mutex_init(&player->update_tag_lock);
4578 /* create gapless play mutex */
4579 g_mutex_init(&player->gapless_play_thread_mutex);
4581 /* create gapless play cond */
4582 g_cond_init(&player->gapless_play_thread_cond);
4584 /* create gapless play thread */
4585 player->gapless_play_thread =
4586 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4587 if (!player->gapless_play_thread) {
4588 LOGE("failed to create gapless play thread");
4589 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4590 g_mutex_clear(&player->gapless_play_thread_mutex);
4591 g_cond_clear(&player->gapless_play_thread_cond);
4595 player->bus_msg_q = g_queue_new();
4596 if (!player->bus_msg_q) {
4597 LOGE("failed to create queue for bus_msg");
4598 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4602 ret = _mmplayer_initialize_video_capture(player);
4603 if (ret != MM_ERROR_NONE) {
4604 LOGE("failed to initialize video capture");
4608 /* initialize resource manager */
4609 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4610 __resource_release_cb, player, &player->resource_manager)
4611 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4612 LOGE("failed to initialize resource manager");
4613 ret = MM_ERROR_PLAYER_INTERNAL;
4617 /* create video bo lock and cond */
4618 g_mutex_init(&player->video_bo_mutex);
4619 g_cond_init(&player->video_bo_cond);
4621 /* create media stream callback mutex */
4622 g_mutex_init(&player->media_stream_cb_lock);
4624 /* create subtitle info lock and cond */
4625 g_mutex_init(&player->subtitle_info_mutex);
4626 g_cond_init(&player->subtitle_info_cond);
4628 player->streaming_type = STREAMING_SERVICE_NONE;
4630 /* give default value of audio effect setting */
4631 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4632 player->sound.rg_enable = false;
4633 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4635 player->play_subtitle = FALSE;
4636 player->has_closed_caption = FALSE;
4637 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4638 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4639 player->pending_resume = FALSE;
4640 if (player->ini.dump_element_keyword[0][0] == '\0')
4641 player->ini.set_dump_element_flag = FALSE;
4643 player->ini.set_dump_element_flag = TRUE;
4645 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4646 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4647 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4649 /* Set video360 settings to their defaults for just-created player.
4652 player->is_360_feature_enabled = FALSE;
4653 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4654 LOGI("spherical feature info: %d", enabled);
4656 player->is_360_feature_enabled = TRUE;
4658 LOGE("failed to get spherical feature info");
4661 player->is_content_spherical = FALSE;
4662 player->is_video360_enabled = TRUE;
4663 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4664 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4665 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4666 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4667 player->video360_zoom = 1.0f;
4668 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4669 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4671 __mmplayer_initialize_video_roi(player);
4673 /* set player state to null */
4674 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4675 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4679 return MM_ERROR_NONE;
4683 g_mutex_clear(&player->fsink_lock);
4684 /* free update tag lock */
4685 g_mutex_clear(&player->update_tag_lock);
4686 g_queue_free(player->bus_msg_q);
4687 player->bus_msg_q = NULL;
4688 /* free gapless play thread */
4689 if (player->gapless_play_thread) {
4690 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4691 player->gapless_play_thread_exit = TRUE;
4692 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4693 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4695 g_thread_join(player->gapless_play_thread);
4696 player->gapless_play_thread = NULL;
4698 g_mutex_clear(&player->gapless_play_thread_mutex);
4699 g_cond_clear(&player->gapless_play_thread_cond);
4702 /* release attributes */
4703 _mmplayer_deconstruct_attribute(handle);
4711 __mmplayer_init_gstreamer(mmplayer_t *player)
4713 static gboolean initialized = FALSE;
4714 static const int max_argc = 50;
4716 gchar **argv = NULL;
4717 gchar **argv2 = NULL;
4723 LOGD("gstreamer already initialized.");
4728 argc = malloc(sizeof(int));
4729 argv = malloc(sizeof(gchar *) * max_argc);
4730 argv2 = malloc(sizeof(gchar *) * max_argc);
4732 if (!argc || !argv || !argv2)
4735 memset(argv, 0, sizeof(gchar *) * max_argc);
4736 memset(argv2, 0, sizeof(gchar *) * max_argc);
4740 argv[0] = g_strdup("mmplayer");
4743 for (i = 0; i < 5; i++) {
4744 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4745 if (strlen(player->ini.gst_param[i]) > 0) {
4746 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4751 /* we would not do fork for scanning plugins */
4752 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4755 /* check disable registry scan */
4756 if (player->ini.skip_rescan) {
4757 argv[*argc] = g_strdup("--gst-disable-registry-update");
4761 /* check disable segtrap */
4762 if (player->ini.disable_segtrap) {
4763 argv[*argc] = g_strdup("--gst-disable-segtrap");
4767 LOGD("initializing gstreamer with following parameter");
4768 LOGD("argc : %d", *argc);
4771 for (i = 0; i < arg_count; i++) {
4773 LOGD("argv[%d] : %s", i, argv2[i]);
4776 /* initializing gstreamer */
4777 if (!gst_init_check(argc, &argv, &err)) {
4778 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4785 for (i = 0; i < arg_count; i++) {
4786 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4787 MMPLAYER_FREEIF(argv2[i]);
4790 MMPLAYER_FREEIF(argv);
4791 MMPLAYER_FREEIF(argv2);
4792 MMPLAYER_FREEIF(argc);
4802 for (i = 0; i < arg_count; i++) {
4803 LOGD("free[%d] : %s", i, argv2[i]);
4804 MMPLAYER_FREEIF(argv2[i]);
4807 MMPLAYER_FREEIF(argv);
4808 MMPLAYER_FREEIF(argv2);
4809 MMPLAYER_FREEIF(argc);
4815 __mmplayer_check_async_state_transition(mmplayer_t *player)
4817 GstState element_state = GST_STATE_VOID_PENDING;
4818 GstState element_pending_state = GST_STATE_VOID_PENDING;
4819 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4820 GstElement *element = NULL;
4821 gboolean async = FALSE;
4823 /* check player handle */
4824 MMPLAYER_RETURN_IF_FAIL(player &&
4826 player->pipeline->mainbin &&
4827 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4830 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4832 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4833 LOGD("don't need to check the pipeline state");
4837 MMPLAYER_PRINT_STATE(player);
4839 /* wait for state transition */
4840 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4841 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4843 if (ret == GST_STATE_CHANGE_FAILURE) {
4844 LOGE(" [%s] state : %s pending : %s",
4845 GST_ELEMENT_NAME(element),
4846 gst_element_state_get_name(element_state),
4847 gst_element_state_get_name(element_pending_state));
4849 /* dump state of all element */
4850 __mmplayer_dump_pipeline_state(player);
4855 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4860 _mmplayer_destroy(MMHandleType handle)
4862 mmplayer_t *player = MM_PLAYER_CAST(handle);
4866 /* check player handle */
4867 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4869 /* destroy can called at anytime */
4870 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4872 /* check async state transition */
4873 __mmplayer_check_async_state_transition(player);
4875 /* release gapless play thread */
4876 if (player->gapless_play_thread) {
4877 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4878 player->gapless_play_thread_exit = TRUE;
4879 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4880 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4882 LOGD("waitting for gapless play thread exit");
4883 g_thread_join(player->gapless_play_thread);
4884 g_mutex_clear(&player->gapless_play_thread_mutex);
4885 g_cond_clear(&player->gapless_play_thread_cond);
4886 LOGD("gapless play thread released");
4889 _mmplayer_release_video_capture(player);
4891 /* de-initialize resource manager */
4892 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4893 player->resource_manager))
4894 LOGE("failed to deinitialize resource manager");
4896 /* release pipeline */
4897 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4898 LOGE("failed to destory pipeline");
4899 return MM_ERROR_PLAYER_INTERNAL;
4902 g_queue_free(player->bus_msg_q);
4904 /* release subtitle info lock and cond */
4905 g_mutex_clear(&player->subtitle_info_mutex);
4906 g_cond_clear(&player->subtitle_info_cond);
4908 __mmplayer_release_dump_list(player->dump_list);
4910 /* release miscellaneous information */
4911 __mmplayer_release_misc(player);
4913 /* release miscellaneous information.
4914 these info needs to be released after pipeline is destroyed. */
4915 __mmplayer_release_misc_post(player);
4917 /* release attributes */
4918 _mmplayer_deconstruct_attribute(handle);
4921 g_mutex_clear(&player->fsink_lock);
4924 g_mutex_clear(&player->update_tag_lock);
4926 /* release video bo lock and cond */
4927 g_mutex_clear(&player->video_bo_mutex);
4928 g_cond_clear(&player->video_bo_cond);
4930 /* release media stream callback lock */
4931 g_mutex_clear(&player->media_stream_cb_lock);
4935 return MM_ERROR_NONE;
4939 _mmplayer_realize(MMHandleType hplayer)
4941 mmplayer_t *player = (mmplayer_t *)hplayer;
4944 MMHandleType attrs = 0;
4945 int ret = MM_ERROR_NONE;
4949 /* check player handle */
4950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4952 /* check current state */
4953 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4955 attrs = MMPLAYER_GET_ATTRS(player);
4957 LOGE("fail to get attributes.");
4958 return MM_ERROR_PLAYER_INTERNAL;
4960 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4961 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4963 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4964 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4966 if (ret != MM_ERROR_NONE) {
4967 LOGE("failed to parse profile");
4972 if (uri && (strstr(uri, "es_buff://"))) {
4973 if (strstr(uri, "es_buff://push_mode"))
4974 player->es_player_push_mode = TRUE;
4976 player->es_player_push_mode = FALSE;
4979 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4980 LOGW("mms protocol is not supported format.");
4981 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4984 if (MMPLAYER_IS_STREAMING(player))
4985 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4987 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4989 player->smooth_streaming = FALSE;
4990 player->videodec_linked = 0;
4991 player->audiodec_linked = 0;
4992 player->textsink_linked = 0;
4993 player->is_external_subtitle_present = FALSE;
4994 player->is_external_subtitle_added_now = FALSE;
4995 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4996 player->video360_metadata.is_spherical = -1;
4997 player->is_openal_plugin_used = FALSE;
4998 player->demux_pad_index = 0;
4999 player->subtitle_language_list = NULL;
5000 player->is_subtitle_force_drop = FALSE;
5002 __mmplayer_track_initialize(player);
5003 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5005 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5006 gint prebuffer_ms = 0, rebuffer_ms = 0;
5008 player->streamer = __mm_player_streaming_create();
5009 __mm_player_streaming_initialize(player->streamer, TRUE);
5011 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5012 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5014 if (prebuffer_ms > 0) {
5015 prebuffer_ms = MAX(prebuffer_ms, 1000);
5016 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5019 if (rebuffer_ms > 0) {
5020 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5021 rebuffer_ms = MAX(rebuffer_ms, 1000);
5022 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5025 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5026 player->streamer->buffering_req.rebuffer_time);
5029 /* realize pipeline */
5030 ret = __mmplayer_gst_realize(player);
5031 if (ret != MM_ERROR_NONE)
5032 LOGE("fail to realize the player.");
5034 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5042 _mmplayer_unrealize(MMHandleType hplayer)
5044 mmplayer_t *player = (mmplayer_t *)hplayer;
5045 int ret = MM_ERROR_NONE;
5049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5051 MMPLAYER_CMD_UNLOCK(player);
5052 /* destroy the gst bus msg thread which is created during realize.
5053 this funct have to be called before getting cmd lock. */
5054 __mmplayer_bus_msg_thread_destroy(player);
5055 MMPLAYER_CMD_LOCK(player);
5057 /* check current state */
5058 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5060 /* check async state transition */
5061 __mmplayer_check_async_state_transition(player);
5063 /* unrealize pipeline */
5064 ret = __mmplayer_gst_unrealize(player);
5066 /* set asm stop if success */
5067 if (MM_ERROR_NONE == ret) {
5068 if (!player->interrupted_by_resource) {
5069 if (player->video_decoder_resource != NULL) {
5070 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5071 player->video_decoder_resource);
5072 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5073 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
5075 player->video_decoder_resource = NULL;
5078 if (player->video_overlay_resource != NULL) {
5079 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5080 player->video_overlay_resource);
5081 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5082 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
5084 player->video_overlay_resource = NULL;
5087 ret = mm_resource_manager_commit(player->resource_manager);
5088 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5089 LOGE("failed to commit resource releases, ret(0x%x)", ret);
5092 LOGE("failed and don't change asm state to stop");
5100 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5102 mmplayer_t *player = (mmplayer_t *)hplayer;
5104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5110 _mmplayer_get_state(MMHandleType hplayer, int *state)
5112 mmplayer_t *player = (mmplayer_t *)hplayer;
5114 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5116 *state = MMPLAYER_CURRENT_STATE(player);
5118 return MM_ERROR_NONE;
5122 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5124 GstElement *vol_element = NULL;
5125 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5128 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5129 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5131 /* check pipeline handle */
5132 if (!player->pipeline || !player->pipeline->audiobin) {
5133 LOGD("'%s' will be applied when audiobin is created", prop_name);
5135 /* NOTE : stored value will be used in create_audiobin
5136 * returning MM_ERROR_NONE here makes application to able to
5137 * set audio volume or mute at anytime.
5139 return MM_ERROR_NONE;
5142 if (player->build_audio_offload) {
5143 LOGD("offload pipeline");
5144 volume_elem_id = MMPLAYER_A_SINK;
5147 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5149 LOGE("failed to get vol element %d", volume_elem_id);
5150 return MM_ERROR_PLAYER_INTERNAL;
5153 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5155 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5156 LOGE("there is no '%s' property", prop_name);
5157 return MM_ERROR_PLAYER_INTERNAL;
5160 if (!strcmp(prop_name, "volume")) {
5161 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5162 } else if (!strcmp(prop_name, "mute")) {
5163 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5165 LOGE("invalid property %s", prop_name);
5166 return MM_ERROR_PLAYER_INTERNAL;
5169 return MM_ERROR_NONE;
5173 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5175 int ret = MM_ERROR_NONE;
5176 mmplayer_t *player = (mmplayer_t *)hplayer;
5179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5181 LOGD("volume = %f", volume);
5183 /* invalid factor range or not */
5184 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5185 LOGE("Invalid volume value");
5186 return MM_ERROR_INVALID_ARGUMENT;
5189 player->sound.volume = volume;
5191 ret = __mmplayer_gst_set_volume_property(player, "volume");
5198 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5200 mmplayer_t *player = (mmplayer_t *)hplayer;
5204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5205 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5207 *volume = player->sound.volume;
5209 LOGD("current vol = %f", *volume);
5212 return MM_ERROR_NONE;
5216 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5218 int ret = MM_ERROR_NONE;
5219 mmplayer_t *player = (mmplayer_t *)hplayer;
5222 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5224 LOGD("mute = %d", mute);
5226 player->sound.mute = mute;
5228 ret = __mmplayer_gst_set_volume_property(player, "mute");
5235 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5237 mmplayer_t *player = (mmplayer_t *)hplayer;
5241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5242 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5244 *mute = player->sound.mute;
5246 LOGD("current mute = %d", *mute);
5250 return MM_ERROR_NONE;
5254 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5256 mmplayer_t *player = (mmplayer_t *)hplayer;
5260 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5262 player->video_stream_changed_cb = callback;
5263 player->video_stream_changed_cb_user_param = user_param;
5264 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5268 return MM_ERROR_NONE;
5272 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5274 mmplayer_t *player = (mmplayer_t *)hplayer;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 player->audio_stream_changed_cb = callback;
5281 player->audio_stream_changed_cb_user_param = user_param;
5282 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5286 return MM_ERROR_NONE;
5290 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5292 mmplayer_t *player = (mmplayer_t *)hplayer;
5296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5298 player->audio_decoded_cb = callback;
5299 player->audio_decoded_cb_user_param = user_param;
5300 player->audio_extract_opt = opt;
5301 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5305 return MM_ERROR_NONE;
5309 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5311 mmplayer_t *player = (mmplayer_t *)hplayer;
5315 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5317 if (callback && !player->bufmgr)
5318 player->bufmgr = tbm_bufmgr_init(-1);
5320 player->set_mode.video_export = (callback) ? true : false;
5321 player->video_decoded_cb = callback;
5322 player->video_decoded_cb_user_param = user_param;
5324 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5328 return MM_ERROR_NONE;
5332 _mmplayer_start(MMHandleType hplayer)
5334 mmplayer_t *player = (mmplayer_t *)hplayer;
5335 gint ret = MM_ERROR_NONE;
5339 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5341 /* check current state */
5342 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5344 /* start pipeline */
5345 ret = __mmplayer_gst_start(player);
5346 if (ret != MM_ERROR_NONE)
5347 LOGE("failed to start player.");
5349 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5350 LOGD("force playing start even during buffering");
5351 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5359 /* NOTE: post "not supported codec message" to application
5360 * when one codec is not found during AUTOPLUGGING in MSL.
5361 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5362 * And, if any codec is not found, don't send message here.
5363 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5366 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5368 MMMessageParamType msg_param;
5369 memset(&msg_param, 0, sizeof(MMMessageParamType));
5370 gboolean post_msg_direct = FALSE;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5377 player->not_supported_codec, player->can_support_codec);
5379 if (player->not_found_demuxer) {
5380 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5381 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5383 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5384 MMPLAYER_FREEIF(msg_param.data);
5386 return MM_ERROR_NONE;
5389 if (player->not_supported_codec) {
5390 if (player->can_support_codec) {
5391 // There is one codec to play
5392 post_msg_direct = TRUE;
5394 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5395 post_msg_direct = TRUE;
5398 if (post_msg_direct) {
5399 MMMessageParamType msg_param;
5400 memset(&msg_param, 0, sizeof(MMMessageParamType));
5402 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5403 LOGW("not found AUDIO codec, posting error code to application.");
5405 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5406 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5407 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5408 LOGW("not found VIDEO codec, posting error code to application.");
5410 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5411 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5414 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5416 MMPLAYER_FREEIF(msg_param.data);
5418 return MM_ERROR_NONE;
5420 // no any supported codec case
5421 LOGW("not found any codec, posting error code to application.");
5423 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5424 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5425 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5427 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5428 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5431 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5433 MMPLAYER_FREEIF(msg_param.data);
5439 return MM_ERROR_NONE;
5443 __mmplayer_check_pipeline(mmplayer_t *player)
5445 GstState element_state = GST_STATE_VOID_PENDING;
5446 GstState element_pending_state = GST_STATE_VOID_PENDING;
5448 int ret = MM_ERROR_NONE;
5450 if (!player->gapless.reconfigure)
5453 LOGW("pipeline is under construction.");
5455 MMPLAYER_PLAYBACK_LOCK(player);
5456 MMPLAYER_PLAYBACK_UNLOCK(player);
5458 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5460 /* wait for state transition */
5461 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5462 if (ret == GST_STATE_CHANGE_FAILURE)
5463 LOGE("failed to change pipeline state within %d sec", timeout);
5466 /* NOTE : it should be able to call 'stop' anytime*/
5468 _mmplayer_stop(MMHandleType hplayer)
5470 mmplayer_t *player = (mmplayer_t *)hplayer;
5471 int ret = MM_ERROR_NONE;
5475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5477 /* check current state */
5478 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5480 /* check pipline building state */
5481 __mmplayer_check_pipeline(player);
5482 __mmplayer_reset_gapless_state(player);
5484 /* NOTE : application should not wait for EOS after calling STOP */
5485 __mmplayer_cancel_eos_timer(player);
5488 player->seek_state = MMPLAYER_SEEK_NONE;
5491 ret = __mmplayer_gst_stop(player);
5493 if (ret != MM_ERROR_NONE)
5494 LOGE("failed to stop player.");
5502 _mmplayer_pause(MMHandleType hplayer)
5504 mmplayer_t *player = (mmplayer_t *)hplayer;
5505 gint64 pos_nsec = 0;
5506 gboolean async = FALSE;
5507 gint ret = MM_ERROR_NONE;
5511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5513 /* check current state */
5514 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5516 /* check pipline building state */
5517 __mmplayer_check_pipeline(player);
5519 switch (MMPLAYER_CURRENT_STATE(player)) {
5520 case MM_PLAYER_STATE_READY:
5522 /* check prepare async or not.
5523 * In the case of streaming playback, it's recommned to avoid blocking wait.
5525 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5526 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5528 /* Changing back sync of rtspsrc to async */
5529 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5530 LOGD("async prepare working mode for rtsp");
5536 case MM_PLAYER_STATE_PLAYING:
5538 /* NOTE : store current point to overcome some bad operation
5539 *(returning zero when getting current position in paused state) of some
5542 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5543 LOGW("getting current position failed in paused");
5545 player->last_position = pos_nsec;
5547 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5548 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5549 This causes problem is position calculation during normal pause resume scenarios also.
5550 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5551 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5552 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5553 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5559 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5560 LOGD("doing async pause in case of ms buff src");
5564 /* pause pipeline */
5565 ret = __mmplayer_gst_pause(player, async);
5567 if (ret != MM_ERROR_NONE)
5568 LOGE("failed to pause player. ret : 0x%x", ret);
5570 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5571 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5572 LOGE("failed to update display_rotation");
5580 /* in case of streaming, pause could take long time.*/
5582 _mmplayer_abort_pause(MMHandleType hplayer)
5584 mmplayer_t *player = (mmplayer_t *)hplayer;
5585 int ret = MM_ERROR_NONE;
5589 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5591 player->pipeline->mainbin,
5592 MM_ERROR_PLAYER_NOT_INITIALIZED);
5594 LOGD("set the pipeline state to READY");
5596 /* set state to READY */
5597 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5598 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5599 if (ret != MM_ERROR_NONE) {
5600 LOGE("fail to change state to READY");
5601 return MM_ERROR_PLAYER_INTERNAL;
5604 LOGD("succeeded in changing state to READY");
5609 _mmplayer_resume(MMHandleType hplayer)
5611 mmplayer_t *player = (mmplayer_t *)hplayer;
5612 int ret = MM_ERROR_NONE;
5613 gboolean async = FALSE;
5617 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5619 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5620 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5621 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5625 /* Changing back sync mode rtspsrc to async */
5626 LOGD("async resume for rtsp case");
5630 /* check current state */
5631 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5633 ret = __mmplayer_gst_resume(player, async);
5634 if (ret != MM_ERROR_NONE)
5635 LOGE("failed to resume player.");
5637 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5638 LOGD("force resume even during buffering");
5639 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5648 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5650 mmplayer_t *player = (mmplayer_t *)hplayer;
5651 gint64 pos_nsec = 0;
5652 int ret = MM_ERROR_NONE;
5654 signed long long start = 0, stop = 0;
5655 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5658 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5659 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5661 /* The sound of video is not supported under 0.0 and over 2.0. */
5662 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5663 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5666 _mmplayer_set_mute(hplayer, mute);
5668 if (player->playback_rate == rate)
5669 return MM_ERROR_NONE;
5671 /* If the position is reached at start potion during fast backward, EOS is posted.
5672 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5674 player->playback_rate = rate;
5676 current_state = MMPLAYER_CURRENT_STATE(player);
5678 if (current_state != MM_PLAYER_STATE_PAUSED)
5679 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5681 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5683 if ((current_state == MM_PLAYER_STATE_PAUSED)
5684 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5685 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5686 pos_nsec = player->last_position;
5691 stop = GST_CLOCK_TIME_NONE;
5693 start = GST_CLOCK_TIME_NONE;
5697 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5698 player->playback_rate,
5700 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5701 GST_SEEK_TYPE_SET, start,
5702 GST_SEEK_TYPE_SET, stop)) {
5703 LOGE("failed to set speed playback");
5704 return MM_ERROR_PLAYER_SEEK;
5707 LOGD("succeeded to set speed playback as %0.1f", rate);
5711 return MM_ERROR_NONE;;
5715 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5717 mmplayer_t *player = (mmplayer_t *)hplayer;
5718 int ret = MM_ERROR_NONE;
5722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5724 /* check pipline building state */
5725 __mmplayer_check_pipeline(player);
5727 ret = __mmplayer_gst_set_position(player, position, FALSE);
5735 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5737 mmplayer_t *player = (mmplayer_t *)hplayer;
5738 int ret = MM_ERROR_NONE;
5740 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5742 ret = __mmplayer_gst_get_position(player, position);
5748 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5750 mmplayer_t *player = (mmplayer_t *)hplayer;
5751 int ret = MM_ERROR_NONE;
5753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5754 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5756 if (g_strrstr(player->type, "video/mpegts"))
5757 __mmplayer_update_duration_value(player);
5759 *duration = player->duration;
5764 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5766 mmplayer_t *player = (mmplayer_t *)hplayer;
5767 int ret = MM_ERROR_NONE;
5769 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5771 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5777 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5779 mmplayer_t *player = (mmplayer_t *)hplayer;
5780 int ret = MM_ERROR_NONE;
5784 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5786 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5794 __mmplayer_is_midi_type(gchar *str_caps)
5796 if ((g_strrstr(str_caps, "audio/midi")) ||
5797 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5798 (g_strrstr(str_caps, "application/x-smaf")) ||
5799 (g_strrstr(str_caps, "audio/x-imelody")) ||
5800 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5801 (g_strrstr(str_caps, "audio/xmf")) ||
5802 (g_strrstr(str_caps, "audio/mxmf"))) {
5811 __mmplayer_is_only_mp3_type(gchar *str_caps)
5813 if (g_strrstr(str_caps, "application/x-id3") ||
5814 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5820 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5822 GstStructure *caps_structure = NULL;
5823 gint samplerate = 0;
5827 MMPLAYER_RETURN_IF_FAIL(player && caps);
5829 caps_structure = gst_caps_get_structure(caps, 0);
5831 /* set stream information */
5832 gst_structure_get_int(caps_structure, "rate", &samplerate);
5833 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5835 gst_structure_get_int(caps_structure, "channels", &channels);
5836 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5838 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5842 __mmplayer_update_content_type_info(mmplayer_t *player)
5845 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5847 if (__mmplayer_is_midi_type(player->type)) {
5848 player->bypass_audio_effect = TRUE;
5852 if (!player->streamer) {
5853 LOGD("no need to check streaming type");
5857 if (g_strrstr(player->type, "application/x-hls")) {
5858 /* If it can't know exact type when it parses uri because of redirection case,
5859 * it will be fixed by typefinder or when doing autoplugging.
5861 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5862 player->streamer->is_adaptive_streaming = TRUE;
5863 } else if (g_strrstr(player->type, "application/dash+xml")) {
5864 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5865 player->streamer->is_adaptive_streaming = TRUE;
5868 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5869 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5870 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5872 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5873 if (player->streamer->is_adaptive_streaming)
5874 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5876 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5880 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5885 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5886 GstCaps *caps, gpointer data)
5888 mmplayer_t *player = (mmplayer_t *)data;
5893 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5895 /* store type string */
5896 MMPLAYER_FREEIF(player->type);
5897 player->type = gst_caps_to_string(caps);
5899 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5900 player, player->type, probability, gst_caps_get_size(caps));
5902 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5903 (g_strrstr(player->type, "audio/x-raw-int"))) {
5904 LOGE("not support media format");
5906 if (player->msg_posted == FALSE) {
5907 MMMessageParamType msg_param;
5908 memset(&msg_param, 0, sizeof(MMMessageParamType));
5910 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5911 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5913 /* don't post more if one was sent already */
5914 player->msg_posted = TRUE;
5919 __mmplayer_update_content_type_info(player);
5921 pad = gst_element_get_static_pad(tf, "src");
5923 LOGE("fail to get typefind src pad.");
5927 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5928 gboolean async = FALSE;
5929 LOGE("failed to autoplug %s", player->type);
5931 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5933 if (async && player->msg_posted == FALSE)
5934 __mmplayer_handle_missed_plugin(player);
5938 gst_object_unref(GST_OBJECT(pad));
5946 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5948 GstElement *decodebin = NULL;
5952 /* create decodebin */
5953 decodebin = gst_element_factory_make("decodebin", NULL);
5956 LOGE("fail to create decodebin");
5960 /* raw pad handling signal */
5961 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5962 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5964 /* no-more-pad pad handling signal */
5965 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5966 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5968 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5969 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5971 /* This signal is emitted when a pad for which there is no further possible
5972 decoding is added to the decodebin.*/
5973 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5974 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5976 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5977 before looking for any elements that can handle that stream.*/
5978 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5979 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5981 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5982 before looking for any elements that can handle that stream.*/
5983 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5984 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5986 /* This signal is emitted once decodebin has finished decoding all the data.*/
5987 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5988 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5990 /* This signal is emitted when a element is added to the bin.*/
5991 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5992 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5999 __mmplayer_gst_make_queue2(mmplayer_t *player)
6001 GstElement *queue2 = NULL;
6002 gint64 dur_bytes = 0L;
6003 mmplayer_gst_element_t *mainbin = NULL;
6004 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6007 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6009 mainbin = player->pipeline->mainbin;
6011 queue2 = gst_element_factory_make("queue2", "queue2");
6013 LOGE("failed to create buffering queue element");
6017 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6018 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6020 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6022 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6023 * skip the pull mode(file or ring buffering) setting. */
6024 if (dur_bytes > 0) {
6025 if (!g_strrstr(player->type, "video/mpegts")) {
6026 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6027 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6033 __mm_player_streaming_set_queue2(player->streamer,
6037 (guint64)dur_bytes); /* no meaning at the moment */
6043 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6045 mmplayer_gst_element_t *mainbin = NULL;
6046 GstElement *decodebin = NULL;
6047 GstElement *queue2 = NULL;
6048 GstPad *sinkpad = NULL;
6049 GstPad *qsrcpad = NULL;
6052 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6054 mainbin = player->pipeline->mainbin;
6056 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6058 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6059 LOGW("need to check: muxed buffer is not null");
6062 queue2 = __mmplayer_gst_make_queue2(player);
6064 LOGE("failed to make queue2");
6068 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6069 LOGE("failed to add buffering queue");
6073 sinkpad = gst_element_get_static_pad(queue2, "sink");
6074 qsrcpad = gst_element_get_static_pad(queue2, "src");
6076 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6077 LOGE("failed to link [%s:%s]-[%s:%s]",
6078 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6082 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6083 LOGE("failed to sync queue2 state with parent");
6087 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6088 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6092 gst_object_unref(GST_OBJECT(sinkpad));
6096 /* create decodebin */
6097 decodebin = __mmplayer_gst_make_decodebin(player);
6099 LOGE("failed to make decodebin");
6103 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6104 LOGE("failed to add decodebin");
6108 /* to force caps on the decodebin element and avoid reparsing stuff by
6109 * typefind. It also avoids a deadlock in the way typefind activates pads in
6110 * the state change */
6111 g_object_set(decodebin, "sink-caps", caps, NULL);
6113 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6115 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6116 LOGE("failed to link [%s:%s]-[%s:%s]",
6117 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6121 gst_object_unref(GST_OBJECT(sinkpad));
6123 gst_object_unref(GST_OBJECT(qsrcpad));
6126 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6127 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6129 /* set decodebin property about buffer in streaming playback. *
6130 * in case of HLS/DASH, it does not need to have big buffer *
6131 * because it is kind of adaptive streaming. */
6132 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6133 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6134 gint high_percent = 0;
6136 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6137 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6139 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6141 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6143 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6144 "high-percent", high_percent,
6145 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6146 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6147 "max-size-buffers", 0, NULL); // disable or automatic
6150 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6151 LOGE("failed to sync decodebin state with parent");
6162 gst_object_unref(GST_OBJECT(sinkpad));
6165 gst_object_unref(GST_OBJECT(qsrcpad));
6168 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6169 * You need to explicitly set elements to the NULL state before
6170 * dropping the final reference, to allow them to clean up.
6172 gst_element_set_state(queue2, GST_STATE_NULL);
6174 /* And, it still has a parent "player".
6175 * You need to let the parent manage the object instead of unreffing the object directly.
6177 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6178 gst_object_unref(queue2);
6183 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6184 * You need to explicitly set elements to the NULL state before
6185 * dropping the final reference, to allow them to clean up.
6187 gst_element_set_state(decodebin, GST_STATE_NULL);
6189 /* And, it still has a parent "player".
6190 * You need to let the parent manage the object instead of unreffing the object directly.
6193 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6194 gst_object_unref(decodebin);
6202 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6207 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6209 LOGD("class : %s, mime : %s", factory_class, mime);
6211 /* add missing plugin */
6212 /* NOTE : msl should check missing plugin for image mime type.
6213 * Some motion jpeg clips can have playable audio track.
6214 * So, msl have to play audio after displaying popup written video format not supported.
6216 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6217 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6218 LOGD("not found demuxer");
6219 player->not_found_demuxer = TRUE;
6220 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6226 if (!g_strrstr(factory_class, "Demuxer")) {
6227 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6228 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6229 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6231 /* check that clip have multi tracks or not */
6232 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6233 LOGD("video plugin is already linked");
6235 LOGW("add VIDEO to missing plugin");
6236 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6237 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6239 } else if (g_str_has_prefix(mime, "audio")) {
6240 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6241 LOGD("audio plugin is already linked");
6243 LOGW("add AUDIO to missing plugin");
6244 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6245 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6253 return MM_ERROR_NONE;
6257 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6259 mmplayer_t *player = (mmplayer_t *)data;
6263 MMPLAYER_RETURN_IF_FAIL(player);
6265 /* remove fakesink. */
6266 if (!__mmplayer_gst_remove_fakesink(player,
6267 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6268 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6269 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6270 * source element are not same. To overcome this situation, this function will called
6271 * several places and several times. Therefore, this is not an error case.
6276 LOGD("[handle: %p] pipeline has completely constructed", player);
6278 if ((player->ini.async_start) &&
6279 (player->msg_posted == FALSE) &&
6280 (player->cmd >= MMPLAYER_COMMAND_START))
6281 __mmplayer_handle_missed_plugin(player);
6283 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6287 __mmplayer_check_profile(void)
6290 static int profile_tv = -1;
6292 if (__builtin_expect(profile_tv != -1, 1))
6295 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6296 switch (*profileName) {
6311 __mmplayer_get_next_uri(mmplayer_t *player)
6313 mmplayer_parse_profile_t profile;
6315 guint num_of_list = 0;
6318 num_of_list = g_list_length(player->uri_info.uri_list);
6319 uri_idx = player->uri_info.uri_idx;
6321 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6322 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6323 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6325 LOGW("next uri does not exist");
6329 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6330 LOGE("failed to parse profile");
6334 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6335 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6336 LOGW("uri type is not supported(%d)", profile.uri_type);
6340 LOGD("success to find next uri %d", uri_idx);
6344 if (uri_idx == num_of_list) {
6345 LOGE("failed to find next uri");
6349 player->uri_info.uri_idx = uri_idx;
6350 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6352 if (mm_attrs_commit_all(player->attrs)) {
6353 LOGE("failed to commit");
6357 SECURE_LOGD("next playback uri: %s", uri);
6362 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6364 #define REPEAT_COUNT_INFINITELY -1
6365 #define REPEAT_COUNT_MIN 2
6367 MMHandleType attrs = 0;
6371 guint num_of_list = 0;
6372 int profile_tv = -1;
6376 LOGD("checking for gapless play option");
6378 if (player->pipeline->textbin) {
6379 LOGE("subtitle path is enabled. gapless play is not supported.");
6383 attrs = MMPLAYER_GET_ATTRS(player);
6385 LOGE("fail to get attributes.");
6389 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6391 /* gapless playback is not supported in case of video at TV profile. */
6392 profile_tv = __mmplayer_check_profile();
6393 if (profile_tv && video) {
6394 LOGW("not support video gapless playback");
6398 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6399 LOGE("failed to get play count");
6401 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6402 LOGE("failed to get gapless mode");
6404 /* check repeat count in case of audio */
6406 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6407 LOGW("gapless is disabled");
6411 num_of_list = g_list_length(player->uri_info.uri_list);
6413 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6415 if (num_of_list == 0) {
6416 /* audio looping path */
6417 if (count >= REPEAT_COUNT_MIN) {
6418 /* decrease play count */
6419 /* we succeeded to rewind. update play count and then wait for next EOS */
6421 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6422 /* commit attribute */
6423 if (mm_attrs_commit_all(attrs))
6424 LOGE("failed to commit attribute");
6426 } else if (count != REPEAT_COUNT_INFINITELY) {
6427 LOGD("there is no next uri and no repeat");
6430 LOGD("looping cnt %d", count);
6432 /* gapless playback path */
6433 if (!__mmplayer_get_next_uri(player)) {
6434 LOGE("failed to get next uri");
6441 LOGE("unable to play gapless path. EOS will be posted soon");
6446 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6452 player->smooth_streaming = FALSE;
6453 player->videodec_linked = 0;
6454 player->audiodec_linked = 0;
6455 player->textsink_linked = 0;
6456 player->is_external_subtitle_present = FALSE;
6457 player->is_external_subtitle_added_now = FALSE;
6458 player->not_supported_codec = MISSING_PLUGIN_NONE;
6459 player->can_support_codec = FOUND_PLUGIN_NONE;
6460 player->pending_seek.is_pending = false;
6461 player->pending_seek.pos = 0;
6462 player->msg_posted = FALSE;
6463 player->has_many_types = FALSE;
6464 player->no_more_pad = FALSE;
6465 player->not_found_demuxer = 0;
6466 player->seek_state = MMPLAYER_SEEK_NONE;
6467 player->is_subtitle_force_drop = FALSE;
6468 player->play_subtitle = FALSE;
6469 player->adjust_subtitle_pos = 0;
6471 player->total_bitrate = 0;
6472 player->total_maximum_bitrate = 0;
6474 __mmplayer_track_initialize(player);
6475 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6477 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6478 player->bitrate[i] = 0;
6479 player->maximum_bitrate[i] = 0;
6482 if (player->v_stream_caps) {
6483 gst_caps_unref(player->v_stream_caps);
6484 player->v_stream_caps = NULL;
6487 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6489 /* clean found audio decoders */
6490 if (player->audio_decoders) {
6491 GList *a_dec = player->audio_decoders;
6492 for (; a_dec; a_dec = g_list_next(a_dec)) {
6493 gchar *name = a_dec->data;
6494 MMPLAYER_FREEIF(name);
6496 g_list_free(player->audio_decoders);
6497 player->audio_decoders = NULL;
6504 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6506 mmplayer_gst_element_t *mainbin = NULL;
6507 MMMessageParamType msg_param = {0,};
6508 GstElement *element = NULL;
6509 MMHandleType attrs = 0;
6511 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6515 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6516 LOGE("player is not initialized");
6520 mainbin = player->pipeline->mainbin;
6521 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6523 attrs = MMPLAYER_GET_ATTRS(player);
6525 LOGE("fail to get attributes");
6529 /* Initialize Player values */
6530 __mmplayer_initialize_gapless_play(player);
6532 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6534 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6535 LOGE("failed to parse profile");
6536 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6540 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6541 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6542 LOGE("dash or hls is not supportable");
6543 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6547 element = __mmplayer_gst_create_source(player);
6549 LOGE("no source element was created");
6553 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6554 LOGE("failed to add source element to pipeline");
6555 gst_object_unref(GST_OBJECT(element));
6560 /* take source element */
6561 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6562 mainbin[MMPLAYER_M_SRC].gst = element;
6566 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6567 if (player->streamer == NULL) {
6568 player->streamer = __mm_player_streaming_create();
6569 __mm_player_streaming_initialize(player->streamer, TRUE);
6572 elem_idx = MMPLAYER_M_TYPEFIND;
6573 element = gst_element_factory_make("typefind", "typefinder");
6574 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6575 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6577 elem_idx = MMPLAYER_M_AUTOPLUG;
6578 element = __mmplayer_gst_make_decodebin(player);
6581 /* check autoplug element is OK */
6583 LOGE("can not create element(%d)", elem_idx);
6587 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6588 LOGE("failed to add sinkbin to pipeline");
6589 gst_object_unref(GST_OBJECT(element));
6594 mainbin[elem_idx].id = elem_idx;
6595 mainbin[elem_idx].gst = element;
6597 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6598 LOGE("Failed to link src - autoplug(or typefind)");
6602 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6603 LOGE("Failed to change state of src element");
6607 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6608 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6609 LOGE("Failed to change state of decodebin");
6613 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6614 LOGE("Failed to change state of src element");
6619 player->gapless.stream_changed = TRUE;
6620 player->gapless.running = TRUE;
6626 MMPLAYER_PLAYBACK_UNLOCK(player);
6628 if (!player->msg_posted) {
6629 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6630 player->msg_posted = TRUE;
6637 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6639 mmplayer_selector_t *selector = &player->selector[type];
6640 mmplayer_gst_element_t *sinkbin = NULL;
6641 main_element_id_e selectorId = MMPLAYER_M_NUM;
6642 main_element_id_e sinkId = MMPLAYER_M_NUM;
6643 GstPad *srcpad = NULL;
6644 GstPad *sinkpad = NULL;
6645 gboolean send_notice = FALSE;
6648 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6650 LOGD("type %d", type);
6653 case MM_PLAYER_TRACK_TYPE_AUDIO:
6654 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6655 sinkId = MMPLAYER_A_BIN;
6656 sinkbin = player->pipeline->audiobin;
6658 case MM_PLAYER_TRACK_TYPE_VIDEO:
6659 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6660 sinkId = MMPLAYER_V_BIN;
6661 sinkbin = player->pipeline->videobin;
6664 case MM_PLAYER_TRACK_TYPE_TEXT:
6665 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6666 sinkId = MMPLAYER_T_BIN;
6667 sinkbin = player->pipeline->textbin;
6670 LOGE("requested type is not supportable");
6675 if (player->pipeline->mainbin[selectorId].gst) {
6678 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6680 if (selector->event_probe_id != 0)
6681 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6682 selector->event_probe_id = 0;
6684 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6685 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6687 if (srcpad && sinkpad) {
6688 /* after getting drained signal there is no data flows, so no need to do pad_block */
6689 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6690 gst_pad_unlink(srcpad, sinkpad);
6692 /* send custom event to sink pad to handle it at video sink */
6694 LOGD("send custom event to sinkpad");
6695 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6696 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6697 gst_pad_send_event(sinkpad, event);
6701 gst_object_unref(sinkpad);
6704 gst_object_unref(srcpad);
6707 LOGD("selector release");
6709 /* release and unref requests pad from the selector */
6710 for (n = 0; n < selector->channels->len; n++) {
6711 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6712 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6714 g_ptr_array_set_size(selector->channels, 0);
6716 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6717 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6719 player->pipeline->mainbin[selectorId].gst = NULL;
6727 __mmplayer_deactivate_old_path(mmplayer_t *player)
6730 MMPLAYER_RETURN_IF_FAIL(player);
6732 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6733 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6734 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6735 LOGE("deactivate selector error");
6739 __mmplayer_track_destroy(player);
6740 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6742 if (player->streamer) {
6743 __mm_player_streaming_initialize(player->streamer, FALSE);
6744 __mm_player_streaming_destroy(player->streamer);
6745 player->streamer = NULL;
6748 MMPLAYER_PLAYBACK_LOCK(player);
6749 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6756 if (!player->msg_posted) {
6757 MMMessageParamType msg = {0,};
6760 msg.code = MM_ERROR_PLAYER_INTERNAL;
6761 LOGE("gapless_uri_play> deactivate error");
6763 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6764 player->msg_posted = TRUE;
6770 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6772 int result = MM_ERROR_NONE;
6773 mmplayer_t *player = (mmplayer_t *)hplayer;
6776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6778 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6779 if (mm_attrs_commit_all(player->attrs)) {
6780 LOGE("failed to commit the original uri.");
6781 result = MM_ERROR_PLAYER_INTERNAL;
6783 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6784 LOGE("failed to add the original uri in the uri list.");
6792 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6794 mmplayer_t *player = (mmplayer_t *)hplayer;
6795 guint num_of_list = 0;
6799 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6800 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6802 if (player->pipeline && player->pipeline->textbin) {
6803 LOGE("subtitle path is enabled.");
6804 return MM_ERROR_PLAYER_INVALID_STATE;
6807 num_of_list = g_list_length(player->uri_info.uri_list);
6809 if (is_first_path) {
6810 if (num_of_list == 0) {
6811 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6812 SECURE_LOGD("add original path : %s", uri);
6814 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6815 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6817 SECURE_LOGD("change original path : %s", uri);
6820 MMHandleType attrs = 0;
6821 attrs = MMPLAYER_GET_ATTRS(player);
6823 if (num_of_list == 0) {
6824 char *original_uri = NULL;
6827 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6829 if (!original_uri) {
6830 LOGE("there is no original uri.");
6831 return MM_ERROR_PLAYER_INVALID_STATE;
6834 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6835 player->uri_info.uri_idx = 0;
6837 SECURE_LOGD("add original path at first : %s", original_uri);
6841 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6842 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6846 return MM_ERROR_NONE;
6850 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6852 mmplayer_t *player = (mmplayer_t *)hplayer;
6853 char *next_uri = NULL;
6854 guint num_of_list = 0;
6857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6859 num_of_list = g_list_length(player->uri_info.uri_list);
6861 if (num_of_list > 0) {
6862 gint uri_idx = player->uri_info.uri_idx;
6864 if (uri_idx < num_of_list-1)
6869 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6870 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6872 *uri = g_strdup(next_uri);
6876 return MM_ERROR_NONE;
6880 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6881 GstCaps *caps, gpointer data)
6883 mmplayer_t *player = (mmplayer_t *)data;
6884 const gchar *klass = NULL;
6885 const gchar *mime = NULL;
6886 gchar *caps_str = NULL;
6888 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6889 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6890 caps_str = gst_caps_to_string(caps);
6892 LOGW("unknown type of caps : %s from %s",
6893 caps_str, GST_ELEMENT_NAME(elem));
6895 MMPLAYER_FREEIF(caps_str);
6897 /* There is no available codec. */
6898 __mmplayer_check_not_supported_codec(player, klass, mime);
6902 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6903 GstCaps *caps, gpointer data)
6905 mmplayer_t *player = (mmplayer_t *)data;
6906 const char *mime = NULL;
6907 gboolean ret = TRUE;
6909 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6910 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6912 if (g_str_has_prefix(mime, "audio")) {
6913 GstStructure *caps_structure = NULL;
6914 gint samplerate = 0;
6916 gchar *caps_str = NULL;
6918 caps_structure = gst_caps_get_structure(caps, 0);
6919 gst_structure_get_int(caps_structure, "rate", &samplerate);
6920 gst_structure_get_int(caps_structure, "channels", &channels);
6922 if ((channels > 0 && samplerate == 0)) {
6923 LOGD("exclude audio...");
6927 caps_str = gst_caps_to_string(caps);
6928 /* set it directly because not sent by TAG */
6929 if (g_strrstr(caps_str, "mobile-xmf"))
6930 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6931 MMPLAYER_FREEIF(caps_str);
6932 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6933 MMMessageParamType msg_param;
6934 memset(&msg_param, 0, sizeof(MMMessageParamType));
6935 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6936 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6937 LOGD("video file is not supported on this device");
6939 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6940 LOGD("already video linked");
6943 LOGD("found new stream");
6950 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6952 gboolean ret = TRUE;
6953 GDBusConnection *conn = NULL;
6955 GVariant *result = NULL;
6956 const gchar *dbus_device_type = NULL;
6957 const gchar *dbus_ret = NULL;
6960 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6962 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6968 result = g_dbus_connection_call_sync(conn,
6969 "org.pulseaudio.Server",
6970 "/org/pulseaudio/StreamManager",
6971 "org.pulseaudio.StreamManager",
6972 "GetCurrentMediaRoutingPath",
6973 g_variant_new("(s)", "out"),
6974 G_VARIANT_TYPE("(ss)"),
6975 G_DBUS_CALL_FLAGS_NONE,
6979 if (!result || err) {
6980 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6986 /* device type is listed in stream-map.json at mmfw-sysconf */
6987 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6989 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6990 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6995 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6996 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6997 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6998 LOGD("audio offload is supportable");
7004 LOGD("audio offload is not supportable");
7008 g_variant_unref(result);
7009 g_object_unref(conn);
7014 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7016 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7017 gint64 position = 0;
7019 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7020 player->pipeline && player->pipeline->mainbin);
7022 MMPLAYER_CMD_LOCK(player);
7023 current_state = MMPLAYER_CURRENT_STATE(player);
7025 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7026 LOGW("getting current position failed in paused");
7028 _mmplayer_unrealize((MMHandleType)player);
7029 _mmplayer_realize((MMHandleType)player);
7031 _mmplayer_set_position((MMHandleType)player, position);
7033 /* async not to be blocked in streaming case */
7034 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
7035 if (mm_attrs_commit_all(player->attrs))
7036 LOGE("failed to commit");
7038 _mmplayer_pause((MMHandleType)player);
7040 if (current_state == MM_PLAYER_STATE_PLAYING)
7041 _mmplayer_start((MMHandleType)player);
7042 MMPLAYER_CMD_UNLOCK(player);
7044 LOGD("rebuilding audio pipeline is completed.");
7047 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7049 mmplayer_t *player = (mmplayer_t *)user_data;
7050 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7051 gboolean is_supportable = FALSE;
7053 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7054 LOGW("failed to get device type");
7056 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7058 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7059 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7060 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7061 LOGD("ignore this dev connected info");
7065 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7066 if (player->build_audio_offload == is_supportable) {
7067 LOGD("keep current pipeline without re-building");
7071 /* rebuild pipeline */
7072 LOGD("re-build pipeline - offload: %d", is_supportable);
7073 player->build_audio_offload = FALSE;
7074 __mmplayer_rebuild_audio_pipeline(player);
7080 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7082 unsigned int id = 0;
7084 if (player->audio_device_cb_id != 0) {
7085 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7089 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7090 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7091 LOGD("added device connected cb (%u)", id);
7092 player->audio_device_cb_id = id;
7094 LOGW("failed to add device connected cb");
7102 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7104 gboolean ret = FALSE;
7105 GstElementFactory *factory = NULL;
7108 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7110 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7111 if (!__mmplayer_is_only_mp3_type(player->type))
7114 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7115 LOGD("there is no audio offload sink");
7119 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7120 LOGW("there is no audio device type to support offload");
7124 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7126 LOGW("there is no installed audio offload sink element");
7129 gst_object_unref(factory);
7131 if (!__mmplayer_add_audio_device_connected_cb(player))
7134 if (!__mmplayer_is_audio_offload_device_type(player))
7137 LOGD("audio offload can be built");
7145 static GstAutoplugSelectResult
7146 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7148 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7150 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7151 int audio_offload = 0;
7153 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7154 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7156 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7157 LOGD("expose audio path to build offload output path");
7158 player->build_audio_offload = TRUE;
7159 /* update codec info */
7160 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7161 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7162 player->audiodec_linked = 1;
7164 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7168 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7170 LOGD("audio codec type: %d", codec_type);
7171 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7172 /* sw codec will be skipped */
7173 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7174 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7175 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7176 ret = GST_AUTOPLUG_SELECT_SKIP;
7180 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7181 /* hw codec will be skipped */
7182 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7183 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7184 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7185 ret = GST_AUTOPLUG_SELECT_SKIP;
7190 /* set stream information */
7191 if (!player->audiodec_linked)
7192 __mmplayer_set_audio_attrs(player, caps);
7194 /* update codec info */
7195 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7196 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7197 player->audiodec_linked = 1;
7199 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7201 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7203 LOGD("video codec type: %d", codec_type);
7204 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7205 /* sw codec is skipped */
7206 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7207 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7208 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7209 ret = GST_AUTOPLUG_SELECT_SKIP;
7213 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7214 /* hw codec is skipped */
7215 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7216 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7217 ret = GST_AUTOPLUG_SELECT_SKIP;
7222 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7223 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7225 /* mark video decoder for acquire */
7226 if (player->video_decoder_resource == NULL) {
7227 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7228 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7229 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7230 &player->video_decoder_resource)
7231 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7232 LOGE("could not mark video_decoder resource for acquire");
7233 ret = GST_AUTOPLUG_SELECT_SKIP;
7237 LOGW("video decoder resource is already acquired, skip it.");
7238 ret = GST_AUTOPLUG_SELECT_SKIP;
7242 player->interrupted_by_resource = FALSE;
7243 /* acquire resources for video playing */
7244 if (mm_resource_manager_commit(player->resource_manager)
7245 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7246 LOGE("could not acquire resources for video decoding");
7247 ret = GST_AUTOPLUG_SELECT_SKIP;
7252 /* update codec info */
7253 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7254 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7255 player->videodec_linked = 1;
7263 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7264 GstCaps *caps, GstElementFactory *factory, gpointer data)
7266 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7267 mmplayer_t *player = (mmplayer_t *)data;
7269 gchar *factory_name = NULL;
7270 gchar *caps_str = NULL;
7271 const gchar *klass = NULL;
7274 factory_name = GST_OBJECT_NAME(factory);
7275 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7276 caps_str = gst_caps_to_string(caps);
7278 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7280 /* store type string */
7281 if (player->type == NULL) {
7282 player->type = gst_caps_to_string(caps);
7283 __mmplayer_update_content_type_info(player);
7286 /* filtering exclude keyword */
7287 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7288 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7289 LOGW("skipping [%s] by exculde keyword [%s]",
7290 factory_name, player->ini.exclude_element_keyword[idx]);
7292 result = GST_AUTOPLUG_SELECT_SKIP;
7297 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7298 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7299 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7300 factory_name, player->ini.unsupported_codec_keyword[idx]);
7301 result = GST_AUTOPLUG_SELECT_SKIP;
7306 /* exclude webm format */
7307 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7308 * because webm format is not supportable.
7309 * If webm is disabled in "autoplug-continue", there is no state change
7310 * failure or error because the decodebin will expose the pad directly.
7311 * It make MSL invoke _prepare_async_callback.
7312 * So, we need to disable webm format in "autoplug-select" */
7313 if (caps_str && strstr(caps_str, "webm")) {
7314 LOGW("webm is not supported");
7315 result = GST_AUTOPLUG_SELECT_SKIP;
7319 /* check factory class for filtering */
7320 /* NOTE : msl don't need to use image plugins.
7321 * So, those plugins should be skipped for error handling.
7323 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7324 LOGD("skipping [%s] by not required", factory_name);
7325 result = GST_AUTOPLUG_SELECT_SKIP;
7329 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7330 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7331 // TO CHECK : subtitle if needed, add subparse exception.
7332 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7333 result = GST_AUTOPLUG_SELECT_SKIP;
7337 if (g_strrstr(factory_name, "mpegpsdemux")) {
7338 LOGD("skipping PS container - not support");
7339 result = GST_AUTOPLUG_SELECT_SKIP;
7343 if (g_strrstr(factory_name, "mssdemux"))
7344 player->smooth_streaming = TRUE;
7346 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7347 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7350 GstStructure *str = NULL;
7351 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7353 /* don't make video because of not required */
7354 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7355 (!player->set_mode.video_export)) {
7356 LOGD("no need video decoding, expose pad");
7357 result = GST_AUTOPLUG_SELECT_EXPOSE;
7361 /* get w/h for omx state-tune */
7362 /* FIXME: deprecated? */
7363 str = gst_caps_get_structure(caps, 0);
7364 gst_structure_get_int(str, "width", &width);
7367 if (player->v_stream_caps) {
7368 gst_caps_unref(player->v_stream_caps);
7369 player->v_stream_caps = NULL;
7372 player->v_stream_caps = gst_caps_copy(caps);
7373 LOGD("take caps for video state tune");
7374 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7378 if (g_strrstr(klass, "Codec/Decoder")) {
7379 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7380 if (result != GST_AUTOPLUG_SELECT_TRY) {
7381 LOGW("skip add decoder");
7387 MMPLAYER_FREEIF(caps_str);
7393 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7396 //mmplayer_t *player = (mmplayer_t *)data;
7397 GstCaps *caps = NULL;
7399 LOGD("[Decodebin2] pad-removed signal");
7401 caps = gst_pad_query_caps(new_pad, NULL);
7403 LOGW("query caps is NULL");
7407 gchar *caps_str = NULL;
7408 caps_str = gst_caps_to_string(caps);
7410 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7412 MMPLAYER_FREEIF(caps_str);
7413 gst_caps_unref(caps);
7417 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7419 mmplayer_t *player = (mmplayer_t *)data;
7420 GstIterator *iter = NULL;
7421 GValue item = { 0, };
7423 gboolean done = FALSE;
7424 gboolean is_all_drained = TRUE;
7427 MMPLAYER_RETURN_IF_FAIL(player);
7429 LOGD("__mmplayer_gst_decode_drained");
7431 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7432 LOGW("Fail to get cmd lock");
7436 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7437 !__mmplayer_verify_gapless_play_path(player)) {
7438 LOGD("decoding is finished.");
7439 __mmplayer_reset_gapless_state(player);
7440 MMPLAYER_CMD_UNLOCK(player);
7444 player->gapless.reconfigure = TRUE;
7446 /* check decodebin src pads whether they received EOS or not */
7447 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7450 switch (gst_iterator_next(iter, &item)) {
7451 case GST_ITERATOR_OK:
7452 pad = g_value_get_object(&item);
7453 if (pad && !GST_PAD_IS_EOS(pad)) {
7454 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7455 is_all_drained = FALSE;
7458 g_value_reset(&item);
7460 case GST_ITERATOR_RESYNC:
7461 gst_iterator_resync(iter);
7463 case GST_ITERATOR_ERROR:
7464 case GST_ITERATOR_DONE:
7469 g_value_unset(&item);
7470 gst_iterator_free(iter);
7472 if (!is_all_drained) {
7473 LOGD("Wait util the all pads get EOS.");
7474 MMPLAYER_CMD_UNLOCK(player);
7479 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7480 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7482 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7483 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7484 __mmplayer_deactivate_old_path(player);
7485 MMPLAYER_CMD_UNLOCK(player);
7491 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7493 mmplayer_t *player = (mmplayer_t *)data;
7494 const gchar *klass = NULL;
7495 gchar *factory_name = NULL;
7497 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7498 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7500 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7502 if (__mmplayer_add_dump_buffer_probe(player, element))
7503 LOGD("add buffer probe");
7505 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7506 gchar *selected = NULL;
7507 selected = g_strdup(GST_ELEMENT_NAME(element));
7508 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7511 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7512 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7513 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7515 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7516 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7518 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7519 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7520 "max-video-width", player->adaptive_info.limit.width,
7521 "max-video-height", player->adaptive_info.limit.height, NULL);
7523 } else if (g_strrstr(klass, "Demuxer")) {
7524 //LOGD("plugged element is demuxer. take it");
7525 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7526 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7529 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7530 int surface_type = 0;
7532 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7535 // to support trust-zone only
7536 if (g_strrstr(factory_name, "asfdemux")) {
7537 LOGD("set file-location %s", player->profile.uri);
7538 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7539 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7540 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7541 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7542 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7543 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7544 (__mmplayer_is_only_mp3_type(player->type))) {
7545 LOGD("[mpegaudioparse] set streaming pull mode.");
7546 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7548 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7549 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7552 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7553 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7554 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7556 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7557 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7559 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7560 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7561 (MMPLAYER_IS_DASH_STREAMING(player))) {
7562 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7563 __mm_player_streaming_set_multiqueue(player->streamer, element);
7564 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7573 __mmplayer_release_misc(mmplayer_t *player)
7576 bool cur_mode = player->set_mode.rich_audio;
7579 MMPLAYER_RETURN_IF_FAIL(player);
7581 player->video_decoded_cb = NULL;
7582 player->video_decoded_cb_user_param = NULL;
7583 player->video_stream_prerolled = false;
7585 player->audio_decoded_cb = NULL;
7586 player->audio_decoded_cb_user_param = NULL;
7587 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7589 player->video_stream_changed_cb = NULL;
7590 player->video_stream_changed_cb_user_param = NULL;
7592 player->audio_stream_changed_cb = NULL;
7593 player->audio_stream_changed_cb_user_param = NULL;
7595 player->sent_bos = FALSE;
7596 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7598 player->seek_state = MMPLAYER_SEEK_NONE;
7600 player->total_bitrate = 0;
7601 player->total_maximum_bitrate = 0;
7603 player->not_found_demuxer = 0;
7605 player->last_position = 0;
7606 player->duration = 0;
7607 player->http_content_size = 0;
7608 player->not_supported_codec = MISSING_PLUGIN_NONE;
7609 player->can_support_codec = FOUND_PLUGIN_NONE;
7610 player->pending_seek.is_pending = false;
7611 player->pending_seek.pos = 0;
7612 player->msg_posted = FALSE;
7613 player->has_many_types = FALSE;
7614 player->is_subtitle_force_drop = FALSE;
7615 player->play_subtitle = FALSE;
7616 player->adjust_subtitle_pos = 0;
7617 player->has_closed_caption = FALSE;
7618 player->set_mode.video_export = false;
7619 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7620 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7622 player->set_mode.rich_audio = cur_mode;
7624 if (player->audio_device_cb_id > 0 &&
7625 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7626 LOGW("failed to remove audio device_connected_callback");
7627 player->audio_device_cb_id = 0;
7629 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7630 player->bitrate[i] = 0;
7631 player->maximum_bitrate[i] = 0;
7634 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7636 /* remove media stream cb(appsrc cb) */
7637 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7638 player->media_stream_buffer_status_cb[i] = NULL;
7639 player->media_stream_seek_data_cb[i] = NULL;
7640 player->buffer_cb_user_param[i] = NULL;
7641 player->seek_cb_user_param[i] = NULL;
7643 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7645 /* free memory related to audio effect */
7646 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7648 if (player->adaptive_info.var_list) {
7649 g_list_free_full(player->adaptive_info.var_list, g_free);
7650 player->adaptive_info.var_list = NULL;
7653 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7654 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7655 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7657 /* Reset video360 settings to their defaults in case if the pipeline is to be
7660 player->video360_metadata.is_spherical = -1;
7661 player->is_openal_plugin_used = FALSE;
7663 player->is_content_spherical = FALSE;
7664 player->is_video360_enabled = TRUE;
7665 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7666 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7667 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7668 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7669 player->video360_zoom = 1.0f;
7670 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7671 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7673 player->sound.rg_enable = false;
7675 __mmplayer_initialize_video_roi(player);
7680 __mmplayer_release_misc_post(mmplayer_t *player)
7682 char *original_uri = NULL;
7685 /* player->pipeline is already released before. */
7687 MMPLAYER_RETURN_IF_FAIL(player);
7689 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7691 /* clean found audio decoders */
7692 if (player->audio_decoders) {
7693 GList *a_dec = player->audio_decoders;
7694 for (; a_dec; a_dec = g_list_next(a_dec)) {
7695 gchar *name = a_dec->data;
7696 MMPLAYER_FREEIF(name);
7698 g_list_free(player->audio_decoders);
7699 player->audio_decoders = NULL;
7702 /* clean the uri list except original uri */
7703 if (player->uri_info.uri_list) {
7704 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7706 if (player->attrs) {
7707 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7708 LOGD("restore original uri = %s", original_uri);
7710 if (mm_attrs_commit_all(player->attrs))
7711 LOGE("failed to commit the original uri.");
7714 GList *uri_list = player->uri_info.uri_list;
7715 for (; uri_list; uri_list = g_list_next(uri_list)) {
7716 gchar *uri = uri_list->data;
7717 MMPLAYER_FREEIF(uri);
7719 g_list_free(player->uri_info.uri_list);
7720 player->uri_info.uri_list = NULL;
7723 /* clear the audio stream buffer list */
7724 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7726 /* clear the video stream bo list */
7727 __mmplayer_video_stream_destroy_bo_list(player);
7728 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7730 if (player->profile.input_mem.buf) {
7731 free(player->profile.input_mem.buf);
7732 player->profile.input_mem.buf = NULL;
7734 player->profile.input_mem.len = 0;
7735 player->profile.input_mem.offset = 0;
7737 player->uri_info.uri_idx = 0;
7742 __mmplayer_check_subtitle(mmplayer_t *player)
7744 MMHandleType attrs = 0;
7745 char *subtitle_uri = NULL;
7749 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7751 /* get subtitle attribute */
7752 attrs = MMPLAYER_GET_ATTRS(player);
7756 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7757 if (!subtitle_uri || !strlen(subtitle_uri))
7760 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7761 player->is_external_subtitle_present = TRUE;
7769 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7771 MMPLAYER_RETURN_IF_FAIL(player);
7773 if (player->eos_timer) {
7774 LOGD("cancel eos timer");
7775 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7776 player->eos_timer = 0;
7783 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7787 MMPLAYER_RETURN_IF_FAIL(player);
7788 MMPLAYER_RETURN_IF_FAIL(sink);
7790 player->sink_elements = g_list_append(player->sink_elements, sink);
7796 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7800 MMPLAYER_RETURN_IF_FAIL(player);
7801 MMPLAYER_RETURN_IF_FAIL(sink);
7803 player->sink_elements = g_list_remove(player->sink_elements, sink);
7809 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7810 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7812 mmplayer_signal_item_t *item = NULL;
7815 MMPLAYER_RETURN_IF_FAIL(player);
7817 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7818 LOGE("invalid signal type [%d]", type);
7822 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7824 LOGE("cannot connect signal [%s]", signal);
7829 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7830 player->signals[type] = g_list_append(player->signals[type], item);
7836 /* NOTE : be careful with calling this api. please refer to below glib comment
7837 * glib comment : Note that there is a bug in GObject that makes this function much
7838 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7839 * will no longer be called, but, the signal handler is not currently disconnected.
7840 * If the instance is itself being freed at the same time than this doesn't matter,
7841 * since the signal will automatically be removed, but if instance persists,
7842 * then the signal handler will leak. You should not remove the signal yourself
7843 * because in a future versions of GObject, the handler will automatically be
7846 * It's possible to work around this problem in a way that will continue to work
7847 * with future versions of GObject by checking that the signal handler is still
7848 * connected before disconnected it:
7850 * if (g_signal_handler_is_connected(instance, id))
7851 * g_signal_handler_disconnect(instance, id);
7854 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7856 GList *sig_list = NULL;
7857 mmplayer_signal_item_t *item = NULL;
7861 MMPLAYER_RETURN_IF_FAIL(player);
7863 LOGD("release signals type : %d", type);
7865 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7866 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7867 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7868 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7869 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7870 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7874 sig_list = player->signals[type];
7876 for (; sig_list; sig_list = sig_list->next) {
7877 item = sig_list->data;
7879 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7880 if (g_signal_handler_is_connected(item->obj, item->sig))
7881 g_signal_handler_disconnect(item->obj, item->sig);
7884 MMPLAYER_FREEIF(item);
7887 g_list_free(player->signals[type]);
7888 player->signals[type] = NULL;
7896 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7898 mmplayer_t *player = 0;
7899 int prev_display_surface_type = 0;
7900 void *prev_display_overlay = NULL;
7904 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7905 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7907 player = MM_PLAYER_CAST(handle);
7909 /* check video sinkbin is created */
7910 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7911 LOGE("Videosink is already created");
7912 return MM_ERROR_NONE;
7915 LOGD("videosink element is not yet ready");
7917 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7918 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7920 return MM_ERROR_INVALID_ARGUMENT;
7923 /* load previous attributes */
7924 if (player->attrs) {
7925 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7926 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7927 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7928 if (prev_display_surface_type == surface_type) {
7929 LOGD("incoming display surface type is same as previous one, do nothing..");
7931 return MM_ERROR_NONE;
7934 LOGE("failed to load attributes");
7936 return MM_ERROR_PLAYER_INTERNAL;
7939 /* videobin is not created yet, so we just set attributes related to display surface */
7940 LOGD("store display attribute for given surface type(%d)", surface_type);
7941 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7942 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7943 if (mm_attrs_commit_all(player->attrs)) {
7944 LOGE("failed to commit attribute");
7946 return MM_ERROR_PLAYER_INTERNAL;
7950 return MM_ERROR_NONE;
7953 /* Note : if silent is true, then subtitle would not be displayed. :*/
7955 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7957 mmplayer_t *player = (mmplayer_t *)hplayer;
7961 /* check player handle */
7962 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7964 player->set_mode.subtitle_off = silent;
7966 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7970 return MM_ERROR_NONE;
7974 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7976 mmplayer_gst_element_t *mainbin = NULL;
7977 mmplayer_gst_element_t *textbin = NULL;
7978 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7979 GstState current_state = GST_STATE_VOID_PENDING;
7980 GstState element_state = GST_STATE_VOID_PENDING;
7981 GstState element_pending_state = GST_STATE_VOID_PENDING;
7983 GstEvent *event = NULL;
7984 int result = MM_ERROR_NONE;
7986 GstClock *curr_clock = NULL;
7987 GstClockTime base_time, start_time, curr_time;
7992 /* check player handle */
7993 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7995 player->pipeline->mainbin &&
7996 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7998 mainbin = player->pipeline->mainbin;
7999 textbin = player->pipeline->textbin;
8001 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8003 // sync clock with current pipeline
8004 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8005 curr_time = gst_clock_get_time(curr_clock);
8007 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8008 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8010 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8011 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8013 if (current_state > GST_STATE_READY) {
8014 // sync state with current pipeline
8015 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8016 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8017 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8019 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8020 if (GST_STATE_CHANGE_FAILURE == ret) {
8021 LOGE("fail to state change.");
8022 result = MM_ERROR_PLAYER_INTERNAL;
8026 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8027 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8030 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8031 gst_object_unref(curr_clock);
8034 // seek to current position
8035 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8036 result = MM_ERROR_PLAYER_INVALID_STATE;
8037 LOGE("gst_element_query_position failed, invalid state");
8041 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8042 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);
8044 __mmplayer_gst_send_event_to_sink(player, event);
8046 result = MM_ERROR_PLAYER_INTERNAL;
8047 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8051 /* sync state with current pipeline */
8052 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8053 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8054 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8056 return MM_ERROR_NONE;
8059 /* release text pipeline resource */
8060 player->textsink_linked = 0;
8062 /* release signal */
8063 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8065 /* release textbin with it's childs */
8066 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8067 MMPLAYER_FREEIF(player->pipeline->textbin);
8068 player->pipeline->textbin = NULL;
8070 /* release subtitle elem */
8071 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8072 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8078 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8080 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8081 GstState current_state = GST_STATE_VOID_PENDING;
8083 MMHandleType attrs = 0;
8084 mmplayer_gst_element_t *mainbin = NULL;
8085 mmplayer_gst_element_t *textbin = NULL;
8087 gchar *subtitle_uri = NULL;
8088 int result = MM_ERROR_NONE;
8089 const gchar *charset = NULL;
8093 /* check player handle */
8094 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8096 player->pipeline->mainbin &&
8097 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8098 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8100 mainbin = player->pipeline->mainbin;
8101 textbin = player->pipeline->textbin;
8103 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8104 if (current_state < GST_STATE_READY) {
8105 result = MM_ERROR_PLAYER_INVALID_STATE;
8106 LOGE("Pipeline is not in proper state");
8110 attrs = MMPLAYER_GET_ATTRS(player);
8112 LOGE("cannot get content attribute");
8113 result = MM_ERROR_PLAYER_INTERNAL;
8117 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8118 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8119 LOGE("subtitle uri is not proper filepath");
8120 result = MM_ERROR_PLAYER_INVALID_URI;
8124 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8125 LOGE("failed to get storage info of subtitle path");
8126 result = MM_ERROR_PLAYER_INVALID_URI;
8130 LOGD("old subtitle file path is [%s]", subtitle_uri);
8131 LOGD("new subtitle file path is [%s]", filepath);
8133 if (!strcmp(filepath, subtitle_uri)) {
8134 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8137 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8138 if (mm_attrs_commit_all(player->attrs)) {
8139 LOGE("failed to commit.");
8144 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8145 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8146 player->subtitle_language_list = NULL;
8147 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8149 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8150 if (ret != GST_STATE_CHANGE_SUCCESS) {
8151 LOGE("failed to change state of textbin to READY");
8152 result = MM_ERROR_PLAYER_INTERNAL;
8156 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8157 if (ret != GST_STATE_CHANGE_SUCCESS) {
8158 LOGE("failed to change state of subparse to READY");
8159 result = MM_ERROR_PLAYER_INTERNAL;
8163 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8164 if (ret != GST_STATE_CHANGE_SUCCESS) {
8165 LOGE("failed to change state of filesrc to READY");
8166 result = MM_ERROR_PLAYER_INTERNAL;
8170 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8172 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8174 charset = util_get_charset(filepath);
8176 LOGD("detected charset is %s", charset);
8177 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8180 result = _mmplayer_sync_subtitle_pipeline(player);
8187 /* API to switch between external subtitles */
8189 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8191 int result = MM_ERROR_NONE;
8192 mmplayer_t *player = (mmplayer_t *)hplayer;
8197 /* check player handle */
8198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8200 /* filepath can be null in idle state */
8202 /* check file path */
8203 if ((path = strstr(filepath, "file://")))
8204 result = util_exist_file_path(path + 7);
8206 result = util_exist_file_path(filepath);
8208 if (result != MM_ERROR_NONE) {
8209 LOGE("invalid subtitle path 0x%X", result);
8210 return result; /* file not found or permission denied */
8214 if (!player->pipeline) {
8216 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8217 if (mm_attrs_commit_all(player->attrs)) {
8218 LOGE("failed to commit"); /* subtitle path will not be created */
8219 return MM_ERROR_PLAYER_INTERNAL;
8222 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8223 /* check filepath */
8224 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8226 if (!__mmplayer_check_subtitle(player)) {
8227 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8228 if (mm_attrs_commit_all(player->attrs)) {
8229 LOGE("failed to commit");
8230 return MM_ERROR_PLAYER_INTERNAL;
8233 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8234 LOGE("fail to create text pipeline");
8235 return MM_ERROR_PLAYER_INTERNAL;
8238 result = _mmplayer_sync_subtitle_pipeline(player);
8240 result = __mmplayer_change_external_subtitle_language(player, filepath);
8243 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8244 player->is_external_subtitle_added_now = TRUE;
8246 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8247 if (!player->subtitle_language_list) {
8248 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8249 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8250 LOGW("subtitle language list is not updated yet");
8252 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8260 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8262 int result = MM_ERROR_NONE;
8263 gchar *change_pad_name = NULL;
8264 GstPad *sinkpad = NULL;
8265 mmplayer_gst_element_t *mainbin = NULL;
8266 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8267 GstCaps *caps = NULL;
8268 gint total_track_num = 0;
8272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8273 MM_ERROR_PLAYER_NOT_INITIALIZED);
8275 LOGD("Change Track(%d) to %d", type, index);
8277 mainbin = player->pipeline->mainbin;
8279 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8280 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8281 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8282 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8284 /* Changing Video Track is not supported. */
8285 LOGE("Track Type Error");
8289 if (mainbin[elem_idx].gst == NULL) {
8290 result = MM_ERROR_PLAYER_NO_OP;
8291 LOGD("Req track doesn't exist");
8295 total_track_num = player->selector[type].total_track_num;
8296 if (total_track_num <= 0) {
8297 result = MM_ERROR_PLAYER_NO_OP;
8298 LOGD("Language list is not available");
8302 if ((index < 0) || (index >= total_track_num)) {
8303 result = MM_ERROR_INVALID_ARGUMENT;
8304 LOGD("Not a proper index : %d", index);
8308 /*To get the new pad from the selector*/
8309 change_pad_name = g_strdup_printf("sink_%u", index);
8310 if (change_pad_name == NULL) {
8311 result = MM_ERROR_PLAYER_INTERNAL;
8312 LOGD("Pad does not exists");
8316 LOGD("new active pad name: %s", change_pad_name);
8318 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8319 if (sinkpad == NULL) {
8320 LOGD("sinkpad is NULL");
8321 result = MM_ERROR_PLAYER_INTERNAL;
8325 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8326 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8328 caps = gst_pad_get_current_caps(sinkpad);
8329 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8332 gst_object_unref(sinkpad);
8334 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8335 __mmplayer_set_audio_attrs(player, caps);
8338 MMPLAYER_FREEIF(change_pad_name);
8343 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8345 int result = MM_ERROR_NONE;
8346 mmplayer_t *player = NULL;
8347 mmplayer_gst_element_t *mainbin = NULL;
8349 gint current_active_index = 0;
8351 GstState current_state = GST_STATE_VOID_PENDING;
8352 GstEvent *event = NULL;
8357 player = (mmplayer_t *)hplayer;
8358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8360 if (!player->pipeline) {
8361 LOGE("Track %d pre setting -> %d", type, index);
8363 player->selector[type].active_pad_index = index;
8367 mainbin = player->pipeline->mainbin;
8369 current_active_index = player->selector[type].active_pad_index;
8371 /*If index is same as running index no need to change the pad*/
8372 if (current_active_index == index)
8375 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8376 result = MM_ERROR_PLAYER_INVALID_STATE;
8380 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8381 if (current_state < GST_STATE_PAUSED) {
8382 result = MM_ERROR_PLAYER_INVALID_STATE;
8383 LOGW("Pipeline not in porper state");
8387 result = __mmplayer_change_selector_pad(player, type, index);
8388 if (result != MM_ERROR_NONE) {
8389 LOGE("change selector pad error");
8393 player->selector[type].active_pad_index = index;
8395 if (current_state == GST_STATE_PLAYING) {
8396 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8397 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8398 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8400 __mmplayer_gst_send_event_to_sink(player, event);
8402 result = MM_ERROR_PLAYER_INTERNAL;
8412 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8414 mmplayer_t *player = (mmplayer_t *)hplayer;
8418 /* check player handle */
8419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8421 *silent = player->set_mode.subtitle_off;
8423 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8427 return MM_ERROR_NONE;
8431 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8433 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8434 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8436 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8437 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8441 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8442 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8443 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8444 mmplayer_dump_t *dump_s;
8445 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8446 if (dump_s == NULL) {
8447 LOGE("malloc fail");
8451 dump_s->dump_element_file = NULL;
8452 dump_s->dump_pad = NULL;
8453 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8455 if (dump_s->dump_pad) {
8456 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8457 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]);
8458 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8459 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);
8460 /* add list for removed buffer probe and close FILE */
8461 player->dump_list = g_list_append(player->dump_list, dump_s);
8462 LOGD("%s sink pad added buffer probe for dump", factory_name);
8465 MMPLAYER_FREEIF(dump_s);
8466 LOGE("failed to get %s sink pad added", factory_name);
8473 static GstPadProbeReturn
8474 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8476 FILE *dump_data = (FILE *)u_data;
8478 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8479 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8481 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8483 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8485 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8487 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8489 gst_buffer_unmap(buffer, &probe_info);
8491 return GST_PAD_PROBE_OK;
8495 __mmplayer_release_dump_list(GList *dump_list)
8497 GList *d_list = dump_list;
8502 for (; d_list; d_list = g_list_next(d_list)) {
8503 mmplayer_dump_t *dump_s = d_list->data;
8504 if (dump_s->dump_pad) {
8505 if (dump_s->probe_handle_id)
8506 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8507 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8509 if (dump_s->dump_element_file) {
8510 fclose(dump_s->dump_element_file);
8511 dump_s->dump_element_file = NULL;
8513 MMPLAYER_FREEIF(dump_s);
8515 g_list_free(dump_list);
8520 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8522 mmplayer_t *player = (mmplayer_t *)hplayer;
8526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8527 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8529 *exist = (bool)player->has_closed_caption;
8533 return MM_ERROR_NONE;
8537 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8541 // LOGD("unref internal gst buffer %p", buffer);
8542 gst_buffer_unref((GstBuffer *)buffer);
8549 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8551 mmplayer_t *player = (mmplayer_t *)hplayer;
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8558 if (MMPLAYER_IS_STREAMING(player))
8559 *timeout = (int)player->ini.live_state_change_timeout;
8561 *timeout = (int)player->ini.localplayback_state_change_timeout;
8563 LOGD("timeout = %d", *timeout);
8566 return MM_ERROR_NONE;
8570 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8572 mmplayer_t *player = (mmplayer_t *)hplayer;
8576 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8577 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8579 *num = player->video_num_buffers;
8580 *extra_num = player->video_extra_num_buffers;
8582 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8585 return MM_ERROR_NONE;
8589 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8593 MMPLAYER_RETURN_IF_FAIL(player);
8595 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8597 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8598 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8599 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8600 player->storage_info[i].id = -1;
8601 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8603 if (path_type != MMPLAYER_PATH_MAX)
8612 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8614 int ret = MM_ERROR_NONE;
8615 mmplayer_t *player = (mmplayer_t *)hplayer;
8616 MMMessageParamType msg_param = {0, };
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8621 LOGW("state changed storage %d:%d", id, state);
8623 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8624 return MM_ERROR_NONE;
8626 /* FIXME: text path should be handled seperately. */
8627 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8628 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8629 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8630 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8631 LOGW("external storage is removed");
8633 if (player->msg_posted == FALSE) {
8634 memset(&msg_param, 0, sizeof(MMMessageParamType));
8635 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8636 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8637 player->msg_posted = TRUE;
8640 /* unrealize the player */
8641 ret = _mmplayer_unrealize(hplayer);
8642 if (ret != MM_ERROR_NONE)
8643 LOGE("failed to unrealize");
8651 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8653 int ret = MM_ERROR_NONE;
8654 mmplayer_t *player = (mmplayer_t *)hplayer;
8655 int idx = 0, total = 0;
8656 gchar *result = NULL, *tmp = NULL;
8659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8660 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8662 total = *num = g_list_length(player->adaptive_info.var_list);
8664 LOGW("There is no stream variant info.");
8668 result = g_strdup("");
8669 for (idx = 0 ; idx < total ; idx++) {
8670 stream_variant_t *v_data = NULL;
8671 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8674 gchar data[64] = {0};
8675 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8677 tmp = g_strconcat(result, data, NULL);
8681 LOGW("There is no variant data in %d", idx);
8686 *var_info = (char *)result;
8688 LOGD("variant info %d:%s", *num, *var_info);
8694 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8696 int ret = MM_ERROR_NONE;
8697 mmplayer_t *player = (mmplayer_t *)hplayer;
8700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8702 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8704 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8705 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8706 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8708 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8709 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8710 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8711 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8713 /* FIXME: seek to current position for applying new variant limitation */
8722 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8724 int ret = MM_ERROR_NONE;
8725 mmplayer_t *player = (mmplayer_t *)hplayer;
8728 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8729 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8731 *bandwidth = player->adaptive_info.limit.bandwidth;
8732 *width = player->adaptive_info.limit.width;
8733 *height = player->adaptive_info.limit.height;
8735 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8742 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8744 int ret = MM_ERROR_NONE;
8745 mmplayer_t *player = (mmplayer_t *)hplayer;
8748 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8749 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8750 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8752 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8754 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8755 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8756 else /* live case */
8757 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8759 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8766 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8768 #define IDX_FIRST_SW_CODEC 0
8769 mmplayer_t *player = (mmplayer_t *)hplayer;
8770 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8771 MMHandleType attrs = 0;
8774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8776 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8777 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8778 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8780 switch (stream_type) {
8781 case MM_PLAYER_STREAM_TYPE_AUDIO:
8782 /* to support audio codec selection, codec info have to be added in ini file as below.
8783 audio codec element hw = xxxx
8784 audio codec element sw = avdec */
8785 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8786 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8787 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8788 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8789 LOGE("There is no audio codec info for codec_type %d", codec_type);
8790 return MM_ERROR_PLAYER_NO_OP;
8793 case MM_PLAYER_STREAM_TYPE_VIDEO:
8794 /* to support video codec selection, codec info have to be added in ini file as below.
8795 video codec element hw = omx
8796 video codec element sw = avdec */
8797 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8798 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8799 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8800 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8801 LOGE("There is no video codec info for codec_type %d", codec_type);
8802 return MM_ERROR_PLAYER_NO_OP;
8806 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8807 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8811 LOGD("update %s codec_type to %d", attr_name, codec_type);
8813 attrs = MMPLAYER_GET_ATTRS(player);
8814 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8816 if (mm_attrs_commit_all(player->attrs)) {
8817 LOGE("failed to commit codec_type attributes");
8818 return MM_ERROR_PLAYER_INTERNAL;
8822 return MM_ERROR_NONE;
8826 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8828 mmplayer_t *player = (mmplayer_t *)hplayer;
8829 GstElement *rg_vol_element = NULL;
8833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8835 player->sound.rg_enable = enabled;
8837 /* just hold rgvolume enable value if pipeline is not ready */
8838 if (!player->pipeline || !player->pipeline->audiobin) {
8839 LOGD("pipeline is not ready. holding rgvolume enable value");
8840 return MM_ERROR_NONE;
8843 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8845 if (!rg_vol_element) {
8846 LOGD("rgvolume element is not created");
8847 return MM_ERROR_PLAYER_INTERNAL;
8851 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8853 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8857 return MM_ERROR_NONE;
8861 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8863 mmplayer_t *player = (mmplayer_t *)hplayer;
8864 GstElement *rg_vol_element = NULL;
8865 gboolean enable = FALSE;
8869 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8870 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8872 /* just hold enable_rg value if pipeline is not ready */
8873 if (!player->pipeline || !player->pipeline->audiobin) {
8874 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8875 *enabled = player->sound.rg_enable;
8876 return MM_ERROR_NONE;
8879 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8881 if (!rg_vol_element) {
8882 LOGD("rgvolume element is not created");
8883 return MM_ERROR_PLAYER_INTERNAL;
8886 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8887 *enabled = (bool)enable;
8891 return MM_ERROR_NONE;
8895 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8897 mmplayer_t *player = (mmplayer_t *)hplayer;
8898 MMHandleType attrs = 0;
8899 void *handle = NULL;
8900 int ret = MM_ERROR_NONE;
8904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8906 attrs = MMPLAYER_GET_ATTRS(player);
8907 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8909 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8911 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8912 return MM_ERROR_PLAYER_INTERNAL;
8915 player->video_roi.scale_x = scale_x;
8916 player->video_roi.scale_y = scale_y;
8917 player->video_roi.scale_width = scale_width;
8918 player->video_roi.scale_height = scale_height;
8920 /* check video sinkbin is created */
8921 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8922 return MM_ERROR_NONE;
8924 if (!gst_video_overlay_set_video_roi_area(
8925 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8926 scale_x, scale_y, scale_width, scale_height))
8927 ret = MM_ERROR_PLAYER_INTERNAL;
8929 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8930 scale_x, scale_y, scale_width, scale_height);
8938 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8940 mmplayer_t *player = (mmplayer_t *)hplayer;
8941 int ret = MM_ERROR_NONE;
8945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8946 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8948 *scale_x = player->video_roi.scale_x;
8949 *scale_y = player->video_roi.scale_y;
8950 *scale_width = player->video_roi.scale_width;
8951 *scale_height = player->video_roi.scale_height;
8953 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8954 *scale_x, *scale_y, *scale_width, *scale_height);
8960 __mmplayer_update_duration_value(mmplayer_t *player)
8962 gboolean ret = FALSE;
8963 gint64 dur_nsec = 0;
8964 LOGD("try to update duration");
8966 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8967 player->duration = dur_nsec;
8968 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8972 if (player->duration < 0) {
8973 LOGW("duration is Non-Initialized !!!");
8974 player->duration = 0;
8977 /* update streaming service type */
8978 player->streaming_type = __mmplayer_get_stream_service_type(player);
8980 /* check duration is OK */
8981 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8982 /* FIXIT : find another way to get duration here. */
8983 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8989 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8991 /* update audio params
8992 NOTE : We need original audio params and it can be only obtained from src pad of audio
8993 decoder. Below code only valid when we are not using 'resampler' just before
8994 'audioconverter'. */
8995 GstCaps *caps_a = NULL;
8997 gint samplerate = 0, channels = 0;
8998 GstStructure *p = NULL;
8999 GstElement *aconv = NULL;
9001 LOGD("try to update audio attrs");
9003 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9005 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9006 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9007 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9008 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9010 LOGE("there is no audio converter");
9014 pad = gst_element_get_static_pad(aconv, "sink");
9017 LOGW("failed to get pad from audio converter");
9021 caps_a = gst_pad_get_current_caps(pad);
9023 LOGW("not ready to get audio caps");
9024 gst_object_unref(pad);
9028 p = gst_caps_get_structure(caps_a, 0);
9030 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9032 gst_structure_get_int(p, "rate", &samplerate);
9033 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
9035 gst_structure_get_int(p, "channels", &channels);
9036 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
9038 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9040 gst_caps_unref(caps_a);
9041 gst_object_unref(pad);
9047 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9049 LOGD("try to update video attrs");
9051 GstCaps *caps_v = NULL;
9055 GstStructure *p = NULL;
9057 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9058 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9060 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9062 LOGD("no videosink sink pad");
9066 caps_v = gst_pad_get_current_caps(pad);
9067 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9068 if (!caps_v && player->v_stream_caps) {
9069 caps_v = player->v_stream_caps;
9070 gst_caps_ref(caps_v);
9074 LOGD("no negitiated caps from videosink");
9075 gst_object_unref(pad);
9079 p = gst_caps_get_structure(caps_v, 0);
9080 gst_structure_get_int(p, "width", &width);
9081 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
9083 gst_structure_get_int(p, "height", &height);
9084 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
9086 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9088 SECURE_LOGD("width : %d height : %d", width, height);
9090 gst_caps_unref(caps_v);
9091 gst_object_unref(pad);
9094 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
9095 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9102 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9104 gboolean ret = FALSE;
9105 guint64 data_size = 0;
9109 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9110 if (!player->duration)
9113 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9114 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9115 if (stat(path, &sb) == 0)
9116 data_size = (guint64)sb.st_size;
9118 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9119 data_size = player->http_content_size;
9122 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9125 guint64 bitrate = 0;
9126 guint64 msec_dur = 0;
9128 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9130 bitrate = data_size * 8 * 1000 / msec_dur;
9131 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9132 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9136 LOGD("player duration is less than 0");
9140 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9141 if (player->total_bitrate) {
9142 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9151 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9153 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9154 data->uri_type = uri_type;
9158 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9160 int ret = MM_ERROR_PLAYER_INVALID_URI;
9162 char *buffer = NULL;
9163 char *seperator = strchr(path, ',');
9164 char ext[100] = {0,}, size[100] = {0,};
9167 if ((buffer = strstr(path, "ext="))) {
9168 buffer += strlen("ext=");
9170 if (strlen(buffer)) {
9171 strncpy(ext, buffer, 99);
9173 if ((seperator = strchr(ext, ','))
9174 || (seperator = strchr(ext, ' '))
9175 || (seperator = strchr(ext, '\0'))) {
9176 seperator[0] = '\0';
9181 if ((buffer = strstr(path, "size="))) {
9182 buffer += strlen("size=");
9184 if (strlen(buffer) > 0) {
9185 strncpy(size, buffer, 99);
9187 if ((seperator = strchr(size, ','))
9188 || (seperator = strchr(size, ' '))
9189 || (seperator = strchr(size, '\0'))) {
9190 seperator[0] = '\0';
9193 mem_size = atoi(size);
9198 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9200 if (mem_size && param) {
9201 if (data->input_mem.buf)
9202 free(data->input_mem.buf);
9203 data->input_mem.buf = malloc(mem_size);
9205 if (data->input_mem.buf) {
9206 memcpy(data->input_mem.buf, param, mem_size);
9207 data->input_mem.len = mem_size;
9208 ret = MM_ERROR_NONE;
9210 LOGE("failed to alloc mem %d", mem_size);
9211 ret = MM_ERROR_PLAYER_INTERNAL;
9214 data->input_mem.offset = 0;
9215 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9222 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9224 gchar *location = NULL;
9227 int ret = MM_ERROR_NONE;
9229 if ((path = strstr(uri, "file://"))) {
9230 location = g_filename_from_uri(uri, NULL, &err);
9231 if (!location || (err != NULL)) {
9232 LOGE("Invalid URI '%s' for filesrc: %s", path,
9233 (err != NULL) ? err->message : "unknown error");
9237 MMPLAYER_FREEIF(location);
9239 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9240 return MM_ERROR_PLAYER_INVALID_URI;
9242 LOGD("path from uri: %s", location);
9245 path = (location != NULL) ? (location) : ((char *)uri);
9248 ret = util_exist_file_path(path);
9250 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9251 if (ret == MM_ERROR_NONE) {
9252 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9253 if (util_is_sdp_file(path)) {
9254 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9255 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9257 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9259 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9260 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9262 LOGE("invalid uri, could not play..");
9263 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9266 MMPLAYER_FREEIF(location);
9271 static mmplayer_video_decoded_data_info_t *
9272 __mmplayer_create_stream_from_pad(GstPad *pad)
9274 GstCaps *caps = NULL;
9275 GstStructure *structure = NULL;
9276 unsigned int fourcc = 0;
9277 const gchar *string_format = NULL;
9278 mmplayer_video_decoded_data_info_t *stream = NULL;
9280 MMPixelFormatType format;
9283 caps = gst_pad_get_current_caps(pad);
9285 LOGE("Caps is NULL.");
9289 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9290 structure = gst_caps_get_structure(caps, 0);
9291 gst_structure_get_int(structure, "width", &width);
9292 gst_structure_get_int(structure, "height", &height);
9293 string_format = gst_structure_get_string(structure, "format");
9296 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9297 format = util_get_pixtype(fourcc);
9298 gst_video_info_from_caps(&info, caps);
9299 gst_caps_unref(caps);
9302 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9303 LOGE("Wrong condition!!");
9307 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9309 LOGE("failed to alloc mem for video data");
9313 stream->width = width;
9314 stream->height = height;
9315 stream->format = format;
9316 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9322 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9324 unsigned int pitch = 0;
9325 unsigned int size = 0;
9327 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9330 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9331 bo = gst_tizen_memory_get_bos(mem, index);
9333 stream->bo[index] = tbm_bo_ref(bo);
9335 LOGE("failed to get bo for index %d", index);
9338 for (index = 0; index < stream->plane_num; index++) {
9339 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9340 stream->stride[index] = pitch;
9342 stream->elevation[index] = size / pitch;
9344 stream->elevation[index] = stream->height;
9349 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9351 if (stream->format == MM_PIXEL_FORMAT_I420) {
9352 int ret = TBM_SURFACE_ERROR_NONE;
9353 tbm_surface_h surface;
9354 tbm_surface_info_s info;
9356 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9358 ret = tbm_surface_get_info(surface, &info);
9359 if (ret != TBM_SURFACE_ERROR_NONE) {
9360 tbm_surface_destroy(surface);
9364 tbm_surface_destroy(surface);
9365 stream->stride[0] = info.planes[0].stride;
9366 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9367 stream->stride[1] = info.planes[1].stride;
9368 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9369 stream->stride[2] = info.planes[2].stride;
9370 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9371 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9372 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9373 stream->stride[0] = stream->width * 4;
9374 stream->elevation[0] = stream->height;
9375 stream->bo_size = stream->stride[0] * stream->height;
9377 LOGE("Not support format %d", stream->format);
9385 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9387 tbm_bo_handle thandle;
9389 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9390 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9391 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9395 unsigned char *src = NULL;
9396 unsigned char *dest = NULL;
9397 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9399 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9401 LOGE("fail to gst_memory_map");
9405 if (!mapinfo.data) {
9406 LOGE("data pointer is wrong");
9410 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9411 if (!stream->bo[0]) {
9412 LOGE("Fail to tbm_bo_alloc!!");
9416 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9418 LOGE("thandle pointer is wrong");
9422 if (stream->format == MM_PIXEL_FORMAT_I420) {
9423 src_stride[0] = GST_ROUND_UP_4(stream->width);
9424 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9425 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9426 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9429 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9430 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9432 for (i = 0; i < 3; i++) {
9433 src = mapinfo.data + src_offset[i];
9434 dest = thandle.ptr + dest_offset[i];
9439 for (j = 0; j < stream->height >> k; j++) {
9440 memcpy(dest, src, stream->width>>k);
9441 src += src_stride[i];
9442 dest += stream->stride[i];
9445 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9446 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9448 LOGE("Not support format %d", stream->format);
9452 tbm_bo_unmap(stream->bo[0]);
9453 gst_memory_unmap(mem, &mapinfo);
9459 tbm_bo_unmap(stream->bo[0]);
9462 gst_memory_unmap(mem, &mapinfo);
9468 __mmplayer_set_pause_state(mmplayer_t *player)
9470 if (player->sent_bos)
9473 /* rtsp case, get content attrs by GstMessage */
9474 if (MMPLAYER_IS_RTSP_STREAMING(player))
9477 /* it's first time to update all content attrs. */
9478 __mmplayer_update_content_attrs(player, ATTR_ALL);
9482 __mmplayer_set_playing_state(mmplayer_t *player)
9484 gchar *audio_codec = NULL;
9486 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9487 /* initialize because auto resume is done well. */
9488 player->resumed_by_rewind = FALSE;
9489 player->playback_rate = 1.0;
9492 if (player->sent_bos)
9495 /* try to get content metadata */
9497 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9498 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9499 * legacy mmfw-player api
9501 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9503 if ((player->cmd == MMPLAYER_COMMAND_START)
9504 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9505 __mmplayer_handle_missed_plugin(player);
9508 /* check audio codec field is set or not
9509 * we can get it from typefinder or codec's caps.
9511 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9513 /* The codec format can't be sent for audio only case like amr, mid etc.
9514 * Because, parser don't make related TAG.
9515 * So, if it's not set yet, fill it with found data.
9518 if (g_strrstr(player->type, "audio/midi"))
9519 audio_codec = "MIDI";
9520 else if (g_strrstr(player->type, "audio/x-amr"))
9521 audio_codec = "AMR";
9522 else if (g_strrstr(player->type, "audio/mpeg")
9523 && !g_strrstr(player->type, "mpegversion=(int)1"))
9524 audio_codec = "AAC";
9526 audio_codec = "unknown";
9528 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9530 if (mm_attrs_commit_all(player->attrs))
9531 LOGE("failed to update attributes");
9533 LOGD("set audio codec type with caps");