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;
2290 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2291 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2297 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2299 mmplayer_t *player = (mmplayer_t *)data;
2300 const gchar *pcm_format = NULL;
2304 gint endianness = 0;
2305 guint64 channel_mask = 0;
2306 void *a_data = NULL;
2308 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2309 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2313 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2315 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2316 a_data = mapinfo.data;
2317 a_size = mapinfo.size;
2319 GstCaps *caps = gst_pad_get_current_caps(pad);
2320 GstStructure *structure = gst_caps_get_structure(caps, 0);
2322 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2323 pcm_format = gst_structure_get_string(structure, "format");
2324 gst_structure_get_int(structure, "rate", &rate);
2325 gst_structure_get_int(structure, "channels", &channel);
2326 gst_structure_get_int(structure, "depth", &depth);
2327 gst_structure_get_int(structure, "endianness", &endianness);
2328 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2329 gst_caps_unref(GST_CAPS(caps));
2331 /* In case of the sync is false, use buffer list. *
2332 * The num of buffer list depends on the num of audio channels */
2333 if (player->audio_stream_buff_list) {
2334 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2335 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2337 if (channel_mask == tmp->channel_mask) {
2338 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2339 if (tmp->data_size + a_size < tmp->buff_size) {
2340 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2341 tmp->data_size += a_size;
2343 /* send data to client */
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 if (a_size > tmp->buff_size) {
2347 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2348 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2349 if (tmp->pcm_data == NULL) {
2350 LOGE("failed to realloc data.");
2353 tmp->buff_size = a_size;
2355 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2356 memcpy(tmp->pcm_data, a_data, a_size);
2357 tmp->data_size = a_size;
2362 LOGE("data is empty in list.");
2368 /* create new audio stream data */
2369 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2370 if (a_buffer == NULL) {
2371 LOGE("failed to alloc data.");
2374 a_buffer->bitrate = rate;
2375 a_buffer->channel = channel;
2376 a_buffer->depth = depth;
2377 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2378 a_buffer->channel_mask = channel_mask;
2379 a_buffer->data_size = a_size;
2380 a_buffer->pcm_format = util_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2382 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2383 /* If sync is FALSE, use buffer list to reduce the IPC. */
2384 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2385 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2386 if (a_buffer->pcm_data == NULL) {
2387 LOGE("failed to alloc data.");
2388 MMPLAYER_FREEIF(a_buffer);
2391 memcpy(a_buffer->pcm_data, a_data, a_size);
2392 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2393 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2395 /* If sync is TRUE, send data directly. */
2396 a_buffer->pcm_data = a_data;
2397 __mmplayer_audio_stream_send_data(player, a_buffer);
2398 MMPLAYER_FREEIF(a_buffer);
2402 gst_buffer_unmap(buffer, &mapinfo);
2407 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2409 mmplayer_t *player = (mmplayer_t *)data;
2410 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2411 GstPad *sinkpad = NULL;
2412 GstElement *queue = NULL, *sink = NULL;
2415 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2417 queue = gst_element_factory_make("queue", NULL);
2418 if (queue == NULL) {
2419 LOGD("fail make queue");
2423 sink = gst_element_factory_make("fakesink", NULL);
2425 LOGD("fail make fakesink");
2429 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2431 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2432 LOGW("failed to link queue & sink");
2436 sinkpad = gst_element_get_static_pad(queue, "sink");
2438 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2439 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2443 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2445 gst_object_unref(sinkpad);
2446 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2447 g_object_set(sink, "sync", TRUE, NULL);
2448 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2450 /* keep the first sink reference only */
2451 if (!audiobin[MMPLAYER_A_SINK].gst) {
2452 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2453 audiobin[MMPLAYER_A_SINK].gst = sink;
2456 gst_element_set_state(sink, GST_STATE_PAUSED);
2457 gst_element_set_state(queue, GST_STATE_PAUSED);
2459 __mmplayer_add_signal_connection(player,
2461 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2463 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2466 __mmplayer_add_sink(player, sink);
2472 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2474 gst_object_unref(GST_OBJECT(queue));
2478 gst_object_unref(GST_OBJECT(sink));
2482 gst_object_unref(GST_OBJECT(sinkpad));
2490 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2492 #define MAX_PROPS_LEN 128
2493 gint latency_mode = 0;
2494 gchar *stream_type = NULL;
2495 gchar *latency = NULL;
2497 gchar stream_props[MAX_PROPS_LEN] = {0,};
2498 GstStructure *props = NULL;
2501 * It should be set after player creation through attribute.
2502 * But, it can not be changed during playing.
2505 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2507 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2508 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2511 LOGE("stream_type is null.");
2513 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2514 stream_type, stream_id);
2515 props = gst_structure_from_string(stream_props, NULL);
2516 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2517 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2518 gst_structure_free(props);
2521 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2523 switch (latency_mode) {
2524 case AUDIO_LATENCY_MODE_LOW:
2525 latency = g_strndup("low", 3);
2527 case AUDIO_LATENCY_MODE_MID:
2528 latency = g_strndup("mid", 3);
2530 case AUDIO_LATENCY_MODE_HIGH:
2531 latency = g_strndup("high", 4);
2535 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2539 LOGD("audiosink property - latency=%s", latency);
2541 MMPLAYER_FREEIF(latency);
2547 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2549 mmplayer_gst_element_t *audiobin = NULL;
2552 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2554 audiobin = player->pipeline->audiobin;
2556 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2557 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2558 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2560 if (player->video360_yaw_radians <= M_PI &&
2561 player->video360_yaw_radians >= -M_PI &&
2562 player->video360_pitch_radians <= M_PI_2 &&
2563 player->video360_pitch_radians >= -M_PI_2) {
2564 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2565 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2566 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2567 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2568 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2569 "source-orientation-y", player->video360_metadata.init_view_heading,
2570 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2577 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2579 mmplayer_gst_element_t *audiobin = NULL;
2580 GstPad *sink_pad = NULL;
2581 GstCaps *acaps = NULL;
2583 int pitch_control = 0;
2584 double pitch_value = 1.0;
2587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2588 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2590 audiobin = player->pipeline->audiobin;
2592 LOGD("make element for normal audio playback");
2594 /* audio bin structure for playback. {} means optional.
2595 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2597 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2598 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2601 /* for pitch control */
2602 mm_attrs_multiple_get(player->attrs, NULL,
2603 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2604 MM_PLAYER_PITCH_VALUE, &pitch_value,
2607 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2608 if (pitch_control && (player->videodec_linked == 0)) {
2609 GstElementFactory *factory;
2611 factory = gst_element_factory_find("pitch");
2613 gst_object_unref(factory);
2616 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2619 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2620 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2622 LOGW("there is no pitch element");
2627 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2629 /* replaygain volume */
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2631 if (player->sound.rg_enable)
2632 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2637 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2639 /* for logical volume control */
2640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2641 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2643 if (player->sound.mute) {
2644 LOGD("mute enabled");
2645 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2648 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2650 /* audio effect element. if audio effect is enabled */
2651 if ((strcmp(player->ini.audioeffect_element, ""))
2653 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2654 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2656 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2658 if ((!player->bypass_audio_effect)
2659 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2660 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2661 if (!_mmplayer_audio_effect_custom_apply(player))
2662 LOGI("apply audio effect(custom) setting success");
2666 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2667 && (player->set_mode.rich_audio)) {
2668 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2672 /* create audio sink */
2673 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2674 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2675 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2677 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2678 if (player->is_360_feature_enabled &&
2679 player->is_content_spherical &&
2681 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2682 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2683 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2685 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2689 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2690 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2691 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2692 gst_caps_unref(acaps);
2694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2696 player->is_openal_plugin_used = TRUE;
2698 if (player->is_360_feature_enabled && player->is_content_spherical)
2699 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2703 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2704 (player->videodec_linked && player->ini.use_system_clock)) {
2705 LOGD("system clock will be used.");
2706 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2709 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2710 __mmplayer_gst_set_pulsesink_property(player);
2711 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2712 __mmplayer_gst_set_openalsink_property(player);
2715 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2718 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2719 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2720 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2721 gst_object_unref(GST_OBJECT(sink_pad));
2723 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2726 return MM_ERROR_NONE;
2728 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2730 return MM_ERROR_PLAYER_INTERNAL;
2734 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2736 mmplayer_gst_element_t *audiobin = NULL;
2737 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2739 gchar *dst_format = NULL;
2741 int dst_samplerate = 0;
2742 int dst_channels = 0;
2743 GstCaps *caps = NULL;
2744 char *caps_str = NULL;
2747 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2748 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2750 audiobin = player->pipeline->audiobin;
2752 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2754 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2756 [case 1] extract interleave audio pcm without playback
2757 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2758 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2760 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2762 [case 2] deinterleave for each channel without playback
2763 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2764 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2766 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2767 - fakesink (sync or not)
2770 [case 3] [case 1(sync only)] + playback
2771 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2773 * src - ... - tee - queue1 - playback path
2774 - queue2 - [case1 pipeline with sync]
2776 [case 4] [case 2(sync only)] + playback
2777 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2779 * src - ... - tee - queue1 - playback path
2780 - queue2 - [case2 pipeline with sync]
2784 /* 1. create tee and playback path
2785 'tee' should be added at first to copy the decoded stream
2787 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2788 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2791 /* tee - path 1 : for playback path */
2792 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2793 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2795 /* tee - path 2 : for extract path */
2796 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2797 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2800 /* if there is tee, 'tee - path 2' is linked here */
2802 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2807 /* 2. decide the extract pcm format */
2808 mm_attrs_multiple_get(player->attrs, NULL,
2809 "pcm_audioformat", &dst_format, &dst_len,
2810 "pcm_extraction_samplerate", &dst_samplerate,
2811 "pcm_extraction_channels", &dst_channels,
2814 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2815 dst_format, dst_len, dst_samplerate, dst_channels);
2817 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2818 mm_attrs_multiple_get(player->attrs, NULL,
2819 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2820 "content_audio_samplerate", &dst_samplerate,
2821 "content_audio_channels", &dst_channels,
2824 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2825 dst_format, dst_len, dst_samplerate, dst_channels);
2827 /* If there is no enough information, set it to platform default value. */
2828 if (dst_format == NULL || util_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2829 LOGD("set platform default format");
2830 dst_format = DEFAULT_PCM_OUT_FORMAT;
2832 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2833 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2836 /* 3. create capsfilter */
2837 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2838 caps = gst_caps_new_simple("audio/x-raw",
2839 "format", G_TYPE_STRING, dst_format,
2840 "rate", G_TYPE_INT, dst_samplerate,
2841 "channels", G_TYPE_INT, dst_channels,
2844 caps_str = gst_caps_to_string(caps);
2845 LOGD("new caps : %s", caps_str);
2847 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2850 gst_caps_unref(caps);
2851 MMPLAYER_FREEIF(caps_str);
2853 /* 4-1. create deinterleave to extract pcm for each channel */
2854 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2855 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2856 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2858 /* audiosink will be added after getting signal for each channel */
2859 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2860 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2862 /* 4-2. create fakesink to extract interlevaed pcm */
2863 LOGD("add audio fakesink for interleaved audio");
2864 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2865 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2866 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2867 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2869 __mmplayer_add_signal_connection(player,
2870 G_OBJECT(audiobin[extract_sink_id].gst),
2871 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2873 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2876 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2880 return MM_ERROR_NONE;
2882 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2884 return MM_ERROR_PLAYER_INTERNAL;
2888 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2890 int ret = MM_ERROR_NONE;
2891 mmplayer_gst_element_t *audiobin = NULL;
2892 GList *element_bucket = NULL;
2895 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2896 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2898 audiobin = player->pipeline->audiobin;
2900 if (player->build_audio_offload) { /* skip all the audio filters */
2901 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2902 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2903 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2904 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2908 /* FIXME: need to mention the supportable condition at API reference */
2909 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2910 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2912 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2914 if (ret != MM_ERROR_NONE)
2917 LOGD("success to make audio bin element");
2918 *bucket = element_bucket;
2921 return MM_ERROR_NONE;
2924 LOGE("failed to make audio bin element");
2925 g_list_free(element_bucket);
2929 return MM_ERROR_PLAYER_INTERNAL;
2933 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2935 mmplayer_gst_element_t *first_element = NULL;
2936 mmplayer_gst_element_t *audiobin = NULL;
2938 GstPad *ghostpad = NULL;
2939 GList *element_bucket = NULL;
2943 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2946 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2948 LOGE("failed to allocate memory for audiobin");
2949 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2953 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2954 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2955 if (!audiobin[MMPLAYER_A_BIN].gst) {
2956 LOGE("failed to create audiobin");
2961 player->pipeline->audiobin = audiobin;
2963 /* create audio filters and audiosink */
2964 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2967 /* adding created elements to bin */
2968 LOGD("adding created elements to bin");
2969 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2972 /* linking elements in the bucket by added order. */
2973 LOGD("Linking elements in the bucket by added order.");
2974 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2977 /* get first element's sinkpad for creating ghostpad */
2978 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2979 if (!first_element) {
2980 LOGE("failed to get first elem");
2984 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2986 LOGE("failed to get pad from first element of audiobin");
2990 ghostpad = gst_ghost_pad_new("sink", pad);
2992 LOGE("failed to create ghostpad");
2996 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2997 LOGE("failed to add ghostpad to audiobin");
3001 gst_object_unref(pad);
3003 g_list_free(element_bucket);
3006 return MM_ERROR_NONE;
3009 LOGD("ERROR : releasing audiobin");
3012 gst_object_unref(GST_OBJECT(pad));
3015 gst_object_unref(GST_OBJECT(ghostpad));
3018 g_list_free(element_bucket);
3020 /* release element which are not added to bin */
3021 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3022 /* NOTE : skip bin */
3023 if (audiobin[i].gst) {
3024 GstObject *parent = NULL;
3025 parent = gst_element_get_parent(audiobin[i].gst);
3028 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3029 audiobin[i].gst = NULL;
3031 gst_object_unref(GST_OBJECT(parent));
3035 /* release audiobin with it's childs */
3036 if (audiobin[MMPLAYER_A_BIN].gst)
3037 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3039 MMPLAYER_FREEIF(audiobin);
3041 player->pipeline->audiobin = NULL;
3043 return MM_ERROR_PLAYER_INTERNAL;
3047 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3049 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3053 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3055 int ret = MM_ERROR_NONE;
3057 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3058 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3060 MMPLAYER_VIDEO_BO_LOCK(player);
3062 if (player->video_bo_list) {
3063 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3064 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3065 if (tmp && tmp->bo == bo) {
3067 LOGD("release bo %p", bo);
3068 tbm_bo_unref(tmp->bo);
3069 MMPLAYER_VIDEO_BO_UNLOCK(player);
3070 MMPLAYER_VIDEO_BO_SIGNAL(player);
3075 /* hw codec is running or the list was reset for DRC. */
3076 LOGW("there is no bo list.");
3078 MMPLAYER_VIDEO_BO_UNLOCK(player);
3080 LOGW("failed to find bo %p", bo);
3085 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3090 MMPLAYER_RETURN_IF_FAIL(player);
3092 MMPLAYER_VIDEO_BO_LOCK(player);
3093 if (player->video_bo_list) {
3094 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3095 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3096 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3099 tbm_bo_unref(tmp->bo);
3103 g_list_free(player->video_bo_list);
3104 player->video_bo_list = NULL;
3106 player->video_bo_size = 0;
3107 MMPLAYER_VIDEO_BO_UNLOCK(player);
3114 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3117 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3118 gboolean ret = TRUE;
3120 /* check DRC, if it is, destroy the prev bo list to create again */
3121 if (player->video_bo_size != size) {
3122 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3123 __mmplayer_video_stream_destroy_bo_list(player);
3124 player->video_bo_size = size;
3127 MMPLAYER_VIDEO_BO_LOCK(player);
3129 if ((!player->video_bo_list) ||
3130 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3132 /* create bo list */
3134 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3136 if (player->video_bo_list) {
3137 /* if bo list did not created all, try it again. */
3138 idx = g_list_length(player->video_bo_list);
3139 LOGD("bo list exist(len: %d)", idx);
3142 for (; idx < player->ini.num_of_video_bo; idx++) {
3143 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3145 LOGE("Fail to alloc bo_info.");
3148 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3150 LOGE("Fail to tbm_bo_alloc.");
3151 MMPLAYER_FREEIF(bo_info);
3154 bo_info->used = FALSE;
3155 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3158 /* update video num buffers */
3159 player->video_num_buffers = idx;
3160 if (idx == player->ini.num_of_video_bo)
3161 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3164 MMPLAYER_VIDEO_BO_UNLOCK(player);
3168 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3172 /* get bo from list*/
3173 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3174 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3175 if (tmp && (tmp->used == FALSE)) {
3176 LOGD("found bo %p to use", tmp->bo);
3178 MMPLAYER_VIDEO_BO_UNLOCK(player);
3179 return tbm_bo_ref(tmp->bo);
3183 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3184 MMPLAYER_VIDEO_BO_UNLOCK(player);
3188 if (player->ini.video_bo_timeout <= 0) {
3189 MMPLAYER_VIDEO_BO_WAIT(player);
3191 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3192 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3199 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3201 mmplayer_t *player = (mmplayer_t *)data;
3203 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3205 /* send prerolled pkt */
3206 player->video_stream_prerolled = false;
3208 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3210 /* not to send prerolled pkt again */
3211 player->video_stream_prerolled = true;
3215 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3217 mmplayer_t *player = (mmplayer_t *)data;
3218 mmplayer_video_decoded_data_info_t *stream = NULL;
3219 GstMemory *mem = NULL;
3222 MMPLAYER_RETURN_IF_FAIL(player);
3223 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3225 if (player->video_stream_prerolled) {
3226 player->video_stream_prerolled = false;
3227 LOGD("skip the prerolled pkt not to send it again");
3231 /* clear stream data structure */
3232 stream = __mmplayer_create_stream_from_pad(pad);
3234 LOGE("failed to alloc stream");
3238 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3240 /* set size and timestamp */
3241 mem = gst_buffer_peek_memory(buffer, 0);
3242 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3243 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3245 /* check zero-copy */
3246 if (player->set_mode.video_zc &&
3247 player->set_mode.video_export &&
3248 gst_is_tizen_memory(mem)) {
3249 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3250 stream->internal_buffer = gst_buffer_ref(buffer);
3251 } else { /* sw codec */
3252 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3255 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3259 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3260 LOGE("failed to send video decoded data.");
3267 LOGE("release video stream resource.");
3268 if (gst_is_tizen_memory(mem)) {
3270 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3272 tbm_bo_unref(stream->bo[i]);
3275 /* unref gst buffer */
3276 if (stream->internal_buffer)
3277 gst_buffer_unref(stream->internal_buffer);
3280 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3282 MMPLAYER_FREEIF(stream);
3287 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3289 mmplayer_gst_element_t *videobin = NULL;
3292 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3294 videobin = player->pipeline->videobin;
3296 /* Set spatial media metadata and/or user settings to the element.
3298 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3299 "projection-type", player->video360_metadata.projection_type, NULL);
3301 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3302 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3304 if (player->video360_metadata.full_pano_width_pixels &&
3305 player->video360_metadata.full_pano_height_pixels &&
3306 player->video360_metadata.cropped_area_image_width &&
3307 player->video360_metadata.cropped_area_image_height) {
3308 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3309 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3310 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3311 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3312 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3313 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3314 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3318 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3319 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3320 "horizontal-fov", player->video360_horizontal_fov,
3321 "vertical-fov", player->video360_vertical_fov, NULL);
3324 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3325 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3326 "zoom", 1.0f / player->video360_zoom, NULL);
3329 if (player->video360_yaw_radians <= M_PI &&
3330 player->video360_yaw_radians >= -M_PI &&
3331 player->video360_pitch_radians <= M_PI_2 &&
3332 player->video360_pitch_radians >= -M_PI_2) {
3333 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3334 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3335 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3336 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3337 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3338 "pose-yaw", player->video360_metadata.init_view_heading,
3339 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "passthrough", !player->is_video360_enabled, NULL);
3350 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3352 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3353 GList *element_bucket = NULL;
3356 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3358 /* create video360 filter */
3359 if (player->is_360_feature_enabled && player->is_content_spherical) {
3360 LOGD("create video360 element");
3361 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3362 __mmplayer_gst_set_video360_property(player);
3366 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3367 LOGD("skip creating the videoconv and rotator");
3368 return MM_ERROR_NONE;
3371 /* in case of sw codec & overlay surface type, except 360 playback.
3372 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3373 LOGD("create video converter: %s", video_csc);
3374 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3377 *bucket = element_bucket;
3379 return MM_ERROR_NONE;
3381 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3382 g_list_free(element_bucket);
3386 return MM_ERROR_PLAYER_INTERNAL;
3390 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3392 gchar *factory_name = NULL;
3394 switch (surface_type) {
3395 case MM_DISPLAY_SURFACE_OVERLAY:
3396 if (strlen(player->ini.videosink_element_overlay) > 0)
3397 factory_name = player->ini.videosink_element_overlay;
3399 case MM_DISPLAY_SURFACE_REMOTE:
3400 case MM_DISPLAY_SURFACE_NULL:
3401 if (strlen(player->ini.videosink_element_fake) > 0)
3402 factory_name = player->ini.videosink_element_fake;
3405 LOGE("unidentified surface type");
3409 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3410 return factory_name;
3414 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3416 gchar *factory_name = NULL;
3417 mmplayer_gst_element_t *videobin = NULL;
3422 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3424 videobin = player->pipeline->videobin;
3425 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3427 attrs = MMPLAYER_GET_ATTRS(player);
3429 LOGE("cannot get content attribute");
3430 return MM_ERROR_PLAYER_INTERNAL;
3433 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3434 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3435 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3437 /* support shard memory with S/W codec on HawkP */
3438 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3439 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3440 "use-tbm", use_tbm, NULL);
3444 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3445 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3448 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3450 LOGD("disable last-sample");
3451 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3454 if (player->set_mode.video_export) {
3456 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3457 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3458 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3460 __mmplayer_add_signal_connection(player,
3461 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3462 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3464 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3467 __mmplayer_add_signal_connection(player,
3468 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3469 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3471 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3475 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3476 return MM_ERROR_PLAYER_INTERNAL;
3478 if (videobin[MMPLAYER_V_SINK].gst) {
3479 GstPad *sink_pad = NULL;
3480 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3482 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3483 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3484 gst_object_unref(GST_OBJECT(sink_pad));
3486 LOGE("failed to get sink pad from videosink");
3490 return MM_ERROR_NONE;
3495 * - video overlay surface(arm/x86) : tizenwlsink
3498 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3501 GList *element_bucket = NULL;
3502 mmplayer_gst_element_t *first_element = NULL;
3503 mmplayer_gst_element_t *videobin = NULL;
3504 gchar *videosink_factory_name = NULL;
3507 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3510 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3512 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3514 player->pipeline->videobin = videobin;
3517 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3518 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3519 if (!videobin[MMPLAYER_V_BIN].gst) {
3520 LOGE("failed to create videobin");
3524 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3527 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3528 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3530 /* additional setting for sink plug-in */
3531 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3532 LOGE("failed to set video property");
3536 /* store it as it's sink element */
3537 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3539 /* adding created elements to bin */
3540 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3541 LOGE("failed to add elements");
3545 /* Linking elements in the bucket by added order */
3546 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3547 LOGE("failed to link elements");
3551 /* get first element's sinkpad for creating ghostpad */
3552 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3553 if (!first_element) {
3554 LOGE("failed to get first element from bucket");
3558 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3560 LOGE("failed to get pad from first element");
3564 /* create ghostpad */
3565 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3566 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3567 LOGE("failed to add ghostpad to videobin");
3570 gst_object_unref(pad);
3572 /* done. free allocated variables */
3573 g_list_free(element_bucket);
3577 return MM_ERROR_NONE;
3580 LOGE("ERROR : releasing videobin");
3581 g_list_free(element_bucket);
3584 gst_object_unref(GST_OBJECT(pad));
3586 /* release videobin with it's childs */
3587 if (videobin[MMPLAYER_V_BIN].gst)
3588 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3590 MMPLAYER_FREEIF(videobin);
3591 player->pipeline->videobin = NULL;
3593 return MM_ERROR_PLAYER_INTERNAL;
3597 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3599 GList *element_bucket = NULL;
3600 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3602 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3603 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3604 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3605 "signal-handoffs", FALSE,
3608 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3609 __mmplayer_add_signal_connection(player,
3610 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3611 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3613 G_CALLBACK(__mmplayer_update_subtitle),
3616 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3617 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3619 if (!player->play_subtitle) {
3620 LOGD("add textbin sink as sink element of whole pipeline.");
3621 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3624 /* adding created elements to bin */
3625 LOGD("adding created elements to bin");
3626 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3627 LOGE("failed to add elements");
3631 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3632 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3633 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3635 /* linking elements in the bucket by added order. */
3636 LOGD("Linking elements in the bucket by added order.");
3637 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3638 LOGE("failed to link elements");
3642 /* done. free allocated variables */
3643 g_list_free(element_bucket);
3645 if (textbin[MMPLAYER_T_QUEUE].gst) {
3647 GstPad *ghostpad = NULL;
3649 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3651 LOGE("failed to get sink pad of text queue");
3655 ghostpad = gst_ghost_pad_new("text_sink", pad);
3656 gst_object_unref(pad);
3659 LOGE("failed to create ghostpad of textbin");
3663 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3664 LOGE("failed to add ghostpad to textbin");
3665 gst_object_unref(ghostpad);
3670 return MM_ERROR_NONE;
3673 g_list_free(element_bucket);
3675 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3676 LOGE("remove textbin sink from sink list");
3677 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3680 /* release element at __mmplayer_gst_create_text_sink_bin */
3681 return MM_ERROR_PLAYER_INTERNAL;
3685 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3687 mmplayer_gst_element_t *textbin = NULL;
3688 GList *element_bucket = NULL;
3689 int surface_type = 0;
3694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3697 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3699 LOGE("failed to allocate memory for textbin");
3700 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3704 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3705 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3706 if (!textbin[MMPLAYER_T_BIN].gst) {
3707 LOGE("failed to create textbin");
3712 player->pipeline->textbin = textbin;
3715 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3716 LOGD("surface type for subtitle : %d", surface_type);
3717 switch (surface_type) {
3718 case MM_DISPLAY_SURFACE_OVERLAY:
3719 case MM_DISPLAY_SURFACE_NULL:
3720 case MM_DISPLAY_SURFACE_REMOTE:
3721 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3722 LOGE("failed to make plain text elements");
3733 return MM_ERROR_NONE;
3737 LOGD("ERROR : releasing textbin");
3739 g_list_free(element_bucket);
3741 /* release signal */
3742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3744 /* release element which are not added to bin */
3745 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3746 /* NOTE : skip bin */
3747 if (textbin[i].gst) {
3748 GstObject *parent = NULL;
3749 parent = gst_element_get_parent(textbin[i].gst);
3752 gst_object_unref(GST_OBJECT(textbin[i].gst));
3753 textbin[i].gst = NULL;
3755 gst_object_unref(GST_OBJECT(parent));
3760 /* release textbin with it's childs */
3761 if (textbin[MMPLAYER_T_BIN].gst)
3762 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3764 MMPLAYER_FREEIF(player->pipeline->textbin);
3765 player->pipeline->textbin = NULL;
3768 return MM_ERROR_PLAYER_INTERNAL;
3772 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3774 mmplayer_gst_element_t *mainbin = NULL;
3775 mmplayer_gst_element_t *textbin = NULL;
3776 MMHandleType attrs = 0;
3777 GstElement *subsrc = NULL;
3778 GstElement *subparse = NULL;
3779 gchar *subtitle_uri = NULL;
3780 const gchar *charset = NULL;
3786 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3788 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3790 mainbin = player->pipeline->mainbin;
3792 attrs = MMPLAYER_GET_ATTRS(player);
3794 LOGE("cannot get content attribute");
3795 return MM_ERROR_PLAYER_INTERNAL;
3798 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3799 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3800 LOGE("subtitle uri is not proper filepath.");
3801 return MM_ERROR_PLAYER_INVALID_URI;
3804 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3805 LOGE("failed to get storage info of subtitle path");
3806 return MM_ERROR_PLAYER_INVALID_URI;
3809 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3811 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3812 player->subtitle_language_list = NULL;
3813 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3815 /* create the subtitle source */
3816 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3818 LOGE("failed to create filesrc element");
3821 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3823 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3824 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3826 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3827 LOGW("failed to add queue");
3828 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3829 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3830 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3835 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3837 LOGE("failed to create subparse element");
3841 charset = util_get_charset(subtitle_uri);
3843 LOGD("detected charset is %s", charset);
3844 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3847 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3848 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3850 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3851 LOGW("failed to add subparse");
3852 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3853 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3854 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3858 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3859 LOGW("failed to link subsrc and subparse");
3863 player->play_subtitle = TRUE;
3864 player->adjust_subtitle_pos = 0;
3866 LOGD("play subtitle using subtitle file");
3868 if (player->pipeline->textbin == NULL) {
3869 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3870 LOGE("failed to create text sink bin. continuing without text");
3874 textbin = player->pipeline->textbin;
3876 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3877 LOGW("failed to add textbin");
3879 /* release signal */
3880 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3882 /* release textbin with it's childs */
3883 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3884 MMPLAYER_FREEIF(player->pipeline->textbin);
3885 player->pipeline->textbin = textbin = NULL;
3889 LOGD("link text input selector and textbin ghost pad");
3891 player->textsink_linked = 1;
3892 player->external_text_idx = 0;
3893 LOGI("textsink is linked");
3895 textbin = player->pipeline->textbin;
3896 LOGD("text bin has been created. reuse it.");
3897 player->external_text_idx = 1;
3900 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3901 LOGW("failed to link subparse and textbin");
3905 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3907 LOGE("failed to get sink pad from textsink to probe data");
3911 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3912 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3914 gst_object_unref(pad);
3917 /* create dot. for debugging */
3918 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3921 return MM_ERROR_NONE;
3924 /* release text pipeline resource */
3925 player->textsink_linked = 0;
3927 /* release signal */
3928 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3930 if (player->pipeline->textbin) {
3931 LOGE("remove textbin");
3933 /* release textbin with it's childs */
3934 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3935 MMPLAYER_FREEIF(player->pipeline->textbin);
3936 player->pipeline->textbin = NULL;
3940 /* release subtitle elem */
3941 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3942 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3944 return MM_ERROR_PLAYER_INTERNAL;
3948 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3950 mmplayer_t *player = (mmplayer_t *)data;
3951 MMMessageParamType msg = {0, };
3952 GstClockTime duration = 0;
3953 gpointer text = NULL;
3954 guint text_size = 0;
3955 gboolean ret = TRUE;
3956 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3960 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3961 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3963 if (player->is_subtitle_force_drop) {
3964 LOGW("subtitle is dropped forcedly.");
3968 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3969 text = mapinfo.data;
3970 text_size = mapinfo.size;
3972 if (player->set_mode.subtitle_off) {
3973 LOGD("subtitle is OFF.");
3977 if (!text || (text_size == 0)) {
3978 LOGD("There is no subtitle to be displayed.");
3982 msg.data = (void *)text;
3984 duration = GST_BUFFER_DURATION(buffer);
3986 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3987 if (player->duration > GST_BUFFER_PTS(buffer))
3988 duration = player->duration - GST_BUFFER_PTS(buffer);
3991 LOGI("subtitle duration is invalid, subtitle duration change "
3992 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3994 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3996 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3998 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3999 gst_buffer_unmap(buffer, &mapinfo);
4006 static GstPadProbeReturn
4007 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4009 mmplayer_t *player = (mmplayer_t *)u_data;
4010 GstClockTime cur_timestamp = 0;
4011 gint64 adjusted_timestamp = 0;
4012 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4014 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4016 if (player->set_mode.subtitle_off) {
4017 LOGD("subtitle is OFF.");
4021 if (player->adjust_subtitle_pos == 0) {
4022 LOGD("nothing to do");
4026 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4027 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4029 if (adjusted_timestamp < 0) {
4030 LOGD("adjusted_timestamp under zero");
4035 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4036 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4037 GST_TIME_ARGS(cur_timestamp),
4038 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4040 return GST_PAD_PROBE_OK;
4044 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4048 /* check player and subtitlebin are created */
4049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4050 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4052 if (position == 0) {
4053 LOGD("nothing to do");
4055 return MM_ERROR_NONE;
4058 /* check current postion */
4059 player->adjust_subtitle_pos = position;
4061 LOGD("save adjust_subtitle_pos in player");
4065 return MM_ERROR_NONE;
4069 * This function is to create audio or video pipeline for playing.
4071 * @param player [in] handle of player
4073 * @return This function returns zero on success.
4078 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4080 int ret = MM_ERROR_NONE;
4081 mmplayer_gst_element_t *mainbin = NULL;
4082 MMHandleType attrs = 0;
4085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4087 /* get profile attribute */
4088 attrs = MMPLAYER_GET_ATTRS(player);
4090 LOGE("failed to get content attribute");
4094 /* create pipeline handles */
4095 if (player->pipeline) {
4096 LOGE("pipeline should be released before create new one");
4100 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4101 if (player->pipeline == NULL)
4104 /* create mainbin */
4105 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4106 if (mainbin == NULL)
4109 /* create pipeline */
4110 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4111 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4112 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4113 LOGE("failed to create pipeline");
4118 player->pipeline->mainbin = mainbin;
4120 /* create the source and decoder elements */
4121 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4122 ret = __mmplayer_gst_build_es_pipeline(player);
4124 ret = __mmplayer_gst_build_pipeline(player);
4126 if (ret != MM_ERROR_NONE) {
4127 LOGE("failed to create some elements");
4131 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4132 if (__mmplayer_check_subtitle(player)
4133 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4134 LOGE("failed to create text pipeline");
4137 ret = __mmplayer_gst_add_bus_watch(player);
4138 if (ret != MM_ERROR_NONE) {
4139 LOGE("failed to add bus watch");
4144 return MM_ERROR_NONE;
4147 __mmplayer_gst_destroy_pipeline(player);
4148 return MM_ERROR_PLAYER_INTERNAL;
4152 __mmplayer_reset_gapless_state(mmplayer_t *player)
4155 MMPLAYER_RETURN_IF_FAIL(player
4157 && player->pipeline->audiobin
4158 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4160 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4167 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4170 int ret = MM_ERROR_NONE;
4174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4176 /* cleanup stuffs */
4177 MMPLAYER_FREEIF(player->type);
4178 player->no_more_pad = FALSE;
4179 player->num_dynamic_pad = 0;
4180 player->demux_pad_index = 0;
4182 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4183 player->subtitle_language_list = NULL;
4184 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4186 __mmplayer_reset_gapless_state(player);
4188 if (player->streamer) {
4189 __mm_player_streaming_initialize(player->streamer, FALSE);
4190 __mm_player_streaming_destroy(player->streamer);
4191 player->streamer = NULL;
4194 /* cleanup unlinked mime type */
4195 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4196 MMPLAYER_FREEIF(player->unlinked_video_mime);
4197 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4199 /* cleanup running stuffs */
4200 __mmplayer_cancel_eos_timer(player);
4202 /* cleanup gst stuffs */
4203 if (player->pipeline) {
4204 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4205 GstTagList *tag_list = player->pipeline->tag_list;
4207 /* first we need to disconnect all signal hander */
4208 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4211 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4212 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4213 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4214 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4215 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4216 gst_object_unref(bus);
4218 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4219 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4220 if (ret != MM_ERROR_NONE) {
4221 LOGE("fail to change state to NULL");
4222 return MM_ERROR_PLAYER_INTERNAL;
4225 LOGW("succeeded in changing state to NULL");
4227 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4230 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4231 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4233 /* free avsysaudiosink
4234 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4235 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4237 MMPLAYER_FREEIF(audiobin);
4238 MMPLAYER_FREEIF(videobin);
4239 MMPLAYER_FREEIF(textbin);
4240 MMPLAYER_FREEIF(mainbin);
4244 gst_tag_list_unref(tag_list);
4246 MMPLAYER_FREEIF(player->pipeline);
4248 MMPLAYER_FREEIF(player->album_art);
4250 if (player->v_stream_caps) {
4251 gst_caps_unref(player->v_stream_caps);
4252 player->v_stream_caps = NULL;
4255 if (player->a_stream_caps) {
4256 gst_caps_unref(player->a_stream_caps);
4257 player->a_stream_caps = NULL;
4260 if (player->s_stream_caps) {
4261 gst_caps_unref(player->s_stream_caps);
4262 player->s_stream_caps = NULL;
4264 __mmplayer_track_destroy(player);
4266 if (player->sink_elements)
4267 g_list_free(player->sink_elements);
4268 player->sink_elements = NULL;
4270 if (player->bufmgr) {
4271 tbm_bufmgr_deinit(player->bufmgr);
4272 player->bufmgr = NULL;
4275 LOGW("finished destroy pipeline");
4283 __mmplayer_gst_realize(mmplayer_t *player)
4286 int ret = MM_ERROR_NONE;
4290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4292 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4294 ret = __mmplayer_gst_create_pipeline(player);
4296 LOGE("failed to create pipeline");
4300 /* set pipeline state to READY */
4301 /* NOTE : state change to READY must be performed sync. */
4302 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4303 ret = __mmplayer_gst_set_state(player,
4304 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4306 if (ret != MM_ERROR_NONE) {
4307 /* return error if failed to set state */
4308 LOGE("failed to set READY state");
4312 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4314 /* create dot before error-return. for debugging */
4315 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4323 __mmplayer_gst_unrealize(mmplayer_t *player)
4325 int ret = MM_ERROR_NONE;
4329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4332 MMPLAYER_PRINT_STATE(player);
4334 /* release miscellaneous information */
4335 __mmplayer_release_misc(player);
4337 /* destroy pipeline */
4338 ret = __mmplayer_gst_destroy_pipeline(player);
4339 if (ret != MM_ERROR_NONE) {
4340 LOGE("failed to destory pipeline");
4344 /* release miscellaneous information.
4345 these info needs to be released after pipeline is destroyed. */
4346 __mmplayer_release_misc_post(player);
4348 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4356 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4361 LOGW("set_message_callback is called with invalid player handle");
4362 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4365 player->msg_cb = callback;
4366 player->msg_cb_param = user_param;
4368 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4372 return MM_ERROR_NONE;
4376 __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4378 int ret = MM_ERROR_NONE;
4383 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4384 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4385 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4387 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4389 if (strstr(uri, "es_buff://")) {
4390 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4391 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4392 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4393 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4395 tmp = g_ascii_strdown(uri, strlen(uri));
4396 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4397 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4399 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4401 } else if (strstr(uri, "mms://")) {
4402 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4403 } else if ((path = strstr(uri, "mem://"))) {
4404 ret = __mmplayer_set_mem_uri(data, path, param);
4406 ret = __mmplayer_set_file_uri(data, uri);
4409 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4410 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4411 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4412 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4414 /* dump parse result */
4415 SECURE_LOGW("incoming uri : %s", uri);
4416 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4417 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4425 __mmplayer_can_do_interrupt(mmplayer_t *player)
4427 if (!player || !player->pipeline || !player->attrs) {
4428 LOGW("not initialized");
4432 if (player->audio_decoded_cb) {
4433 LOGW("not support in pcm extraction mode");
4437 /* check if seeking */
4438 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4439 MMMessageParamType msg_param;
4440 memset(&msg_param, 0, sizeof(MMMessageParamType));
4441 msg_param.code = MM_ERROR_PLAYER_SEEK;
4442 player->seek_state = MMPLAYER_SEEK_NONE;
4443 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4447 /* check other thread */
4448 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4449 LOGW("locked already, cmd state : %d", player->cmd);
4451 /* check application command */
4452 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4453 LOGW("playing.. should wait cmd lock then, will be interrupted");
4455 /* lock will be released at mrp_resource_release_cb() */
4456 MMPLAYER_CMD_LOCK(player);
4459 LOGW("nothing to do");
4462 LOGW("can interrupt immediately");
4466 FAILED: /* with CMD UNLOCKED */
4469 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4474 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4477 mmplayer_t *player = NULL;
4481 if (user_data == NULL) {
4482 LOGE("- user_data is null");
4485 player = (mmplayer_t *)user_data;
4487 /* do something to release resource here.
4488 * player stop and interrupt forwarding */
4489 if (!__mmplayer_can_do_interrupt(player)) {
4490 LOGW("no need to interrupt, so leave");
4492 MMMessageParamType msg = {0, };
4495 player->interrupted_by_resource = TRUE;
4497 /* get last play position */
4498 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4499 LOGW("failed to get play position.");
4501 msg.union_type = MM_MSG_UNION_TIME;
4502 msg.time.elapsed = pos;
4503 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4505 LOGD("video resource conflict so, resource will be freed by unrealizing");
4506 if (_mmplayer_unrealize((MMHandleType)player))
4507 LOGW("failed to unrealize");
4509 /* lock is called in __mmplayer_can_do_interrupt() */
4510 MMPLAYER_CMD_UNLOCK(player);
4513 if (res == player->video_overlay_resource)
4514 player->video_overlay_resource = FALSE;
4516 player->video_decoder_resource = FALSE;
4524 __mmplayer_initialize_video_roi(mmplayer_t *player)
4526 player->video_roi.scale_x = 0.0;
4527 player->video_roi.scale_y = 0.0;
4528 player->video_roi.scale_width = 1.0;
4529 player->video_roi.scale_height = 1.0;
4533 _mmplayer_create_player(MMHandleType handle)
4535 int ret = MM_ERROR_PLAYER_INTERNAL;
4536 bool enabled = false;
4538 mmplayer_t *player = MM_PLAYER_CAST(handle);
4542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4544 /* initialize player state */
4545 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4546 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4547 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4548 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4550 /* check current state */
4551 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4553 /* construct attributes */
4554 player->attrs = _mmplayer_construct_attribute(handle);
4556 if (!player->attrs) {
4557 LOGE("Failed to construct attributes");
4561 /* initialize gstreamer with configured parameter */
4562 if (!__mmplayer_init_gstreamer(player)) {
4563 LOGE("Initializing gstreamer failed");
4564 _mmplayer_deconstruct_attribute(handle);
4568 /* create lock. note that g_tread_init() has already called in gst_init() */
4569 g_mutex_init(&player->fsink_lock);
4571 /* create update tag lock */
4572 g_mutex_init(&player->update_tag_lock);
4574 /* create gapless play mutex */
4575 g_mutex_init(&player->gapless_play_thread_mutex);
4577 /* create gapless play cond */
4578 g_cond_init(&player->gapless_play_thread_cond);
4580 /* create gapless play thread */
4581 player->gapless_play_thread =
4582 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4583 if (!player->gapless_play_thread) {
4584 LOGE("failed to create gapless play thread");
4585 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4586 g_mutex_clear(&player->gapless_play_thread_mutex);
4587 g_cond_clear(&player->gapless_play_thread_cond);
4591 player->bus_msg_q = g_queue_new();
4592 if (!player->bus_msg_q) {
4593 LOGE("failed to create queue for bus_msg");
4594 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4598 ret = _mmplayer_initialize_video_capture(player);
4599 if (ret != MM_ERROR_NONE) {
4600 LOGE("failed to initialize video capture");
4604 /* initialize resource manager */
4605 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4606 __resource_release_cb, player, &player->resource_manager)
4607 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4608 LOGE("failed to initialize resource manager");
4609 ret = MM_ERROR_PLAYER_INTERNAL;
4613 /* create video bo lock and cond */
4614 g_mutex_init(&player->video_bo_mutex);
4615 g_cond_init(&player->video_bo_cond);
4617 /* create media stream callback mutex */
4618 g_mutex_init(&player->media_stream_cb_lock);
4620 /* create subtitle info lock and cond */
4621 g_mutex_init(&player->subtitle_info_mutex);
4622 g_cond_init(&player->subtitle_info_cond);
4624 player->streaming_type = STREAMING_SERVICE_NONE;
4626 /* give default value of audio effect setting */
4627 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4628 player->sound.rg_enable = false;
4629 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4631 player->play_subtitle = FALSE;
4632 player->has_closed_caption = FALSE;
4633 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4634 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4635 player->pending_resume = FALSE;
4636 if (player->ini.dump_element_keyword[0][0] == '\0')
4637 player->ini.set_dump_element_flag = FALSE;
4639 player->ini.set_dump_element_flag = TRUE;
4641 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4642 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4643 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4645 /* Set video360 settings to their defaults for just-created player.
4648 player->is_360_feature_enabled = FALSE;
4649 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4650 LOGI("spherical feature info: %d", enabled);
4652 player->is_360_feature_enabled = TRUE;
4654 LOGE("failed to get spherical feature info");
4657 player->is_content_spherical = FALSE;
4658 player->is_video360_enabled = TRUE;
4659 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4660 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4661 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4662 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4663 player->video360_zoom = 1.0f;
4664 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4665 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4667 __mmplayer_initialize_video_roi(player);
4669 /* set player state to null */
4670 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4671 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4675 return MM_ERROR_NONE;
4679 g_mutex_clear(&player->fsink_lock);
4680 /* free update tag lock */
4681 g_mutex_clear(&player->update_tag_lock);
4682 g_queue_free(player->bus_msg_q);
4683 /* free gapless play thread */
4684 if (player->gapless_play_thread) {
4685 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4686 player->gapless_play_thread_exit = TRUE;
4687 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4688 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4690 g_thread_join(player->gapless_play_thread);
4691 player->gapless_play_thread = NULL;
4693 g_mutex_clear(&player->gapless_play_thread_mutex);
4694 g_cond_clear(&player->gapless_play_thread_cond);
4697 /* release attributes */
4698 _mmplayer_deconstruct_attribute(handle);
4706 __mmplayer_init_gstreamer(mmplayer_t *player)
4708 static gboolean initialized = FALSE;
4709 static const int max_argc = 50;
4711 gchar **argv = NULL;
4712 gchar **argv2 = NULL;
4718 LOGD("gstreamer already initialized.");
4723 argc = malloc(sizeof(int));
4724 argv = malloc(sizeof(gchar *) * max_argc);
4725 argv2 = malloc(sizeof(gchar *) * max_argc);
4727 if (!argc || !argv || !argv2)
4730 memset(argv, 0, sizeof(gchar *) * max_argc);
4731 memset(argv2, 0, sizeof(gchar *) * max_argc);
4735 argv[0] = g_strdup("mmplayer");
4738 for (i = 0; i < 5; i++) {
4739 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4740 if (strlen(player->ini.gst_param[i]) > 0) {
4741 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4746 /* we would not do fork for scanning plugins */
4747 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4750 /* check disable registry scan */
4751 if (player->ini.skip_rescan) {
4752 argv[*argc] = g_strdup("--gst-disable-registry-update");
4756 /* check disable segtrap */
4757 if (player->ini.disable_segtrap) {
4758 argv[*argc] = g_strdup("--gst-disable-segtrap");
4762 LOGD("initializing gstreamer with following parameter");
4763 LOGD("argc : %d", *argc);
4766 for (i = 0; i < arg_count; i++) {
4768 LOGD("argv[%d] : %s", i, argv2[i]);
4771 /* initializing gstreamer */
4772 if (!gst_init_check(argc, &argv, &err)) {
4773 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4780 for (i = 0; i < arg_count; i++) {
4781 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4782 MMPLAYER_FREEIF(argv2[i]);
4785 MMPLAYER_FREEIF(argv);
4786 MMPLAYER_FREEIF(argv2);
4787 MMPLAYER_FREEIF(argc);
4797 for (i = 0; i < arg_count; i++) {
4798 LOGD("free[%d] : %s", i, argv2[i]);
4799 MMPLAYER_FREEIF(argv2[i]);
4802 MMPLAYER_FREEIF(argv);
4803 MMPLAYER_FREEIF(argv2);
4804 MMPLAYER_FREEIF(argc);
4810 __mmplayer_check_async_state_transition(mmplayer_t *player)
4812 GstState element_state = GST_STATE_VOID_PENDING;
4813 GstState element_pending_state = GST_STATE_VOID_PENDING;
4814 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4815 GstElement *element = NULL;
4816 gboolean async = FALSE;
4818 /* check player handle */
4819 MMPLAYER_RETURN_IF_FAIL(player &&
4821 player->pipeline->mainbin &&
4822 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4825 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4827 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4828 LOGD("don't need to check the pipeline state");
4832 MMPLAYER_PRINT_STATE(player);
4834 /* wait for state transition */
4835 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4836 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4838 if (ret == GST_STATE_CHANGE_FAILURE) {
4839 LOGE(" [%s] state : %s pending : %s",
4840 GST_ELEMENT_NAME(element),
4841 gst_element_state_get_name(element_state),
4842 gst_element_state_get_name(element_pending_state));
4844 /* dump state of all element */
4845 __mmplayer_dump_pipeline_state(player);
4850 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4855 _mmplayer_destroy(MMHandleType handle)
4857 mmplayer_t *player = MM_PLAYER_CAST(handle);
4861 /* check player handle */
4862 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4864 /* destroy can called at anytime */
4865 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4867 /* check async state transition */
4868 __mmplayer_check_async_state_transition(player);
4870 /* release gapless play thread */
4871 if (player->gapless_play_thread) {
4872 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4873 player->gapless_play_thread_exit = TRUE;
4874 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4875 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4877 LOGD("waitting for gapless play thread exit");
4878 g_thread_join(player->gapless_play_thread);
4879 g_mutex_clear(&player->gapless_play_thread_mutex);
4880 g_cond_clear(&player->gapless_play_thread_cond);
4881 LOGD("gapless play thread released");
4884 _mmplayer_release_video_capture(player);
4886 /* de-initialize resource manager */
4887 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4888 player->resource_manager))
4889 LOGE("failed to deinitialize resource manager");
4891 /* release pipeline */
4892 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4893 LOGE("failed to destory pipeline");
4894 return MM_ERROR_PLAYER_INTERNAL;
4897 g_queue_free(player->bus_msg_q);
4899 /* release subtitle info lock and cond */
4900 g_mutex_clear(&player->subtitle_info_mutex);
4901 g_cond_clear(&player->subtitle_info_cond);
4903 __mmplayer_release_dump_list(player->dump_list);
4905 /* release miscellaneous information */
4906 __mmplayer_release_misc(player);
4908 /* release miscellaneous information.
4909 these info needs to be released after pipeline is destroyed. */
4910 __mmplayer_release_misc_post(player);
4912 /* release attributes */
4913 _mmplayer_deconstruct_attribute(handle);
4916 g_mutex_clear(&player->fsink_lock);
4919 g_mutex_clear(&player->update_tag_lock);
4921 /* release video bo lock and cond */
4922 g_mutex_clear(&player->video_bo_mutex);
4923 g_cond_clear(&player->video_bo_cond);
4925 /* release media stream callback lock */
4926 g_mutex_clear(&player->media_stream_cb_lock);
4930 return MM_ERROR_NONE;
4934 _mmplayer_realize(MMHandleType hplayer)
4936 mmplayer_t *player = (mmplayer_t *)hplayer;
4939 MMHandleType attrs = 0;
4940 int ret = MM_ERROR_NONE;
4944 /* check player handle */
4945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4947 /* check current state */
4948 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4950 attrs = MMPLAYER_GET_ATTRS(player);
4952 LOGE("fail to get attributes.");
4953 return MM_ERROR_PLAYER_INTERNAL;
4955 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4956 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4958 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4959 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4961 if (ret != MM_ERROR_NONE) {
4962 LOGE("failed to parse profile");
4967 if (uri && (strstr(uri, "es_buff://"))) {
4968 if (strstr(uri, "es_buff://push_mode"))
4969 player->es_player_push_mode = TRUE;
4971 player->es_player_push_mode = FALSE;
4974 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4975 LOGW("mms protocol is not supported format.");
4976 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4979 if (MMPLAYER_IS_STREAMING(player))
4980 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4982 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4984 player->smooth_streaming = FALSE;
4985 player->videodec_linked = 0;
4986 player->audiodec_linked = 0;
4987 player->textsink_linked = 0;
4988 player->is_external_subtitle_present = FALSE;
4989 player->is_external_subtitle_added_now = FALSE;
4990 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4991 player->video360_metadata.is_spherical = -1;
4992 player->is_openal_plugin_used = FALSE;
4993 player->demux_pad_index = 0;
4994 player->subtitle_language_list = NULL;
4995 player->is_subtitle_force_drop = FALSE;
4997 __mmplayer_track_initialize(player);
4998 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5000 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5001 gint prebuffer_ms = 0, rebuffer_ms = 0;
5003 player->streamer = __mm_player_streaming_create();
5004 __mm_player_streaming_initialize(player->streamer, TRUE);
5006 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5007 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5009 if (prebuffer_ms > 0) {
5010 prebuffer_ms = MAX(prebuffer_ms, 1000);
5011 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5014 if (rebuffer_ms > 0) {
5015 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5016 rebuffer_ms = MAX(rebuffer_ms, 1000);
5017 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5020 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5021 player->streamer->buffering_req.rebuffer_time);
5024 /* realize pipeline */
5025 ret = __mmplayer_gst_realize(player);
5026 if (ret != MM_ERROR_NONE)
5027 LOGE("fail to realize the player.");
5029 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5037 _mmplayer_unrealize(MMHandleType hplayer)
5039 mmplayer_t *player = (mmplayer_t *)hplayer;
5040 int ret = MM_ERROR_NONE;
5044 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5046 MMPLAYER_CMD_UNLOCK(player);
5047 /* destroy the gst bus msg thread which is created during realize.
5048 this funct have to be called before getting cmd lock. */
5049 __mmplayer_bus_msg_thread_destroy(player);
5050 MMPLAYER_CMD_LOCK(player);
5052 /* check current state */
5053 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5055 /* check async state transition */
5056 __mmplayer_check_async_state_transition(player);
5058 /* unrealize pipeline */
5059 ret = __mmplayer_gst_unrealize(player);
5061 /* set asm stop if success */
5062 if (MM_ERROR_NONE == ret) {
5063 if (!player->interrupted_by_resource) {
5064 if (player->video_decoder_resource != NULL) {
5065 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5066 player->video_decoder_resource);
5067 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5068 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
5070 player->video_decoder_resource = NULL;
5073 if (player->video_overlay_resource != NULL) {
5074 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5075 player->video_overlay_resource);
5076 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5077 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
5079 player->video_overlay_resource = NULL;
5082 ret = mm_resource_manager_commit(player->resource_manager);
5083 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5084 LOGE("failed to commit resource releases, ret(0x%x)", ret);
5087 LOGE("failed and don't change asm state to stop");
5095 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5097 mmplayer_t *player = (mmplayer_t *)hplayer;
5099 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5101 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5105 _mmplayer_get_state(MMHandleType hplayer, int *state)
5107 mmplayer_t *player = (mmplayer_t *)hplayer;
5109 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5111 *state = MMPLAYER_CURRENT_STATE(player);
5113 return MM_ERROR_NONE;
5118 _mmplayer_set_volume(MMHandleType hplayer, mmplayer_volume_type_t volume)
5120 mmplayer_t *player = (mmplayer_t *)hplayer;
5121 GstElement *vol_element = NULL;
5126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5128 LOGD("volume [L]=%f:[R]=%f",
5129 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5131 /* invalid factor range or not */
5132 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5133 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5134 LOGE("Invalid factor!(valid factor:0~1.0)");
5135 return MM_ERROR_INVALID_ARGUMENT;
5139 /* not support to set other value into each channel */
5140 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5141 return MM_ERROR_INVALID_ARGUMENT;
5143 /* Save volume to handle. Currently the first array element will be saved. */
5144 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5146 /* check pipeline handle */
5147 if (!player->pipeline || !player->pipeline->audiobin) {
5148 LOGD("audiobin is not created yet");
5149 LOGD("but, current stored volume will be set when it's created.");
5151 /* NOTE : stored volume will be used in create_audiobin
5152 * returning MM_ERROR_NONE here makes application to able to
5153 * set volume at anytime.
5155 return MM_ERROR_NONE;
5158 /* setting volume to volume element */
5159 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5162 LOGD("volume is set [%f]", player->sound.volume);
5163 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5168 return MM_ERROR_NONE;
5172 _mmplayer_get_volume(MMHandleType hplayer, mmplayer_volume_type_t *volume)
5174 mmplayer_t *player = (mmplayer_t *)hplayer;
5179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5180 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5182 /* returning stored volume */
5183 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5184 volume->level[i] = player->sound.volume;
5188 return MM_ERROR_NONE;
5192 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5194 mmplayer_t *player = (mmplayer_t *)hplayer;
5195 GstElement *vol_element = NULL;
5199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5201 /* mute value shoud 0 or 1 */
5202 if (mute != 0 && mute != 1) {
5203 LOGE("bad mute value");
5205 /* FIXIT : definitly, we need _BAD_PARAM error code */
5206 return MM_ERROR_INVALID_ARGUMENT;
5209 player->sound.mute = mute;
5211 /* just hold mute value if pipeline is not ready */
5212 if (!player->pipeline || !player->pipeline->audiobin) {
5213 LOGD("pipeline is not ready. holding mute value");
5214 return MM_ERROR_NONE;
5217 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5219 /* NOTE : volume will only created when the bt is enabled */
5221 LOGD("mute : %d", mute);
5222 g_object_set(vol_element, "mute", mute, NULL);
5224 LOGD("volume elemnet is not created. using volume in audiosink");
5228 return MM_ERROR_NONE;
5232 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5234 mmplayer_t *player = (mmplayer_t *)hplayer;
5238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5239 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5241 /* just hold mute value if pipeline is not ready */
5242 if (!player->pipeline || !player->pipeline->audiobin) {
5243 LOGD("pipeline is not ready. returning stored value");
5244 *pmute = player->sound.mute;
5245 return MM_ERROR_NONE;
5248 *pmute = player->sound.mute;
5252 return MM_ERROR_NONE;
5256 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5258 mmplayer_t *player = (mmplayer_t *)hplayer;
5262 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5264 player->video_stream_changed_cb = callback;
5265 player->video_stream_changed_cb_user_param = user_param;
5266 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5270 return MM_ERROR_NONE;
5274 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5276 mmplayer_t *player = (mmplayer_t *)hplayer;
5280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282 player->audio_stream_changed_cb = callback;
5283 player->audio_stream_changed_cb_user_param = user_param;
5284 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5288 return MM_ERROR_NONE;
5292 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 player->audio_decoded_cb = callback;
5301 player->audio_decoded_cb_user_param = user_param;
5302 player->audio_extract_opt = opt;
5303 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5307 return MM_ERROR_NONE;
5311 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5313 mmplayer_t *player = (mmplayer_t *)hplayer;
5317 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5319 if (callback && !player->bufmgr)
5320 player->bufmgr = tbm_bufmgr_init(-1);
5322 player->set_mode.video_export = (callback) ? true : false;
5323 player->video_decoded_cb = callback;
5324 player->video_decoded_cb_user_param = user_param;
5326 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5330 return MM_ERROR_NONE;
5334 _mmplayer_start(MMHandleType hplayer)
5336 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 gint ret = MM_ERROR_NONE;
5341 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5343 /* check current state */
5344 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5346 /* start pipeline */
5347 ret = __mmplayer_gst_start(player);
5348 if (ret != MM_ERROR_NONE)
5349 LOGE("failed to start player.");
5351 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5352 LOGD("force playing start even during buffering");
5353 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5361 /* NOTE: post "not supported codec message" to application
5362 * when one codec is not found during AUTOPLUGGING in MSL.
5363 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5364 * And, if any codec is not found, don't send message here.
5365 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5368 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5370 MMMessageParamType msg_param;
5371 memset(&msg_param, 0, sizeof(MMMessageParamType));
5372 gboolean post_msg_direct = FALSE;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5379 player->not_supported_codec, player->can_support_codec);
5381 if (player->not_found_demuxer) {
5382 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5383 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5385 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5386 MMPLAYER_FREEIF(msg_param.data);
5388 return MM_ERROR_NONE;
5391 if (player->not_supported_codec) {
5392 if (player->can_support_codec) {
5393 // There is one codec to play
5394 post_msg_direct = TRUE;
5396 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5397 post_msg_direct = TRUE;
5400 if (post_msg_direct) {
5401 MMMessageParamType msg_param;
5402 memset(&msg_param, 0, sizeof(MMMessageParamType));
5404 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5405 LOGW("not found AUDIO codec, posting error code to application.");
5407 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5408 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5409 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5410 LOGW("not found VIDEO codec, posting error code to application.");
5412 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5413 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5416 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5418 MMPLAYER_FREEIF(msg_param.data);
5420 return MM_ERROR_NONE;
5422 // no any supported codec case
5423 LOGW("not found any codec, posting error code to application.");
5425 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5426 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5429 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5430 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5433 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5435 MMPLAYER_FREEIF(msg_param.data);
5441 return MM_ERROR_NONE;
5445 __mmplayer_check_pipeline(mmplayer_t *player)
5447 GstState element_state = GST_STATE_VOID_PENDING;
5448 GstState element_pending_state = GST_STATE_VOID_PENDING;
5450 int ret = MM_ERROR_NONE;
5452 if (!player->gapless.reconfigure)
5455 LOGW("pipeline is under construction.");
5457 MMPLAYER_PLAYBACK_LOCK(player);
5458 MMPLAYER_PLAYBACK_UNLOCK(player);
5460 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5462 /* wait for state transition */
5463 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5464 if (ret == GST_STATE_CHANGE_FAILURE)
5465 LOGE("failed to change pipeline state within %d sec", timeout);
5468 /* NOTE : it should be able to call 'stop' anytime*/
5470 _mmplayer_stop(MMHandleType hplayer)
5472 mmplayer_t *player = (mmplayer_t *)hplayer;
5473 int ret = MM_ERROR_NONE;
5477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5479 /* check current state */
5480 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5482 /* check pipline building state */
5483 __mmplayer_check_pipeline(player);
5484 __mmplayer_reset_gapless_state(player);
5486 /* NOTE : application should not wait for EOS after calling STOP */
5487 __mmplayer_cancel_eos_timer(player);
5490 player->seek_state = MMPLAYER_SEEK_NONE;
5493 ret = __mmplayer_gst_stop(player);
5495 if (ret != MM_ERROR_NONE)
5496 LOGE("failed to stop player.");
5504 _mmplayer_pause(MMHandleType hplayer)
5506 mmplayer_t *player = (mmplayer_t *)hplayer;
5507 gint64 pos_nsec = 0;
5508 gboolean async = FALSE;
5509 gint ret = MM_ERROR_NONE;
5513 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5515 /* check current state */
5516 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5518 /* check pipline building state */
5519 __mmplayer_check_pipeline(player);
5521 switch (MMPLAYER_CURRENT_STATE(player)) {
5522 case MM_PLAYER_STATE_READY:
5524 /* check prepare async or not.
5525 * In the case of streaming playback, it's recommned to avoid blocking wait.
5527 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5528 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5530 /* Changing back sync of rtspsrc to async */
5531 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5532 LOGD("async prepare working mode for rtsp");
5538 case MM_PLAYER_STATE_PLAYING:
5540 /* NOTE : store current point to overcome some bad operation
5541 *(returning zero when getting current position in paused state) of some
5544 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5545 LOGW("getting current position failed in paused");
5547 player->last_position = pos_nsec;
5549 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5550 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5551 This causes problem is position calculation during normal pause resume scenarios also.
5552 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5553 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5554 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5555 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5561 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5562 LOGD("doing async pause in case of ms buff src");
5566 /* pause pipeline */
5567 ret = __mmplayer_gst_pause(player, async);
5569 if (ret != MM_ERROR_NONE)
5570 LOGE("failed to pause player. ret : 0x%x", ret);
5572 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5573 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5574 LOGE("failed to update display_rotation");
5582 /* in case of streaming, pause could take long time.*/
5584 _mmplayer_abort_pause(MMHandleType hplayer)
5586 mmplayer_t *player = (mmplayer_t *)hplayer;
5587 int ret = MM_ERROR_NONE;
5591 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5593 player->pipeline->mainbin,
5594 MM_ERROR_PLAYER_NOT_INITIALIZED);
5596 LOGD("set the pipeline state to READY");
5598 /* set state to READY */
5599 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5600 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5601 if (ret != MM_ERROR_NONE) {
5602 LOGE("fail to change state to READY");
5603 return MM_ERROR_PLAYER_INTERNAL;
5606 LOGD("succeeded in changing state to READY");
5611 _mmplayer_resume(MMHandleType hplayer)
5613 mmplayer_t *player = (mmplayer_t *)hplayer;
5614 int ret = MM_ERROR_NONE;
5615 gboolean async = FALSE;
5619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5621 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5622 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5623 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5627 /* Changing back sync mode rtspsrc to async */
5628 LOGD("async resume for rtsp case");
5632 /* check current state */
5633 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5635 ret = __mmplayer_gst_resume(player, async);
5636 if (ret != MM_ERROR_NONE)
5637 LOGE("failed to resume player.");
5639 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5640 LOGD("force resume even during buffering");
5641 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5650 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5652 mmplayer_t *player = (mmplayer_t *)hplayer;
5653 gint64 pos_nsec = 0;
5654 int ret = MM_ERROR_NONE;
5656 signed long long start = 0, stop = 0;
5657 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5660 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5661 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5663 /* The sound of video is not supported under 0.0 and over 2.0. */
5664 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5665 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5668 _mmplayer_set_mute(hplayer, mute);
5670 if (player->playback_rate == rate)
5671 return MM_ERROR_NONE;
5673 /* If the position is reached at start potion during fast backward, EOS is posted.
5674 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5676 player->playback_rate = rate;
5678 current_state = MMPLAYER_CURRENT_STATE(player);
5680 if (current_state != MM_PLAYER_STATE_PAUSED)
5681 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5683 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5685 if ((current_state == MM_PLAYER_STATE_PAUSED)
5686 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5687 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5688 pos_nsec = player->last_position;
5693 stop = GST_CLOCK_TIME_NONE;
5695 start = GST_CLOCK_TIME_NONE;
5699 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5700 player->playback_rate,
5702 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5703 GST_SEEK_TYPE_SET, start,
5704 GST_SEEK_TYPE_SET, stop)) {
5705 LOGE("failed to set speed playback");
5706 return MM_ERROR_PLAYER_SEEK;
5709 LOGD("succeeded to set speed playback as %0.1f", rate);
5713 return MM_ERROR_NONE;;
5717 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5719 mmplayer_t *player = (mmplayer_t *)hplayer;
5720 int ret = MM_ERROR_NONE;
5724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5726 /* check pipline building state */
5727 __mmplayer_check_pipeline(player);
5729 ret = __mmplayer_gst_set_position(player, position, FALSE);
5737 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5739 mmplayer_t *player = (mmplayer_t *)hplayer;
5740 int ret = MM_ERROR_NONE;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5744 ret = __mmplayer_gst_get_position(player, position);
5750 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5752 mmplayer_t *player = (mmplayer_t *)hplayer;
5753 int ret = MM_ERROR_NONE;
5755 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5756 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5758 if (g_strrstr(player->type, "video/mpegts"))
5759 __mmplayer_update_duration_value(player);
5761 *duration = player->duration;
5766 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5768 mmplayer_t *player = (mmplayer_t *)hplayer;
5769 int ret = MM_ERROR_NONE;
5771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5773 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5779 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5781 mmplayer_t *player = (mmplayer_t *)hplayer;
5782 int ret = MM_ERROR_NONE;
5786 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5788 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5796 __mmplayer_is_midi_type(gchar *str_caps)
5798 if ((g_strrstr(str_caps, "audio/midi")) ||
5799 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5800 (g_strrstr(str_caps, "application/x-smaf")) ||
5801 (g_strrstr(str_caps, "audio/x-imelody")) ||
5802 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5803 (g_strrstr(str_caps, "audio/xmf")) ||
5804 (g_strrstr(str_caps, "audio/mxmf"))) {
5813 __mmplayer_is_only_mp3_type(gchar *str_caps)
5815 if (g_strrstr(str_caps, "application/x-id3") ||
5816 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5822 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5824 GstStructure *caps_structure = NULL;
5825 gint samplerate = 0;
5829 MMPLAYER_RETURN_IF_FAIL(player && caps);
5831 caps_structure = gst_caps_get_structure(caps, 0);
5833 /* set stream information */
5834 gst_structure_get_int(caps_structure, "rate", &samplerate);
5835 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5837 gst_structure_get_int(caps_structure, "channels", &channels);
5838 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5840 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5844 __mmplayer_update_content_type_info(mmplayer_t *player)
5847 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5849 if (__mmplayer_is_midi_type(player->type)) {
5850 player->bypass_audio_effect = TRUE;
5854 if (!player->streamer) {
5855 LOGD("no need to check streaming type");
5859 if (g_strrstr(player->type, "application/x-hls")) {
5860 /* If it can't know exact type when it parses uri because of redirection case,
5861 * it will be fixed by typefinder or when doing autoplugging.
5863 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5864 player->streamer->is_adaptive_streaming = TRUE;
5865 } else if (g_strrstr(player->type, "application/dash+xml")) {
5866 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5867 player->streamer->is_adaptive_streaming = TRUE;
5870 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5871 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5872 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5874 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5875 if (player->streamer->is_adaptive_streaming)
5876 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5878 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5882 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5887 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5888 GstCaps *caps, gpointer data)
5890 mmplayer_t *player = (mmplayer_t *)data;
5895 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5897 /* store type string */
5898 MMPLAYER_FREEIF(player->type);
5899 player->type = gst_caps_to_string(caps);
5901 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5902 player, player->type, probability, gst_caps_get_size(caps));
5904 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5905 (g_strrstr(player->type, "audio/x-raw-int"))) {
5906 LOGE("not support media format");
5908 if (player->msg_posted == FALSE) {
5909 MMMessageParamType msg_param;
5910 memset(&msg_param, 0, sizeof(MMMessageParamType));
5912 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5913 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5915 /* don't post more if one was sent already */
5916 player->msg_posted = TRUE;
5921 __mmplayer_update_content_type_info(player);
5923 pad = gst_element_get_static_pad(tf, "src");
5925 LOGE("fail to get typefind src pad.");
5929 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5930 gboolean async = FALSE;
5931 LOGE("failed to autoplug %s", player->type);
5933 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5935 if (async && player->msg_posted == FALSE)
5936 __mmplayer_handle_missed_plugin(player);
5940 gst_object_unref(GST_OBJECT(pad));
5948 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5950 GstElement *decodebin = NULL;
5954 /* create decodebin */
5955 decodebin = gst_element_factory_make("decodebin", NULL);
5958 LOGE("fail to create decodebin");
5962 /* raw pad handling signal */
5963 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5964 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5966 /* no-more-pad pad handling signal */
5967 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5968 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5970 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5971 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5973 /* This signal is emitted when a pad for which there is no further possible
5974 decoding is added to the decodebin.*/
5975 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5976 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5978 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5979 before looking for any elements that can handle that stream.*/
5980 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5981 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5983 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5984 before looking for any elements that can handle that stream.*/
5985 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5986 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5988 /* This signal is emitted once decodebin has finished decoding all the data.*/
5989 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5990 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5992 /* This signal is emitted when a element is added to the bin.*/
5993 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5994 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
6001 __mmplayer_gst_make_queue2(mmplayer_t *player)
6003 GstElement *queue2 = NULL;
6004 gint64 dur_bytes = 0L;
6005 mmplayer_gst_element_t *mainbin = NULL;
6006 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6009 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6011 mainbin = player->pipeline->mainbin;
6013 queue2 = gst_element_factory_make("queue2", "queue2");
6015 LOGE("failed to create buffering queue element");
6019 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6020 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6022 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6024 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6025 * skip the pull mode(file or ring buffering) setting. */
6026 if (dur_bytes > 0) {
6027 if (!g_strrstr(player->type, "video/mpegts")) {
6028 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6029 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6035 __mm_player_streaming_set_queue2(player->streamer,
6039 (guint64)dur_bytes); /* no meaning at the moment */
6045 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6047 mmplayer_gst_element_t *mainbin = NULL;
6048 GstElement *decodebin = NULL;
6049 GstElement *queue2 = NULL;
6050 GstPad *sinkpad = NULL;
6051 GstPad *qsrcpad = NULL;
6054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6056 mainbin = player->pipeline->mainbin;
6058 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6060 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6061 LOGW("need to check: muxed buffer is not null");
6064 queue2 = __mmplayer_gst_make_queue2(player);
6066 LOGE("failed to make queue2");
6070 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6071 LOGE("failed to add buffering queue");
6075 sinkpad = gst_element_get_static_pad(queue2, "sink");
6076 qsrcpad = gst_element_get_static_pad(queue2, "src");
6078 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6079 LOGE("failed to link [%s:%s]-[%s:%s]",
6080 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6084 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6085 LOGE("failed to sync queue2 state with parent");
6089 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6090 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6094 gst_object_unref(GST_OBJECT(sinkpad));
6098 /* create decodebin */
6099 decodebin = __mmplayer_gst_make_decodebin(player);
6101 LOGE("failed to make decodebin");
6105 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6106 LOGE("failed to add decodebin");
6110 /* to force caps on the decodebin element and avoid reparsing stuff by
6111 * typefind. It also avoids a deadlock in the way typefind activates pads in
6112 * the state change */
6113 g_object_set(decodebin, "sink-caps", caps, NULL);
6115 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6117 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6118 LOGE("failed to link [%s:%s]-[%s:%s]",
6119 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6123 gst_object_unref(GST_OBJECT(sinkpad));
6125 gst_object_unref(GST_OBJECT(qsrcpad));
6128 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6129 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6131 /* set decodebin property about buffer in streaming playback. *
6132 * in case of HLS/DASH, it does not need to have big buffer *
6133 * because it is kind of adaptive streaming. */
6134 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6135 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6136 gint high_percent = 0;
6138 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6139 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6141 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6143 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6145 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6146 "high-percent", high_percent,
6147 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6148 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6149 "max-size-buffers", 0, NULL); // disable or automatic
6152 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6153 LOGE("failed to sync decodebin state with parent");
6164 gst_object_unref(GST_OBJECT(sinkpad));
6167 gst_object_unref(GST_OBJECT(qsrcpad));
6170 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6171 * You need to explicitly set elements to the NULL state before
6172 * dropping the final reference, to allow them to clean up.
6174 gst_element_set_state(queue2, GST_STATE_NULL);
6176 /* And, it still has a parent "player".
6177 * You need to let the parent manage the object instead of unreffing the object directly.
6179 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6180 gst_object_unref(queue2);
6185 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6186 * You need to explicitly set elements to the NULL state before
6187 * dropping the final reference, to allow them to clean up.
6189 gst_element_set_state(decodebin, GST_STATE_NULL);
6191 /* And, it still has a parent "player".
6192 * You need to let the parent manage the object instead of unreffing the object directly.
6195 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6196 gst_object_unref(decodebin);
6204 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6209 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6211 LOGD("class : %s, mime : %s", factory_class, mime);
6213 /* add missing plugin */
6214 /* NOTE : msl should check missing plugin for image mime type.
6215 * Some motion jpeg clips can have playable audio track.
6216 * So, msl have to play audio after displaying popup written video format not supported.
6218 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6219 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6220 LOGD("not found demuxer");
6221 player->not_found_demuxer = TRUE;
6222 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6228 if (!g_strrstr(factory_class, "Demuxer")) {
6229 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6230 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6231 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6233 /* check that clip have multi tracks or not */
6234 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6235 LOGD("video plugin is already linked");
6237 LOGW("add VIDEO to missing plugin");
6238 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6239 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6241 } else if (g_str_has_prefix(mime, "audio")) {
6242 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6243 LOGD("audio plugin is already linked");
6245 LOGW("add AUDIO to missing plugin");
6246 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6247 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6255 return MM_ERROR_NONE;
6259 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6261 mmplayer_t *player = (mmplayer_t *)data;
6265 MMPLAYER_RETURN_IF_FAIL(player);
6267 /* remove fakesink. */
6268 if (!__mmplayer_gst_remove_fakesink(player,
6269 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6270 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6271 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6272 * source element are not same. To overcome this situation, this function will called
6273 * several places and several times. Therefore, this is not an error case.
6278 LOGD("[handle: %p] pipeline has completely constructed", player);
6280 if ((player->ini.async_start) &&
6281 (player->msg_posted == FALSE) &&
6282 (player->cmd >= MMPLAYER_COMMAND_START))
6283 __mmplayer_handle_missed_plugin(player);
6285 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6289 __mmplayer_check_profile(void)
6292 static int profile_tv = -1;
6294 if (__builtin_expect(profile_tv != -1, 1))
6297 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6298 switch (*profileName) {
6313 __mmplayer_get_next_uri(mmplayer_t *player)
6315 mmplayer_parse_profile_t profile;
6317 guint num_of_list = 0;
6320 num_of_list = g_list_length(player->uri_info.uri_list);
6321 uri_idx = player->uri_info.uri_idx;
6323 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6324 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6325 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6327 LOGW("next uri does not exist");
6331 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6332 LOGE("failed to parse profile");
6336 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6337 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6338 LOGW("uri type is not supported(%d)", profile.uri_type);
6342 LOGD("success to find next uri %d", uri_idx);
6346 if (uri_idx == num_of_list) {
6347 LOGE("failed to find next uri");
6351 player->uri_info.uri_idx = uri_idx;
6352 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6354 if (mm_attrs_commit_all(player->attrs)) {
6355 LOGE("failed to commit");
6359 SECURE_LOGD("next playback uri: %s", uri);
6364 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6366 #define REPEAT_COUNT_INFINITELY -1
6367 #define REPEAT_COUNT_MIN 2
6369 MMHandleType attrs = 0;
6373 guint num_of_list = 0;
6374 int profile_tv = -1;
6378 LOGD("checking for gapless play option");
6380 if (player->pipeline->textbin) {
6381 LOGE("subtitle path is enabled. gapless play is not supported.");
6385 attrs = MMPLAYER_GET_ATTRS(player);
6387 LOGE("fail to get attributes.");
6391 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6393 /* gapless playback is not supported in case of video at TV profile. */
6394 profile_tv = __mmplayer_check_profile();
6395 if (profile_tv && video) {
6396 LOGW("not support video gapless playback");
6400 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6401 LOGE("failed to get play count");
6403 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6404 LOGE("failed to get gapless mode");
6406 /* check repeat count in case of audio */
6408 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6409 LOGW("gapless is disabled");
6413 num_of_list = g_list_length(player->uri_info.uri_list);
6415 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6417 if (num_of_list == 0) {
6418 /* audio looping path */
6419 if (count >= REPEAT_COUNT_MIN) {
6420 /* decrease play count */
6421 /* we succeeded to rewind. update play count and then wait for next EOS */
6423 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6424 /* commit attribute */
6425 if (mm_attrs_commit_all(attrs))
6426 LOGE("failed to commit attribute");
6428 } else if (count != REPEAT_COUNT_INFINITELY) {
6429 LOGD("there is no next uri and no repeat");
6432 LOGD("looping cnt %d", count);
6434 /* gapless playback path */
6435 if (!__mmplayer_get_next_uri(player)) {
6436 LOGE("failed to get next uri");
6443 LOGE("unable to play gapless path. EOS will be posted soon");
6448 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6454 player->smooth_streaming = FALSE;
6455 player->videodec_linked = 0;
6456 player->audiodec_linked = 0;
6457 player->textsink_linked = 0;
6458 player->is_external_subtitle_present = FALSE;
6459 player->is_external_subtitle_added_now = FALSE;
6460 player->not_supported_codec = MISSING_PLUGIN_NONE;
6461 player->can_support_codec = FOUND_PLUGIN_NONE;
6462 player->pending_seek.is_pending = false;
6463 player->pending_seek.pos = 0;
6464 player->msg_posted = FALSE;
6465 player->has_many_types = FALSE;
6466 player->no_more_pad = FALSE;
6467 player->not_found_demuxer = 0;
6468 player->seek_state = MMPLAYER_SEEK_NONE;
6469 player->is_subtitle_force_drop = FALSE;
6470 player->play_subtitle = FALSE;
6471 player->adjust_subtitle_pos = 0;
6473 player->total_bitrate = 0;
6474 player->total_maximum_bitrate = 0;
6476 __mmplayer_track_initialize(player);
6477 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6479 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6480 player->bitrate[i] = 0;
6481 player->maximum_bitrate[i] = 0;
6484 if (player->v_stream_caps) {
6485 gst_caps_unref(player->v_stream_caps);
6486 player->v_stream_caps = NULL;
6489 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6491 /* clean found audio decoders */
6492 if (player->audio_decoders) {
6493 GList *a_dec = player->audio_decoders;
6494 for (; a_dec; a_dec = g_list_next(a_dec)) {
6495 gchar *name = a_dec->data;
6496 MMPLAYER_FREEIF(name);
6498 g_list_free(player->audio_decoders);
6499 player->audio_decoders = NULL;
6506 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6508 mmplayer_gst_element_t *mainbin = NULL;
6509 MMMessageParamType msg_param = {0,};
6510 GstElement *element = NULL;
6511 MMHandleType attrs = 0;
6513 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6517 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6518 LOGE("player is not initialized");
6522 mainbin = player->pipeline->mainbin;
6523 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6525 attrs = MMPLAYER_GET_ATTRS(player);
6527 LOGE("fail to get attributes");
6531 /* Initialize Player values */
6532 __mmplayer_initialize_gapless_play(player);
6534 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6536 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6537 LOGE("failed to parse profile");
6538 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6542 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6543 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6544 LOGE("dash or hls is not supportable");
6545 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6549 element = __mmplayer_gst_create_source(player);
6551 LOGE("no source element was created");
6555 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6556 LOGE("failed to add source element to pipeline");
6557 gst_object_unref(GST_OBJECT(element));
6562 /* take source element */
6563 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6564 mainbin[MMPLAYER_M_SRC].gst = element;
6568 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6569 if (player->streamer == NULL) {
6570 player->streamer = __mm_player_streaming_create();
6571 __mm_player_streaming_initialize(player->streamer, TRUE);
6574 elem_idx = MMPLAYER_M_TYPEFIND;
6575 element = gst_element_factory_make("typefind", "typefinder");
6576 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6577 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6579 elem_idx = MMPLAYER_M_AUTOPLUG;
6580 element = __mmplayer_gst_make_decodebin(player);
6583 /* check autoplug element is OK */
6585 LOGE("can not create element(%d)", elem_idx);
6589 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6590 LOGE("failed to add sinkbin to pipeline");
6591 gst_object_unref(GST_OBJECT(element));
6596 mainbin[elem_idx].id = elem_idx;
6597 mainbin[elem_idx].gst = element;
6599 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6600 LOGE("Failed to link src - autoplug(or typefind)");
6604 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6605 LOGE("Failed to change state of src element");
6609 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6610 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6611 LOGE("Failed to change state of decodebin");
6615 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6616 LOGE("Failed to change state of src element");
6621 player->gapless.stream_changed = TRUE;
6622 player->gapless.running = TRUE;
6628 MMPLAYER_PLAYBACK_UNLOCK(player);
6630 if (!player->msg_posted) {
6631 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6632 player->msg_posted = TRUE;
6639 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6641 mmplayer_selector_t *selector = &player->selector[type];
6642 mmplayer_gst_element_t *sinkbin = NULL;
6643 main_element_id_e selectorId = MMPLAYER_M_NUM;
6644 main_element_id_e sinkId = MMPLAYER_M_NUM;
6645 GstPad *srcpad = NULL;
6646 GstPad *sinkpad = NULL;
6647 gboolean send_notice = FALSE;
6650 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6652 LOGD("type %d", type);
6655 case MM_PLAYER_TRACK_TYPE_AUDIO:
6656 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6657 sinkId = MMPLAYER_A_BIN;
6658 sinkbin = player->pipeline->audiobin;
6660 case MM_PLAYER_TRACK_TYPE_VIDEO:
6661 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6662 sinkId = MMPLAYER_V_BIN;
6663 sinkbin = player->pipeline->videobin;
6666 case MM_PLAYER_TRACK_TYPE_TEXT:
6667 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6668 sinkId = MMPLAYER_T_BIN;
6669 sinkbin = player->pipeline->textbin;
6672 LOGE("requested type is not supportable");
6677 if (player->pipeline->mainbin[selectorId].gst) {
6680 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6682 if (selector->event_probe_id != 0)
6683 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6684 selector->event_probe_id = 0;
6686 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6687 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6689 if (srcpad && sinkpad) {
6690 /* after getting drained signal there is no data flows, so no need to do pad_block */
6691 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6692 gst_pad_unlink(srcpad, sinkpad);
6694 /* send custom event to sink pad to handle it at video sink */
6696 LOGD("send custom event to sinkpad");
6697 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6698 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6699 gst_pad_send_event(sinkpad, event);
6703 gst_object_unref(sinkpad);
6706 gst_object_unref(srcpad);
6709 LOGD("selector release");
6711 /* release and unref requests pad from the selector */
6712 for (n = 0; n < selector->channels->len; n++) {
6713 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6714 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6716 g_ptr_array_set_size(selector->channels, 0);
6718 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6719 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6721 player->pipeline->mainbin[selectorId].gst = NULL;
6729 __mmplayer_deactivate_old_path(mmplayer_t *player)
6732 MMPLAYER_RETURN_IF_FAIL(player);
6734 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6735 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6736 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6737 LOGE("deactivate selector error");
6741 __mmplayer_track_destroy(player);
6742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6744 if (player->streamer) {
6745 __mm_player_streaming_initialize(player->streamer, FALSE);
6746 __mm_player_streaming_destroy(player->streamer);
6747 player->streamer = NULL;
6750 MMPLAYER_PLAYBACK_LOCK(player);
6751 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6758 if (!player->msg_posted) {
6759 MMMessageParamType msg = {0,};
6762 msg.code = MM_ERROR_PLAYER_INTERNAL;
6763 LOGE("gapless_uri_play> deactivate error");
6765 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6766 player->msg_posted = TRUE;
6772 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6774 int result = MM_ERROR_NONE;
6775 mmplayer_t *player = (mmplayer_t *)hplayer;
6778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6780 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6781 if (mm_attrs_commit_all(player->attrs)) {
6782 LOGE("failed to commit the original uri.");
6783 result = MM_ERROR_PLAYER_INTERNAL;
6785 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6786 LOGE("failed to add the original uri in the uri list.");
6794 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6796 mmplayer_t *player = (mmplayer_t *)hplayer;
6797 guint num_of_list = 0;
6801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6802 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6804 if (player->pipeline && player->pipeline->textbin) {
6805 LOGE("subtitle path is enabled.");
6806 return MM_ERROR_PLAYER_INVALID_STATE;
6809 num_of_list = g_list_length(player->uri_info.uri_list);
6811 if (is_first_path) {
6812 if (num_of_list == 0) {
6813 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6814 SECURE_LOGD("add original path : %s", uri);
6816 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6817 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6819 SECURE_LOGD("change original path : %s", uri);
6822 MMHandleType attrs = 0;
6823 attrs = MMPLAYER_GET_ATTRS(player);
6825 if (num_of_list == 0) {
6826 char *original_uri = NULL;
6829 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6831 if (!original_uri) {
6832 LOGE("there is no original uri.");
6833 return MM_ERROR_PLAYER_INVALID_STATE;
6836 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6837 player->uri_info.uri_idx = 0;
6839 SECURE_LOGD("add original path at first : %s", original_uri);
6843 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6844 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6848 return MM_ERROR_NONE;
6852 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6854 mmplayer_t *player = (mmplayer_t *)hplayer;
6855 char *next_uri = NULL;
6856 guint num_of_list = 0;
6859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6861 num_of_list = g_list_length(player->uri_info.uri_list);
6863 if (num_of_list > 0) {
6864 gint uri_idx = player->uri_info.uri_idx;
6866 if (uri_idx < num_of_list-1)
6871 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6872 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6874 *uri = g_strdup(next_uri);
6878 return MM_ERROR_NONE;
6882 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6883 GstCaps *caps, gpointer data)
6885 mmplayer_t *player = (mmplayer_t *)data;
6886 const gchar *klass = NULL;
6887 const gchar *mime = NULL;
6888 gchar *caps_str = NULL;
6890 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6891 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6892 caps_str = gst_caps_to_string(caps);
6894 LOGW("unknown type of caps : %s from %s",
6895 caps_str, GST_ELEMENT_NAME(elem));
6897 MMPLAYER_FREEIF(caps_str);
6899 /* There is no available codec. */
6900 __mmplayer_check_not_supported_codec(player, klass, mime);
6904 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6905 GstCaps *caps, gpointer data)
6907 mmplayer_t *player = (mmplayer_t *)data;
6908 const char *mime = NULL;
6909 gboolean ret = TRUE;
6911 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6912 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6914 if (g_str_has_prefix(mime, "audio")) {
6915 GstStructure *caps_structure = NULL;
6916 gint samplerate = 0;
6918 gchar *caps_str = NULL;
6920 caps_structure = gst_caps_get_structure(caps, 0);
6921 gst_structure_get_int(caps_structure, "rate", &samplerate);
6922 gst_structure_get_int(caps_structure, "channels", &channels);
6924 if ((channels > 0 && samplerate == 0)) {
6925 LOGD("exclude audio...");
6929 caps_str = gst_caps_to_string(caps);
6930 /* set it directly because not sent by TAG */
6931 if (g_strrstr(caps_str, "mobile-xmf"))
6932 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6933 MMPLAYER_FREEIF(caps_str);
6934 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6935 MMMessageParamType msg_param;
6936 memset(&msg_param, 0, sizeof(MMMessageParamType));
6937 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6938 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6939 LOGD("video file is not supported on this device");
6941 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6942 LOGD("already video linked");
6945 LOGD("found new stream");
6952 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6954 gboolean ret = TRUE;
6955 GDBusConnection *conn = NULL;
6957 GVariant *result = NULL;
6958 const gchar *dbus_device_type = NULL;
6959 const gchar *dbus_ret = NULL;
6962 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6964 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6970 result = g_dbus_connection_call_sync(conn,
6971 "org.pulseaudio.Server",
6972 "/org/pulseaudio/StreamManager",
6973 "org.pulseaudio.StreamManager",
6974 "GetCurrentMediaRoutingPath",
6975 g_variant_new("(s)", "out"),
6976 G_VARIANT_TYPE("(ss)"),
6977 G_DBUS_CALL_FLAGS_NONE,
6981 if (!result || err) {
6982 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6988 /* device type is listed in stream-map.json at mmfw-sysconf */
6989 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6991 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6992 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6997 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6998 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6999 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7000 LOGD("audio offload is supportable");
7006 LOGD("audio offload is not supportable");
7010 g_variant_unref(result);
7011 g_object_unref(conn);
7016 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7018 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7019 gint64 position = 0;
7021 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7022 player->pipeline && player->pipeline->mainbin);
7024 MMPLAYER_CMD_LOCK(player);
7025 current_state = MMPLAYER_CURRENT_STATE(player);
7027 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7028 LOGW("getting current position failed in paused");
7030 _mmplayer_unrealize((MMHandleType)player);
7031 _mmplayer_realize((MMHandleType)player);
7033 _mmplayer_set_position((MMHandleType)player, position);
7035 /* async not to be blocked in streaming case */
7036 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
7037 if (mm_attrs_commit_all(player->attrs))
7038 LOGE("failed to commit");
7040 _mmplayer_pause((MMHandleType)player);
7042 if (current_state == MM_PLAYER_STATE_PLAYING)
7043 _mmplayer_start((MMHandleType)player);
7044 MMPLAYER_CMD_UNLOCK(player);
7046 LOGD("rebuilding audio pipeline is completed.");
7049 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7051 mmplayer_t *player = (mmplayer_t *)user_data;
7052 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7053 gboolean is_supportable = FALSE;
7055 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7056 LOGW("failed to get device type");
7058 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7060 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7061 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7062 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7063 LOGD("ignore this dev connected info");
7067 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7068 if (player->build_audio_offload == is_supportable) {
7069 LOGD("keep current pipeline without re-building");
7073 /* rebuild pipeline */
7074 LOGD("re-build pipeline - offload: %d", is_supportable);
7075 player->build_audio_offload = FALSE;
7076 __mmplayer_rebuild_audio_pipeline(player);
7082 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7084 unsigned int id = 0;
7086 if (player->audio_device_cb_id != 0) {
7087 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7091 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7092 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7093 LOGD("added device connected cb (%u)", id);
7094 player->audio_device_cb_id = id;
7096 LOGW("failed to add device connected cb");
7104 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7106 gboolean ret = FALSE;
7107 GstElementFactory *factory = NULL;
7110 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7112 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7113 if (!__mmplayer_is_only_mp3_type(player->type))
7116 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7117 LOGD("there is no audio offload sink");
7121 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7122 LOGW("there is no audio device type to support offload");
7126 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7128 LOGW("there is no installed audio offload sink element");
7131 gst_object_unref(factory);
7133 if (!__mmplayer_add_audio_device_connected_cb(player))
7136 if (!__mmplayer_is_audio_offload_device_type(player))
7139 LOGD("audio offload can be built");
7147 static GstAutoplugSelectResult
7148 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7150 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7152 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7153 int audio_offload = 0;
7155 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7156 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7158 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7159 LOGD("expose audio path to build offload output path");
7160 player->build_audio_offload = TRUE;
7161 /* update codec info */
7162 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7163 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7164 player->audiodec_linked = 1;
7166 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7170 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7172 LOGD("audio codec type: %d", codec_type);
7173 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7174 /* sw codec will be skipped */
7175 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7176 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7177 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7178 ret = GST_AUTOPLUG_SELECT_SKIP;
7182 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7183 /* hw codec will be skipped */
7184 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7185 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7186 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7187 ret = GST_AUTOPLUG_SELECT_SKIP;
7192 /* set stream information */
7193 if (!player->audiodec_linked)
7194 __mmplayer_set_audio_attrs(player, caps);
7196 /* update codec info */
7197 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7198 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7199 player->audiodec_linked = 1;
7201 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7203 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7205 LOGD("video codec type: %d", codec_type);
7206 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7207 /* sw codec is skipped */
7208 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7209 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7210 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7211 ret = GST_AUTOPLUG_SELECT_SKIP;
7215 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7216 /* hw codec is skipped */
7217 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7218 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7219 ret = GST_AUTOPLUG_SELECT_SKIP;
7224 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7225 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7227 /* mark video decoder for acquire */
7228 if (player->video_decoder_resource == NULL) {
7229 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7230 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7231 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7232 &player->video_decoder_resource)
7233 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7234 LOGE("could not mark video_decoder resource for acquire");
7235 ret = GST_AUTOPLUG_SELECT_SKIP;
7239 LOGW("video decoder resource is already acquired, skip it.");
7240 ret = GST_AUTOPLUG_SELECT_SKIP;
7244 player->interrupted_by_resource = FALSE;
7245 /* acquire resources for video playing */
7246 if (mm_resource_manager_commit(player->resource_manager)
7247 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7248 LOGE("could not acquire resources for video decoding");
7249 ret = GST_AUTOPLUG_SELECT_SKIP;
7254 /* update codec info */
7255 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7256 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7257 player->videodec_linked = 1;
7265 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7266 GstCaps *caps, GstElementFactory *factory, gpointer data)
7268 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7269 mmplayer_t *player = (mmplayer_t *)data;
7271 gchar *factory_name = NULL;
7272 gchar *caps_str = NULL;
7273 const gchar *klass = NULL;
7276 factory_name = GST_OBJECT_NAME(factory);
7277 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7278 caps_str = gst_caps_to_string(caps);
7280 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7282 /* store type string */
7283 if (player->type == NULL) {
7284 player->type = gst_caps_to_string(caps);
7285 __mmplayer_update_content_type_info(player);
7288 /* filtering exclude keyword */
7289 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7290 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7291 LOGW("skipping [%s] by exculde keyword [%s]",
7292 factory_name, player->ini.exclude_element_keyword[idx]);
7294 result = GST_AUTOPLUG_SELECT_SKIP;
7299 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7300 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7301 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7302 factory_name, player->ini.unsupported_codec_keyword[idx]);
7303 result = GST_AUTOPLUG_SELECT_SKIP;
7308 /* exclude webm format */
7309 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7310 * because webm format is not supportable.
7311 * If webm is disabled in "autoplug-continue", there is no state change
7312 * failure or error because the decodebin will expose the pad directly.
7313 * It make MSL invoke _prepare_async_callback.
7314 * So, we need to disable webm format in "autoplug-select" */
7315 if (caps_str && strstr(caps_str, "webm")) {
7316 LOGW("webm is not supported");
7317 result = GST_AUTOPLUG_SELECT_SKIP;
7321 /* check factory class for filtering */
7322 /* NOTE : msl don't need to use image plugins.
7323 * So, those plugins should be skipped for error handling.
7325 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7326 LOGD("skipping [%s] by not required", factory_name);
7327 result = GST_AUTOPLUG_SELECT_SKIP;
7331 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7332 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7333 // TO CHECK : subtitle if needed, add subparse exception.
7334 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7335 result = GST_AUTOPLUG_SELECT_SKIP;
7339 if (g_strrstr(factory_name, "mpegpsdemux")) {
7340 LOGD("skipping PS container - not support");
7341 result = GST_AUTOPLUG_SELECT_SKIP;
7345 if (g_strrstr(factory_name, "mssdemux"))
7346 player->smooth_streaming = TRUE;
7348 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7349 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7352 GstStructure *str = NULL;
7353 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7355 /* don't make video because of not required */
7356 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7357 (!player->set_mode.video_export)) {
7358 LOGD("no need video decoding, expose pad");
7359 result = GST_AUTOPLUG_SELECT_EXPOSE;
7363 /* get w/h for omx state-tune */
7364 /* FIXME: deprecated? */
7365 str = gst_caps_get_structure(caps, 0);
7366 gst_structure_get_int(str, "width", &width);
7369 if (player->v_stream_caps) {
7370 gst_caps_unref(player->v_stream_caps);
7371 player->v_stream_caps = NULL;
7374 player->v_stream_caps = gst_caps_copy(caps);
7375 LOGD("take caps for video state tune");
7376 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7380 if (g_strrstr(klass, "Codec/Decoder")) {
7381 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7382 if (result != GST_AUTOPLUG_SELECT_TRY) {
7383 LOGW("skip add decoder");
7389 MMPLAYER_FREEIF(caps_str);
7395 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7398 //mmplayer_t *player = (mmplayer_t *)data;
7399 GstCaps *caps = NULL;
7401 LOGD("[Decodebin2] pad-removed signal");
7403 caps = gst_pad_query_caps(new_pad, NULL);
7405 LOGW("query caps is NULL");
7409 gchar *caps_str = NULL;
7410 caps_str = gst_caps_to_string(caps);
7412 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7414 MMPLAYER_FREEIF(caps_str);
7415 gst_caps_unref(caps);
7419 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7421 mmplayer_t *player = (mmplayer_t *)data;
7422 GstIterator *iter = NULL;
7423 GValue item = { 0, };
7425 gboolean done = FALSE;
7426 gboolean is_all_drained = TRUE;
7429 MMPLAYER_RETURN_IF_FAIL(player);
7431 LOGD("__mmplayer_gst_decode_drained");
7433 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7434 LOGW("Fail to get cmd lock");
7438 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7439 !__mmplayer_verify_gapless_play_path(player)) {
7440 LOGD("decoding is finished.");
7441 __mmplayer_reset_gapless_state(player);
7442 MMPLAYER_CMD_UNLOCK(player);
7446 player->gapless.reconfigure = TRUE;
7448 /* check decodebin src pads whether they received EOS or not */
7449 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7452 switch (gst_iterator_next(iter, &item)) {
7453 case GST_ITERATOR_OK:
7454 pad = g_value_get_object(&item);
7455 if (pad && !GST_PAD_IS_EOS(pad)) {
7456 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7457 is_all_drained = FALSE;
7460 g_value_reset(&item);
7462 case GST_ITERATOR_RESYNC:
7463 gst_iterator_resync(iter);
7465 case GST_ITERATOR_ERROR:
7466 case GST_ITERATOR_DONE:
7471 g_value_unset(&item);
7472 gst_iterator_free(iter);
7474 if (!is_all_drained) {
7475 LOGD("Wait util the all pads get EOS.");
7476 MMPLAYER_CMD_UNLOCK(player);
7481 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7482 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7484 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7485 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7486 __mmplayer_deactivate_old_path(player);
7487 MMPLAYER_CMD_UNLOCK(player);
7493 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7495 mmplayer_t *player = (mmplayer_t *)data;
7496 const gchar *klass = NULL;
7497 gchar *factory_name = NULL;
7499 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7500 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7502 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7504 if (__mmplayer_add_dump_buffer_probe(player, element))
7505 LOGD("add buffer probe");
7507 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7508 gchar *selected = NULL;
7509 selected = g_strdup(GST_ELEMENT_NAME(element));
7510 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7513 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7514 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7515 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7517 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7518 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7520 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7521 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7522 "max-video-width", player->adaptive_info.limit.width,
7523 "max-video-height", player->adaptive_info.limit.height, NULL);
7525 } else if (g_strrstr(klass, "Demuxer")) {
7526 //LOGD("plugged element is demuxer. take it");
7527 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7528 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7531 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7532 int surface_type = 0;
7534 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7537 // to support trust-zone only
7538 if (g_strrstr(factory_name, "asfdemux")) {
7539 LOGD("set file-location %s", player->profile.uri);
7540 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7541 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7542 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7543 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7544 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7545 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7546 (__mmplayer_is_only_mp3_type(player->type))) {
7547 LOGD("[mpegaudioparse] set streaming pull mode.");
7548 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7550 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7551 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7554 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7555 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7556 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7558 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7559 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7561 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7562 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7563 (MMPLAYER_IS_DASH_STREAMING(player))) {
7564 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7565 __mm_player_streaming_set_multiqueue(player->streamer, element);
7566 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7575 __mmplayer_release_misc(mmplayer_t *player)
7578 bool cur_mode = player->set_mode.rich_audio;
7581 MMPLAYER_RETURN_IF_FAIL(player);
7583 player->video_decoded_cb = NULL;
7584 player->video_decoded_cb_user_param = NULL;
7585 player->video_stream_prerolled = false;
7587 player->audio_decoded_cb = NULL;
7588 player->audio_decoded_cb_user_param = NULL;
7589 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7591 player->video_stream_changed_cb = NULL;
7592 player->video_stream_changed_cb_user_param = NULL;
7594 player->audio_stream_changed_cb = NULL;
7595 player->audio_stream_changed_cb_user_param = NULL;
7597 player->sent_bos = FALSE;
7598 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7600 player->seek_state = MMPLAYER_SEEK_NONE;
7602 player->total_bitrate = 0;
7603 player->total_maximum_bitrate = 0;
7605 player->not_found_demuxer = 0;
7607 player->last_position = 0;
7608 player->duration = 0;
7609 player->http_content_size = 0;
7610 player->not_supported_codec = MISSING_PLUGIN_NONE;
7611 player->can_support_codec = FOUND_PLUGIN_NONE;
7612 player->pending_seek.is_pending = false;
7613 player->pending_seek.pos = 0;
7614 player->msg_posted = FALSE;
7615 player->has_many_types = FALSE;
7616 player->is_subtitle_force_drop = FALSE;
7617 player->play_subtitle = FALSE;
7618 player->adjust_subtitle_pos = 0;
7619 player->has_closed_caption = FALSE;
7620 player->set_mode.video_export = false;
7621 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7622 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7624 player->set_mode.rich_audio = cur_mode;
7626 if (player->audio_device_cb_id > 0 &&
7627 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7628 LOGW("failed to remove audio device_connected_callback");
7629 player->audio_device_cb_id = 0;
7631 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7632 player->bitrate[i] = 0;
7633 player->maximum_bitrate[i] = 0;
7636 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7638 /* remove media stream cb(appsrc cb) */
7639 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7640 player->media_stream_buffer_status_cb[i] = NULL;
7641 player->media_stream_seek_data_cb[i] = NULL;
7642 player->buffer_cb_user_param[i] = NULL;
7643 player->seek_cb_user_param[i] = NULL;
7645 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7647 /* free memory related to audio effect */
7648 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7650 if (player->adaptive_info.var_list) {
7651 g_list_free_full(player->adaptive_info.var_list, g_free);
7652 player->adaptive_info.var_list = NULL;
7655 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7656 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7657 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7659 /* Reset video360 settings to their defaults in case if the pipeline is to be
7662 player->video360_metadata.is_spherical = -1;
7663 player->is_openal_plugin_used = FALSE;
7665 player->is_content_spherical = FALSE;
7666 player->is_video360_enabled = TRUE;
7667 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7668 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7669 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7670 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7671 player->video360_zoom = 1.0f;
7672 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7673 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7675 player->sound.rg_enable = false;
7677 __mmplayer_initialize_video_roi(player);
7682 __mmplayer_release_misc_post(mmplayer_t *player)
7684 char *original_uri = NULL;
7687 /* player->pipeline is already released before. */
7689 MMPLAYER_RETURN_IF_FAIL(player);
7691 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7693 /* clean found audio decoders */
7694 if (player->audio_decoders) {
7695 GList *a_dec = player->audio_decoders;
7696 for (; a_dec; a_dec = g_list_next(a_dec)) {
7697 gchar *name = a_dec->data;
7698 MMPLAYER_FREEIF(name);
7700 g_list_free(player->audio_decoders);
7701 player->audio_decoders = NULL;
7704 /* clean the uri list except original uri */
7705 if (player->uri_info.uri_list) {
7706 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7708 if (player->attrs) {
7709 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7710 LOGD("restore original uri = %s", original_uri);
7712 if (mm_attrs_commit_all(player->attrs))
7713 LOGE("failed to commit the original uri.");
7716 GList *uri_list = player->uri_info.uri_list;
7717 for (; uri_list; uri_list = g_list_next(uri_list)) {
7718 gchar *uri = uri_list->data;
7719 MMPLAYER_FREEIF(uri);
7721 g_list_free(player->uri_info.uri_list);
7722 player->uri_info.uri_list = NULL;
7725 /* clear the audio stream buffer list */
7726 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7728 /* clear the video stream bo list */
7729 __mmplayer_video_stream_destroy_bo_list(player);
7730 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7732 if (player->profile.input_mem.buf) {
7733 free(player->profile.input_mem.buf);
7734 player->profile.input_mem.buf = NULL;
7736 player->profile.input_mem.len = 0;
7737 player->profile.input_mem.offset = 0;
7739 player->uri_info.uri_idx = 0;
7744 __mmplayer_check_subtitle(mmplayer_t *player)
7746 MMHandleType attrs = 0;
7747 char *subtitle_uri = NULL;
7751 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7753 /* get subtitle attribute */
7754 attrs = MMPLAYER_GET_ATTRS(player);
7758 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7759 if (!subtitle_uri || !strlen(subtitle_uri))
7762 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7763 player->is_external_subtitle_present = TRUE;
7771 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7773 MMPLAYER_RETURN_IF_FAIL(player);
7775 if (player->eos_timer) {
7776 LOGD("cancel eos timer");
7777 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7778 player->eos_timer = 0;
7785 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7789 MMPLAYER_RETURN_IF_FAIL(player);
7790 MMPLAYER_RETURN_IF_FAIL(sink);
7792 player->sink_elements = g_list_append(player->sink_elements, sink);
7798 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7802 MMPLAYER_RETURN_IF_FAIL(player);
7803 MMPLAYER_RETURN_IF_FAIL(sink);
7805 player->sink_elements = g_list_remove(player->sink_elements, sink);
7811 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7812 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7814 mmplayer_signal_item_t *item = NULL;
7817 MMPLAYER_RETURN_IF_FAIL(player);
7819 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7820 LOGE("invalid signal type [%d]", type);
7824 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7826 LOGE("cannot connect signal [%s]", signal);
7831 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7832 player->signals[type] = g_list_append(player->signals[type], item);
7838 /* NOTE : be careful with calling this api. please refer to below glib comment
7839 * glib comment : Note that there is a bug in GObject that makes this function much
7840 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7841 * will no longer be called, but, the signal handler is not currently disconnected.
7842 * If the instance is itself being freed at the same time than this doesn't matter,
7843 * since the signal will automatically be removed, but if instance persists,
7844 * then the signal handler will leak. You should not remove the signal yourself
7845 * because in a future versions of GObject, the handler will automatically be
7848 * It's possible to work around this problem in a way that will continue to work
7849 * with future versions of GObject by checking that the signal handler is still
7850 * connected before disconnected it:
7852 * if (g_signal_handler_is_connected(instance, id))
7853 * g_signal_handler_disconnect(instance, id);
7856 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7858 GList *sig_list = NULL;
7859 mmplayer_signal_item_t *item = NULL;
7863 MMPLAYER_RETURN_IF_FAIL(player);
7865 LOGD("release signals type : %d", type);
7867 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7868 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7869 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7870 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7871 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7872 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7876 sig_list = player->signals[type];
7878 for (; sig_list; sig_list = sig_list->next) {
7879 item = sig_list->data;
7881 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7882 if (g_signal_handler_is_connected(item->obj, item->sig))
7883 g_signal_handler_disconnect(item->obj, item->sig);
7886 MMPLAYER_FREEIF(item);
7889 g_list_free(player->signals[type]);
7890 player->signals[type] = NULL;
7898 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7900 mmplayer_t *player = 0;
7901 int prev_display_surface_type = 0;
7902 void *prev_display_overlay = NULL;
7906 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7907 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7909 player = MM_PLAYER_CAST(handle);
7911 /* check video sinkbin is created */
7912 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7913 LOGE("Videosink is already created");
7914 return MM_ERROR_NONE;
7917 LOGD("videosink element is not yet ready");
7919 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7920 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7922 return MM_ERROR_INVALID_ARGUMENT;
7925 /* load previous attributes */
7926 if (player->attrs) {
7927 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7928 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7929 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7930 if (prev_display_surface_type == surface_type) {
7931 LOGD("incoming display surface type is same as previous one, do nothing..");
7933 return MM_ERROR_NONE;
7936 LOGE("failed to load attributes");
7938 return MM_ERROR_PLAYER_INTERNAL;
7941 /* videobin is not created yet, so we just set attributes related to display surface */
7942 LOGD("store display attribute for given surface type(%d)", surface_type);
7943 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7944 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7945 if (mm_attrs_commit_all(player->attrs)) {
7946 LOGE("failed to commit attribute");
7948 return MM_ERROR_PLAYER_INTERNAL;
7952 return MM_ERROR_NONE;
7955 /* Note : if silent is true, then subtitle would not be displayed. :*/
7957 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7959 mmplayer_t *player = (mmplayer_t *)hplayer;
7963 /* check player handle */
7964 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7966 player->set_mode.subtitle_off = silent;
7968 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7972 return MM_ERROR_NONE;
7976 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7978 mmplayer_gst_element_t *mainbin = NULL;
7979 mmplayer_gst_element_t *textbin = NULL;
7980 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7981 GstState current_state = GST_STATE_VOID_PENDING;
7982 GstState element_state = GST_STATE_VOID_PENDING;
7983 GstState element_pending_state = GST_STATE_VOID_PENDING;
7985 GstEvent *event = NULL;
7986 int result = MM_ERROR_NONE;
7988 GstClock *curr_clock = NULL;
7989 GstClockTime base_time, start_time, curr_time;
7994 /* check player handle */
7995 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7997 player->pipeline->mainbin &&
7998 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8000 mainbin = player->pipeline->mainbin;
8001 textbin = player->pipeline->textbin;
8003 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8005 // sync clock with current pipeline
8006 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8007 curr_time = gst_clock_get_time(curr_clock);
8009 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8010 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8012 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8013 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8015 if (current_state > GST_STATE_READY) {
8016 // sync state with current pipeline
8017 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8018 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8019 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8021 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8022 if (GST_STATE_CHANGE_FAILURE == ret) {
8023 LOGE("fail to state change.");
8024 result = MM_ERROR_PLAYER_INTERNAL;
8028 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8029 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8032 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8033 gst_object_unref(curr_clock);
8036 // seek to current position
8037 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8038 result = MM_ERROR_PLAYER_INVALID_STATE;
8039 LOGE("gst_element_query_position failed, invalid state");
8043 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8044 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);
8046 __mmplayer_gst_send_event_to_sink(player, event);
8048 result = MM_ERROR_PLAYER_INTERNAL;
8049 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8053 /* sync state with current pipeline */
8054 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8055 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8056 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8058 return MM_ERROR_NONE;
8061 /* release text pipeline resource */
8062 player->textsink_linked = 0;
8064 /* release signal */
8065 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8067 /* release textbin with it's childs */
8068 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8069 MMPLAYER_FREEIF(player->pipeline->textbin);
8070 player->pipeline->textbin = NULL;
8072 /* release subtitle elem */
8073 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8074 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8080 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8082 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8083 GstState current_state = GST_STATE_VOID_PENDING;
8085 MMHandleType attrs = 0;
8086 mmplayer_gst_element_t *mainbin = NULL;
8087 mmplayer_gst_element_t *textbin = NULL;
8089 gchar *subtitle_uri = NULL;
8090 int result = MM_ERROR_NONE;
8091 const gchar *charset = NULL;
8095 /* check player handle */
8096 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8098 player->pipeline->mainbin &&
8099 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8100 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8102 mainbin = player->pipeline->mainbin;
8103 textbin = player->pipeline->textbin;
8105 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8106 if (current_state < GST_STATE_READY) {
8107 result = MM_ERROR_PLAYER_INVALID_STATE;
8108 LOGE("Pipeline is not in proper state");
8112 attrs = MMPLAYER_GET_ATTRS(player);
8114 LOGE("cannot get content attribute");
8115 result = MM_ERROR_PLAYER_INTERNAL;
8119 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8120 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8121 LOGE("subtitle uri is not proper filepath");
8122 result = MM_ERROR_PLAYER_INVALID_URI;
8126 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8127 LOGE("failed to get storage info of subtitle path");
8128 result = MM_ERROR_PLAYER_INVALID_URI;
8132 LOGD("old subtitle file path is [%s]", subtitle_uri);
8133 LOGD("new subtitle file path is [%s]", filepath);
8135 if (!strcmp(filepath, subtitle_uri)) {
8136 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8139 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8140 if (mm_attrs_commit_all(player->attrs)) {
8141 LOGE("failed to commit.");
8146 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8147 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8148 player->subtitle_language_list = NULL;
8149 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8151 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8152 if (ret != GST_STATE_CHANGE_SUCCESS) {
8153 LOGE("failed to change state of textbin to READY");
8154 result = MM_ERROR_PLAYER_INTERNAL;
8158 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8159 if (ret != GST_STATE_CHANGE_SUCCESS) {
8160 LOGE("failed to change state of subparse to READY");
8161 result = MM_ERROR_PLAYER_INTERNAL;
8165 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8166 if (ret != GST_STATE_CHANGE_SUCCESS) {
8167 LOGE("failed to change state of filesrc to READY");
8168 result = MM_ERROR_PLAYER_INTERNAL;
8172 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8174 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8176 charset = util_get_charset(filepath);
8178 LOGD("detected charset is %s", charset);
8179 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8182 result = _mmplayer_sync_subtitle_pipeline(player);
8189 /* API to switch between external subtitles */
8191 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8193 int result = MM_ERROR_NONE;
8194 mmplayer_t *player = (mmplayer_t *)hplayer;
8199 /* check player handle */
8200 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8202 /* filepath can be null in idle state */
8204 /* check file path */
8205 if ((path = strstr(filepath, "file://")))
8206 result = util_exist_file_path(path + 7);
8208 result = util_exist_file_path(filepath);
8210 if (result != MM_ERROR_NONE) {
8211 LOGE("invalid subtitle path 0x%X", result);
8212 return result; /* file not found or permission denied */
8216 if (!player->pipeline) {
8218 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8219 if (mm_attrs_commit_all(player->attrs)) {
8220 LOGE("failed to commit"); /* subtitle path will not be created */
8221 return MM_ERROR_PLAYER_INTERNAL;
8224 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8225 /* check filepath */
8226 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8228 if (!__mmplayer_check_subtitle(player)) {
8229 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8230 if (mm_attrs_commit_all(player->attrs)) {
8231 LOGE("failed to commit");
8232 return MM_ERROR_PLAYER_INTERNAL;
8235 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8236 LOGE("fail to create text pipeline");
8237 return MM_ERROR_PLAYER_INTERNAL;
8240 result = _mmplayer_sync_subtitle_pipeline(player);
8242 result = __mmplayer_change_external_subtitle_language(player, filepath);
8245 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8246 player->is_external_subtitle_added_now = TRUE;
8248 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8249 if (!player->subtitle_language_list) {
8250 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8251 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8252 LOGW("subtitle language list is not updated yet");
8254 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8262 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8264 int result = MM_ERROR_NONE;
8265 gchar *change_pad_name = NULL;
8266 GstPad *sinkpad = NULL;
8267 mmplayer_gst_element_t *mainbin = NULL;
8268 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8269 GstCaps *caps = NULL;
8270 gint total_track_num = 0;
8274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8275 MM_ERROR_PLAYER_NOT_INITIALIZED);
8277 LOGD("Change Track(%d) to %d", type, index);
8279 mainbin = player->pipeline->mainbin;
8281 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8282 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8283 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8284 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8286 /* Changing Video Track is not supported. */
8287 LOGE("Track Type Error");
8291 if (mainbin[elem_idx].gst == NULL) {
8292 result = MM_ERROR_PLAYER_NO_OP;
8293 LOGD("Req track doesn't exist");
8297 total_track_num = player->selector[type].total_track_num;
8298 if (total_track_num <= 0) {
8299 result = MM_ERROR_PLAYER_NO_OP;
8300 LOGD("Language list is not available");
8304 if ((index < 0) || (index >= total_track_num)) {
8305 result = MM_ERROR_INVALID_ARGUMENT;
8306 LOGD("Not a proper index : %d", index);
8310 /*To get the new pad from the selector*/
8311 change_pad_name = g_strdup_printf("sink_%u", index);
8312 if (change_pad_name == NULL) {
8313 result = MM_ERROR_PLAYER_INTERNAL;
8314 LOGD("Pad does not exists");
8318 LOGD("new active pad name: %s", change_pad_name);
8320 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8321 if (sinkpad == NULL) {
8322 LOGD("sinkpad is NULL");
8323 result = MM_ERROR_PLAYER_INTERNAL;
8327 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8328 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8330 caps = gst_pad_get_current_caps(sinkpad);
8331 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8334 gst_object_unref(sinkpad);
8336 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8337 __mmplayer_set_audio_attrs(player, caps);
8340 MMPLAYER_FREEIF(change_pad_name);
8345 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8347 int result = MM_ERROR_NONE;
8348 mmplayer_t *player = NULL;
8349 mmplayer_gst_element_t *mainbin = NULL;
8351 gint current_active_index = 0;
8353 GstState current_state = GST_STATE_VOID_PENDING;
8354 GstEvent *event = NULL;
8359 player = (mmplayer_t *)hplayer;
8360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8362 if (!player->pipeline) {
8363 LOGE("Track %d pre setting -> %d", type, index);
8365 player->selector[type].active_pad_index = index;
8369 mainbin = player->pipeline->mainbin;
8371 current_active_index = player->selector[type].active_pad_index;
8373 /*If index is same as running index no need to change the pad*/
8374 if (current_active_index == index)
8377 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8378 result = MM_ERROR_PLAYER_INVALID_STATE;
8382 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8383 if (current_state < GST_STATE_PAUSED) {
8384 result = MM_ERROR_PLAYER_INVALID_STATE;
8385 LOGW("Pipeline not in porper state");
8389 result = __mmplayer_change_selector_pad(player, type, index);
8390 if (result != MM_ERROR_NONE) {
8391 LOGE("change selector pad error");
8395 player->selector[type].active_pad_index = index;
8397 if (current_state == GST_STATE_PLAYING) {
8398 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8399 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8400 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8402 __mmplayer_gst_send_event_to_sink(player, event);
8404 result = MM_ERROR_PLAYER_INTERNAL;
8414 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8416 mmplayer_t *player = (mmplayer_t *)hplayer;
8420 /* check player handle */
8421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8423 *silent = player->set_mode.subtitle_off;
8425 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8429 return MM_ERROR_NONE;
8433 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8435 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8436 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8438 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8439 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8443 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8444 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8445 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8446 mmplayer_dump_t *dump_s;
8447 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8448 if (dump_s == NULL) {
8449 LOGE("malloc fail");
8453 dump_s->dump_element_file = NULL;
8454 dump_s->dump_pad = NULL;
8455 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8457 if (dump_s->dump_pad) {
8458 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8459 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]);
8460 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8461 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);
8462 /* add list for removed buffer probe and close FILE */
8463 player->dump_list = g_list_append(player->dump_list, dump_s);
8464 LOGD("%s sink pad added buffer probe for dump", factory_name);
8467 MMPLAYER_FREEIF(dump_s);
8468 LOGE("failed to get %s sink pad added", factory_name);
8475 static GstPadProbeReturn
8476 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8478 FILE *dump_data = (FILE *)u_data;
8480 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8481 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8483 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8485 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8487 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8489 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8491 gst_buffer_unmap(buffer, &probe_info);
8493 return GST_PAD_PROBE_OK;
8497 __mmplayer_release_dump_list(GList *dump_list)
8499 GList *d_list = dump_list;
8504 for (; d_list; d_list = g_list_next(d_list)) {
8505 mmplayer_dump_t *dump_s = d_list->data;
8506 if (dump_s->dump_pad) {
8507 if (dump_s->probe_handle_id)
8508 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8509 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8511 if (dump_s->dump_element_file) {
8512 fclose(dump_s->dump_element_file);
8513 dump_s->dump_element_file = NULL;
8515 MMPLAYER_FREEIF(dump_s);
8517 g_list_free(dump_list);
8522 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8524 mmplayer_t *player = (mmplayer_t *)hplayer;
8528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8529 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8531 *exist = (bool)player->has_closed_caption;
8535 return MM_ERROR_NONE;
8539 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8543 // LOGD("unref internal gst buffer %p", buffer);
8544 gst_buffer_unref((GstBuffer *)buffer);
8551 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8553 mmplayer_t *player = (mmplayer_t *)hplayer;
8557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8558 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8560 if (MMPLAYER_IS_STREAMING(player))
8561 *timeout = (int)player->ini.live_state_change_timeout;
8563 *timeout = (int)player->ini.localplayback_state_change_timeout;
8565 LOGD("timeout = %d", *timeout);
8568 return MM_ERROR_NONE;
8572 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8574 mmplayer_t *player = (mmplayer_t *)hplayer;
8578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8579 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8581 *num = player->video_num_buffers;
8582 *extra_num = player->video_extra_num_buffers;
8584 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8587 return MM_ERROR_NONE;
8591 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8595 MMPLAYER_RETURN_IF_FAIL(player);
8597 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8599 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8600 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8601 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8602 player->storage_info[i].id = -1;
8603 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8605 if (path_type != MMPLAYER_PATH_MAX)
8614 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8616 int ret = MM_ERROR_NONE;
8617 mmplayer_t *player = (mmplayer_t *)hplayer;
8618 MMMessageParamType msg_param = {0, };
8621 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8623 LOGW("state changed storage %d:%d", id, state);
8625 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8626 return MM_ERROR_NONE;
8628 /* FIXME: text path should be handled seperately. */
8629 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8630 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8631 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8632 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8633 LOGW("external storage is removed");
8635 if (player->msg_posted == FALSE) {
8636 memset(&msg_param, 0, sizeof(MMMessageParamType));
8637 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8638 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8639 player->msg_posted = TRUE;
8642 /* unrealize the player */
8643 ret = _mmplayer_unrealize(hplayer);
8644 if (ret != MM_ERROR_NONE)
8645 LOGE("failed to unrealize");
8653 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8655 int ret = MM_ERROR_NONE;
8656 mmplayer_t *player = (mmplayer_t *)hplayer;
8657 int idx = 0, total = 0;
8658 gchar *result = NULL, *tmp = NULL;
8661 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8662 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8664 total = *num = g_list_length(player->adaptive_info.var_list);
8666 LOGW("There is no stream variant info.");
8670 result = g_strdup("");
8671 for (idx = 0 ; idx < total ; idx++) {
8672 stream_variant_t *v_data = NULL;
8673 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8676 gchar data[64] = {0};
8677 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8679 tmp = g_strconcat(result, data, NULL);
8683 LOGW("There is no variant data in %d", idx);
8688 *var_info = (char *)result;
8690 LOGD("variant info %d:%s", *num, *var_info);
8696 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8698 int ret = MM_ERROR_NONE;
8699 mmplayer_t *player = (mmplayer_t *)hplayer;
8702 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8704 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8706 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8707 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8708 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8710 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8711 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8712 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8713 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8715 /* FIXME: seek to current position for applying new variant limitation */
8724 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8726 int ret = MM_ERROR_NONE;
8727 mmplayer_t *player = (mmplayer_t *)hplayer;
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8733 *bandwidth = player->adaptive_info.limit.bandwidth;
8734 *width = player->adaptive_info.limit.width;
8735 *height = player->adaptive_info.limit.height;
8737 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8744 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8746 int ret = MM_ERROR_NONE;
8747 mmplayer_t *player = (mmplayer_t *)hplayer;
8750 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8751 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8752 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8754 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8756 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8757 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8758 else /* live case */
8759 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8761 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8768 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8770 #define IDX_FIRST_SW_CODEC 0
8771 mmplayer_t *player = (mmplayer_t *)hplayer;
8772 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8773 MMHandleType attrs = 0;
8776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8778 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8779 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8780 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8782 switch (stream_type) {
8783 case MM_PLAYER_STREAM_TYPE_AUDIO:
8784 /* to support audio codec selection, codec info have to be added in ini file as below.
8785 audio codec element hw = xxxx
8786 audio codec element sw = avdec */
8787 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8788 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8789 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8790 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8791 LOGE("There is no audio codec info for codec_type %d", codec_type);
8792 return MM_ERROR_PLAYER_NO_OP;
8795 case MM_PLAYER_STREAM_TYPE_VIDEO:
8796 /* to support video codec selection, codec info have to be added in ini file as below.
8797 video codec element hw = omx
8798 video codec element sw = avdec */
8799 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8800 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8801 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8802 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8803 LOGE("There is no video codec info for codec_type %d", codec_type);
8804 return MM_ERROR_PLAYER_NO_OP;
8808 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8809 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8813 LOGD("update %s codec_type to %d", attr_name, codec_type);
8815 attrs = MMPLAYER_GET_ATTRS(player);
8816 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8818 if (mm_attrs_commit_all(player->attrs)) {
8819 LOGE("failed to commit codec_type attributes");
8820 return MM_ERROR_PLAYER_INTERNAL;
8824 return MM_ERROR_NONE;
8828 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8830 mmplayer_t *player = (mmplayer_t *)hplayer;
8831 GstElement *rg_vol_element = NULL;
8835 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8837 player->sound.rg_enable = enabled;
8839 /* just hold rgvolume enable value if pipeline is not ready */
8840 if (!player->pipeline || !player->pipeline->audiobin) {
8841 LOGD("pipeline is not ready. holding rgvolume enable value");
8842 return MM_ERROR_NONE;
8845 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8847 if (!rg_vol_element) {
8848 LOGD("rgvolume element is not created");
8849 return MM_ERROR_PLAYER_INTERNAL;
8853 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8855 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8859 return MM_ERROR_NONE;
8863 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8865 mmplayer_t *player = (mmplayer_t *)hplayer;
8866 GstElement *rg_vol_element = NULL;
8867 gboolean enable = FALSE;
8871 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8872 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8874 /* just hold enable_rg value if pipeline is not ready */
8875 if (!player->pipeline || !player->pipeline->audiobin) {
8876 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8877 *enabled = player->sound.rg_enable;
8878 return MM_ERROR_NONE;
8881 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8883 if (!rg_vol_element) {
8884 LOGD("rgvolume element is not created");
8885 return MM_ERROR_PLAYER_INTERNAL;
8888 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8889 *enabled = (bool)enable;
8893 return MM_ERROR_NONE;
8897 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8899 mmplayer_t *player = (mmplayer_t *)hplayer;
8900 MMHandleType attrs = 0;
8901 void *handle = NULL;
8902 int ret = MM_ERROR_NONE;
8906 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8908 attrs = MMPLAYER_GET_ATTRS(player);
8909 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8911 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8913 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8914 return MM_ERROR_PLAYER_INTERNAL;
8917 player->video_roi.scale_x = scale_x;
8918 player->video_roi.scale_y = scale_y;
8919 player->video_roi.scale_width = scale_width;
8920 player->video_roi.scale_height = scale_height;
8922 /* check video sinkbin is created */
8923 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8924 return MM_ERROR_NONE;
8926 if (!gst_video_overlay_set_video_roi_area(
8927 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8928 scale_x, scale_y, scale_width, scale_height))
8929 ret = MM_ERROR_PLAYER_INTERNAL;
8931 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8932 scale_x, scale_y, scale_width, scale_height);
8940 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8942 mmplayer_t *player = (mmplayer_t *)hplayer;
8943 int ret = MM_ERROR_NONE;
8947 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8948 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8950 *scale_x = player->video_roi.scale_x;
8951 *scale_y = player->video_roi.scale_y;
8952 *scale_width = player->video_roi.scale_width;
8953 *scale_height = player->video_roi.scale_height;
8955 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8956 *scale_x, *scale_y, *scale_width, *scale_height);
8962 __mmplayer_update_duration_value(mmplayer_t *player)
8964 gboolean ret = FALSE;
8965 gint64 dur_nsec = 0;
8966 LOGD("try to update duration");
8968 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8969 player->duration = dur_nsec;
8970 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8974 if (player->duration < 0) {
8975 LOGW("duration is Non-Initialized !!!");
8976 player->duration = 0;
8979 /* update streaming service type */
8980 player->streaming_type = __mmplayer_get_stream_service_type(player);
8982 /* check duration is OK */
8983 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8984 /* FIXIT : find another way to get duration here. */
8985 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8991 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8993 /* update audio params
8994 NOTE : We need original audio params and it can be only obtained from src pad of audio
8995 decoder. Below code only valid when we are not using 'resampler' just before
8996 'audioconverter'. */
8997 GstCaps *caps_a = NULL;
8999 gint samplerate = 0, channels = 0;
9000 GstStructure *p = NULL;
9001 GstElement *aconv = NULL;
9003 LOGD("try to update audio attrs");
9005 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9007 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9008 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9009 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9010 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9012 LOGE("there is no audio converter");
9016 pad = gst_element_get_static_pad(aconv, "sink");
9019 LOGW("failed to get pad from audio converter");
9023 caps_a = gst_pad_get_current_caps(pad);
9025 LOGW("not ready to get audio caps");
9026 gst_object_unref(pad);
9030 p = gst_caps_get_structure(caps_a, 0);
9032 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9034 gst_structure_get_int(p, "rate", &samplerate);
9035 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
9037 gst_structure_get_int(p, "channels", &channels);
9038 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
9040 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9042 gst_caps_unref(caps_a);
9043 gst_object_unref(pad);
9049 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9051 LOGD("try to update video attrs");
9053 GstCaps *caps_v = NULL;
9057 GstStructure *p = NULL;
9059 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9060 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9062 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9064 LOGD("no videosink sink pad");
9068 caps_v = gst_pad_get_current_caps(pad);
9069 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9070 if (!caps_v && player->v_stream_caps) {
9071 caps_v = player->v_stream_caps;
9072 gst_caps_ref(caps_v);
9076 LOGD("no negitiated caps from videosink");
9077 gst_object_unref(pad);
9081 p = gst_caps_get_structure(caps_v, 0);
9082 gst_structure_get_int(p, "width", &width);
9083 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
9085 gst_structure_get_int(p, "height", &height);
9086 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
9088 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9090 SECURE_LOGD("width : %d height : %d", width, height);
9092 gst_caps_unref(caps_v);
9093 gst_object_unref(pad);
9096 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
9097 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9104 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9106 gboolean ret = FALSE;
9107 guint64 data_size = 0;
9111 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9112 if (!player->duration)
9115 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9116 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9117 if (stat(path, &sb) == 0)
9118 data_size = (guint64)sb.st_size;
9120 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9121 data_size = player->http_content_size;
9124 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9127 guint64 bitrate = 0;
9128 guint64 msec_dur = 0;
9130 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9132 bitrate = data_size * 8 * 1000 / msec_dur;
9133 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9134 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9138 LOGD("player duration is less than 0");
9142 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9143 if (player->total_bitrate) {
9144 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9153 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9155 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9156 data->uri_type = uri_type;
9160 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9162 int ret = MM_ERROR_PLAYER_INVALID_URI;
9164 char *buffer = NULL;
9165 char *seperator = strchr(path, ',');
9166 char ext[100] = {0,}, size[100] = {0,};
9169 if ((buffer = strstr(path, "ext="))) {
9170 buffer += strlen("ext=");
9172 if (strlen(buffer)) {
9173 strncpy(ext, buffer, 99);
9175 if ((seperator = strchr(ext, ','))
9176 || (seperator = strchr(ext, ' '))
9177 || (seperator = strchr(ext, '\0'))) {
9178 seperator[0] = '\0';
9183 if ((buffer = strstr(path, "size="))) {
9184 buffer += strlen("size=");
9186 if (strlen(buffer) > 0) {
9187 strncpy(size, buffer, 99);
9189 if ((seperator = strchr(size, ','))
9190 || (seperator = strchr(size, ' '))
9191 || (seperator = strchr(size, '\0'))) {
9192 seperator[0] = '\0';
9195 mem_size = atoi(size);
9200 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9202 if (mem_size && param) {
9203 if (data->input_mem.buf)
9204 free(data->input_mem.buf);
9205 data->input_mem.buf = malloc(mem_size);
9207 if (data->input_mem.buf) {
9208 memcpy(data->input_mem.buf, param, mem_size);
9209 data->input_mem.len = mem_size;
9210 ret = MM_ERROR_NONE;
9212 LOGE("failed to alloc mem %d", mem_size);
9213 ret = MM_ERROR_PLAYER_INTERNAL;
9216 data->input_mem.offset = 0;
9217 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9224 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9226 gchar *location = NULL;
9229 int ret = MM_ERROR_NONE;
9231 if ((path = strstr(uri, "file://"))) {
9232 location = g_filename_from_uri(uri, NULL, &err);
9233 if (!location || (err != NULL)) {
9234 LOGE("Invalid URI '%s' for filesrc: %s", path,
9235 (err != NULL) ? err->message : "unknown error");
9239 MMPLAYER_FREEIF(location);
9241 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9242 return MM_ERROR_PLAYER_INVALID_URI;
9244 LOGD("path from uri: %s", location);
9247 path = (location != NULL) ? (location) : ((char *)uri);
9250 ret = util_exist_file_path(path);
9252 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9253 if (ret == MM_ERROR_NONE) {
9254 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9255 if (util_is_sdp_file(path)) {
9256 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9257 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9259 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9261 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9262 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9264 LOGE("invalid uri, could not play..");
9265 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9268 MMPLAYER_FREEIF(location);
9273 static mmplayer_video_decoded_data_info_t *
9274 __mmplayer_create_stream_from_pad(GstPad *pad)
9276 GstCaps *caps = NULL;
9277 GstStructure *structure = NULL;
9278 unsigned int fourcc = 0;
9279 const gchar *string_format = NULL;
9280 mmplayer_video_decoded_data_info_t *stream = NULL;
9282 MMPixelFormatType format;
9285 caps = gst_pad_get_current_caps(pad);
9287 LOGE("Caps is NULL.");
9291 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9292 structure = gst_caps_get_structure(caps, 0);
9293 gst_structure_get_int(structure, "width", &width);
9294 gst_structure_get_int(structure, "height", &height);
9295 string_format = gst_structure_get_string(structure, "format");
9298 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9299 format = util_get_pixtype(fourcc);
9300 gst_video_info_from_caps(&info, caps);
9301 gst_caps_unref(caps);
9304 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9305 LOGE("Wrong condition!!");
9309 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9311 LOGE("failed to alloc mem for video data");
9315 stream->width = width;
9316 stream->height = height;
9317 stream->format = format;
9318 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9324 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9326 unsigned int pitch = 0;
9327 unsigned int size = 0;
9329 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9332 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9333 bo = gst_tizen_memory_get_bos(mem, index);
9335 stream->bo[index] = tbm_bo_ref(bo);
9337 LOGE("failed to get bo for index %d", index);
9340 for (index = 0; index < stream->plane_num; index++) {
9341 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9342 stream->stride[index] = pitch;
9344 stream->elevation[index] = size / pitch;
9346 stream->elevation[index] = stream->height;
9351 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9353 if (stream->format == MM_PIXEL_FORMAT_I420) {
9354 int ret = TBM_SURFACE_ERROR_NONE;
9355 tbm_surface_h surface;
9356 tbm_surface_info_s info;
9358 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9360 ret = tbm_surface_get_info(surface, &info);
9361 if (ret != TBM_SURFACE_ERROR_NONE) {
9362 tbm_surface_destroy(surface);
9366 tbm_surface_destroy(surface);
9367 stream->stride[0] = info.planes[0].stride;
9368 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9369 stream->stride[1] = info.planes[1].stride;
9370 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9371 stream->stride[2] = info.planes[2].stride;
9372 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9373 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9374 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9375 stream->stride[0] = stream->width * 4;
9376 stream->elevation[0] = stream->height;
9377 stream->bo_size = stream->stride[0] * stream->height;
9379 LOGE("Not support format %d", stream->format);
9387 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9389 tbm_bo_handle thandle;
9391 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9392 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9393 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9397 unsigned char *src = NULL;
9398 unsigned char *dest = NULL;
9399 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9401 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9403 LOGE("fail to gst_memory_map");
9407 if (!mapinfo.data) {
9408 LOGE("data pointer is wrong");
9412 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9413 if (!stream->bo[0]) {
9414 LOGE("Fail to tbm_bo_alloc!!");
9418 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9420 LOGE("thandle pointer is wrong");
9424 if (stream->format == MM_PIXEL_FORMAT_I420) {
9425 src_stride[0] = GST_ROUND_UP_4(stream->width);
9426 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9427 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9428 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9431 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9432 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9434 for (i = 0; i < 3; i++) {
9435 src = mapinfo.data + src_offset[i];
9436 dest = thandle.ptr + dest_offset[i];
9441 for (j = 0; j < stream->height >> k; j++) {
9442 memcpy(dest, src, stream->width>>k);
9443 src += src_stride[i];
9444 dest += stream->stride[i];
9447 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9448 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9450 LOGE("Not support format %d", stream->format);
9454 tbm_bo_unmap(stream->bo[0]);
9455 gst_memory_unmap(mem, &mapinfo);
9461 tbm_bo_unmap(stream->bo[0]);
9464 gst_memory_unmap(mem, &mapinfo);
9470 __mmplayer_set_pause_state(mmplayer_t *player)
9472 if (player->sent_bos)
9475 /* rtsp case, get content attrs by GstMessage */
9476 if (MMPLAYER_IS_RTSP_STREAMING(player))
9479 /* it's first time to update all content attrs. */
9480 __mmplayer_update_content_attrs(player, ATTR_ALL);
9484 __mmplayer_set_playing_state(mmplayer_t *player)
9486 gchar *audio_codec = NULL;
9488 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9489 /* initialize because auto resume is done well. */
9490 player->resumed_by_rewind = FALSE;
9491 player->playback_rate = 1.0;
9494 if (player->sent_bos)
9497 /* try to get content metadata */
9499 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9500 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9501 * legacy mmfw-player api
9503 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9505 if ((player->cmd == MMPLAYER_COMMAND_START)
9506 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9507 __mmplayer_handle_missed_plugin(player);
9510 /* check audio codec field is set or not
9511 * we can get it from typefinder or codec's caps.
9513 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9515 /* The codec format can't be sent for audio only case like amr, mid etc.
9516 * Because, parser don't make related TAG.
9517 * So, if it's not set yet, fill it with found data.
9520 if (g_strrstr(player->type, "audio/midi"))
9521 audio_codec = "MIDI";
9522 else if (g_strrstr(player->type, "audio/x-amr"))
9523 audio_codec = "AMR";
9524 else if (g_strrstr(player->type, "audio/mpeg")
9525 && !g_strrstr(player->type, "mpegversion=(int)1"))
9526 audio_codec = "AAC";
9528 audio_codec = "unknown";
9530 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9532 if (mm_attrs_commit_all(player->attrs))
9533 LOGE("failed to update attributes");
9535 LOGD("set audio codec type with caps");