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 /* free gapless play thread */
4688 if (player->gapless_play_thread) {
4689 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4690 player->gapless_play_thread_exit = TRUE;
4691 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4692 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4694 g_thread_join(player->gapless_play_thread);
4695 player->gapless_play_thread = NULL;
4697 g_mutex_clear(&player->gapless_play_thread_mutex);
4698 g_cond_clear(&player->gapless_play_thread_cond);
4701 /* release attributes */
4702 _mmplayer_deconstruct_attribute(handle);
4710 __mmplayer_init_gstreamer(mmplayer_t *player)
4712 static gboolean initialized = FALSE;
4713 static const int max_argc = 50;
4715 gchar **argv = NULL;
4716 gchar **argv2 = NULL;
4722 LOGD("gstreamer already initialized.");
4727 argc = malloc(sizeof(int));
4728 argv = malloc(sizeof(gchar *) * max_argc);
4729 argv2 = malloc(sizeof(gchar *) * max_argc);
4731 if (!argc || !argv || !argv2)
4734 memset(argv, 0, sizeof(gchar *) * max_argc);
4735 memset(argv2, 0, sizeof(gchar *) * max_argc);
4739 argv[0] = g_strdup("mmplayer");
4742 for (i = 0; i < 5; i++) {
4743 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4744 if (strlen(player->ini.gst_param[i]) > 0) {
4745 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4750 /* we would not do fork for scanning plugins */
4751 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4754 /* check disable registry scan */
4755 if (player->ini.skip_rescan) {
4756 argv[*argc] = g_strdup("--gst-disable-registry-update");
4760 /* check disable segtrap */
4761 if (player->ini.disable_segtrap) {
4762 argv[*argc] = g_strdup("--gst-disable-segtrap");
4766 LOGD("initializing gstreamer with following parameter");
4767 LOGD("argc : %d", *argc);
4770 for (i = 0; i < arg_count; i++) {
4772 LOGD("argv[%d] : %s", i, argv2[i]);
4775 /* initializing gstreamer */
4776 if (!gst_init_check(argc, &argv, &err)) {
4777 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4784 for (i = 0; i < arg_count; i++) {
4785 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4786 MMPLAYER_FREEIF(argv2[i]);
4789 MMPLAYER_FREEIF(argv);
4790 MMPLAYER_FREEIF(argv2);
4791 MMPLAYER_FREEIF(argc);
4801 for (i = 0; i < arg_count; i++) {
4802 LOGD("free[%d] : %s", i, argv2[i]);
4803 MMPLAYER_FREEIF(argv2[i]);
4806 MMPLAYER_FREEIF(argv);
4807 MMPLAYER_FREEIF(argv2);
4808 MMPLAYER_FREEIF(argc);
4814 __mmplayer_check_async_state_transition(mmplayer_t *player)
4816 GstState element_state = GST_STATE_VOID_PENDING;
4817 GstState element_pending_state = GST_STATE_VOID_PENDING;
4818 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4819 GstElement *element = NULL;
4820 gboolean async = FALSE;
4822 /* check player handle */
4823 MMPLAYER_RETURN_IF_FAIL(player &&
4825 player->pipeline->mainbin &&
4826 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4829 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4831 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4832 LOGD("don't need to check the pipeline state");
4836 MMPLAYER_PRINT_STATE(player);
4838 /* wait for state transition */
4839 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4840 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4842 if (ret == GST_STATE_CHANGE_FAILURE) {
4843 LOGE(" [%s] state : %s pending : %s",
4844 GST_ELEMENT_NAME(element),
4845 gst_element_state_get_name(element_state),
4846 gst_element_state_get_name(element_pending_state));
4848 /* dump state of all element */
4849 __mmplayer_dump_pipeline_state(player);
4854 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4859 _mmplayer_destroy(MMHandleType handle)
4861 mmplayer_t *player = MM_PLAYER_CAST(handle);
4865 /* check player handle */
4866 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4868 /* destroy can called at anytime */
4869 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4871 /* check async state transition */
4872 __mmplayer_check_async_state_transition(player);
4874 /* release gapless play thread */
4875 if (player->gapless_play_thread) {
4876 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4877 player->gapless_play_thread_exit = TRUE;
4878 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4879 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4881 LOGD("waitting for gapless play thread exit");
4882 g_thread_join(player->gapless_play_thread);
4883 g_mutex_clear(&player->gapless_play_thread_mutex);
4884 g_cond_clear(&player->gapless_play_thread_cond);
4885 LOGD("gapless play thread released");
4888 _mmplayer_release_video_capture(player);
4890 /* de-initialize resource manager */
4891 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4892 player->resource_manager))
4893 LOGE("failed to deinitialize resource manager");
4895 /* release pipeline */
4896 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4897 LOGE("failed to destory pipeline");
4898 return MM_ERROR_PLAYER_INTERNAL;
4901 g_queue_free(player->bus_msg_q);
4903 /* release subtitle info lock and cond */
4904 g_mutex_clear(&player->subtitle_info_mutex);
4905 g_cond_clear(&player->subtitle_info_cond);
4907 __mmplayer_release_dump_list(player->dump_list);
4909 /* release miscellaneous information */
4910 __mmplayer_release_misc(player);
4912 /* release miscellaneous information.
4913 these info needs to be released after pipeline is destroyed. */
4914 __mmplayer_release_misc_post(player);
4916 /* release attributes */
4917 _mmplayer_deconstruct_attribute(handle);
4920 g_mutex_clear(&player->fsink_lock);
4923 g_mutex_clear(&player->update_tag_lock);
4925 /* release video bo lock and cond */
4926 g_mutex_clear(&player->video_bo_mutex);
4927 g_cond_clear(&player->video_bo_cond);
4929 /* release media stream callback lock */
4930 g_mutex_clear(&player->media_stream_cb_lock);
4934 return MM_ERROR_NONE;
4938 _mmplayer_realize(MMHandleType hplayer)
4940 mmplayer_t *player = (mmplayer_t *)hplayer;
4943 MMHandleType attrs = 0;
4944 int ret = MM_ERROR_NONE;
4948 /* check player handle */
4949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4951 /* check current state */
4952 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4954 attrs = MMPLAYER_GET_ATTRS(player);
4956 LOGE("fail to get attributes.");
4957 return MM_ERROR_PLAYER_INTERNAL;
4959 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4960 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4962 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4963 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4965 if (ret != MM_ERROR_NONE) {
4966 LOGE("failed to parse profile");
4971 if (uri && (strstr(uri, "es_buff://"))) {
4972 if (strstr(uri, "es_buff://push_mode"))
4973 player->es_player_push_mode = TRUE;
4975 player->es_player_push_mode = FALSE;
4978 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4979 LOGW("mms protocol is not supported format.");
4980 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4983 if (MMPLAYER_IS_STREAMING(player))
4984 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4986 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4988 player->smooth_streaming = FALSE;
4989 player->videodec_linked = 0;
4990 player->audiodec_linked = 0;
4991 player->textsink_linked = 0;
4992 player->is_external_subtitle_present = FALSE;
4993 player->is_external_subtitle_added_now = FALSE;
4994 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4995 player->video360_metadata.is_spherical = -1;
4996 player->is_openal_plugin_used = FALSE;
4997 player->demux_pad_index = 0;
4998 player->subtitle_language_list = NULL;
4999 player->is_subtitle_force_drop = FALSE;
5001 __mmplayer_track_initialize(player);
5002 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5004 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5005 gint prebuffer_ms = 0, rebuffer_ms = 0;
5007 player->streamer = __mm_player_streaming_create();
5008 __mm_player_streaming_initialize(player->streamer, TRUE);
5010 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5011 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5013 if (prebuffer_ms > 0) {
5014 prebuffer_ms = MAX(prebuffer_ms, 1000);
5015 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5018 if (rebuffer_ms > 0) {
5019 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5020 rebuffer_ms = MAX(rebuffer_ms, 1000);
5021 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5024 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5025 player->streamer->buffering_req.rebuffer_time);
5028 /* realize pipeline */
5029 ret = __mmplayer_gst_realize(player);
5030 if (ret != MM_ERROR_NONE)
5031 LOGE("fail to realize the player.");
5033 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5041 _mmplayer_unrealize(MMHandleType hplayer)
5043 mmplayer_t *player = (mmplayer_t *)hplayer;
5044 int ret = MM_ERROR_NONE;
5048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5050 MMPLAYER_CMD_UNLOCK(player);
5051 /* destroy the gst bus msg thread which is created during realize.
5052 this funct have to be called before getting cmd lock. */
5053 __mmplayer_bus_msg_thread_destroy(player);
5054 MMPLAYER_CMD_LOCK(player);
5056 /* check current state */
5057 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5059 /* check async state transition */
5060 __mmplayer_check_async_state_transition(player);
5062 /* unrealize pipeline */
5063 ret = __mmplayer_gst_unrealize(player);
5065 /* set asm stop if success */
5066 if (MM_ERROR_NONE == ret) {
5067 if (!player->interrupted_by_resource) {
5068 if (player->video_decoder_resource != NULL) {
5069 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5070 player->video_decoder_resource);
5071 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5072 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
5074 player->video_decoder_resource = NULL;
5077 if (player->video_overlay_resource != NULL) {
5078 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5079 player->video_overlay_resource);
5080 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5081 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
5083 player->video_overlay_resource = NULL;
5086 ret = mm_resource_manager_commit(player->resource_manager);
5087 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5088 LOGE("failed to commit resource releases, ret(0x%x)", ret);
5091 LOGE("failed and don't change asm state to stop");
5099 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5101 mmplayer_t *player = (mmplayer_t *)hplayer;
5103 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5105 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5109 _mmplayer_get_state(MMHandleType hplayer, int *state)
5111 mmplayer_t *player = (mmplayer_t *)hplayer;
5113 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5115 *state = MMPLAYER_CURRENT_STATE(player);
5117 return MM_ERROR_NONE;
5121 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5123 GstElement *vol_element = NULL;
5124 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5127 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5128 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5130 /* check pipeline handle */
5131 if (!player->pipeline || !player->pipeline->audiobin) {
5132 LOGD("'%s' will be applied when audiobin is created", prop_name);
5134 /* NOTE : stored value will be used in create_audiobin
5135 * returning MM_ERROR_NONE here makes application to able to
5136 * set audio volume or mute at anytime.
5138 return MM_ERROR_NONE;
5141 if (player->build_audio_offload) {
5142 LOGD("offload pipeline");
5143 volume_elem_id = MMPLAYER_A_SINK;
5146 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5148 LOGE("failed to get vol element %d", volume_elem_id);
5149 return MM_ERROR_PLAYER_INTERNAL;
5152 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5154 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5155 LOGE("there is no '%s' property", prop_name);
5156 return MM_ERROR_PLAYER_INTERNAL;
5159 if (!strcmp(prop_name, "volume")) {
5160 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5161 } else if (!strcmp(prop_name, "mute")) {
5162 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5164 LOGE("invalid property %s", prop_name);
5165 return MM_ERROR_PLAYER_INTERNAL;
5168 return MM_ERROR_NONE;
5172 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5174 int ret = MM_ERROR_NONE;
5175 mmplayer_t *player = (mmplayer_t *)hplayer;
5178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5180 LOGD("volume = %f", volume);
5182 /* invalid factor range or not */
5183 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5184 LOGE("Invalid volume value");
5185 return MM_ERROR_INVALID_ARGUMENT;
5188 player->sound.volume = volume;
5190 ret = __mmplayer_gst_set_volume_property(player, "volume");
5197 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5199 mmplayer_t *player = (mmplayer_t *)hplayer;
5203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5204 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5206 *volume = player->sound.volume;
5208 LOGD("current vol = %f", *volume);
5211 return MM_ERROR_NONE;
5215 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5217 int ret = MM_ERROR_NONE;
5218 mmplayer_t *player = (mmplayer_t *)hplayer;
5221 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5223 LOGD("mute = %d", mute);
5225 player->sound.mute = mute;
5227 ret = __mmplayer_gst_set_volume_property(player, "mute");
5234 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5236 mmplayer_t *player = (mmplayer_t *)hplayer;
5240 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5241 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5243 *mute = player->sound.mute;
5245 LOGD("current mute = %d", *mute);
5249 return MM_ERROR_NONE;
5253 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5255 mmplayer_t *player = (mmplayer_t *)hplayer;
5259 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5261 player->video_stream_changed_cb = callback;
5262 player->video_stream_changed_cb_user_param = user_param;
5263 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5267 return MM_ERROR_NONE;
5271 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5273 mmplayer_t *player = (mmplayer_t *)hplayer;
5277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5279 player->audio_stream_changed_cb = callback;
5280 player->audio_stream_changed_cb_user_param = user_param;
5281 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5285 return MM_ERROR_NONE;
5289 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5291 mmplayer_t *player = (mmplayer_t *)hplayer;
5295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5297 player->audio_decoded_cb = callback;
5298 player->audio_decoded_cb_user_param = user_param;
5299 player->audio_extract_opt = opt;
5300 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5304 return MM_ERROR_NONE;
5308 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5310 mmplayer_t *player = (mmplayer_t *)hplayer;
5314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5316 if (callback && !player->bufmgr)
5317 player->bufmgr = tbm_bufmgr_init(-1);
5319 player->set_mode.video_export = (callback) ? true : false;
5320 player->video_decoded_cb = callback;
5321 player->video_decoded_cb_user_param = user_param;
5323 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5327 return MM_ERROR_NONE;
5331 _mmplayer_start(MMHandleType hplayer)
5333 mmplayer_t *player = (mmplayer_t *)hplayer;
5334 gint ret = MM_ERROR_NONE;
5338 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5340 /* check current state */
5341 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5343 /* start pipeline */
5344 ret = __mmplayer_gst_start(player);
5345 if (ret != MM_ERROR_NONE)
5346 LOGE("failed to start player.");
5348 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5349 LOGD("force playing start even during buffering");
5350 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5358 /* NOTE: post "not supported codec message" to application
5359 * when one codec is not found during AUTOPLUGGING in MSL.
5360 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5361 * And, if any codec is not found, don't send message here.
5362 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5365 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5367 MMMessageParamType msg_param;
5368 memset(&msg_param, 0, sizeof(MMMessageParamType));
5369 gboolean post_msg_direct = FALSE;
5373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5375 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5376 player->not_supported_codec, player->can_support_codec);
5378 if (player->not_found_demuxer) {
5379 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5380 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5382 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5383 MMPLAYER_FREEIF(msg_param.data);
5385 return MM_ERROR_NONE;
5388 if (player->not_supported_codec) {
5389 if (player->can_support_codec) {
5390 // There is one codec to play
5391 post_msg_direct = TRUE;
5393 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5394 post_msg_direct = TRUE;
5397 if (post_msg_direct) {
5398 MMMessageParamType msg_param;
5399 memset(&msg_param, 0, sizeof(MMMessageParamType));
5401 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5402 LOGW("not found AUDIO codec, posting error code to application.");
5404 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5405 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5406 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5407 LOGW("not found VIDEO codec, posting error code to application.");
5409 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5410 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5413 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5415 MMPLAYER_FREEIF(msg_param.data);
5417 return MM_ERROR_NONE;
5419 // no any supported codec case
5420 LOGW("not found any codec, posting error code to application.");
5422 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5423 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5424 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5426 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5430 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5432 MMPLAYER_FREEIF(msg_param.data);
5438 return MM_ERROR_NONE;
5442 __mmplayer_check_pipeline(mmplayer_t *player)
5444 GstState element_state = GST_STATE_VOID_PENDING;
5445 GstState element_pending_state = GST_STATE_VOID_PENDING;
5447 int ret = MM_ERROR_NONE;
5449 if (!player->gapless.reconfigure)
5452 LOGW("pipeline is under construction.");
5454 MMPLAYER_PLAYBACK_LOCK(player);
5455 MMPLAYER_PLAYBACK_UNLOCK(player);
5457 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5459 /* wait for state transition */
5460 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5461 if (ret == GST_STATE_CHANGE_FAILURE)
5462 LOGE("failed to change pipeline state within %d sec", timeout);
5465 /* NOTE : it should be able to call 'stop' anytime*/
5467 _mmplayer_stop(MMHandleType hplayer)
5469 mmplayer_t *player = (mmplayer_t *)hplayer;
5470 int ret = MM_ERROR_NONE;
5474 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5476 /* check current state */
5477 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5479 /* check pipline building state */
5480 __mmplayer_check_pipeline(player);
5481 __mmplayer_reset_gapless_state(player);
5483 /* NOTE : application should not wait for EOS after calling STOP */
5484 __mmplayer_cancel_eos_timer(player);
5487 player->seek_state = MMPLAYER_SEEK_NONE;
5490 ret = __mmplayer_gst_stop(player);
5492 if (ret != MM_ERROR_NONE)
5493 LOGE("failed to stop player.");
5501 _mmplayer_pause(MMHandleType hplayer)
5503 mmplayer_t *player = (mmplayer_t *)hplayer;
5504 gint64 pos_nsec = 0;
5505 gboolean async = FALSE;
5506 gint ret = MM_ERROR_NONE;
5510 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5512 /* check current state */
5513 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5515 /* check pipline building state */
5516 __mmplayer_check_pipeline(player);
5518 switch (MMPLAYER_CURRENT_STATE(player)) {
5519 case MM_PLAYER_STATE_READY:
5521 /* check prepare async or not.
5522 * In the case of streaming playback, it's recommned to avoid blocking wait.
5524 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5525 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5527 /* Changing back sync of rtspsrc to async */
5528 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5529 LOGD("async prepare working mode for rtsp");
5535 case MM_PLAYER_STATE_PLAYING:
5537 /* NOTE : store current point to overcome some bad operation
5538 *(returning zero when getting current position in paused state) of some
5541 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5542 LOGW("getting current position failed in paused");
5544 player->last_position = pos_nsec;
5546 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5547 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5548 This causes problem is position calculation during normal pause resume scenarios also.
5549 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5550 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5551 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5552 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5558 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5559 LOGD("doing async pause in case of ms buff src");
5563 /* pause pipeline */
5564 ret = __mmplayer_gst_pause(player, async);
5566 if (ret != MM_ERROR_NONE)
5567 LOGE("failed to pause player. ret : 0x%x", ret);
5569 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5570 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5571 LOGE("failed to update display_rotation");
5579 /* in case of streaming, pause could take long time.*/
5581 _mmplayer_abort_pause(MMHandleType hplayer)
5583 mmplayer_t *player = (mmplayer_t *)hplayer;
5584 int ret = MM_ERROR_NONE;
5588 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5590 player->pipeline->mainbin,
5591 MM_ERROR_PLAYER_NOT_INITIALIZED);
5593 LOGD("set the pipeline state to READY");
5595 /* set state to READY */
5596 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5597 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5598 if (ret != MM_ERROR_NONE) {
5599 LOGE("fail to change state to READY");
5600 return MM_ERROR_PLAYER_INTERNAL;
5603 LOGD("succeeded in changing state to READY");
5608 _mmplayer_resume(MMHandleType hplayer)
5610 mmplayer_t *player = (mmplayer_t *)hplayer;
5611 int ret = MM_ERROR_NONE;
5612 gboolean async = FALSE;
5616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5618 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5619 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5620 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5624 /* Changing back sync mode rtspsrc to async */
5625 LOGD("async resume for rtsp case");
5629 /* check current state */
5630 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5632 ret = __mmplayer_gst_resume(player, async);
5633 if (ret != MM_ERROR_NONE)
5634 LOGE("failed to resume player.");
5636 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5637 LOGD("force resume even during buffering");
5638 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5647 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5649 mmplayer_t *player = (mmplayer_t *)hplayer;
5650 gint64 pos_nsec = 0;
5651 int ret = MM_ERROR_NONE;
5653 signed long long start = 0, stop = 0;
5654 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5657 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5658 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5660 /* The sound of video is not supported under 0.0 and over 2.0. */
5661 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5662 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5665 _mmplayer_set_mute(hplayer, mute);
5667 if (player->playback_rate == rate)
5668 return MM_ERROR_NONE;
5670 /* If the position is reached at start potion during fast backward, EOS is posted.
5671 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5673 player->playback_rate = rate;
5675 current_state = MMPLAYER_CURRENT_STATE(player);
5677 if (current_state != MM_PLAYER_STATE_PAUSED)
5678 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5680 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5682 if ((current_state == MM_PLAYER_STATE_PAUSED)
5683 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5684 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5685 pos_nsec = player->last_position;
5690 stop = GST_CLOCK_TIME_NONE;
5692 start = GST_CLOCK_TIME_NONE;
5696 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5697 player->playback_rate,
5699 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5700 GST_SEEK_TYPE_SET, start,
5701 GST_SEEK_TYPE_SET, stop)) {
5702 LOGE("failed to set speed playback");
5703 return MM_ERROR_PLAYER_SEEK;
5706 LOGD("succeeded to set speed playback as %0.1f", rate);
5710 return MM_ERROR_NONE;;
5714 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5716 mmplayer_t *player = (mmplayer_t *)hplayer;
5717 int ret = MM_ERROR_NONE;
5721 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5723 /* check pipline building state */
5724 __mmplayer_check_pipeline(player);
5726 ret = __mmplayer_gst_set_position(player, position, FALSE);
5734 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5736 mmplayer_t *player = (mmplayer_t *)hplayer;
5737 int ret = MM_ERROR_NONE;
5739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5741 ret = __mmplayer_gst_get_position(player, position);
5747 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5749 mmplayer_t *player = (mmplayer_t *)hplayer;
5750 int ret = MM_ERROR_NONE;
5752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5753 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5755 if (g_strrstr(player->type, "video/mpegts"))
5756 __mmplayer_update_duration_value(player);
5758 *duration = player->duration;
5763 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5765 mmplayer_t *player = (mmplayer_t *)hplayer;
5766 int ret = MM_ERROR_NONE;
5768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5770 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5776 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5778 mmplayer_t *player = (mmplayer_t *)hplayer;
5779 int ret = MM_ERROR_NONE;
5783 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5785 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5793 __mmplayer_is_midi_type(gchar *str_caps)
5795 if ((g_strrstr(str_caps, "audio/midi")) ||
5796 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5797 (g_strrstr(str_caps, "application/x-smaf")) ||
5798 (g_strrstr(str_caps, "audio/x-imelody")) ||
5799 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5800 (g_strrstr(str_caps, "audio/xmf")) ||
5801 (g_strrstr(str_caps, "audio/mxmf"))) {
5810 __mmplayer_is_only_mp3_type(gchar *str_caps)
5812 if (g_strrstr(str_caps, "application/x-id3") ||
5813 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5819 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5821 GstStructure *caps_structure = NULL;
5822 gint samplerate = 0;
5826 MMPLAYER_RETURN_IF_FAIL(player && caps);
5828 caps_structure = gst_caps_get_structure(caps, 0);
5830 /* set stream information */
5831 gst_structure_get_int(caps_structure, "rate", &samplerate);
5832 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5834 gst_structure_get_int(caps_structure, "channels", &channels);
5835 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5837 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5841 __mmplayer_update_content_type_info(mmplayer_t *player)
5844 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5846 if (__mmplayer_is_midi_type(player->type)) {
5847 player->bypass_audio_effect = TRUE;
5851 if (!player->streamer) {
5852 LOGD("no need to check streaming type");
5856 if (g_strrstr(player->type, "application/x-hls")) {
5857 /* If it can't know exact type when it parses uri because of redirection case,
5858 * it will be fixed by typefinder or when doing autoplugging.
5860 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5861 player->streamer->is_adaptive_streaming = TRUE;
5862 } else if (g_strrstr(player->type, "application/dash+xml")) {
5863 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5864 player->streamer->is_adaptive_streaming = TRUE;
5867 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5868 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5869 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5871 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5872 if (player->streamer->is_adaptive_streaming)
5873 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5875 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5879 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5884 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5885 GstCaps *caps, gpointer data)
5887 mmplayer_t *player = (mmplayer_t *)data;
5892 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5894 /* store type string */
5895 MMPLAYER_FREEIF(player->type);
5896 player->type = gst_caps_to_string(caps);
5898 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5899 player, player->type, probability, gst_caps_get_size(caps));
5901 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5902 (g_strrstr(player->type, "audio/x-raw-int"))) {
5903 LOGE("not support media format");
5905 if (player->msg_posted == FALSE) {
5906 MMMessageParamType msg_param;
5907 memset(&msg_param, 0, sizeof(MMMessageParamType));
5909 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5910 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5912 /* don't post more if one was sent already */
5913 player->msg_posted = TRUE;
5918 __mmplayer_update_content_type_info(player);
5920 pad = gst_element_get_static_pad(tf, "src");
5922 LOGE("fail to get typefind src pad.");
5926 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5927 gboolean async = FALSE;
5928 LOGE("failed to autoplug %s", player->type);
5930 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5932 if (async && player->msg_posted == FALSE)
5933 __mmplayer_handle_missed_plugin(player);
5937 gst_object_unref(GST_OBJECT(pad));
5945 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5947 GstElement *decodebin = NULL;
5951 /* create decodebin */
5952 decodebin = gst_element_factory_make("decodebin", NULL);
5955 LOGE("fail to create decodebin");
5959 /* raw pad handling signal */
5960 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5961 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5963 /* no-more-pad pad handling signal */
5964 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5965 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5967 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5968 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5970 /* This signal is emitted when a pad for which there is no further possible
5971 decoding is added to the decodebin.*/
5972 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5973 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5975 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5976 before looking for any elements that can handle that stream.*/
5977 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5978 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5980 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5981 before looking for any elements that can handle that stream.*/
5982 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5983 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5985 /* This signal is emitted once decodebin has finished decoding all the data.*/
5986 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5987 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5989 /* This signal is emitted when a element is added to the bin.*/
5990 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5991 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5998 __mmplayer_gst_make_queue2(mmplayer_t *player)
6000 GstElement *queue2 = NULL;
6001 gint64 dur_bytes = 0L;
6002 mmplayer_gst_element_t *mainbin = NULL;
6003 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6008 mainbin = player->pipeline->mainbin;
6010 queue2 = gst_element_factory_make("queue2", "queue2");
6012 LOGE("failed to create buffering queue element");
6016 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6017 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6019 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6021 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6022 * skip the pull mode(file or ring buffering) setting. */
6023 if (dur_bytes > 0) {
6024 if (!g_strrstr(player->type, "video/mpegts")) {
6025 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6026 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6032 __mm_player_streaming_set_queue2(player->streamer,
6036 (guint64)dur_bytes); /* no meaning at the moment */
6042 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6044 mmplayer_gst_element_t *mainbin = NULL;
6045 GstElement *decodebin = NULL;
6046 GstElement *queue2 = NULL;
6047 GstPad *sinkpad = NULL;
6048 GstPad *qsrcpad = NULL;
6051 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6053 mainbin = player->pipeline->mainbin;
6055 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6057 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6058 LOGW("need to check: muxed buffer is not null");
6061 queue2 = __mmplayer_gst_make_queue2(player);
6063 LOGE("failed to make queue2");
6067 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6068 LOGE("failed to add buffering queue");
6072 sinkpad = gst_element_get_static_pad(queue2, "sink");
6073 qsrcpad = gst_element_get_static_pad(queue2, "src");
6075 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6076 LOGE("failed to link [%s:%s]-[%s:%s]",
6077 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6081 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6082 LOGE("failed to sync queue2 state with parent");
6086 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6087 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6091 gst_object_unref(GST_OBJECT(sinkpad));
6095 /* create decodebin */
6096 decodebin = __mmplayer_gst_make_decodebin(player);
6098 LOGE("failed to make decodebin");
6102 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6103 LOGE("failed to add decodebin");
6107 /* to force caps on the decodebin element and avoid reparsing stuff by
6108 * typefind. It also avoids a deadlock in the way typefind activates pads in
6109 * the state change */
6110 g_object_set(decodebin, "sink-caps", caps, NULL);
6112 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6114 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6115 LOGE("failed to link [%s:%s]-[%s:%s]",
6116 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6120 gst_object_unref(GST_OBJECT(sinkpad));
6122 gst_object_unref(GST_OBJECT(qsrcpad));
6125 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6126 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6128 /* set decodebin property about buffer in streaming playback. *
6129 * in case of HLS/DASH, it does not need to have big buffer *
6130 * because it is kind of adaptive streaming. */
6131 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6132 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6133 gint high_percent = 0;
6135 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6136 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6138 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6140 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6142 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6143 "high-percent", high_percent,
6144 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6145 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6146 "max-size-buffers", 0, NULL); // disable or automatic
6149 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6150 LOGE("failed to sync decodebin state with parent");
6161 gst_object_unref(GST_OBJECT(sinkpad));
6164 gst_object_unref(GST_OBJECT(qsrcpad));
6167 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6168 * You need to explicitly set elements to the NULL state before
6169 * dropping the final reference, to allow them to clean up.
6171 gst_element_set_state(queue2, GST_STATE_NULL);
6173 /* And, it still has a parent "player".
6174 * You need to let the parent manage the object instead of unreffing the object directly.
6176 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6177 gst_object_unref(queue2);
6182 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6183 * You need to explicitly set elements to the NULL state before
6184 * dropping the final reference, to allow them to clean up.
6186 gst_element_set_state(decodebin, GST_STATE_NULL);
6188 /* And, it still has a parent "player".
6189 * You need to let the parent manage the object instead of unreffing the object directly.
6192 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6193 gst_object_unref(decodebin);
6201 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6205 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6206 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6208 LOGD("class : %s, mime : %s", factory_class, mime);
6210 /* add missing plugin */
6211 /* NOTE : msl should check missing plugin for image mime type.
6212 * Some motion jpeg clips can have playable audio track.
6213 * So, msl have to play audio after displaying popup written video format not supported.
6215 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6216 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6217 LOGD("not found demuxer");
6218 player->not_found_demuxer = TRUE;
6219 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6225 if (!g_strrstr(factory_class, "Demuxer")) {
6226 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6227 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6228 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6230 /* check that clip have multi tracks or not */
6231 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6232 LOGD("video plugin is already linked");
6234 LOGW("add VIDEO to missing plugin");
6235 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6236 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6238 } else if (g_str_has_prefix(mime, "audio")) {
6239 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6240 LOGD("audio plugin is already linked");
6242 LOGW("add AUDIO to missing plugin");
6243 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6244 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6252 return MM_ERROR_NONE;
6256 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6258 mmplayer_t *player = (mmplayer_t *)data;
6262 MMPLAYER_RETURN_IF_FAIL(player);
6264 /* remove fakesink. */
6265 if (!__mmplayer_gst_remove_fakesink(player,
6266 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6267 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6268 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6269 * source element are not same. To overcome this situation, this function will called
6270 * several places and several times. Therefore, this is not an error case.
6275 LOGD("[handle: %p] pipeline has completely constructed", player);
6277 if ((player->ini.async_start) &&
6278 (player->msg_posted == FALSE) &&
6279 (player->cmd >= MMPLAYER_COMMAND_START))
6280 __mmplayer_handle_missed_plugin(player);
6282 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6286 __mmplayer_check_profile(void)
6289 static int profile_tv = -1;
6291 if (__builtin_expect(profile_tv != -1, 1))
6294 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6295 switch (*profileName) {
6310 __mmplayer_get_next_uri(mmplayer_t *player)
6312 mmplayer_parse_profile_t profile;
6314 guint num_of_list = 0;
6317 num_of_list = g_list_length(player->uri_info.uri_list);
6318 uri_idx = player->uri_info.uri_idx;
6320 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6321 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6322 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6324 LOGW("next uri does not exist");
6328 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6329 LOGE("failed to parse profile");
6333 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6334 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6335 LOGW("uri type is not supported(%d)", profile.uri_type);
6339 LOGD("success to find next uri %d", uri_idx);
6343 if (uri_idx == num_of_list) {
6344 LOGE("failed to find next uri");
6348 player->uri_info.uri_idx = uri_idx;
6349 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6351 if (mm_attrs_commit_all(player->attrs)) {
6352 LOGE("failed to commit");
6356 SECURE_LOGD("next playback uri: %s", uri);
6361 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6363 #define REPEAT_COUNT_INFINITELY -1
6364 #define REPEAT_COUNT_MIN 2
6366 MMHandleType attrs = 0;
6370 guint num_of_list = 0;
6371 int profile_tv = -1;
6375 LOGD("checking for gapless play option");
6377 if (player->pipeline->textbin) {
6378 LOGE("subtitle path is enabled. gapless play is not supported.");
6382 attrs = MMPLAYER_GET_ATTRS(player);
6384 LOGE("fail to get attributes.");
6388 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6390 /* gapless playback is not supported in case of video at TV profile. */
6391 profile_tv = __mmplayer_check_profile();
6392 if (profile_tv && video) {
6393 LOGW("not support video gapless playback");
6397 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6398 LOGE("failed to get play count");
6400 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6401 LOGE("failed to get gapless mode");
6403 /* check repeat count in case of audio */
6405 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6406 LOGW("gapless is disabled");
6410 num_of_list = g_list_length(player->uri_info.uri_list);
6412 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6414 if (num_of_list == 0) {
6415 /* audio looping path */
6416 if (count >= REPEAT_COUNT_MIN) {
6417 /* decrease play count */
6418 /* we succeeded to rewind. update play count and then wait for next EOS */
6420 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6421 /* commit attribute */
6422 if (mm_attrs_commit_all(attrs))
6423 LOGE("failed to commit attribute");
6425 } else if (count != REPEAT_COUNT_INFINITELY) {
6426 LOGD("there is no next uri and no repeat");
6429 LOGD("looping cnt %d", count);
6431 /* gapless playback path */
6432 if (!__mmplayer_get_next_uri(player)) {
6433 LOGE("failed to get next uri");
6440 LOGE("unable to play gapless path. EOS will be posted soon");
6445 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6451 player->smooth_streaming = FALSE;
6452 player->videodec_linked = 0;
6453 player->audiodec_linked = 0;
6454 player->textsink_linked = 0;
6455 player->is_external_subtitle_present = FALSE;
6456 player->is_external_subtitle_added_now = FALSE;
6457 player->not_supported_codec = MISSING_PLUGIN_NONE;
6458 player->can_support_codec = FOUND_PLUGIN_NONE;
6459 player->pending_seek.is_pending = false;
6460 player->pending_seek.pos = 0;
6461 player->msg_posted = FALSE;
6462 player->has_many_types = FALSE;
6463 player->no_more_pad = FALSE;
6464 player->not_found_demuxer = 0;
6465 player->seek_state = MMPLAYER_SEEK_NONE;
6466 player->is_subtitle_force_drop = FALSE;
6467 player->play_subtitle = FALSE;
6468 player->adjust_subtitle_pos = 0;
6470 player->total_bitrate = 0;
6471 player->total_maximum_bitrate = 0;
6473 __mmplayer_track_initialize(player);
6474 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6476 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6477 player->bitrate[i] = 0;
6478 player->maximum_bitrate[i] = 0;
6481 if (player->v_stream_caps) {
6482 gst_caps_unref(player->v_stream_caps);
6483 player->v_stream_caps = NULL;
6486 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6488 /* clean found audio decoders */
6489 if (player->audio_decoders) {
6490 GList *a_dec = player->audio_decoders;
6491 for (; a_dec; a_dec = g_list_next(a_dec)) {
6492 gchar *name = a_dec->data;
6493 MMPLAYER_FREEIF(name);
6495 g_list_free(player->audio_decoders);
6496 player->audio_decoders = NULL;
6503 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6505 mmplayer_gst_element_t *mainbin = NULL;
6506 MMMessageParamType msg_param = {0,};
6507 GstElement *element = NULL;
6508 MMHandleType attrs = 0;
6510 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6514 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6515 LOGE("player is not initialized");
6519 mainbin = player->pipeline->mainbin;
6520 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6522 attrs = MMPLAYER_GET_ATTRS(player);
6524 LOGE("fail to get attributes");
6528 /* Initialize Player values */
6529 __mmplayer_initialize_gapless_play(player);
6531 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6533 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6534 LOGE("failed to parse profile");
6535 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6539 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6540 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6541 LOGE("dash or hls is not supportable");
6542 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6546 element = __mmplayer_gst_create_source(player);
6548 LOGE("no source element was created");
6552 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6553 LOGE("failed to add source element to pipeline");
6554 gst_object_unref(GST_OBJECT(element));
6559 /* take source element */
6560 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6561 mainbin[MMPLAYER_M_SRC].gst = element;
6565 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6566 if (player->streamer == NULL) {
6567 player->streamer = __mm_player_streaming_create();
6568 __mm_player_streaming_initialize(player->streamer, TRUE);
6571 elem_idx = MMPLAYER_M_TYPEFIND;
6572 element = gst_element_factory_make("typefind", "typefinder");
6573 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6574 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6576 elem_idx = MMPLAYER_M_AUTOPLUG;
6577 element = __mmplayer_gst_make_decodebin(player);
6580 /* check autoplug element is OK */
6582 LOGE("can not create element(%d)", elem_idx);
6586 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6587 LOGE("failed to add sinkbin to pipeline");
6588 gst_object_unref(GST_OBJECT(element));
6593 mainbin[elem_idx].id = elem_idx;
6594 mainbin[elem_idx].gst = element;
6596 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6597 LOGE("Failed to link src - autoplug(or typefind)");
6601 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6602 LOGE("Failed to change state of src element");
6606 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6607 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6608 LOGE("Failed to change state of decodebin");
6612 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6613 LOGE("Failed to change state of src element");
6618 player->gapless.stream_changed = TRUE;
6619 player->gapless.running = TRUE;
6625 MMPLAYER_PLAYBACK_UNLOCK(player);
6627 if (!player->msg_posted) {
6628 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6629 player->msg_posted = TRUE;
6636 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6638 mmplayer_selector_t *selector = &player->selector[type];
6639 mmplayer_gst_element_t *sinkbin = NULL;
6640 main_element_id_e selectorId = MMPLAYER_M_NUM;
6641 main_element_id_e sinkId = MMPLAYER_M_NUM;
6642 GstPad *srcpad = NULL;
6643 GstPad *sinkpad = NULL;
6644 gboolean send_notice = FALSE;
6647 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6649 LOGD("type %d", type);
6652 case MM_PLAYER_TRACK_TYPE_AUDIO:
6653 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6654 sinkId = MMPLAYER_A_BIN;
6655 sinkbin = player->pipeline->audiobin;
6657 case MM_PLAYER_TRACK_TYPE_VIDEO:
6658 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6659 sinkId = MMPLAYER_V_BIN;
6660 sinkbin = player->pipeline->videobin;
6663 case MM_PLAYER_TRACK_TYPE_TEXT:
6664 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6665 sinkId = MMPLAYER_T_BIN;
6666 sinkbin = player->pipeline->textbin;
6669 LOGE("requested type is not supportable");
6674 if (player->pipeline->mainbin[selectorId].gst) {
6677 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6679 if (selector->event_probe_id != 0)
6680 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6681 selector->event_probe_id = 0;
6683 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6684 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6686 if (srcpad && sinkpad) {
6687 /* after getting drained signal there is no data flows, so no need to do pad_block */
6688 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6689 gst_pad_unlink(srcpad, sinkpad);
6691 /* send custom event to sink pad to handle it at video sink */
6693 LOGD("send custom event to sinkpad");
6694 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6695 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6696 gst_pad_send_event(sinkpad, event);
6700 gst_object_unref(sinkpad);
6703 gst_object_unref(srcpad);
6706 LOGD("selector release");
6708 /* release and unref requests pad from the selector */
6709 for (n = 0; n < selector->channels->len; n++) {
6710 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6711 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6713 g_ptr_array_set_size(selector->channels, 0);
6715 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6716 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6718 player->pipeline->mainbin[selectorId].gst = NULL;
6726 __mmplayer_deactivate_old_path(mmplayer_t *player)
6729 MMPLAYER_RETURN_IF_FAIL(player);
6731 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6732 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6733 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6734 LOGE("deactivate selector error");
6738 __mmplayer_track_destroy(player);
6739 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6741 if (player->streamer) {
6742 __mm_player_streaming_initialize(player->streamer, FALSE);
6743 __mm_player_streaming_destroy(player->streamer);
6744 player->streamer = NULL;
6747 MMPLAYER_PLAYBACK_LOCK(player);
6748 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6755 if (!player->msg_posted) {
6756 MMMessageParamType msg = {0,};
6759 msg.code = MM_ERROR_PLAYER_INTERNAL;
6760 LOGE("gapless_uri_play> deactivate error");
6762 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6763 player->msg_posted = TRUE;
6769 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6771 int result = MM_ERROR_NONE;
6772 mmplayer_t *player = (mmplayer_t *)hplayer;
6775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6777 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6778 if (mm_attrs_commit_all(player->attrs)) {
6779 LOGE("failed to commit the original uri.");
6780 result = MM_ERROR_PLAYER_INTERNAL;
6782 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6783 LOGE("failed to add the original uri in the uri list.");
6791 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6793 mmplayer_t *player = (mmplayer_t *)hplayer;
6794 guint num_of_list = 0;
6798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6799 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6801 if (player->pipeline && player->pipeline->textbin) {
6802 LOGE("subtitle path is enabled.");
6803 return MM_ERROR_PLAYER_INVALID_STATE;
6806 num_of_list = g_list_length(player->uri_info.uri_list);
6808 if (is_first_path) {
6809 if (num_of_list == 0) {
6810 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6811 SECURE_LOGD("add original path : %s", uri);
6813 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6814 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6816 SECURE_LOGD("change original path : %s", uri);
6819 MMHandleType attrs = 0;
6820 attrs = MMPLAYER_GET_ATTRS(player);
6822 if (num_of_list == 0) {
6823 char *original_uri = NULL;
6826 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6828 if (!original_uri) {
6829 LOGE("there is no original uri.");
6830 return MM_ERROR_PLAYER_INVALID_STATE;
6833 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6834 player->uri_info.uri_idx = 0;
6836 SECURE_LOGD("add original path at first : %s", original_uri);
6840 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6841 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6845 return MM_ERROR_NONE;
6849 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6851 mmplayer_t *player = (mmplayer_t *)hplayer;
6852 char *next_uri = NULL;
6853 guint num_of_list = 0;
6856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6858 num_of_list = g_list_length(player->uri_info.uri_list);
6860 if (num_of_list > 0) {
6861 gint uri_idx = player->uri_info.uri_idx;
6863 if (uri_idx < num_of_list-1)
6868 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6869 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6871 *uri = g_strdup(next_uri);
6875 return MM_ERROR_NONE;
6879 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6880 GstCaps *caps, gpointer data)
6882 mmplayer_t *player = (mmplayer_t *)data;
6883 const gchar *klass = NULL;
6884 const gchar *mime = NULL;
6885 gchar *caps_str = NULL;
6887 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6888 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6889 caps_str = gst_caps_to_string(caps);
6891 LOGW("unknown type of caps : %s from %s",
6892 caps_str, GST_ELEMENT_NAME(elem));
6894 MMPLAYER_FREEIF(caps_str);
6896 /* There is no available codec. */
6897 __mmplayer_check_not_supported_codec(player, klass, mime);
6901 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6902 GstCaps *caps, gpointer data)
6904 mmplayer_t *player = (mmplayer_t *)data;
6905 const char *mime = NULL;
6906 gboolean ret = TRUE;
6908 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6909 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6911 if (g_str_has_prefix(mime, "audio")) {
6912 GstStructure *caps_structure = NULL;
6913 gint samplerate = 0;
6915 gchar *caps_str = NULL;
6917 caps_structure = gst_caps_get_structure(caps, 0);
6918 gst_structure_get_int(caps_structure, "rate", &samplerate);
6919 gst_structure_get_int(caps_structure, "channels", &channels);
6921 if ((channels > 0 && samplerate == 0)) {
6922 LOGD("exclude audio...");
6926 caps_str = gst_caps_to_string(caps);
6927 /* set it directly because not sent by TAG */
6928 if (g_strrstr(caps_str, "mobile-xmf"))
6929 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6930 MMPLAYER_FREEIF(caps_str);
6931 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6932 MMMessageParamType msg_param;
6933 memset(&msg_param, 0, sizeof(MMMessageParamType));
6934 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6935 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6936 LOGD("video file is not supported on this device");
6938 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6939 LOGD("already video linked");
6942 LOGD("found new stream");
6949 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6951 gboolean ret = TRUE;
6952 GDBusConnection *conn = NULL;
6954 GVariant *result = NULL;
6955 const gchar *dbus_device_type = NULL;
6956 const gchar *dbus_ret = NULL;
6959 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6961 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6967 result = g_dbus_connection_call_sync(conn,
6968 "org.pulseaudio.Server",
6969 "/org/pulseaudio/StreamManager",
6970 "org.pulseaudio.StreamManager",
6971 "GetCurrentMediaRoutingPath",
6972 g_variant_new("(s)", "out"),
6973 G_VARIANT_TYPE("(ss)"),
6974 G_DBUS_CALL_FLAGS_NONE,
6978 if (!result || err) {
6979 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6985 /* device type is listed in stream-map.json at mmfw-sysconf */
6986 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6988 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6989 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6994 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6995 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6996 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6997 LOGD("audio offload is supportable");
7003 LOGD("audio offload is not supportable");
7007 g_variant_unref(result);
7008 g_object_unref(conn);
7013 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7015 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7016 gint64 position = 0;
7018 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7019 player->pipeline && player->pipeline->mainbin);
7021 MMPLAYER_CMD_LOCK(player);
7022 current_state = MMPLAYER_CURRENT_STATE(player);
7024 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7025 LOGW("getting current position failed in paused");
7027 _mmplayer_unrealize((MMHandleType)player);
7028 _mmplayer_realize((MMHandleType)player);
7030 _mmplayer_set_position((MMHandleType)player, position);
7032 /* async not to be blocked in streaming case */
7033 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
7034 if (mm_attrs_commit_all(player->attrs))
7035 LOGE("failed to commit");
7037 _mmplayer_pause((MMHandleType)player);
7039 if (current_state == MM_PLAYER_STATE_PLAYING)
7040 _mmplayer_start((MMHandleType)player);
7041 MMPLAYER_CMD_UNLOCK(player);
7043 LOGD("rebuilding audio pipeline is completed.");
7046 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7048 mmplayer_t *player = (mmplayer_t *)user_data;
7049 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7050 gboolean is_supportable = FALSE;
7052 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7053 LOGW("failed to get device type");
7055 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7057 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7058 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7059 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7060 LOGD("ignore this dev connected info");
7064 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7065 if (player->build_audio_offload == is_supportable) {
7066 LOGD("keep current pipeline without re-building");
7070 /* rebuild pipeline */
7071 LOGD("re-build pipeline - offload: %d", is_supportable);
7072 player->build_audio_offload = FALSE;
7073 __mmplayer_rebuild_audio_pipeline(player);
7079 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7081 unsigned int id = 0;
7083 if (player->audio_device_cb_id != 0) {
7084 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7088 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7089 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7090 LOGD("added device connected cb (%u)", id);
7091 player->audio_device_cb_id = id;
7093 LOGW("failed to add device connected cb");
7101 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7103 gboolean ret = FALSE;
7104 GstElementFactory *factory = NULL;
7107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7109 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7110 if (!__mmplayer_is_only_mp3_type(player->type))
7113 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7114 LOGD("there is no audio offload sink");
7118 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7119 LOGW("there is no audio device type to support offload");
7123 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7125 LOGW("there is no installed audio offload sink element");
7128 gst_object_unref(factory);
7130 if (!__mmplayer_add_audio_device_connected_cb(player))
7133 if (!__mmplayer_is_audio_offload_device_type(player))
7136 LOGD("audio offload can be built");
7144 static GstAutoplugSelectResult
7145 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7147 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7149 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7150 int audio_offload = 0;
7152 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7153 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7155 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7156 LOGD("expose audio path to build offload output path");
7157 player->build_audio_offload = TRUE;
7158 /* update codec info */
7159 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7160 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7161 player->audiodec_linked = 1;
7163 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7167 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7169 LOGD("audio codec type: %d", codec_type);
7170 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7171 /* sw codec will be skipped */
7172 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7173 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7174 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7175 ret = GST_AUTOPLUG_SELECT_SKIP;
7179 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7180 /* hw codec will be skipped */
7181 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7182 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7183 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7184 ret = GST_AUTOPLUG_SELECT_SKIP;
7189 /* set stream information */
7190 if (!player->audiodec_linked)
7191 __mmplayer_set_audio_attrs(player, caps);
7193 /* update codec info */
7194 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7195 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7196 player->audiodec_linked = 1;
7198 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7200 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7202 LOGD("video codec type: %d", codec_type);
7203 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7204 /* sw codec is skipped */
7205 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7206 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7207 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7208 ret = GST_AUTOPLUG_SELECT_SKIP;
7212 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7213 /* hw codec is skipped */
7214 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7215 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7216 ret = GST_AUTOPLUG_SELECT_SKIP;
7221 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7222 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7224 /* mark video decoder for acquire */
7225 if (player->video_decoder_resource == NULL) {
7226 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7227 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7228 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7229 &player->video_decoder_resource)
7230 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7231 LOGE("could not mark video_decoder resource for acquire");
7232 ret = GST_AUTOPLUG_SELECT_SKIP;
7236 LOGW("video decoder resource is already acquired, skip it.");
7237 ret = GST_AUTOPLUG_SELECT_SKIP;
7241 player->interrupted_by_resource = FALSE;
7242 /* acquire resources for video playing */
7243 if (mm_resource_manager_commit(player->resource_manager)
7244 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7245 LOGE("could not acquire resources for video decoding");
7246 ret = GST_AUTOPLUG_SELECT_SKIP;
7251 /* update codec info */
7252 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7253 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7254 player->videodec_linked = 1;
7262 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7263 GstCaps *caps, GstElementFactory *factory, gpointer data)
7265 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7266 mmplayer_t *player = (mmplayer_t *)data;
7268 gchar *factory_name = NULL;
7269 gchar *caps_str = NULL;
7270 const gchar *klass = NULL;
7273 factory_name = GST_OBJECT_NAME(factory);
7274 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7275 caps_str = gst_caps_to_string(caps);
7277 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7279 /* store type string */
7280 if (player->type == NULL) {
7281 player->type = gst_caps_to_string(caps);
7282 __mmplayer_update_content_type_info(player);
7285 /* filtering exclude keyword */
7286 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7287 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7288 LOGW("skipping [%s] by exculde keyword [%s]",
7289 factory_name, player->ini.exclude_element_keyword[idx]);
7291 result = GST_AUTOPLUG_SELECT_SKIP;
7296 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7297 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7298 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7299 factory_name, player->ini.unsupported_codec_keyword[idx]);
7300 result = GST_AUTOPLUG_SELECT_SKIP;
7305 /* exclude webm format */
7306 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7307 * because webm format is not supportable.
7308 * If webm is disabled in "autoplug-continue", there is no state change
7309 * failure or error because the decodebin will expose the pad directly.
7310 * It make MSL invoke _prepare_async_callback.
7311 * So, we need to disable webm format in "autoplug-select" */
7312 if (caps_str && strstr(caps_str, "webm")) {
7313 LOGW("webm is not supported");
7314 result = GST_AUTOPLUG_SELECT_SKIP;
7318 /* check factory class for filtering */
7319 /* NOTE : msl don't need to use image plugins.
7320 * So, those plugins should be skipped for error handling.
7322 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7323 LOGD("skipping [%s] by not required", factory_name);
7324 result = GST_AUTOPLUG_SELECT_SKIP;
7328 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7329 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7330 // TO CHECK : subtitle if needed, add subparse exception.
7331 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7332 result = GST_AUTOPLUG_SELECT_SKIP;
7336 if (g_strrstr(factory_name, "mpegpsdemux")) {
7337 LOGD("skipping PS container - not support");
7338 result = GST_AUTOPLUG_SELECT_SKIP;
7342 if (g_strrstr(factory_name, "mssdemux"))
7343 player->smooth_streaming = TRUE;
7345 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7346 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7349 GstStructure *str = NULL;
7350 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7352 /* don't make video because of not required */
7353 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7354 (!player->set_mode.video_export)) {
7355 LOGD("no need video decoding, expose pad");
7356 result = GST_AUTOPLUG_SELECT_EXPOSE;
7360 /* get w/h for omx state-tune */
7361 /* FIXME: deprecated? */
7362 str = gst_caps_get_structure(caps, 0);
7363 gst_structure_get_int(str, "width", &width);
7366 if (player->v_stream_caps) {
7367 gst_caps_unref(player->v_stream_caps);
7368 player->v_stream_caps = NULL;
7371 player->v_stream_caps = gst_caps_copy(caps);
7372 LOGD("take caps for video state tune");
7373 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7377 if (g_strrstr(klass, "Codec/Decoder")) {
7378 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7379 if (result != GST_AUTOPLUG_SELECT_TRY) {
7380 LOGW("skip add decoder");
7386 MMPLAYER_FREEIF(caps_str);
7392 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7395 //mmplayer_t *player = (mmplayer_t *)data;
7396 GstCaps *caps = NULL;
7398 LOGD("[Decodebin2] pad-removed signal");
7400 caps = gst_pad_query_caps(new_pad, NULL);
7402 LOGW("query caps is NULL");
7406 gchar *caps_str = NULL;
7407 caps_str = gst_caps_to_string(caps);
7409 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7411 MMPLAYER_FREEIF(caps_str);
7412 gst_caps_unref(caps);
7416 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7418 mmplayer_t *player = (mmplayer_t *)data;
7419 GstIterator *iter = NULL;
7420 GValue item = { 0, };
7422 gboolean done = FALSE;
7423 gboolean is_all_drained = TRUE;
7426 MMPLAYER_RETURN_IF_FAIL(player);
7428 LOGD("__mmplayer_gst_decode_drained");
7430 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7431 LOGW("Fail to get cmd lock");
7435 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7436 !__mmplayer_verify_gapless_play_path(player)) {
7437 LOGD("decoding is finished.");
7438 __mmplayer_reset_gapless_state(player);
7439 MMPLAYER_CMD_UNLOCK(player);
7443 player->gapless.reconfigure = TRUE;
7445 /* check decodebin src pads whether they received EOS or not */
7446 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7449 switch (gst_iterator_next(iter, &item)) {
7450 case GST_ITERATOR_OK:
7451 pad = g_value_get_object(&item);
7452 if (pad && !GST_PAD_IS_EOS(pad)) {
7453 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7454 is_all_drained = FALSE;
7457 g_value_reset(&item);
7459 case GST_ITERATOR_RESYNC:
7460 gst_iterator_resync(iter);
7462 case GST_ITERATOR_ERROR:
7463 case GST_ITERATOR_DONE:
7468 g_value_unset(&item);
7469 gst_iterator_free(iter);
7471 if (!is_all_drained) {
7472 LOGD("Wait util the all pads get EOS.");
7473 MMPLAYER_CMD_UNLOCK(player);
7478 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7479 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7481 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7482 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7483 __mmplayer_deactivate_old_path(player);
7484 MMPLAYER_CMD_UNLOCK(player);
7490 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7492 mmplayer_t *player = (mmplayer_t *)data;
7493 const gchar *klass = NULL;
7494 gchar *factory_name = NULL;
7496 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7497 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7499 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7501 if (__mmplayer_add_dump_buffer_probe(player, element))
7502 LOGD("add buffer probe");
7504 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7505 gchar *selected = NULL;
7506 selected = g_strdup(GST_ELEMENT_NAME(element));
7507 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7510 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7511 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7512 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7514 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7515 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7517 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7518 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7519 "max-video-width", player->adaptive_info.limit.width,
7520 "max-video-height", player->adaptive_info.limit.height, NULL);
7522 } else if (g_strrstr(klass, "Demuxer")) {
7523 //LOGD("plugged element is demuxer. take it");
7524 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7525 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7528 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7529 int surface_type = 0;
7531 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7534 // to support trust-zone only
7535 if (g_strrstr(factory_name, "asfdemux")) {
7536 LOGD("set file-location %s", player->profile.uri);
7537 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7538 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7539 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7540 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7541 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7542 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7543 (__mmplayer_is_only_mp3_type(player->type))) {
7544 LOGD("[mpegaudioparse] set streaming pull mode.");
7545 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7547 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7548 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7551 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7552 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7553 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7555 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7556 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7558 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7559 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7560 (MMPLAYER_IS_DASH_STREAMING(player))) {
7561 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7562 __mm_player_streaming_set_multiqueue(player->streamer, element);
7563 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7572 __mmplayer_release_misc(mmplayer_t *player)
7575 bool cur_mode = player->set_mode.rich_audio;
7578 MMPLAYER_RETURN_IF_FAIL(player);
7580 player->video_decoded_cb = NULL;
7581 player->video_decoded_cb_user_param = NULL;
7582 player->video_stream_prerolled = false;
7584 player->audio_decoded_cb = NULL;
7585 player->audio_decoded_cb_user_param = NULL;
7586 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7588 player->video_stream_changed_cb = NULL;
7589 player->video_stream_changed_cb_user_param = NULL;
7591 player->audio_stream_changed_cb = NULL;
7592 player->audio_stream_changed_cb_user_param = NULL;
7594 player->sent_bos = FALSE;
7595 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7597 player->seek_state = MMPLAYER_SEEK_NONE;
7599 player->total_bitrate = 0;
7600 player->total_maximum_bitrate = 0;
7602 player->not_found_demuxer = 0;
7604 player->last_position = 0;
7605 player->duration = 0;
7606 player->http_content_size = 0;
7607 player->not_supported_codec = MISSING_PLUGIN_NONE;
7608 player->can_support_codec = FOUND_PLUGIN_NONE;
7609 player->pending_seek.is_pending = false;
7610 player->pending_seek.pos = 0;
7611 player->msg_posted = FALSE;
7612 player->has_many_types = FALSE;
7613 player->is_subtitle_force_drop = FALSE;
7614 player->play_subtitle = FALSE;
7615 player->adjust_subtitle_pos = 0;
7616 player->has_closed_caption = FALSE;
7617 player->set_mode.video_export = false;
7618 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7619 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7621 player->set_mode.rich_audio = cur_mode;
7623 if (player->audio_device_cb_id > 0 &&
7624 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7625 LOGW("failed to remove audio device_connected_callback");
7626 player->audio_device_cb_id = 0;
7628 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7629 player->bitrate[i] = 0;
7630 player->maximum_bitrate[i] = 0;
7633 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7635 /* remove media stream cb(appsrc cb) */
7636 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7637 player->media_stream_buffer_status_cb[i] = NULL;
7638 player->media_stream_seek_data_cb[i] = NULL;
7639 player->buffer_cb_user_param[i] = NULL;
7640 player->seek_cb_user_param[i] = NULL;
7642 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7644 /* free memory related to audio effect */
7645 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7647 if (player->adaptive_info.var_list) {
7648 g_list_free_full(player->adaptive_info.var_list, g_free);
7649 player->adaptive_info.var_list = NULL;
7652 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7653 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7654 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7656 /* Reset video360 settings to their defaults in case if the pipeline is to be
7659 player->video360_metadata.is_spherical = -1;
7660 player->is_openal_plugin_used = FALSE;
7662 player->is_content_spherical = FALSE;
7663 player->is_video360_enabled = TRUE;
7664 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7665 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7666 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7667 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7668 player->video360_zoom = 1.0f;
7669 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7670 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7672 player->sound.rg_enable = false;
7674 __mmplayer_initialize_video_roi(player);
7679 __mmplayer_release_misc_post(mmplayer_t *player)
7681 char *original_uri = NULL;
7684 /* player->pipeline is already released before. */
7686 MMPLAYER_RETURN_IF_FAIL(player);
7688 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7690 /* clean found audio decoders */
7691 if (player->audio_decoders) {
7692 GList *a_dec = player->audio_decoders;
7693 for (; a_dec; a_dec = g_list_next(a_dec)) {
7694 gchar *name = a_dec->data;
7695 MMPLAYER_FREEIF(name);
7697 g_list_free(player->audio_decoders);
7698 player->audio_decoders = NULL;
7701 /* clean the uri list except original uri */
7702 if (player->uri_info.uri_list) {
7703 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7705 if (player->attrs) {
7706 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7707 LOGD("restore original uri = %s", original_uri);
7709 if (mm_attrs_commit_all(player->attrs))
7710 LOGE("failed to commit the original uri.");
7713 GList *uri_list = player->uri_info.uri_list;
7714 for (; uri_list; uri_list = g_list_next(uri_list)) {
7715 gchar *uri = uri_list->data;
7716 MMPLAYER_FREEIF(uri);
7718 g_list_free(player->uri_info.uri_list);
7719 player->uri_info.uri_list = NULL;
7722 /* clear the audio stream buffer list */
7723 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7725 /* clear the video stream bo list */
7726 __mmplayer_video_stream_destroy_bo_list(player);
7727 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7729 if (player->profile.input_mem.buf) {
7730 free(player->profile.input_mem.buf);
7731 player->profile.input_mem.buf = NULL;
7733 player->profile.input_mem.len = 0;
7734 player->profile.input_mem.offset = 0;
7736 player->uri_info.uri_idx = 0;
7741 __mmplayer_check_subtitle(mmplayer_t *player)
7743 MMHandleType attrs = 0;
7744 char *subtitle_uri = NULL;
7748 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7750 /* get subtitle attribute */
7751 attrs = MMPLAYER_GET_ATTRS(player);
7755 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7756 if (!subtitle_uri || !strlen(subtitle_uri))
7759 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7760 player->is_external_subtitle_present = TRUE;
7768 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7770 MMPLAYER_RETURN_IF_FAIL(player);
7772 if (player->eos_timer) {
7773 LOGD("cancel eos timer");
7774 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7775 player->eos_timer = 0;
7782 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7786 MMPLAYER_RETURN_IF_FAIL(player);
7787 MMPLAYER_RETURN_IF_FAIL(sink);
7789 player->sink_elements = g_list_append(player->sink_elements, sink);
7795 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7799 MMPLAYER_RETURN_IF_FAIL(player);
7800 MMPLAYER_RETURN_IF_FAIL(sink);
7802 player->sink_elements = g_list_remove(player->sink_elements, sink);
7808 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7809 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7811 mmplayer_signal_item_t *item = NULL;
7814 MMPLAYER_RETURN_IF_FAIL(player);
7816 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7817 LOGE("invalid signal type [%d]", type);
7821 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7823 LOGE("cannot connect signal [%s]", signal);
7828 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7829 player->signals[type] = g_list_append(player->signals[type], item);
7835 /* NOTE : be careful with calling this api. please refer to below glib comment
7836 * glib comment : Note that there is a bug in GObject that makes this function much
7837 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7838 * will no longer be called, but, the signal handler is not currently disconnected.
7839 * If the instance is itself being freed at the same time than this doesn't matter,
7840 * since the signal will automatically be removed, but if instance persists,
7841 * then the signal handler will leak. You should not remove the signal yourself
7842 * because in a future versions of GObject, the handler will automatically be
7845 * It's possible to work around this problem in a way that will continue to work
7846 * with future versions of GObject by checking that the signal handler is still
7847 * connected before disconnected it:
7849 * if (g_signal_handler_is_connected(instance, id))
7850 * g_signal_handler_disconnect(instance, id);
7853 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7855 GList *sig_list = NULL;
7856 mmplayer_signal_item_t *item = NULL;
7860 MMPLAYER_RETURN_IF_FAIL(player);
7862 LOGD("release signals type : %d", type);
7864 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7865 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7866 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7867 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7868 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7869 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7873 sig_list = player->signals[type];
7875 for (; sig_list; sig_list = sig_list->next) {
7876 item = sig_list->data;
7878 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7879 if (g_signal_handler_is_connected(item->obj, item->sig))
7880 g_signal_handler_disconnect(item->obj, item->sig);
7883 MMPLAYER_FREEIF(item);
7886 g_list_free(player->signals[type]);
7887 player->signals[type] = NULL;
7895 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7897 mmplayer_t *player = 0;
7898 int prev_display_surface_type = 0;
7899 void *prev_display_overlay = NULL;
7903 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7904 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7906 player = MM_PLAYER_CAST(handle);
7908 /* check video sinkbin is created */
7909 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7910 LOGE("Videosink is already created");
7911 return MM_ERROR_NONE;
7914 LOGD("videosink element is not yet ready");
7916 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7917 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7919 return MM_ERROR_INVALID_ARGUMENT;
7922 /* load previous attributes */
7923 if (player->attrs) {
7924 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7925 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7926 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7927 if (prev_display_surface_type == surface_type) {
7928 LOGD("incoming display surface type is same as previous one, do nothing..");
7930 return MM_ERROR_NONE;
7933 LOGE("failed to load attributes");
7935 return MM_ERROR_PLAYER_INTERNAL;
7938 /* videobin is not created yet, so we just set attributes related to display surface */
7939 LOGD("store display attribute for given surface type(%d)", surface_type);
7940 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7941 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7942 if (mm_attrs_commit_all(player->attrs)) {
7943 LOGE("failed to commit attribute");
7945 return MM_ERROR_PLAYER_INTERNAL;
7949 return MM_ERROR_NONE;
7952 /* Note : if silent is true, then subtitle would not be displayed. :*/
7954 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7956 mmplayer_t *player = (mmplayer_t *)hplayer;
7960 /* check player handle */
7961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7963 player->set_mode.subtitle_off = silent;
7965 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7969 return MM_ERROR_NONE;
7973 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7975 mmplayer_gst_element_t *mainbin = NULL;
7976 mmplayer_gst_element_t *textbin = NULL;
7977 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7978 GstState current_state = GST_STATE_VOID_PENDING;
7979 GstState element_state = GST_STATE_VOID_PENDING;
7980 GstState element_pending_state = GST_STATE_VOID_PENDING;
7982 GstEvent *event = NULL;
7983 int result = MM_ERROR_NONE;
7985 GstClock *curr_clock = NULL;
7986 GstClockTime base_time, start_time, curr_time;
7991 /* check player handle */
7992 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7994 player->pipeline->mainbin &&
7995 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7997 mainbin = player->pipeline->mainbin;
7998 textbin = player->pipeline->textbin;
8000 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8002 // sync clock with current pipeline
8003 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8004 curr_time = gst_clock_get_time(curr_clock);
8006 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8007 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8009 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8010 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8012 if (current_state > GST_STATE_READY) {
8013 // sync state with current pipeline
8014 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8015 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8016 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8018 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8019 if (GST_STATE_CHANGE_FAILURE == ret) {
8020 LOGE("fail to state change.");
8021 result = MM_ERROR_PLAYER_INTERNAL;
8025 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8026 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8029 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8030 gst_object_unref(curr_clock);
8033 // seek to current position
8034 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8035 result = MM_ERROR_PLAYER_INVALID_STATE;
8036 LOGE("gst_element_query_position failed, invalid state");
8040 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8041 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);
8043 __mmplayer_gst_send_event_to_sink(player, event);
8045 result = MM_ERROR_PLAYER_INTERNAL;
8046 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8050 /* sync state with current pipeline */
8051 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8052 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8053 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8055 return MM_ERROR_NONE;
8058 /* release text pipeline resource */
8059 player->textsink_linked = 0;
8061 /* release signal */
8062 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8064 /* release textbin with it's childs */
8065 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8066 MMPLAYER_FREEIF(player->pipeline->textbin);
8067 player->pipeline->textbin = NULL;
8069 /* release subtitle elem */
8070 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8071 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8077 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8079 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8080 GstState current_state = GST_STATE_VOID_PENDING;
8082 MMHandleType attrs = 0;
8083 mmplayer_gst_element_t *mainbin = NULL;
8084 mmplayer_gst_element_t *textbin = NULL;
8086 gchar *subtitle_uri = NULL;
8087 int result = MM_ERROR_NONE;
8088 const gchar *charset = NULL;
8092 /* check player handle */
8093 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8095 player->pipeline->mainbin &&
8096 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8097 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8099 mainbin = player->pipeline->mainbin;
8100 textbin = player->pipeline->textbin;
8102 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8103 if (current_state < GST_STATE_READY) {
8104 result = MM_ERROR_PLAYER_INVALID_STATE;
8105 LOGE("Pipeline is not in proper state");
8109 attrs = MMPLAYER_GET_ATTRS(player);
8111 LOGE("cannot get content attribute");
8112 result = MM_ERROR_PLAYER_INTERNAL;
8116 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8117 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8118 LOGE("subtitle uri is not proper filepath");
8119 result = MM_ERROR_PLAYER_INVALID_URI;
8123 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8124 LOGE("failed to get storage info of subtitle path");
8125 result = MM_ERROR_PLAYER_INVALID_URI;
8129 LOGD("old subtitle file path is [%s]", subtitle_uri);
8130 LOGD("new subtitle file path is [%s]", filepath);
8132 if (!strcmp(filepath, subtitle_uri)) {
8133 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8136 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8137 if (mm_attrs_commit_all(player->attrs)) {
8138 LOGE("failed to commit.");
8143 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8144 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8145 player->subtitle_language_list = NULL;
8146 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8148 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8149 if (ret != GST_STATE_CHANGE_SUCCESS) {
8150 LOGE("failed to change state of textbin to READY");
8151 result = MM_ERROR_PLAYER_INTERNAL;
8155 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8156 if (ret != GST_STATE_CHANGE_SUCCESS) {
8157 LOGE("failed to change state of subparse to READY");
8158 result = MM_ERROR_PLAYER_INTERNAL;
8162 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8163 if (ret != GST_STATE_CHANGE_SUCCESS) {
8164 LOGE("failed to change state of filesrc to READY");
8165 result = MM_ERROR_PLAYER_INTERNAL;
8169 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8171 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8173 charset = util_get_charset(filepath);
8175 LOGD("detected charset is %s", charset);
8176 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8179 result = _mmplayer_sync_subtitle_pipeline(player);
8186 /* API to switch between external subtitles */
8188 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8190 int result = MM_ERROR_NONE;
8191 mmplayer_t *player = (mmplayer_t *)hplayer;
8196 /* check player handle */
8197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8199 /* filepath can be null in idle state */
8201 /* check file path */
8202 if ((path = strstr(filepath, "file://")))
8203 result = util_exist_file_path(path + 7);
8205 result = util_exist_file_path(filepath);
8207 if (result != MM_ERROR_NONE) {
8208 LOGE("invalid subtitle path 0x%X", result);
8209 return result; /* file not found or permission denied */
8213 if (!player->pipeline) {
8215 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8216 if (mm_attrs_commit_all(player->attrs)) {
8217 LOGE("failed to commit"); /* subtitle path will not be created */
8218 return MM_ERROR_PLAYER_INTERNAL;
8221 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8222 /* check filepath */
8223 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8225 if (!__mmplayer_check_subtitle(player)) {
8226 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8227 if (mm_attrs_commit_all(player->attrs)) {
8228 LOGE("failed to commit");
8229 return MM_ERROR_PLAYER_INTERNAL;
8232 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8233 LOGE("fail to create text pipeline");
8234 return MM_ERROR_PLAYER_INTERNAL;
8237 result = _mmplayer_sync_subtitle_pipeline(player);
8239 result = __mmplayer_change_external_subtitle_language(player, filepath);
8242 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8243 player->is_external_subtitle_added_now = TRUE;
8245 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8246 if (!player->subtitle_language_list) {
8247 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8248 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8249 LOGW("subtitle language list is not updated yet");
8251 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8259 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8261 int result = MM_ERROR_NONE;
8262 gchar *change_pad_name = NULL;
8263 GstPad *sinkpad = NULL;
8264 mmplayer_gst_element_t *mainbin = NULL;
8265 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8266 GstCaps *caps = NULL;
8267 gint total_track_num = 0;
8271 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8272 MM_ERROR_PLAYER_NOT_INITIALIZED);
8274 LOGD("Change Track(%d) to %d", type, index);
8276 mainbin = player->pipeline->mainbin;
8278 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8279 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8280 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8281 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8283 /* Changing Video Track is not supported. */
8284 LOGE("Track Type Error");
8288 if (mainbin[elem_idx].gst == NULL) {
8289 result = MM_ERROR_PLAYER_NO_OP;
8290 LOGD("Req track doesn't exist");
8294 total_track_num = player->selector[type].total_track_num;
8295 if (total_track_num <= 0) {
8296 result = MM_ERROR_PLAYER_NO_OP;
8297 LOGD("Language list is not available");
8301 if ((index < 0) || (index >= total_track_num)) {
8302 result = MM_ERROR_INVALID_ARGUMENT;
8303 LOGD("Not a proper index : %d", index);
8307 /*To get the new pad from the selector*/
8308 change_pad_name = g_strdup_printf("sink_%u", index);
8309 if (change_pad_name == NULL) {
8310 result = MM_ERROR_PLAYER_INTERNAL;
8311 LOGD("Pad does not exists");
8315 LOGD("new active pad name: %s", change_pad_name);
8317 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8318 if (sinkpad == NULL) {
8319 LOGD("sinkpad is NULL");
8320 result = MM_ERROR_PLAYER_INTERNAL;
8324 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8325 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8327 caps = gst_pad_get_current_caps(sinkpad);
8328 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8331 gst_object_unref(sinkpad);
8333 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8334 __mmplayer_set_audio_attrs(player, caps);
8337 MMPLAYER_FREEIF(change_pad_name);
8342 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8344 int result = MM_ERROR_NONE;
8345 mmplayer_t *player = NULL;
8346 mmplayer_gst_element_t *mainbin = NULL;
8348 gint current_active_index = 0;
8350 GstState current_state = GST_STATE_VOID_PENDING;
8351 GstEvent *event = NULL;
8356 player = (mmplayer_t *)hplayer;
8357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8359 if (!player->pipeline) {
8360 LOGE("Track %d pre setting -> %d", type, index);
8362 player->selector[type].active_pad_index = index;
8366 mainbin = player->pipeline->mainbin;
8368 current_active_index = player->selector[type].active_pad_index;
8370 /*If index is same as running index no need to change the pad*/
8371 if (current_active_index == index)
8374 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8375 result = MM_ERROR_PLAYER_INVALID_STATE;
8379 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8380 if (current_state < GST_STATE_PAUSED) {
8381 result = MM_ERROR_PLAYER_INVALID_STATE;
8382 LOGW("Pipeline not in porper state");
8386 result = __mmplayer_change_selector_pad(player, type, index);
8387 if (result != MM_ERROR_NONE) {
8388 LOGE("change selector pad error");
8392 player->selector[type].active_pad_index = index;
8394 if (current_state == GST_STATE_PLAYING) {
8395 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8396 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8397 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8399 __mmplayer_gst_send_event_to_sink(player, event);
8401 result = MM_ERROR_PLAYER_INTERNAL;
8411 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8413 mmplayer_t *player = (mmplayer_t *)hplayer;
8417 /* check player handle */
8418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8420 *silent = player->set_mode.subtitle_off;
8422 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8426 return MM_ERROR_NONE;
8430 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8432 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8433 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8435 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8436 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8440 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8441 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8442 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8443 mmplayer_dump_t *dump_s;
8444 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8445 if (dump_s == NULL) {
8446 LOGE("malloc fail");
8450 dump_s->dump_element_file = NULL;
8451 dump_s->dump_pad = NULL;
8452 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8454 if (dump_s->dump_pad) {
8455 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8456 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]);
8457 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8458 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);
8459 /* add list for removed buffer probe and close FILE */
8460 player->dump_list = g_list_append(player->dump_list, dump_s);
8461 LOGD("%s sink pad added buffer probe for dump", factory_name);
8464 MMPLAYER_FREEIF(dump_s);
8465 LOGE("failed to get %s sink pad added", factory_name);
8472 static GstPadProbeReturn
8473 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8475 FILE *dump_data = (FILE *)u_data;
8477 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8478 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8480 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8482 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8484 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8486 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8488 gst_buffer_unmap(buffer, &probe_info);
8490 return GST_PAD_PROBE_OK;
8494 __mmplayer_release_dump_list(GList *dump_list)
8496 GList *d_list = dump_list;
8501 for (; d_list; d_list = g_list_next(d_list)) {
8502 mmplayer_dump_t *dump_s = d_list->data;
8503 if (dump_s->dump_pad) {
8504 if (dump_s->probe_handle_id)
8505 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8506 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8508 if (dump_s->dump_element_file) {
8509 fclose(dump_s->dump_element_file);
8510 dump_s->dump_element_file = NULL;
8512 MMPLAYER_FREEIF(dump_s);
8514 g_list_free(dump_list);
8519 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8521 mmplayer_t *player = (mmplayer_t *)hplayer;
8525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8528 *exist = (bool)player->has_closed_caption;
8532 return MM_ERROR_NONE;
8536 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8540 // LOGD("unref internal gst buffer %p", buffer);
8541 gst_buffer_unref((GstBuffer *)buffer);
8548 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8550 mmplayer_t *player = (mmplayer_t *)hplayer;
8554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8557 if (MMPLAYER_IS_STREAMING(player))
8558 *timeout = (int)player->ini.live_state_change_timeout;
8560 *timeout = (int)player->ini.localplayback_state_change_timeout;
8562 LOGD("timeout = %d", *timeout);
8565 return MM_ERROR_NONE;
8569 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8571 mmplayer_t *player = (mmplayer_t *)hplayer;
8575 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8576 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8578 *num = player->video_num_buffers;
8579 *extra_num = player->video_extra_num_buffers;
8581 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8584 return MM_ERROR_NONE;
8588 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8592 MMPLAYER_RETURN_IF_FAIL(player);
8594 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8596 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8597 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8598 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8599 player->storage_info[i].id = -1;
8600 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8602 if (path_type != MMPLAYER_PATH_MAX)
8611 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8613 int ret = MM_ERROR_NONE;
8614 mmplayer_t *player = (mmplayer_t *)hplayer;
8615 MMMessageParamType msg_param = {0, };
8618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 LOGW("state changed storage %d:%d", id, state);
8622 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8623 return MM_ERROR_NONE;
8625 /* FIXME: text path should be handled seperately. */
8626 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8627 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8628 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8629 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8630 LOGW("external storage is removed");
8632 if (player->msg_posted == FALSE) {
8633 memset(&msg_param, 0, sizeof(MMMessageParamType));
8634 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8635 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8636 player->msg_posted = TRUE;
8639 /* unrealize the player */
8640 ret = _mmplayer_unrealize(hplayer);
8641 if (ret != MM_ERROR_NONE)
8642 LOGE("failed to unrealize");
8650 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8652 int ret = MM_ERROR_NONE;
8653 mmplayer_t *player = (mmplayer_t *)hplayer;
8654 int idx = 0, total = 0;
8655 gchar *result = NULL, *tmp = NULL;
8658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8659 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8661 total = *num = g_list_length(player->adaptive_info.var_list);
8663 LOGW("There is no stream variant info.");
8667 result = g_strdup("");
8668 for (idx = 0 ; idx < total ; idx++) {
8669 stream_variant_t *v_data = NULL;
8670 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8673 gchar data[64] = {0};
8674 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8676 tmp = g_strconcat(result, data, NULL);
8680 LOGW("There is no variant data in %d", idx);
8685 *var_info = (char *)result;
8687 LOGD("variant info %d:%s", *num, *var_info);
8693 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8695 int ret = MM_ERROR_NONE;
8696 mmplayer_t *player = (mmplayer_t *)hplayer;
8699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8701 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8703 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8704 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8705 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8707 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8708 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8709 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8710 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8712 /* FIXME: seek to current position for applying new variant limitation */
8721 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8723 int ret = MM_ERROR_NONE;
8724 mmplayer_t *player = (mmplayer_t *)hplayer;
8727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8728 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8730 *bandwidth = player->adaptive_info.limit.bandwidth;
8731 *width = player->adaptive_info.limit.width;
8732 *height = player->adaptive_info.limit.height;
8734 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8741 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8743 int ret = MM_ERROR_NONE;
8744 mmplayer_t *player = (mmplayer_t *)hplayer;
8747 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8748 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8749 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8751 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8753 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8754 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8755 else /* live case */
8756 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8758 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8765 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8767 #define IDX_FIRST_SW_CODEC 0
8768 mmplayer_t *player = (mmplayer_t *)hplayer;
8769 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8770 MMHandleType attrs = 0;
8773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8775 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8776 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8777 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8779 switch (stream_type) {
8780 case MM_PLAYER_STREAM_TYPE_AUDIO:
8781 /* to support audio codec selection, codec info have to be added in ini file as below.
8782 audio codec element hw = xxxx
8783 audio codec element sw = avdec */
8784 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8785 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8786 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8787 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8788 LOGE("There is no audio codec info for codec_type %d", codec_type);
8789 return MM_ERROR_PLAYER_NO_OP;
8792 case MM_PLAYER_STREAM_TYPE_VIDEO:
8793 /* to support video codec selection, codec info have to be added in ini file as below.
8794 video codec element hw = omx
8795 video codec element sw = avdec */
8796 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8797 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8798 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8799 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8800 LOGE("There is no video codec info for codec_type %d", codec_type);
8801 return MM_ERROR_PLAYER_NO_OP;
8805 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8806 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8810 LOGD("update %s codec_type to %d", attr_name, codec_type);
8812 attrs = MMPLAYER_GET_ATTRS(player);
8813 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8815 if (mm_attrs_commit_all(player->attrs)) {
8816 LOGE("failed to commit codec_type attributes");
8817 return MM_ERROR_PLAYER_INTERNAL;
8821 return MM_ERROR_NONE;
8825 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8827 mmplayer_t *player = (mmplayer_t *)hplayer;
8828 GstElement *rg_vol_element = NULL;
8832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834 player->sound.rg_enable = enabled;
8836 /* just hold rgvolume enable value if pipeline is not ready */
8837 if (!player->pipeline || !player->pipeline->audiobin) {
8838 LOGD("pipeline is not ready. holding rgvolume enable value");
8839 return MM_ERROR_NONE;
8842 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8844 if (!rg_vol_element) {
8845 LOGD("rgvolume element is not created");
8846 return MM_ERROR_PLAYER_INTERNAL;
8850 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8852 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8856 return MM_ERROR_NONE;
8860 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8862 mmplayer_t *player = (mmplayer_t *)hplayer;
8863 GstElement *rg_vol_element = NULL;
8864 gboolean enable = FALSE;
8868 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8869 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8871 /* just hold enable_rg value if pipeline is not ready */
8872 if (!player->pipeline || !player->pipeline->audiobin) {
8873 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8874 *enabled = player->sound.rg_enable;
8875 return MM_ERROR_NONE;
8878 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8880 if (!rg_vol_element) {
8881 LOGD("rgvolume element is not created");
8882 return MM_ERROR_PLAYER_INTERNAL;
8885 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8886 *enabled = (bool)enable;
8890 return MM_ERROR_NONE;
8894 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8896 mmplayer_t *player = (mmplayer_t *)hplayer;
8897 MMHandleType attrs = 0;
8898 void *handle = NULL;
8899 int ret = MM_ERROR_NONE;
8903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8905 attrs = MMPLAYER_GET_ATTRS(player);
8906 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8908 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8910 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8911 return MM_ERROR_PLAYER_INTERNAL;
8914 player->video_roi.scale_x = scale_x;
8915 player->video_roi.scale_y = scale_y;
8916 player->video_roi.scale_width = scale_width;
8917 player->video_roi.scale_height = scale_height;
8919 /* check video sinkbin is created */
8920 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8921 return MM_ERROR_NONE;
8923 if (!gst_video_overlay_set_video_roi_area(
8924 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8925 scale_x, scale_y, scale_width, scale_height))
8926 ret = MM_ERROR_PLAYER_INTERNAL;
8928 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8929 scale_x, scale_y, scale_width, scale_height);
8937 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8939 mmplayer_t *player = (mmplayer_t *)hplayer;
8940 int ret = MM_ERROR_NONE;
8944 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8945 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8947 *scale_x = player->video_roi.scale_x;
8948 *scale_y = player->video_roi.scale_y;
8949 *scale_width = player->video_roi.scale_width;
8950 *scale_height = player->video_roi.scale_height;
8952 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8953 *scale_x, *scale_y, *scale_width, *scale_height);
8959 __mmplayer_update_duration_value(mmplayer_t *player)
8961 gboolean ret = FALSE;
8962 gint64 dur_nsec = 0;
8963 LOGD("try to update duration");
8965 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8966 player->duration = dur_nsec;
8967 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8971 if (player->duration < 0) {
8972 LOGW("duration is Non-Initialized !!!");
8973 player->duration = 0;
8976 /* update streaming service type */
8977 player->streaming_type = __mmplayer_get_stream_service_type(player);
8979 /* check duration is OK */
8980 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8981 /* FIXIT : find another way to get duration here. */
8982 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8988 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8990 /* update audio params
8991 NOTE : We need original audio params and it can be only obtained from src pad of audio
8992 decoder. Below code only valid when we are not using 'resampler' just before
8993 'audioconverter'. */
8994 GstCaps *caps_a = NULL;
8996 gint samplerate = 0, channels = 0;
8997 GstStructure *p = NULL;
8998 GstElement *aconv = NULL;
9000 LOGD("try to update audio attrs");
9002 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9004 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9005 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9006 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9007 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9009 LOGE("there is no audio converter");
9013 pad = gst_element_get_static_pad(aconv, "sink");
9016 LOGW("failed to get pad from audio converter");
9020 caps_a = gst_pad_get_current_caps(pad);
9022 LOGW("not ready to get audio caps");
9023 gst_object_unref(pad);
9027 p = gst_caps_get_structure(caps_a, 0);
9029 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9031 gst_structure_get_int(p, "rate", &samplerate);
9032 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
9034 gst_structure_get_int(p, "channels", &channels);
9035 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
9037 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9039 gst_caps_unref(caps_a);
9040 gst_object_unref(pad);
9046 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9048 LOGD("try to update video attrs");
9050 GstCaps *caps_v = NULL;
9054 GstStructure *p = NULL;
9056 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9057 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9059 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9061 LOGD("no videosink sink pad");
9065 caps_v = gst_pad_get_current_caps(pad);
9066 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9067 if (!caps_v && player->v_stream_caps) {
9068 caps_v = player->v_stream_caps;
9069 gst_caps_ref(caps_v);
9073 LOGD("no negitiated caps from videosink");
9074 gst_object_unref(pad);
9078 p = gst_caps_get_structure(caps_v, 0);
9079 gst_structure_get_int(p, "width", &width);
9080 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
9082 gst_structure_get_int(p, "height", &height);
9083 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
9085 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9087 SECURE_LOGD("width : %d height : %d", width, height);
9089 gst_caps_unref(caps_v);
9090 gst_object_unref(pad);
9093 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
9094 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9101 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9103 gboolean ret = FALSE;
9104 guint64 data_size = 0;
9108 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9109 if (!player->duration)
9112 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9113 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9114 if (stat(path, &sb) == 0)
9115 data_size = (guint64)sb.st_size;
9117 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9118 data_size = player->http_content_size;
9121 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9124 guint64 bitrate = 0;
9125 guint64 msec_dur = 0;
9127 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9129 bitrate = data_size * 8 * 1000 / msec_dur;
9130 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9131 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9135 LOGD("player duration is less than 0");
9139 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9140 if (player->total_bitrate) {
9141 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9150 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9152 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9153 data->uri_type = uri_type;
9157 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9159 int ret = MM_ERROR_PLAYER_INVALID_URI;
9161 char *buffer = NULL;
9162 char *seperator = strchr(path, ',');
9163 char ext[100] = {0,}, size[100] = {0,};
9166 if ((buffer = strstr(path, "ext="))) {
9167 buffer += strlen("ext=");
9169 if (strlen(buffer)) {
9170 strncpy(ext, buffer, 99);
9172 if ((seperator = strchr(ext, ','))
9173 || (seperator = strchr(ext, ' '))
9174 || (seperator = strchr(ext, '\0'))) {
9175 seperator[0] = '\0';
9180 if ((buffer = strstr(path, "size="))) {
9181 buffer += strlen("size=");
9183 if (strlen(buffer) > 0) {
9184 strncpy(size, buffer, 99);
9186 if ((seperator = strchr(size, ','))
9187 || (seperator = strchr(size, ' '))
9188 || (seperator = strchr(size, '\0'))) {
9189 seperator[0] = '\0';
9192 mem_size = atoi(size);
9197 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9199 if (mem_size && param) {
9200 if (data->input_mem.buf)
9201 free(data->input_mem.buf);
9202 data->input_mem.buf = malloc(mem_size);
9204 if (data->input_mem.buf) {
9205 memcpy(data->input_mem.buf, param, mem_size);
9206 data->input_mem.len = mem_size;
9207 ret = MM_ERROR_NONE;
9209 LOGE("failed to alloc mem %d", mem_size);
9210 ret = MM_ERROR_PLAYER_INTERNAL;
9213 data->input_mem.offset = 0;
9214 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9221 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9223 gchar *location = NULL;
9226 int ret = MM_ERROR_NONE;
9228 if ((path = strstr(uri, "file://"))) {
9229 location = g_filename_from_uri(uri, NULL, &err);
9230 if (!location || (err != NULL)) {
9231 LOGE("Invalid URI '%s' for filesrc: %s", path,
9232 (err != NULL) ? err->message : "unknown error");
9236 MMPLAYER_FREEIF(location);
9238 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9239 return MM_ERROR_PLAYER_INVALID_URI;
9241 LOGD("path from uri: %s", location);
9244 path = (location != NULL) ? (location) : ((char *)uri);
9247 ret = util_exist_file_path(path);
9249 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9250 if (ret == MM_ERROR_NONE) {
9251 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9252 if (util_is_sdp_file(path)) {
9253 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9254 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9256 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9258 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9259 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9261 LOGE("invalid uri, could not play..");
9262 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9265 MMPLAYER_FREEIF(location);
9270 static mmplayer_video_decoded_data_info_t *
9271 __mmplayer_create_stream_from_pad(GstPad *pad)
9273 GstCaps *caps = NULL;
9274 GstStructure *structure = NULL;
9275 unsigned int fourcc = 0;
9276 const gchar *string_format = NULL;
9277 mmplayer_video_decoded_data_info_t *stream = NULL;
9279 MMPixelFormatType format;
9282 caps = gst_pad_get_current_caps(pad);
9284 LOGE("Caps is NULL.");
9288 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9289 structure = gst_caps_get_structure(caps, 0);
9290 gst_structure_get_int(structure, "width", &width);
9291 gst_structure_get_int(structure, "height", &height);
9292 string_format = gst_structure_get_string(structure, "format");
9295 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9296 format = util_get_pixtype(fourcc);
9297 gst_video_info_from_caps(&info, caps);
9298 gst_caps_unref(caps);
9301 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9302 LOGE("Wrong condition!!");
9306 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9308 LOGE("failed to alloc mem for video data");
9312 stream->width = width;
9313 stream->height = height;
9314 stream->format = format;
9315 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9321 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9323 unsigned int pitch = 0;
9324 unsigned int size = 0;
9326 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9329 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9330 bo = gst_tizen_memory_get_bos(mem, index);
9332 stream->bo[index] = tbm_bo_ref(bo);
9334 LOGE("failed to get bo for index %d", index);
9337 for (index = 0; index < stream->plane_num; index++) {
9338 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9339 stream->stride[index] = pitch;
9341 stream->elevation[index] = size / pitch;
9343 stream->elevation[index] = stream->height;
9348 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9350 if (stream->format == MM_PIXEL_FORMAT_I420) {
9351 int ret = TBM_SURFACE_ERROR_NONE;
9352 tbm_surface_h surface;
9353 tbm_surface_info_s info;
9355 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9357 ret = tbm_surface_get_info(surface, &info);
9358 if (ret != TBM_SURFACE_ERROR_NONE) {
9359 tbm_surface_destroy(surface);
9363 tbm_surface_destroy(surface);
9364 stream->stride[0] = info.planes[0].stride;
9365 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9366 stream->stride[1] = info.planes[1].stride;
9367 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9368 stream->stride[2] = info.planes[2].stride;
9369 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9370 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9371 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9372 stream->stride[0] = stream->width * 4;
9373 stream->elevation[0] = stream->height;
9374 stream->bo_size = stream->stride[0] * stream->height;
9376 LOGE("Not support format %d", stream->format);
9384 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9386 tbm_bo_handle thandle;
9388 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9389 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9390 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9394 unsigned char *src = NULL;
9395 unsigned char *dest = NULL;
9396 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9398 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9400 LOGE("fail to gst_memory_map");
9404 if (!mapinfo.data) {
9405 LOGE("data pointer is wrong");
9409 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9410 if (!stream->bo[0]) {
9411 LOGE("Fail to tbm_bo_alloc!!");
9415 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9417 LOGE("thandle pointer is wrong");
9421 if (stream->format == MM_PIXEL_FORMAT_I420) {
9422 src_stride[0] = GST_ROUND_UP_4(stream->width);
9423 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9424 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9425 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9428 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9429 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9431 for (i = 0; i < 3; i++) {
9432 src = mapinfo.data + src_offset[i];
9433 dest = thandle.ptr + dest_offset[i];
9438 for (j = 0; j < stream->height >> k; j++) {
9439 memcpy(dest, src, stream->width>>k);
9440 src += src_stride[i];
9441 dest += stream->stride[i];
9444 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9445 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9447 LOGE("Not support format %d", stream->format);
9451 tbm_bo_unmap(stream->bo[0]);
9452 gst_memory_unmap(mem, &mapinfo);
9458 tbm_bo_unmap(stream->bo[0]);
9461 gst_memory_unmap(mem, &mapinfo);
9467 __mmplayer_set_pause_state(mmplayer_t *player)
9469 if (player->sent_bos)
9472 /* rtsp case, get content attrs by GstMessage */
9473 if (MMPLAYER_IS_RTSP_STREAMING(player))
9476 /* it's first time to update all content attrs. */
9477 __mmplayer_update_content_attrs(player, ATTR_ALL);
9481 __mmplayer_set_playing_state(mmplayer_t *player)
9483 gchar *audio_codec = NULL;
9485 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9486 /* initialize because auto resume is done well. */
9487 player->resumed_by_rewind = FALSE;
9488 player->playback_rate = 1.0;
9491 if (player->sent_bos)
9494 /* try to get content metadata */
9496 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9497 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9498 * legacy mmfw-player api
9500 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9502 if ((player->cmd == MMPLAYER_COMMAND_START)
9503 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9504 __mmplayer_handle_missed_plugin(player);
9507 /* check audio codec field is set or not
9508 * we can get it from typefinder or codec's caps.
9510 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9512 /* The codec format can't be sent for audio only case like amr, mid etc.
9513 * Because, parser don't make related TAG.
9514 * So, if it's not set yet, fill it with found data.
9517 if (g_strrstr(player->type, "audio/midi"))
9518 audio_codec = "MIDI";
9519 else if (g_strrstr(player->type, "audio/x-amr"))
9520 audio_codec = "AMR";
9521 else if (g_strrstr(player->type, "audio/mpeg")
9522 && !g_strrstr(player->type, "mpegversion=(int)1"))
9523 audio_codec = "AAC";
9525 audio_codec = "unknown";
9527 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9529 if (mm_attrs_commit_all(player->attrs))
9530 LOGE("failed to update attributes");
9532 LOGD("set audio codec type with caps");