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/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.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"
52 #include <system_info.h>
53 #include <sound_manager.h>
55 /*===========================================================================================
57 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
59 ========================================================================================== */
61 /*---------------------------------------------------------------------------
62 | GLOBAL CONSTANT DEFINITIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED VARIABLE DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED FUNCTION DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
79 #define MM_VOLUME_FACTOR_DEFAULT 1.0
80 #define MM_VOLUME_FACTOR_MIN 0
81 #define MM_VOLUME_FACTOR_MAX 1.0
83 /* Don't need to sleep for sound fadeout
84 * fadeout related fucntion will be deleted(Deprecated)
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
88 #define DEFAULT_PLAYBACK_RATE 1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93 (player->ini.http_use_file_buffer) && \
94 (player->http_file_buffering_path) && \
95 (strlen(player->http_file_buffering_path) > 0))
97 #define PLAYER_DISPLAY_MODE_DST_ROI 5
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
104 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | GLOBAL VARIABLE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | LOCAL VARIABLE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
121 static sound_stream_info_h stream_info;
123 /*---------------------------------------------------------------------------
124 | LOCAL FUNCTION PROTOTYPES: |
125 ---------------------------------------------------------------------------*/
126 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
127 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
128 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
129 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
130 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
131 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
132 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
134 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
135 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
136 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
137 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
138 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
139 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
140 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
141 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
142 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
143 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
144 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
145 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
146 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
152 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
153 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
154 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
155 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_release_misc(mm_player_t* player);
157 static void __mmplayer_release_misc_post(mm_player_t* player);
158 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
159 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
160 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
161 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
162 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
163 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
164 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
166 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
167 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
168 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
170 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
171 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
172 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
173 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
174 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
175 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
176 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
177 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
178 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
179 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
180 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
181 static gpointer __mmplayer_next_play_thread(gpointer data);
182 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
184 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
185 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
186 static void __mmplayer_release_dump_list(GList *dump_list);
188 static int __gst_realize(mm_player_t* player);
189 static int __gst_unrealize(mm_player_t* player);
190 static int __gst_start(mm_player_t* player);
191 static int __gst_stop(mm_player_t* player);
192 static int __gst_pause(mm_player_t* player, gboolean async);
193 static int __gst_resume(mm_player_t* player, gboolean async);
194 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
195 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
196 gint64 cur, GstSeekType stop_type, gint64 stop);
197 static int __gst_pending_seek(mm_player_t* player);
199 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
200 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
201 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
202 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
203 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
205 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
207 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
208 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
211 static gboolean __is_ms_buff_src(mm_player_t* player);
212 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
214 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
215 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
216 static int __mmplayer_start_streaming_ext(mm_player_t *player);
217 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
218 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
220 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
221 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
222 static void __mmplayer_check_pipeline(mm_player_t* player);
223 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
224 static void __mmplayer_deactivate_old_path(mm_player_t *player);
226 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
227 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
229 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
230 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
231 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
232 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
233 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
234 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
235 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
236 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
237 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
238 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
239 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
240 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
241 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
242 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
243 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
244 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
246 /*===========================================================================================
248 | FUNCTION DEFINITIONS |
250 ========================================================================================== */
254 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
258 count = gst_tag_list_get_tag_size(list, tag);
260 LOGD("count = %d", count);
262 for (i = 0; i < count; i++) {
265 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
266 if (!gst_tag_list_get_string_index(list, tag, i, &str))
267 g_assert_not_reached();
269 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
272 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
274 g_print(" : %s\n", str);
281 /* This function should be called after the pipeline goes PAUSED or higher
284 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
286 static gboolean has_duration = FALSE;
287 static gboolean has_video_attrs = FALSE;
288 static gboolean has_audio_attrs = FALSE;
289 static gboolean has_bitrate = FALSE;
290 gboolean missing_only = FALSE;
291 gboolean all = FALSE;
293 GstStructure* p = NULL;
294 MMHandleType attrs = 0;
300 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
302 /* check player state here */
303 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
304 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
305 /* give warning now only */
306 LOGW("be careful. content attributes may not available in this state ");
309 /* get content attribute first */
310 attrs = MMPLAYER_GET_ATTRS(player);
312 LOGE("cannot get content attribute");
316 /* get update flag */
318 if (flag & ATTR_MISSING_ONLY) {
320 LOGD("updating missed attr only");
323 if (flag & ATTR_ALL) {
325 has_duration = FALSE;
326 has_video_attrs = FALSE;
327 has_audio_attrs = FALSE;
330 LOGD("updating all attrs");
333 if (missing_only && all) {
334 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
335 missing_only = FALSE;
338 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
339 LOGD("try to update duration");
340 has_duration = FALSE;
342 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
343 player->duration = dur_nsec;
344 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
347 if (player->duration < 0) {
348 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
349 player->duration = 0;
352 /* update streaming service type */
353 player->streaming_type = __mmplayer_get_stream_service_type(player);
355 /* check duration is OK */
356 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
357 /* FIXIT : find another way to get duration here. */
358 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
361 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
366 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
367 /* update audio params
368 NOTE : We need original audio params and it can be only obtained from src pad of audio
369 decoder. Below code only valid when we are not using 'resampler' just before
372 LOGD("try to update audio attrs");
373 has_audio_attrs = FALSE;
375 if (player->pipeline->audiobin &&
376 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
377 GstCaps *caps_a = NULL;
379 gint samplerate = 0, channels = 0;
381 pad = gst_element_get_static_pad(
382 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
385 caps_a = gst_pad_get_current_caps(pad);
388 p = gst_caps_get_structure(caps_a, 0);
390 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
392 gst_structure_get_int(p, "rate", &samplerate);
393 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
395 gst_structure_get_int(p, "channels", &channels);
396 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
398 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
400 gst_caps_unref(caps_a);
403 has_audio_attrs = TRUE;
405 LOGW("not ready to get audio caps");
407 gst_object_unref(pad);
409 LOGW("failed to get pad from audiosink");
413 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
414 LOGD("try to update video attrs");
415 has_video_attrs = FALSE;
417 if (player->pipeline->videobin &&
418 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
419 GstCaps *caps_v = NULL;
424 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
426 caps_v = gst_pad_get_current_caps(pad);
428 /* Use v_stream_caps, if fail to get video_sink sink pad*/
429 if (!caps_v && player->v_stream_caps) {
430 caps_v = player->v_stream_caps;
431 gst_caps_ref(caps_v);
435 p = gst_caps_get_structure(caps_v, 0);
436 gst_structure_get_int(p, "width", &width);
437 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
439 gst_structure_get_int(p, "height", &height);
440 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
442 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
444 SECURE_LOGD("width : %d height : %d", width, height);
446 gst_caps_unref(caps_v);
450 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
451 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
454 has_video_attrs = TRUE;
456 LOGD("no negitiated caps from videosink");
457 gst_object_unref(pad);
460 LOGD("no videosink sink pad");
465 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
468 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
469 if (player->duration) {
470 guint64 data_size = 0;
472 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
473 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
475 if (stat(path, &sb) == 0)
476 data_size = (guint64)sb.st_size;
477 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
478 data_size = player->http_content_size;
480 LOGD("try to update bitrate : data_size = %lld", data_size);
484 guint64 msec_dur = 0;
486 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
488 bitrate = data_size * 8 * 1000 / msec_dur;
489 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
490 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
494 LOGD("player duration is less than 0");
498 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
499 if (player->total_bitrate) {
500 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
508 if (mmf_attrs_commit(attrs)) {
509 LOGE("failed to update attributes\n");
518 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
520 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
524 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
526 player->pipeline->mainbin &&
527 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
528 STREAMING_SERVICE_NONE);
530 /* streaming service type if streaming */
531 if (!MMPLAYER_IS_STREAMING(player))
532 return STREAMING_SERVICE_NONE;
534 if (MMPLAYER_IS_HTTP_STREAMING(player))
535 streaming_type = (player->duration == 0) ?
536 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
538 switch (streaming_type) {
539 case STREAMING_SERVICE_LIVE:
540 LOGD("it's live streaming");
542 case STREAMING_SERVICE_VOD:
543 LOGD("it's vod streaming");
546 LOGE("should not get here");
552 return streaming_type;
556 /* this function sets the player state and also report
557 * it to applicaton by calling callback function
560 __mmplayer_set_state(mm_player_t* player, int state)
562 MMMessageParamType msg = {0, };
563 gboolean post_bos = FALSE;
565 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
567 if (MMPLAYER_CURRENT_STATE(player) == state) {
568 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
569 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
570 return MM_ERROR_NONE;
573 /* update player states */
574 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
575 MMPLAYER_CURRENT_STATE(player) = state;
577 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
578 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
581 MMPLAYER_PRINT_STATE(player);
583 switch (MMPLAYER_CURRENT_STATE(player)) {
584 case MM_PLAYER_STATE_NULL:
585 case MM_PLAYER_STATE_READY:
588 case MM_PLAYER_STATE_PAUSED:
590 if (!player->sent_bos) {
591 /* rtsp case, get content attrs by GstMessage */
592 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
593 /* it's first time to update all content attrs. */
594 _mmplayer_update_content_attrs(player, ATTR_ALL);
598 /* add audio callback probe if condition is satisfied */
599 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
600 __mmplayer_configure_audio_callback(player);
602 /* FIXIT : handle return value */
606 case MM_PLAYER_STATE_PLAYING:
608 /* try to get content metadata */
609 if (!player->sent_bos) {
610 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
611 * c-api since c-api doesn't use _start() anymore. It may not work propery with
612 * legacy mmfw-player api */
613 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
616 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
617 if (!player->sent_bos)
618 __mmplayer_handle_missed_plugin(player);
621 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
622 /* initialize because auto resume is done well. */
623 player->resumed_by_rewind = FALSE;
624 player->playback_rate = 1.0;
627 if (!player->sent_bos) {
628 /* check audio codec field is set or not
629 * we can get it from typefinder or codec's caps.
631 gchar *audio_codec = NULL;
632 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
634 /* The codec format can't be sent for audio only case like amr, mid etc.
635 * Because, parser don't make related TAG.
636 * So, if it's not set yet, fill it with found data.
639 if (g_strrstr(player->type, "audio/midi"))
640 audio_codec = g_strdup("MIDI");
641 else if (g_strrstr(player->type, "audio/x-amr"))
642 audio_codec = g_strdup("AMR");
643 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
644 audio_codec = g_strdup("AAC");
646 audio_codec = g_strdup("unknown");
647 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
649 MMPLAYER_FREEIF(audio_codec);
650 if (mmf_attrs_commit(player->attrs))
651 LOGE("failed to update attributes\n");
653 LOGD("set audio codec type with caps\n");
661 case MM_PLAYER_STATE_NONE:
663 LOGW("invalid target state, there is nothing to do.\n");
668 /* post message to application */
669 if (MMPLAYER_TARGET_STATE(player) == state) {
670 /* fill the message with state of player */
671 msg.union_type = MM_MSG_UNION_STATE;
672 msg.state.previous = MMPLAYER_PREV_STATE(player);
673 msg.state.current = MMPLAYER_CURRENT_STATE(player);
675 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
677 /* state changed by resource callback */
678 if (player->interrupted_by_resource) {
679 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
680 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
681 } else { /* state changed by usecase */
682 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
685 LOGD("intermediate state, do nothing.\n");
686 MMPLAYER_PRINT_STATE(player);
687 return MM_ERROR_NONE;
691 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
692 player->sent_bos = TRUE;
695 return MM_ERROR_NONE;
698 static gpointer __mmplayer_next_play_thread(gpointer data)
700 mm_player_t* player = (mm_player_t*) data;
701 MMPlayerGstElement *mainbin = NULL;
703 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
705 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
706 while (!player->next_play_thread_exit) {
707 LOGD("next play thread started. waiting for signal.\n");
708 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
710 LOGD("reconfigure pipeline for gapless play.\n");
712 if (player->next_play_thread_exit) {
713 if (player->gapless.reconfigure) {
714 player->gapless.reconfigure = false;
715 MMPLAYER_PLAYBACK_UNLOCK(player);
717 LOGD("exiting gapless play thread\n");
721 mainbin = player->pipeline->mainbin;
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
725 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
729 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
739 MMHandleType attrs = 0;
740 guint64 data_size = 0;
742 unsigned long pos_msec = 0;
745 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
747 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
749 attrs = MMPLAYER_GET_ATTRS(player);
751 LOGE("fail to get attributes.\n");
755 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
756 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
758 if (stat(path, &sb) == 0)
759 data_size = (guint64)sb.st_size;
760 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
761 data_size = player->http_content_size;
763 __mm_player_streaming_buffering(player->streamer,
766 player->last_position,
769 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
775 __mmplayer_handle_buffering_message(mm_player_t* player)
777 int ret = MM_ERROR_NONE;
778 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
779 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
780 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
781 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
783 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
784 LOGW("do nothing for buffering msg\n");
785 ret = MM_ERROR_PLAYER_INVALID_STATE;
789 prev_state = MMPLAYER_PREV_STATE(player);
790 current_state = MMPLAYER_CURRENT_STATE(player);
791 target_state = MMPLAYER_TARGET_STATE(player);
792 pending_state = MMPLAYER_PENDING_STATE(player);
794 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
795 MMPLAYER_STATE_GET_NAME(prev_state),
796 MMPLAYER_STATE_GET_NAME(current_state),
797 MMPLAYER_STATE_GET_NAME(pending_state),
798 MMPLAYER_STATE_GET_NAME(target_state),
799 player->streamer->is_buffering);
801 if (!player->streamer->is_buffering) {
802 /* NOTE : if buffering has done, player has to go to target state. */
803 switch (target_state) {
804 case MM_PLAYER_STATE_PAUSED:
806 switch (pending_state) {
807 case MM_PLAYER_STATE_PLAYING:
808 __gst_pause(player, TRUE);
811 case MM_PLAYER_STATE_PAUSED:
812 LOGD("player is already going to paused state, there is nothing to do.\n");
815 case MM_PLAYER_STATE_NONE:
816 case MM_PLAYER_STATE_NULL:
817 case MM_PLAYER_STATE_READY:
819 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
825 case MM_PLAYER_STATE_PLAYING:
827 switch (pending_state) {
828 case MM_PLAYER_STATE_NONE:
830 if (current_state != MM_PLAYER_STATE_PLAYING)
831 __gst_resume(player, TRUE);
835 case MM_PLAYER_STATE_PAUSED:
836 /* NOTE: It should be worked as asynchronously.
837 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
839 if (current_state == MM_PLAYER_STATE_PLAYING) {
840 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
841 * The current state should be changed to paused purposely to prevent state conflict.
843 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
845 __gst_resume(player, TRUE);
848 case MM_PLAYER_STATE_PLAYING:
849 LOGD("player is already going to playing state, there is nothing to do.\n");
852 case MM_PLAYER_STATE_NULL:
853 case MM_PLAYER_STATE_READY:
855 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
861 case MM_PLAYER_STATE_NULL:
862 case MM_PLAYER_STATE_READY:
863 case MM_PLAYER_STATE_NONE:
865 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
869 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
870 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
872 switch (pending_state) {
873 case MM_PLAYER_STATE_NONE:
875 if (current_state != MM_PLAYER_STATE_PAUSED) {
876 /* rtsp streaming pause makes rtsp server stop sending data. */
877 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
878 LOGD("set pause state during buffering\n");
879 __gst_pause(player, TRUE);
885 case MM_PLAYER_STATE_PLAYING:
886 /* rtsp streaming pause makes rtsp server stop sending data. */
887 if (!MMPLAYER_IS_RTSP_STREAMING(player))
888 __gst_pause(player, TRUE);
891 case MM_PLAYER_STATE_PAUSED:
894 case MM_PLAYER_STATE_NULL:
895 case MM_PLAYER_STATE_READY:
897 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
907 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
909 MMPlayerGstElement *textbin;
912 MMPLAYER_RETURN_IF_FAIL(player &&
914 player->pipeline->textbin);
916 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
918 textbin = player->pipeline->textbin;
921 LOGD("Drop subtitle text after getting EOS\n");
923 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
924 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
926 player->is_subtitle_force_drop = TRUE;
928 if (player->is_subtitle_force_drop == TRUE) {
929 LOGD("Enable subtitle data path without drop\n");
931 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
932 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
934 LOGD("non-connected with external display");
936 player->is_subtitle_force_drop = FALSE;
942 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
944 VariantData *var_info = NULL;
945 g_return_val_if_fail(self != NULL, NULL);
947 var_info = g_new0(VariantData, 1);
948 if (!var_info) return NULL;
949 var_info->bandwidth = self->bandwidth;
950 var_info->width = self->width;
951 var_info->height = self->height;
955 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
957 mm_player_t* player = (mm_player_t*)hplayer;
960 MMPLAYER_RETURN_IF_FAIL(player);
962 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
964 /* destroy the gst bus msg thread */
965 if (player->bus_msg_thread) {
966 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
967 player->bus_msg_thread_exit = TRUE;
968 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
969 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
971 LOGD("gst bus msg thread exit.");
972 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
973 player->bus_msg_thread = NULL;
975 g_mutex_clear(&player->bus_msg_thread_mutex);
976 g_cond_clear(&player->bus_msg_thread_cond);
982 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
984 mm_player_t *player = (mm_player_t*)(data);
985 GstMessage *msg = NULL;
989 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
991 player->pipeline->mainbin &&
992 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
995 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
997 LOGE("cannot get BUS from the pipeline");
1001 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1003 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1004 while (!player->bus_msg_thread_exit) {
1005 msg = gst_bus_pop(bus);
1007 int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1008 MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1012 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1013 /* handle the gst msg */
1014 __mmplayer_gst_callback(msg, player);
1015 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016 gst_message_unref(msg);
1019 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1020 gst_object_unref(GST_OBJECT(bus));
1027 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1029 mm_player_t* player = (mm_player_t*)(data);
1030 static gboolean async_done = FALSE;
1032 MMPLAYER_RETURN_IF_FAIL(player);
1033 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1035 switch (GST_MESSAGE_TYPE(msg)) {
1036 case GST_MESSAGE_UNKNOWN:
1037 LOGD("unknown message received\n");
1040 case GST_MESSAGE_EOS:
1042 MMHandleType attrs = 0;
1045 LOGD("GST_MESSAGE_EOS received\n");
1047 /* NOTE : EOS event is comming multiple time. watch out it */
1048 /* check state. we only process EOS when pipeline state goes to PLAYING */
1049 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1050 LOGD("EOS received on non-playing state. ignoring it\n");
1054 if (player->pipeline) {
1055 if (player->pipeline->textbin)
1056 __mmplayer_drop_subtitle(player, TRUE);
1058 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1061 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1063 LOGD("release audio callback\n");
1065 /* release audio callback */
1066 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1067 player->audio_cb_probe_id = 0;
1068 /* audio callback should be free because it can be called even though probe remove.*/
1069 player->audio_stream_cb = NULL;
1070 player->audio_stream_cb_user_param = NULL;
1074 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1075 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1077 /* rewind if repeat count is greater then zero */
1078 /* get play count */
1079 attrs = MMPLAYER_GET_ATTRS(player);
1082 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1084 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1086 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1087 if (player->playback_rate < 0.0) {
1088 player->resumed_by_rewind = TRUE;
1089 _mmplayer_set_mute((MMHandleType)player, 0);
1090 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1093 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1096 player->sent_bos = FALSE;
1098 /* not posting eos when repeating */
1103 if (player->pipeline)
1104 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1106 /* post eos message to application */
1107 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1109 /* reset last position */
1110 player->last_position = 0;
1114 case GST_MESSAGE_ERROR:
1116 GError *error = NULL;
1117 gchar* debug = NULL;
1119 /* generating debug info before returning error */
1120 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1122 /* get error code */
1123 gst_message_parse_error(msg, &error, &debug);
1125 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1126 /* Note : the streaming error from the streaming source is handled
1127 * using __mmplayer_handle_streaming_error.
1129 __mmplayer_handle_streaming_error(player, msg);
1131 /* dump state of all element */
1132 __mmplayer_dump_pipeline_state(player);
1134 /* traslate gst error code to msl error code. then post it
1135 * to application if needed
1137 __mmplayer_handle_gst_error(player, msg, error);
1140 LOGE("error debug : %s", debug);
1143 if (MMPLAYER_IS_HTTP_PD(player))
1144 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1146 MMPLAYER_FREEIF(debug);
1147 g_error_free(error);
1151 case GST_MESSAGE_WARNING:
1154 GError* error = NULL;
1156 gst_message_parse_warning(msg, &error, &debug);
1158 LOGD("warning : %s\n", error->message);
1159 LOGD("debug : %s\n", debug);
1161 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1163 MMPLAYER_FREEIF(debug);
1164 g_error_free(error);
1168 case GST_MESSAGE_TAG:
1170 LOGD("GST_MESSAGE_TAG\n");
1171 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1172 LOGW("failed to extract tags from gstmessage\n");
1176 case GST_MESSAGE_BUFFERING:
1178 MMMessageParamType msg_param = {0, };
1179 int bRet = MM_ERROR_NONE;
1181 if (!(player->pipeline && player->pipeline->mainbin)) {
1182 LOGE("player pipeline handle is null");
1186 if (!MMPLAYER_IS_STREAMING(player))
1189 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1190 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1191 /* skip the playback control by buffering msg while user request is handled. */
1194 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1196 gst_message_parse_buffering(msg, &per);
1197 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1199 msg_param.connection.buffering = per;
1200 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1204 MMPLAYER_CMD_LOCK(player);
1207 /* ignore the prev buffering message */
1208 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1209 && (player->streamer->is_buffering_done == TRUE)) {
1210 gint buffer_percent = 0;
1212 gst_message_parse_buffering(msg, &buffer_percent);
1214 if (buffer_percent == MAX_BUFFER_PERCENT) {
1215 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1216 player->streamer->is_buffering_done = FALSE;
1218 MMPLAYER_CMD_UNLOCK(player);
1222 __mmplayer_update_buffer_setting(player, msg);
1224 bRet = __mmplayer_handle_buffering_message(player);
1226 if (bRet == MM_ERROR_NONE) {
1227 msg_param.connection.buffering = player->streamer->buffering_percent;
1228 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1230 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1231 player->pending_resume &&
1232 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1234 player->is_external_subtitle_added_now = FALSE;
1235 player->pending_resume = FALSE;
1236 _mmplayer_resume((MMHandleType)player);
1239 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1240 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1242 if (player->doing_seek) {
1243 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1244 player->doing_seek = FALSE;
1245 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1246 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1251 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1252 if (!player->streamer) {
1253 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1254 MMPLAYER_CMD_UNLOCK(player);
1258 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1260 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1261 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1263 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1264 msg_param.connection.buffering = player->streamer->buffering_percent;
1265 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1267 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1270 msg_param.connection.buffering = player->streamer->buffering_percent;
1271 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1274 MMPLAYER_CMD_UNLOCK(player);
1278 case GST_MESSAGE_STATE_CHANGED:
1280 MMPlayerGstElement *mainbin;
1281 const GValue *voldstate, *vnewstate, *vpending;
1282 GstState oldstate = GST_STATE_NULL;
1283 GstState newstate = GST_STATE_NULL;
1284 GstState pending = GST_STATE_NULL;
1286 if (!(player->pipeline && player->pipeline->mainbin)) {
1287 LOGE("player pipeline handle is null");
1291 mainbin = player->pipeline->mainbin;
1293 /* we only handle messages from pipeline */
1294 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1297 /* get state info from msg */
1298 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1299 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1300 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1302 if (!voldstate || !vnewstate) {
1303 LOGE("received msg has wrong format.");
1307 oldstate = (GstState)voldstate->data[0].v_int;
1308 newstate = (GstState)vnewstate->data[0].v_int;
1310 pending = (GstState)vpending->data[0].v_int;
1312 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1313 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1314 gst_element_state_get_name((GstState)oldstate),
1315 gst_element_state_get_name((GstState)newstate),
1316 gst_element_state_get_name((GstState)pending));
1318 if (newstate == GST_STATE_PLAYING) {
1319 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1321 int retVal = MM_ERROR_NONE;
1322 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1324 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1326 if (MM_ERROR_NONE != retVal)
1327 LOGE("failed to seek pending postion. just keep staying current position.\n");
1329 player->pending_seek.is_pending = FALSE;
1333 if (oldstate == newstate) {
1334 LOGD("pipeline reports state transition to old state");
1339 case GST_STATE_VOID_PENDING:
1342 case GST_STATE_NULL:
1345 case GST_STATE_READY:
1348 case GST_STATE_PAUSED:
1350 gboolean prepare_async = FALSE;
1351 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1353 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1354 __mmplayer_configure_audio_callback(player);
1356 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1357 // managed prepare async case
1358 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1359 LOGD("checking prepare mode for async transition - %d", prepare_async);
1362 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1363 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1365 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1366 __mm_player_streaming_set_content_bitrate(player->streamer,
1367 player->total_maximum_bitrate, player->total_bitrate);
1369 if (player->pending_seek.is_pending) {
1370 LOGW("trying to do pending seek");
1371 MMPLAYER_CMD_LOCK(player);
1372 __gst_pending_seek(player);
1373 MMPLAYER_CMD_UNLOCK(player);
1379 case GST_STATE_PLAYING:
1381 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1383 if (MMPLAYER_IS_STREAMING(player)) {
1384 // managed prepare async case when buffering is completed
1385 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1386 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1387 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1388 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1390 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1392 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1393 if (player->streamer->buffering_percent < 100) {
1395 MMMessageParamType msg_param = {0, };
1396 LOGW("Posting Buffering Completed Message to Application !!!");
1398 msg_param.connection.buffering = 100;
1399 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1404 if (player->gapless.stream_changed) {
1405 _mmplayer_update_content_attrs(player, ATTR_ALL);
1406 player->gapless.stream_changed = FALSE;
1409 if (player->doing_seek && async_done) {
1410 player->doing_seek = FALSE;
1412 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1423 case GST_MESSAGE_CLOCK_LOST:
1425 GstClock *clock = NULL;
1426 gboolean need_new_clock = FALSE;
1428 gst_message_parse_clock_lost(msg, &clock);
1429 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1431 if (!player->videodec_linked)
1432 need_new_clock = TRUE;
1433 else if (!player->ini.use_system_clock)
1434 need_new_clock = TRUE;
1436 if (need_new_clock) {
1437 LOGD("Provide clock is TRUE, do pause->resume\n");
1438 __gst_pause(player, FALSE);
1439 __gst_resume(player, FALSE);
1444 case GST_MESSAGE_NEW_CLOCK:
1446 GstClock *clock = NULL;
1447 gst_message_parse_new_clock(msg, &clock);
1448 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1452 case GST_MESSAGE_ELEMENT:
1454 const gchar *structure_name;
1455 gint count = 0, idx = 0;
1456 MMHandleType attrs = 0;
1458 attrs = MMPLAYER_GET_ATTRS(player);
1460 LOGE("cannot get content attribute");
1464 if (gst_message_get_structure(msg) == NULL)
1467 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1468 if (!structure_name)
1471 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1473 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1474 const GValue *var_info = NULL;
1476 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1477 if (var_info != NULL) {
1478 if (player->adaptive_info.var_list)
1479 g_list_free_full(player->adaptive_info.var_list, g_free);
1481 /* share addr or copy the list */
1482 player->adaptive_info.var_list =
1483 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1485 count = g_list_length(player->adaptive_info.var_list);
1487 VariantData *temp = NULL;
1489 /* print out for debug */
1490 LOGD("num of variant_info %d", count);
1491 for (idx = 0; idx < count; idx++) {
1492 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1494 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1500 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1501 gint num_buffers = 0;
1502 gint extra_num_buffers = 0;
1504 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1505 player->video_num_buffers = num_buffers;
1506 LOGD("video_num_buffers : %d", player->video_num_buffers);
1509 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1510 player->video_extra_num_buffers = extra_num_buffers;
1511 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1516 if (!strcmp(structure_name, "Language_list")) {
1517 const GValue *lang_list = NULL;
1518 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1519 if (lang_list != NULL) {
1520 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1522 LOGD("Total audio tracks(from parser) = %d \n", count);
1526 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1527 const GValue *lang_list = NULL;
1528 MMPlayerLangStruct *temp = NULL;
1530 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1531 if (lang_list != NULL) {
1532 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1534 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1535 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1536 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1537 if (mmf_attrs_commit(attrs))
1538 LOGE("failed to commit.\n");
1539 LOGD("Total subtitle tracks = %d \n", count);
1542 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1544 LOGD("value of lang_key is %s and lang_code is %s",
1545 temp->language_key, temp->language_code);
1548 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1549 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1554 /* custom message */
1555 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1556 MMMessageParamType msg_param = {0,};
1557 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1558 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1561 /* custom message for RTSP attribute :
1562 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1563 sdp which has contents info is received when rtsp connection is opened.
1564 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1565 if (!strcmp(structure_name, "rtspsrc_properties")) {
1567 gchar *audio_codec = NULL;
1568 gchar *video_codec = NULL;
1569 gchar *video_frame_size = NULL;
1571 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1572 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1573 player->streaming_type = __mmplayer_get_stream_service_type(player);
1574 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1576 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1577 LOGD("rtsp_audio_codec : %s", audio_codec);
1579 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1581 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1582 LOGD("rtsp_video_codec : %s", video_codec);
1584 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1586 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1587 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1588 if (video_frame_size) {
1590 char *seperator = strchr(video_frame_size, '-');
1593 char video_width[10] = {0,};
1594 int frame_size_len = strlen(video_frame_size);
1595 int separtor_len = strlen(seperator);
1597 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1598 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1601 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1605 if (mmf_attrs_commit(attrs))
1606 LOGE("failed to commit.\n");
1611 case GST_MESSAGE_DURATION_CHANGED:
1613 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1614 if (!__mmplayer_gst_handle_duration(player, msg))
1615 LOGW("failed to update duration");
1620 case GST_MESSAGE_ASYNC_START:
1621 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1624 case GST_MESSAGE_ASYNC_DONE:
1626 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1628 /* we only handle messages from pipeline */
1629 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1632 if (player->doing_seek) {
1633 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1634 player->doing_seek = FALSE;
1635 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1636 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1637 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1638 (player->streamer) &&
1639 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1640 (player->streamer->is_buffering == FALSE)) {
1641 GstQuery *query = NULL;
1642 gboolean busy = FALSE;
1645 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1646 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1647 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1648 gst_query_parse_buffering_percent(query, &busy, &percent);
1649 gst_query_unref(query);
1651 LOGD("buffered percent(%s): %d\n",
1652 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1655 if (percent >= 100) {
1656 player->streamer->is_buffering = FALSE;
1657 __mmplayer_handle_buffering_message(player);
1667 #if 0 /* delete unnecessary logs */
1668 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1669 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1670 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1671 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1672 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1673 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1674 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1675 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1676 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1677 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1678 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1679 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1680 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1681 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1682 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1689 /* should not call 'gst_message_unref(msg)' */
1694 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1700 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1701 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1703 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1704 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1705 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1707 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1708 LOGD("data total size of http content: %lld", bytes);
1709 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1712 /* handling audio clip which has vbr. means duration is keep changing */
1713 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1720 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1721 mm_player_spherical_metadata_t *metadata) {
1722 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1723 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1724 gst_tag_list_get_string(tags, "stitching_software",
1725 &metadata->stitching_software);
1726 gst_tag_list_get_string(tags, "projection_type",
1727 &metadata->projection_type_string);
1728 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1729 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1730 gst_tag_list_get_int(tags, "init_view_heading",
1731 &metadata->init_view_heading);
1732 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1733 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1734 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1735 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1736 &metadata->full_pano_width_pixels);
1737 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1738 &metadata->full_pano_height_pixels);
1739 gst_tag_list_get_int(tags, "cropped_area_image_width",
1740 &metadata->cropped_area_image_width);
1741 gst_tag_list_get_int(tags, "cropped_area_image_height",
1742 &metadata->cropped_area_image_height);
1743 gst_tag_list_get_int(tags, "cropped_area_left",
1744 &metadata->cropped_area_left);
1745 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1746 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1747 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1748 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1752 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1755 /* macro for better code readability */
1756 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1757 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1758 if (string != NULL) { \
1759 SECURE_LOGD("update tag string : %s\n", string); \
1760 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1761 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1762 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1763 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1764 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1765 g_free(new_string); \
1766 new_string = NULL; \
1768 mm_attrs_set_string_by_name(attribute, playertag, string); \
1775 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1777 GstSample *sample = NULL;\
1778 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1779 GstMapInfo info = GST_MAP_INFO_INIT;\
1780 buffer = gst_sample_get_buffer(sample);\
1781 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1782 LOGD("failed to get image data from tag");\
1783 gst_sample_unref(sample);\
1786 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1787 MMPLAYER_FREEIF(player->album_art);\
1788 player->album_art = (gchar *)g_malloc(info.size);\
1789 if (player->album_art) {\
1790 memcpy(player->album_art, info.data, info.size);\
1791 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1792 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1793 msg_param.data = (void *)player->album_art;\
1794 msg_param.size = info.size;\
1795 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1796 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1799 gst_buffer_unmap(buffer, &info);\
1800 gst_sample_unref(sample);\
1804 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1806 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1809 gchar *tag_list_str = NULL; \
1810 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1811 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1812 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1813 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1814 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1816 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1817 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1818 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1819 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1820 player->bitrate[track_type] = v_uint; \
1821 player->total_bitrate = 0; \
1822 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1823 player->total_bitrate += player->bitrate[i]; \
1824 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1825 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1826 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1827 player->maximum_bitrate[track_type] = v_uint; \
1828 player->total_maximum_bitrate = 0; \
1829 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1830 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1831 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1832 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1834 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1837 g_free(tag_list_str); \
1842 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1843 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1844 if (date != NULL) {\
1845 string = g_strdup_printf("%d", g_date_get_year(date));\
1846 mm_attrs_set_string_by_name(attribute, playertag, string);\
1847 SECURE_LOGD("metainfo year : %s\n", string);\
1848 MMPLAYER_FREEIF(string);\
1853 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1854 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1855 if (datetime != NULL) {\
1856 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1857 mm_attrs_set_string_by_name(attribute, playertag, string);\
1858 SECURE_LOGD("metainfo year : %s\n", string);\
1859 MMPLAYER_FREEIF(string);\
1860 gst_date_time_unref(datetime);\
1864 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1865 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1867 /* FIXIT : don't know how to store date */\
1873 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1874 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1876 /* FIXIT : don't know how to store date */\
1882 /* function start */
1883 GstTagList* tag_list = NULL;
1885 MMHandleType attrs = 0;
1887 char *string = NULL;
1890 GstDateTime *datetime = NULL;
1892 GstBuffer *buffer = NULL;
1894 MMMessageParamType msg_param = {0, };
1896 /* currently not used. but those are needed for above macro */
1897 //guint64 v_uint64 = 0;
1898 //gdouble v_double = 0;
1900 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1902 attrs = MMPLAYER_GET_ATTRS(player);
1904 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1906 /* get tag list from gst message */
1907 gst_message_parse_tag(msg, &tag_list);
1909 /* store tags to player attributes */
1910 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1911 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1912 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1913 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1914 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1915 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1916 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1917 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1918 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1919 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1920 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1922 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1923 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1924 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1925 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1927 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1928 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1929 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1930 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1931 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1932 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1933 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1939 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1940 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1941 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1942 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1943 MMPLAYER_UPDATE_TAG_LOCK(player);
1944 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1945 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1946 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1947 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1948 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1949 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1950 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1951 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1952 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1953 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1954 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1955 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1956 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1958 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1960 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1961 if (player->video360_metadata.is_spherical == -1) {
1962 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1963 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1964 player->video360_metadata.is_spherical);
1965 if (player->video360_metadata.is_spherical == 1) {
1966 LOGD("This is spherical content for 360 playback.");
1967 player->is_content_spherical = TRUE;
1969 LOGD("This is not spherical content");
1970 player->is_content_spherical = FALSE;
1973 if (player->video360_metadata.projection_type_string) {
1974 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1975 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1977 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1978 player->is_content_spherical = player->is_video360_enabled = FALSE;
1982 if (player->video360_metadata.stereo_mode_string) {
1983 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1984 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1985 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1986 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1987 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1988 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1990 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1991 player->is_content_spherical = player->is_video360_enabled = FALSE;
1997 if (mmf_attrs_commit(attrs))
1998 LOGE("failed to commit.\n");
2000 gst_tag_list_free(tag_list);
2006 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2008 mm_player_t* player = (mm_player_t*) data;
2012 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2013 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2014 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2015 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2017 * [1] audio and video will be dumped with filesink.
2018 * [2] autoplugging is done by just using pad caps.
2019 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2020 * and the video will be dumped via filesink.
2022 if (player->num_dynamic_pad == 0) {
2023 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2025 if (!__mmplayer_gst_remove_fakesink(player,
2026 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2027 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2028 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2029 * source element are not same. To overcome this situation, this function will called
2030 * several places and several times. Therefore, this is not an error case.
2035 /* create dot before error-return. for debugging */
2036 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2038 player->no_more_pad = TRUE;
2044 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2046 GstElement* parent = NULL;
2048 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2050 /* if we have no fakesink. this meas we are using decodebin which doesn'
2051 t need to add extra fakesink */
2052 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2055 MMPLAYER_FSINK_LOCK(player);
2060 /* get parent of fakesink */
2061 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2063 LOGD("fakesink already removed\n");
2067 gst_element_set_locked_state(fakesink->gst, TRUE);
2069 /* setting the state to NULL never returns async
2070 * so no need to wait for completion of state transiton
2072 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2073 LOGE("fakesink state change failure!\n");
2074 /* FIXIT : should I return here? or try to proceed to next? */
2077 /* remove fakesink from it's parent */
2078 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2079 LOGE("failed to remove fakesink\n");
2081 gst_object_unref(parent);
2086 gst_object_unref(parent);
2088 LOGD("state-holder removed\n");
2090 gst_element_set_locked_state(fakesink->gst, FALSE);
2092 MMPLAYER_FSINK_UNLOCK(player);
2097 gst_element_set_locked_state(fakesink->gst, FALSE);
2099 MMPLAYER_FSINK_UNLOCK(player);
2105 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2107 GstPad *sinkpad = NULL;
2108 GstCaps* caps = NULL;
2109 GstElement* new_element = NULL;
2110 GstStructure* str = NULL;
2111 const gchar* name = NULL;
2113 mm_player_t* player = (mm_player_t*) data;
2117 MMPLAYER_RETURN_IF_FAIL(element && pad);
2118 MMPLAYER_RETURN_IF_FAIL(player &&
2120 player->pipeline->mainbin);
2123 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2124 * num_dynamic_pad will decreased after creating a sinkbin.
2126 player->num_dynamic_pad++;
2127 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2129 caps = gst_pad_query_caps(pad, NULL);
2131 MMPLAYER_CHECK_NULL(caps);
2133 /* clear previous result*/
2134 player->have_dynamic_pad = FALSE;
2136 str = gst_caps_get_structure(caps, 0);
2139 LOGE("cannot get structure from caps.\n");
2143 name = gst_structure_get_name(str);
2145 LOGE("cannot get mimetype from structure.\n");
2149 if (strstr(name, "video")) {
2151 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2153 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2154 if (player->v_stream_caps) {
2155 gst_caps_unref(player->v_stream_caps);
2156 player->v_stream_caps = NULL;
2159 new_element = gst_element_factory_make("fakesink", NULL);
2160 player->num_dynamic_pad--;
2165 /* clear previous result*/
2166 player->have_dynamic_pad = FALSE;
2168 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2169 LOGE("failed to autoplug for caps");
2173 /* check if there's dynamic pad*/
2174 if (player->have_dynamic_pad) {
2175 LOGE("using pad caps assums there's no dynamic pad !\n");
2179 gst_caps_unref(caps);
2184 /* excute new_element if created*/
2186 LOGD("adding new element to pipeline\n");
2188 /* set state to READY before add to bin */
2189 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2191 /* add new element to the pipeline */
2192 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2193 LOGE("failed to add autoplug element to bin\n");
2197 /* get pad from element */
2198 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2200 LOGE("failed to get sinkpad from autoplug element\n");
2205 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2206 LOGE("failed to link autoplug element\n");
2210 gst_object_unref(sinkpad);
2213 /* run. setting PLAYING here since streamming source is live source */
2214 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2218 gst_caps_unref(caps);
2224 STATE_CHANGE_FAILED:
2226 /* FIXIT : take care if new_element has already added to pipeline */
2228 gst_object_unref(GST_OBJECT(new_element));
2231 gst_object_unref(GST_OBJECT(sinkpad));
2234 gst_caps_unref(caps);
2236 /* FIXIT : how to inform this error to MSL ????? */
2237 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2238 * then post an error to application
2242 static GstPadProbeReturn
2243 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2245 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2246 return GST_PAD_PROBE_OK;
2249 static GstPadProbeReturn
2250 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2252 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2253 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2254 mm_player_t* player = (mm_player_t*)data;
2255 GstCaps* caps = NULL;
2256 GstStructure* str = NULL;
2257 const gchar* name = NULL;
2258 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2261 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2262 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2263 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2264 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2265 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2267 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2268 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2272 caps = gst_pad_query_caps(pad, NULL);
2274 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2278 str = gst_caps_get_structure(caps, 0);
2280 LOGE("failed to get structure from caps");
2284 name = gst_structure_get_name(str);
2286 LOGE("failed to get name from str");
2290 if (strstr(name, "audio")) {
2291 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2292 } else if (strstr(name, "video")) {
2293 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2295 /* text track is not supportable */
2296 LOGE("invalid name %s", name);
2300 switch (GST_EVENT_TYPE(event)) {
2303 /* in case of gapless, drop eos event not to send it to sink */
2304 if (player->gapless.reconfigure && !player->msg_posted) {
2305 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2306 ret = GST_PAD_PROBE_DROP;
2310 case GST_EVENT_STREAM_START:
2312 gint64 stop_running_time = 0;
2313 gint64 position_running_time = 0;
2314 gint64 position = 0;
2317 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2318 if ((player->gapless.update_segment[idx] == TRUE) ||
2319 !(player->selector[idx].event_probe_id)) {
2320 /* LOGW("[%d] skip", idx); */
2324 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2326 gst_segment_to_running_time(&player->gapless.segment[idx],
2327 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2328 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2330 gst_segment_to_running_time(&player->gapless.segment[idx],
2331 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2333 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2335 gst_segment_to_running_time(&player->gapless.segment[idx],
2336 GST_FORMAT_TIME, player->duration);
2339 position_running_time =
2340 gst_segment_to_running_time(&player->gapless.segment[idx],
2341 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2343 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2344 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2346 GST_TIME_ARGS(stop_running_time),
2347 GST_TIME_ARGS(position_running_time),
2348 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2349 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2351 position_running_time = MAX(position_running_time, stop_running_time);
2352 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2353 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2354 position_running_time = MAX(0, position_running_time);
2355 position = MAX(position, position_running_time);
2358 if (position != 0) {
2359 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2360 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2361 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2363 player->gapless.start_time[stream_type] += position;
2367 case GST_EVENT_FLUSH_STOP:
2369 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2370 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2371 player->gapless.start_time[stream_type] = 0;
2374 case GST_EVENT_SEGMENT:
2379 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2380 gst_event_copy_segment(event, &segment);
2382 if (segment.format == GST_FORMAT_TIME) {
2383 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2384 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2385 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2386 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2387 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2388 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2390 /* keep the all the segment ev to cover the seeking */
2391 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2392 player->gapless.update_segment[stream_type] = TRUE;
2394 if (!player->gapless.running)
2397 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2399 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2401 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2402 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2403 gst_event_unref(event);
2404 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2410 gdouble proportion = 0.0;
2411 GstClockTimeDiff diff = 0;
2412 GstClockTime timestamp = 0;
2413 gint64 running_time_diff = -1;
2414 GstQOSType type = 0;
2415 GstEvent *tmpev = NULL;
2417 running_time_diff = player->gapless.segment[stream_type].base;
2419 if (running_time_diff <= 0) /* don't need to adjust */
2422 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2423 gst_event_unref(event);
2425 if (timestamp < running_time_diff) {
2426 LOGW("QOS event from previous group");
2427 ret = GST_PAD_PROBE_DROP;
2431 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2432 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2433 stream_type, GST_TIME_ARGS(timestamp),
2434 GST_TIME_ARGS(running_time_diff),
2435 GST_TIME_ARGS(timestamp - running_time_diff));
2437 timestamp -= running_time_diff;
2439 /* That case is invalid for QoS events */
2440 if (diff < 0 && -diff > timestamp) {
2441 LOGW("QOS event from previous group");
2442 ret = GST_PAD_PROBE_DROP;
2446 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2447 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2457 gst_caps_unref(caps);
2462 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2464 mm_player_t* player = NULL;
2465 GstElement* pipeline = NULL;
2466 GstElement* selector = NULL;
2467 GstElement* fakesink = NULL;
2468 GstCaps* caps = NULL;
2469 GstStructure* str = NULL;
2470 const gchar* name = NULL;
2471 GstPad* sinkpad = NULL;
2472 GstPad* srcpad = NULL;
2473 gboolean first_track = FALSE;
2475 enum MainElementID elemId = MMPLAYER_M_NUM;
2476 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2479 player = (mm_player_t*)data;
2481 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2482 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2484 //LOGD("pad-added signal handling\n");
2486 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2488 /* get mimetype from caps */
2489 caps = gst_pad_query_caps(pad, NULL);
2491 LOGE("cannot get caps from pad.\n");
2495 str = gst_caps_get_structure(caps, 0);
2497 LOGE("cannot get structure from caps.\n");
2501 name = gst_structure_get_name(str);
2503 LOGE("cannot get mimetype from structure.\n");
2507 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2508 //LOGD("detected mimetype : %s\n", name);
2510 if (strstr(name, "video")) {
2513 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2514 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2516 /* don't make video because of not required, and not support multiple track */
2517 if (stype == MM_DISPLAY_SURFACE_NULL) {
2518 LOGD("no video sink by null surface");
2520 gchar *caps_str = gst_caps_to_string(caps);
2521 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2522 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2523 player->set_mode.video_zc = TRUE;
2525 MMPLAYER_FREEIF(caps_str);
2527 if (player->v_stream_caps) {
2528 gst_caps_unref(player->v_stream_caps);
2529 player->v_stream_caps = NULL;
2532 LOGD("create fakesink instead of videobin");
2535 fakesink = gst_element_factory_make("fakesink", NULL);
2536 if (fakesink == NULL) {
2537 LOGE("ERROR : fakesink create error\n");
2541 if (player->ini.set_dump_element_flag)
2542 __mmplayer_add_dump_buffer_probe(player, fakesink);
2544 player->video_fakesink = fakesink;
2546 /* store it as it's sink element */
2547 __mmplayer_add_sink(player, player->video_fakesink);
2549 gst_bin_add(GST_BIN(pipeline), fakesink);
2552 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2554 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2555 LOGW("failed to link fakesink\n");
2556 gst_object_unref(GST_OBJECT(fakesink));
2560 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2561 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2562 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2565 if (player->set_mode.media_packet_video_stream) {
2566 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2568 MMPLAYER_SIGNAL_CONNECT(player,
2570 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2572 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2575 MMPLAYER_SIGNAL_CONNECT(player,
2577 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2579 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2583 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2584 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2588 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2589 __mmplayer_gst_decode_callback(elem, pad, player);
2593 LOGD("video selector \n");
2594 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2595 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2597 if (strstr(name, "audio")) {
2598 gint samplerate = 0;
2601 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2602 __mmplayer_gst_decode_callback(elem, pad, player);
2606 LOGD("audio selector \n");
2607 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2608 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2610 gst_structure_get_int(str, "rate", &samplerate);
2611 gst_structure_get_int(str, "channels", &channels);
2613 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2615 fakesink = gst_element_factory_make("fakesink", NULL);
2616 if (fakesink == NULL) {
2617 LOGE("ERROR : fakesink create error\n");
2621 gst_bin_add(GST_BIN(pipeline), fakesink);
2624 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2626 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2627 LOGW("failed to link fakesink\n");
2628 gst_object_unref(GST_OBJECT(fakesink));
2632 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2633 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2634 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2638 } else if (strstr(name, "text")) {
2639 LOGD("text selector \n");
2640 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2641 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2643 LOGE("wrong elem id \n");
2648 selector = player->pipeline->mainbin[elemId].gst;
2649 if (selector == NULL) {
2650 selector = gst_element_factory_make("input-selector", NULL);
2651 LOGD("Creating input-selector\n");
2652 if (selector == NULL) {
2653 LOGE("ERROR : input-selector create error\n");
2656 g_object_set(selector, "sync-streams", TRUE, NULL);
2658 player->pipeline->mainbin[elemId].id = elemId;
2659 player->pipeline->mainbin[elemId].gst = selector;
2662 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2664 srcpad = gst_element_get_static_pad(selector, "src");
2666 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2667 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2668 __mmplayer_gst_selector_blocked, NULL, NULL);
2669 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2670 __mmplayer_gst_selector_event_probe, player, NULL);
2672 gst_element_set_state(selector, GST_STATE_PAUSED);
2673 gst_bin_add(GST_BIN(pipeline), selector);
2675 LOGD("input-selector is already created.\n");
2678 LOGD("Calling request pad with selector %p \n", selector);
2679 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2681 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2683 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2684 LOGW("failed to link selector\n");
2685 gst_object_unref(GST_OBJECT(selector));
2690 LOGD("this is first track --> active track \n");
2691 g_object_set(selector, "active-pad", sinkpad, NULL);
2694 _mmplayer_track_update_info(player, stream_type, sinkpad);
2701 gst_caps_unref(caps);
2704 gst_object_unref(GST_OBJECT(sinkpad));
2709 gst_object_unref(GST_OBJECT(srcpad));
2716 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2718 GstPad* srcpad = NULL;
2719 MMHandleType attrs = 0;
2720 gint active_index = 0;
2722 // [link] input-selector :: textbin
2723 srcpad = gst_element_get_static_pad(text_selector, "src");
2725 LOGE("failed to get srcpad from selector\n");
2729 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2731 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2732 if ((active_index != DEFAULT_TRACK) &&
2733 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2734 LOGW("failed to change text track\n");
2735 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2738 player->no_more_pad = TRUE;
2739 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2741 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2742 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2743 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2744 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2747 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2749 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2750 player->has_closed_caption = TRUE;
2752 attrs = MMPLAYER_GET_ATTRS(player);
2754 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2755 if (mmf_attrs_commit(attrs))
2756 LOGE("failed to commit.\n");
2758 LOGE("cannot get content attribute");
2761 gst_object_unref(GST_OBJECT(srcpad));
2767 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2769 mm_player_t* player = (mm_player_t*)data;
2770 GstElement* selector = NULL;
2771 GstElement* queue = NULL;
2773 GstPad* srcpad = NULL;
2774 GstPad* sinkpad = NULL;
2775 GstCaps* caps = NULL;
2776 gchar* caps_str = NULL;
2779 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2781 caps = gst_pad_get_current_caps(pad);
2782 caps_str = gst_caps_to_string(caps);
2783 LOGD("deinterleave new caps : %s\n", caps_str);
2784 MMPLAYER_FREEIF(caps_str);
2785 gst_caps_unref(caps);
2787 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2788 LOGE("ERROR : queue create error\n");
2792 g_object_set(G_OBJECT(queue),
2793 "max-size-buffers", 10,
2794 "max-size-bytes", 0,
2795 "max-size-time", (guint64)0,
2798 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2801 LOGE("there is no audio channel selector.\n");
2805 srcpad = gst_element_get_static_pad(queue, "src");
2806 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2808 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2810 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2811 LOGW("failed to link deinterleave - selector\n");
2815 gst_element_set_state(queue, GST_STATE_PAUSED);
2816 player->audio_mode.total_track_num++;
2821 gst_object_unref(GST_OBJECT(srcpad));
2826 gst_object_unref(GST_OBJECT(sinkpad));
2835 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2837 mm_player_t* player = NULL;
2838 GstElement* selector = NULL;
2839 GstPad* sinkpad = NULL;
2840 gint active_index = 0;
2841 gchar* change_pad_name = NULL;
2842 GstCaps* caps = NULL; // no need to unref
2843 gint default_audio_ch = 0;
2846 player = (mm_player_t*) data;
2848 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2851 LOGE("there is no audio channel selector.\n");
2855 active_index = player->audio_mode.active_pad_index;
2857 if (active_index != default_audio_ch) {
2858 gint audio_ch = default_audio_ch;
2860 /*To get the new pad from the selector*/
2861 change_pad_name = g_strdup_printf("sink%d", active_index);
2862 if (change_pad_name != NULL) {
2863 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2864 if (sinkpad != NULL) {
2865 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2866 g_object_set(selector, "active-pad", sinkpad, NULL);
2868 audio_ch = active_index;
2870 caps = gst_pad_get_current_caps(sinkpad);
2871 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2873 __mmplayer_set_audio_attrs(player, caps);
2874 gst_caps_unref(caps);
2876 MMPLAYER_FREEIF(change_pad_name);
2879 player->audio_mode.active_pad_index = audio_ch;
2880 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2886 gst_object_unref(sinkpad);
2893 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2895 mm_player_t* player = NULL;
2896 MMPlayerGstElement *mainbin = NULL;
2898 GstElement* tee = NULL;
2899 GstElement* stereo_queue = NULL;
2900 GstElement* mono_queue = NULL;
2901 GstElement* conv = NULL;
2902 GstElement* filter = NULL;
2903 GstElement* deinterleave = NULL;
2904 GstElement* selector = NULL;
2906 GstPad* srcpad = NULL;
2907 GstPad* selector_srcpad = NULL;
2908 GstPad* sinkpad = NULL;
2909 GstCaps* caps = NULL;
2910 gulong block_id = 0;
2915 player = (mm_player_t*) data;
2917 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2918 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2920 mainbin = player->pipeline->mainbin;
2923 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2924 LOGE("ERROR : tee create error\n");
2928 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2929 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2931 gst_element_set_state(tee, GST_STATE_PAUSED);
2934 srcpad = gst_element_get_request_pad(tee, "src_%u");
2935 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2936 LOGE("ERROR : stereo queue create error\n");
2940 g_object_set(G_OBJECT(stereo_queue),
2941 "max-size-buffers", 10,
2942 "max-size-bytes", 0,
2943 "max-size-time", (guint64)0,
2946 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2947 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2950 gst_object_unref(GST_OBJECT(srcpad));
2954 srcpad = gst_element_get_request_pad(tee, "src_%u");
2956 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2957 LOGE("ERROR : mono queue create error\n");
2961 g_object_set(G_OBJECT(mono_queue),
2962 "max-size-buffers", 10,
2963 "max-size-bytes", 0,
2964 "max-size-time", (guint64)0,
2967 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2968 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2970 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2971 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2974 srcpad = gst_element_get_static_pad(mono_queue, "src");
2975 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2976 LOGE("ERROR : audioconvert create error\n");
2980 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2981 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2985 gst_object_unref(GST_OBJECT(srcpad));
2988 srcpad = gst_element_get_static_pad(conv, "src");
2990 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2991 LOGE("ERROR : capsfilter create error\n");
2995 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2996 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2998 caps = gst_caps_from_string("audio/x-raw-int, "
2999 "width = (int) 16, "
3000 "depth = (int) 16, "
3001 "channels = (int) 2");
3003 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3004 gst_caps_unref(caps);
3006 gst_element_set_state(conv, GST_STATE_PAUSED);
3007 gst_element_set_state(filter, GST_STATE_PAUSED);
3011 gst_object_unref(GST_OBJECT(srcpad));
3014 srcpad = gst_element_get_static_pad(filter, "src");
3016 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3017 LOGE("ERROR : deinterleave create error\n");
3021 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3023 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3024 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3026 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3027 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3029 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3030 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3033 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3034 if (selector == NULL) {
3035 LOGE("ERROR : audio-selector create error\n");
3039 g_object_set(selector, "sync-streams", TRUE, NULL);
3040 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3042 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3043 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3045 selector_srcpad = gst_element_get_static_pad(selector, "src");
3047 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3049 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3050 __mmplayer_gst_selector_blocked, NULL, NULL);
3053 gst_object_unref(GST_OBJECT(srcpad));
3057 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3058 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3060 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3061 LOGW("failed to link queue_stereo - selector\n");
3065 player->audio_mode.total_track_num++;
3067 g_object_set(selector, "active-pad", sinkpad, NULL);
3068 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3069 gst_element_set_state(selector, GST_STATE_PAUSED);
3071 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3075 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3076 if (block_id != 0) {
3077 gst_pad_remove_probe(selector_srcpad, block_id);
3082 gst_object_unref(GST_OBJECT(sinkpad));
3087 gst_object_unref(GST_OBJECT(srcpad));
3091 if (selector_srcpad) {
3092 gst_object_unref(GST_OBJECT(selector_srcpad));
3093 selector_srcpad = NULL;
3101 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3103 mm_player_t* player = NULL;
3104 GstPad* srcpad = NULL;
3105 GstElement* video_selector = NULL;
3106 GstElement* audio_selector = NULL;
3107 GstElement* text_selector = NULL;
3108 MMHandleType attrs = 0;
3109 gint active_index = 0;
3110 gint64 dur_bytes = 0L;
3112 player = (mm_player_t*) data;
3114 LOGD("no-more-pad signal handling\n");
3116 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3117 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3118 LOGW("no need to go more");
3120 if (player->gapless.reconfigure) {
3121 player->gapless.reconfigure = FALSE;
3122 MMPLAYER_PLAYBACK_UNLOCK(player);
3128 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3129 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3130 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3131 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3132 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3134 if (NULL == player->streamer) {
3135 LOGW("invalid state for buffering");
3139 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3140 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3142 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3143 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3145 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3147 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3148 LOGE("fail to get duration.\n");
3150 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3151 // use file information was already set on Q2 when it was created.
3152 __mm_player_streaming_set_queue2(player->streamer,
3153 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3154 TRUE, // use_buffering
3156 init_buffering_time,
3158 player->ini.http_buffering_limit, // high percent
3159 MUXED_BUFFER_TYPE_MEM_QUEUE,
3161 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3164 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3165 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3166 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3167 if (video_selector) {
3168 // [link] input-selector :: videobin
3169 srcpad = gst_element_get_static_pad(video_selector, "src");
3171 LOGE("failed to get srcpad from video selector\n");
3175 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3176 if (!text_selector && !audio_selector)
3177 player->no_more_pad = TRUE;
3179 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3181 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3182 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3183 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3184 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3188 if (audio_selector) {
3189 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3190 if ((active_index != DEFAULT_TRACK) &&
3191 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3192 LOGW("failed to change audio track\n");
3193 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3196 // [link] input-selector :: audiobin
3197 srcpad = gst_element_get_static_pad(audio_selector, "src");
3199 LOGE("failed to get srcpad from selector\n");
3203 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3205 player->no_more_pad = TRUE;
3207 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3208 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3209 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3210 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3211 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3214 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3216 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3218 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3219 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3220 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3221 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3225 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3227 attrs = MMPLAYER_GET_ATTRS(player);
3229 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3230 if (mmf_attrs_commit(attrs))
3231 LOGE("failed to commit.\n");
3233 LOGE("cannot get content attribute");
3235 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3236 LOGD("There is no audio track : remove audiobin");
3238 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3239 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3241 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3242 MMPLAYER_FREEIF(player->pipeline->audiobin);
3245 if (player->num_dynamic_pad == 0)
3246 __mmplayer_pipeline_complete(NULL, player);
3249 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3251 __mmplayer_handle_text_decode_path(player, text_selector);
3258 gst_object_unref(GST_OBJECT(srcpad));
3262 if (player->gapless.reconfigure) {
3263 player->gapless.reconfigure = FALSE;
3264 MMPLAYER_PLAYBACK_UNLOCK(player);
3269 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3271 mm_player_t* player = NULL;
3272 MMHandleType attrs = 0;
3273 GstElement* pipeline = NULL;
3274 GstCaps* caps = NULL;
3275 gchar* caps_str = NULL;
3276 GstStructure* str = NULL;
3277 const gchar* name = NULL;
3278 GstPad* sinkpad = NULL;
3279 GstElement* sinkbin = NULL;
3280 gboolean reusing = FALSE;
3281 GstElement *text_selector = NULL;
3284 player = (mm_player_t*) data;
3286 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3287 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3289 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3291 attrs = MMPLAYER_GET_ATTRS(player);
3293 LOGE("cannot get content attribute\n");
3297 /* get mimetype from caps */
3298 caps = gst_pad_query_caps(pad, NULL);
3300 LOGE("cannot get caps from pad.\n");
3303 caps_str = gst_caps_to_string(caps);
3305 str = gst_caps_get_structure(caps, 0);
3307 LOGE("cannot get structure from caps.\n");
3311 name = gst_structure_get_name(str);
3313 LOGE("cannot get mimetype from structure.\n");
3317 //LOGD("detected mimetype : %s\n", name);
3319 if (strstr(name, "audio")) {
3320 if (player->pipeline->audiobin == NULL) {
3321 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3322 LOGE("failed to create audiobin. continuing without audio\n");
3326 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3327 LOGD("creating audiosink bin success\n");
3330 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3331 LOGD("reusing audiobin\n");
3332 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3335 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3336 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3338 player->audiosink_linked = 1;
3340 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3342 LOGE("failed to get pad from sinkbin\n");
3345 } else if (strstr(name, "video")) {
3346 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3347 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3348 player->set_mode.video_zc = TRUE;
3350 if (player->pipeline->videobin == NULL) {
3351 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3352 /* get video surface type */
3353 int surface_type = 0;
3354 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3355 LOGD("display_surface_type(%d)\n", surface_type);
3357 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3358 LOGD("not make videobin because it dose not want\n");
3362 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3363 /* mark video overlay for acquire */
3364 if (player->video_overlay_resource == NULL) {
3365 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3366 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3367 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3368 &player->video_overlay_resource)
3369 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3370 LOGE("could not mark video_overlay resource for acquire\n");
3376 player->interrupted_by_resource = FALSE;
3377 /* acquire resources for video overlay */
3378 if (mm_resource_manager_commit(player->resource_manager) !=
3379 MM_RESOURCE_MANAGER_ERROR_NONE) {
3380 LOGE("could not acquire resources for video playing\n");
3384 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3385 LOGE("failed to create videobin. continuing without video\n");
3389 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3390 LOGD("creating videosink bin success\n");
3393 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3394 LOGD("re-using videobin\n");
3395 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3398 player->videosink_linked = 1;
3400 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3402 LOGE("failed to get pad from sinkbin\n");
3405 } else if (strstr(name, "text")) {
3406 if (player->pipeline->textbin == NULL) {
3407 MMPlayerGstElement* mainbin = NULL;
3409 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3410 LOGE("failed to create text sink bin. continuing without text\n");
3414 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3415 LOGD("creating textsink bin success\n");
3417 /* FIXIT : track number shouldn't be hardcoded */
3418 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3420 player->textsink_linked = 1;
3421 LOGI("player->textsink_linked set to 1\n");
3423 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3425 LOGE("failed to get pad from sinkbin\n");
3429 mainbin = player->pipeline->mainbin;
3431 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3432 /* input selector */
3433 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3434 if (!text_selector) {
3435 LOGE("failed to create subtitle input selector element\n");
3438 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3440 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3441 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3444 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3445 LOGE("failed to set state(READY) to sinkbin\n");
3449 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3450 LOGW("failed to add subtitle input selector\n");
3454 LOGD("created element input-selector");
3457 LOGD("already having subtitle input selector");
3458 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3461 if (!player->textsink_linked) {
3462 LOGD("re-using textbin\n");
3465 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3467 player->textsink_linked = 1;
3468 LOGI("player->textsink_linked set to 1\n");
3470 LOGD("ignoring internal subtutle since external subtitle is available");
3473 LOGW("unknown type of elementary stream!ignoring it...\n");
3480 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3481 LOGE("failed to set state(READY) to sinkbin\n");
3485 /* Added for multi audio support to avoid adding audio bin again*/
3487 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3488 LOGE("failed to add sinkbin to pipeline\n");
3494 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3495 LOGE("failed to get pad from sinkbin\n");
3501 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3502 LOGE("failed to set state(PAUSED) to sinkbin\n");
3506 if (text_selector) {
3507 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3508 LOGE("failed to set state(PAUSED) to sinkbin\n");
3514 gst_object_unref(sinkpad);
3518 LOGD("[handle: %p] linking sink bin success", player);
3520 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3521 * streaming task. if the task blocked, then buffer will not flow to the next element
3522 *(autoplugging element). so this is special hack for streaming. please try to remove it
3524 /* dec stream count. we can remove fakesink if it's zero */
3525 if (player->num_dynamic_pad)
3526 player->num_dynamic_pad--;
3528 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3530 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3531 __mmplayer_pipeline_complete(NULL, player);
3535 MMPLAYER_FREEIF(caps_str);
3538 gst_caps_unref(caps);
3541 gst_object_unref(GST_OBJECT(sinkpad));
3543 /* flusing out new attributes */
3544 if (mmf_attrs_commit(attrs))
3545 LOGE("failed to comit attributes\n");
3551 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3553 int pro_value = 0; // in the case of expection, default will be returned.
3554 int dest_angle = rotation_angle;
3555 int rotation_type = -1;
3557 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3558 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3559 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3561 if (rotation_angle >= 360)
3562 dest_angle = rotation_angle - 360;
3564 /* chech if supported or not */
3565 if (dest_angle % 90) {
3566 LOGD("not supported rotation angle = %d", rotation_angle);
3572 * custom_convert - none (B)
3573 * videoflip - none (C)
3575 if (player->set_mode.video_zc) {
3576 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3577 rotation_type = ROTATION_USING_CUSTOM;
3579 rotation_type = ROTATION_USING_SINK;
3581 int surface_type = 0;
3582 rotation_type = ROTATION_USING_FLIP;
3584 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3585 LOGD("check display surface type attribute: %d", surface_type);
3587 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3588 rotation_type = ROTATION_USING_SINK;
3590 rotation_type = ROTATION_USING_FLIP; //C
3592 LOGD("using %d type for rotation", rotation_type);
3595 /* get property value for setting */
3596 switch (rotation_type) {
3597 case ROTATION_USING_SINK: // tizenwlsink
3599 switch (dest_angle) {
3603 pro_value = 3; // clockwise 90
3609 pro_value = 1; // counter-clockwise 90
3614 case ROTATION_USING_CUSTOM:
3616 gchar *ename = NULL;
3617 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3619 if (g_strrstr(ename, "fimcconvert")) {
3620 switch (dest_angle) {
3624 pro_value = 90; // clockwise 90
3630 pro_value = 270; // counter-clockwise 90
3636 case ROTATION_USING_FLIP: // videoflip
3638 switch (dest_angle) {
3642 pro_value = 1; // clockwise 90
3648 pro_value = 3; // counter-clockwise 90
3655 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3663 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3665 /* check video sinkbin is created */
3666 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3668 player->pipeline->videobin &&
3669 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3670 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3671 MM_ERROR_PLAYER_NOT_INITIALIZED);
3673 return MM_ERROR_NONE;
3677 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3679 int rotation_value = 0;
3680 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3684 /* check video sinkbin is created */
3685 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3688 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3690 /* get rotation value to set */
3691 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3692 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3693 LOGD("set video param : rotate %d", rotation_value);
3697 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3699 MMHandleType attrs = 0;
3703 /* check video sinkbin is created */
3704 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3707 attrs = MMPLAYER_GET_ATTRS(player);
3708 MMPLAYER_RETURN_IF_FAIL(attrs);
3710 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3711 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3712 LOGD("set video param : visible %d", visible);
3716 __mmplayer_video_param_set_display_method(mm_player_t* player)
3718 MMHandleType attrs = 0;
3719 int display_method = 0;
3722 /* check video sinkbin is created */
3723 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3726 attrs = MMPLAYER_GET_ATTRS(player);
3727 MMPLAYER_RETURN_IF_FAIL(attrs);
3729 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3730 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3731 LOGD("set video param : method %d", display_method);
3735 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3737 MMHandleType attrs = 0;
3738 void *handle = NULL;
3740 int wl_window_x = 0;
3741 int wl_window_y = 0;
3742 int wl_window_width = 0;
3743 int wl_window_height = 0;
3746 /* check video sinkbin is created */
3747 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3750 attrs = MMPLAYER_GET_ATTRS(player);
3751 MMPLAYER_RETURN_IF_FAIL(attrs);
3753 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3756 /*It should be set after setting window*/
3757 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3758 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3759 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3760 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3762 /* After setting window handle, set render rectangle */
3763 gst_video_overlay_set_render_rectangle(
3764 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3765 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3766 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3767 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3772 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3774 MMHandleType attrs = 0;
3775 void *handle = NULL;
3777 /* check video sinkbin is created */
3778 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3781 attrs = MMPLAYER_GET_ATTRS(player);
3782 MMPLAYER_RETURN_IF_FAIL(attrs);
3784 /* common case if using overlay surface */
3785 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3788 /* default is using wl_surface_id */
3789 unsigned int wl_surface_id = 0;
3790 wl_surface_id = *(int*)handle;
3791 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3792 gst_video_overlay_set_wl_window_wl_surface_id(
3793 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3796 /* FIXIT : is it error case? */
3797 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3802 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3804 bool update_all_param = FALSE;
3807 /* check video sinkbin is created */
3808 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3809 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3811 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3812 LOGE("can not find tizenwlsink");
3813 return MM_ERROR_PLAYER_INTERNAL;
3816 LOGD("param_name : %s", param_name);
3817 if (!g_strcmp0(param_name, "update_all_param"))
3818 update_all_param = TRUE;
3820 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3821 __mmplayer_video_param_set_display_overlay(player);
3822 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3823 __mmplayer_video_param_set_display_method(player);
3824 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3825 __mmplayer_video_param_set_render_rectangle(player);
3826 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3827 __mmplayer_video_param_set_display_visible(player);
3828 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3829 __mmplayer_video_param_set_display_rotation(player);
3831 return MM_ERROR_NONE;
3835 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3837 MMHandleType attrs = 0;
3838 int surface_type = 0;
3839 int ret = MM_ERROR_NONE;
3843 /* check video sinkbin is created */
3844 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3845 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3847 attrs = MMPLAYER_GET_ATTRS(player);
3849 LOGE("cannot get content attribute");
3850 return MM_ERROR_PLAYER_INTERNAL;
3852 LOGD("param_name : %s", param_name);
3854 /* update display surface */
3855 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3856 LOGD("check display surface type attribute: %d", surface_type);
3858 /* configuring display */
3859 switch (surface_type) {
3860 case MM_DISPLAY_SURFACE_OVERLAY:
3862 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3863 if (ret != MM_ERROR_NONE)
3871 return MM_ERROR_NONE;
3875 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3877 gboolean disable_overlay = FALSE;
3878 mm_player_t* player = (mm_player_t*) hplayer;
3879 int ret = MM_ERROR_NONE;
3882 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3883 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3884 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3885 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3887 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3888 LOGW("Display control is not supported");
3889 return MM_ERROR_PLAYER_INTERNAL;
3892 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3894 if (audio_only == (bool)disable_overlay) {
3895 LOGE("It's the same with current setting: (%d)", audio_only);
3896 return MM_ERROR_NONE;
3900 LOGE("disable overlay");
3901 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3903 /* release overlay resource */
3904 if (player->video_overlay_resource != NULL) {
3905 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3906 player->video_overlay_resource);
3907 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3908 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3911 player->video_overlay_resource = NULL;
3914 ret = mm_resource_manager_commit(player->resource_manager);
3915 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3916 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3920 /* mark video overlay for acquire */
3921 if (player->video_overlay_resource == NULL) {
3922 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3923 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3924 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3925 &player->video_overlay_resource);
3926 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3927 LOGE("could not prepare for video_overlay resource\n");
3932 player->interrupted_by_resource = FALSE;
3933 /* acquire resources for video overlay */
3934 ret = mm_resource_manager_commit(player->resource_manager);
3935 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3936 LOGE("could not acquire resources for video playing\n");
3940 LOGD("enable overlay");
3941 __mmplayer_video_param_set_display_overlay(player);
3942 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3947 return MM_ERROR_NONE;
3951 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3953 mm_player_t* player = (mm_player_t*) hplayer;
3954 gboolean disable_overlay = FALSE;
3958 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3959 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3960 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3961 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3962 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3964 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3965 LOGW("Display control is not supported");
3966 return MM_ERROR_PLAYER_INTERNAL;
3969 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3971 *paudio_only = (bool)(disable_overlay);
3973 LOGD("audio_only : %d", *paudio_only);
3977 return MM_ERROR_NONE;
3981 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3983 GList* bucket = element_bucket;
3984 MMPlayerGstElement* element = NULL;
3985 MMPlayerGstElement* prv_element = NULL;
3986 gint successful_link_count = 0;
3990 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3992 prv_element = (MMPlayerGstElement*)bucket->data;
3993 bucket = bucket->next;
3995 for (; bucket; bucket = bucket->next) {
3996 element = (MMPlayerGstElement*)bucket->data;
3998 if (element && element->gst) {
3999 /* If next element is audio appsrc then make a separate audio pipeline */
4000 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4001 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4002 prv_element = element;
4006 if (prv_element && prv_element->gst) {
4007 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4008 LOGD("linking [%s] to [%s] success\n",
4009 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4010 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4011 successful_link_count++;
4013 LOGD("linking [%s] to [%s] failed\n",
4014 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4015 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4021 prv_element = element;
4026 return successful_link_count;
4030 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4032 GList* bucket = element_bucket;
4033 MMPlayerGstElement* element = NULL;
4034 int successful_add_count = 0;
4038 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4039 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4041 for (; bucket; bucket = bucket->next) {
4042 element = (MMPlayerGstElement*)bucket->data;
4044 if (element && element->gst) {
4045 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4046 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4047 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4048 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4051 successful_add_count++;
4057 return successful_add_count;
4060 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4062 mm_player_t* player = (mm_player_t*) data;
4063 GstCaps *caps = NULL;
4064 GstStructure *str = NULL;
4069 MMPLAYER_RETURN_IF_FAIL(pad)
4070 MMPLAYER_RETURN_IF_FAIL(unused)
4071 MMPLAYER_RETURN_IF_FAIL(data)
4073 caps = gst_pad_get_current_caps(pad);
4077 str = gst_caps_get_structure(caps, 0);
4081 name = gst_structure_get_name(str);
4085 LOGD("name = %s\n", name);
4087 if (strstr(name, "audio")) {
4088 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4090 if (player->audio_stream_changed_cb) {
4091 LOGE("call the audio stream changed cb\n");
4092 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4094 } else if (strstr(name, "video")) {
4095 if ((name = gst_structure_get_string(str, "format")))
4096 player->set_mode.video_zc = name[0] == 'S';
4098 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4100 if (player->video_stream_changed_cb) {
4101 LOGE("call the video stream changed cb\n");
4102 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4109 gst_caps_unref(caps);
4119 * This function is to create audio pipeline for playing.
4121 * @param player [in] handle of player
4123 * @return This function returns zero on success.
4125 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4127 /* macro for code readability. just for sinkbin-creation functions */
4128 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4130 x_bin[x_id].id = x_id;\
4131 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4132 if (!x_bin[x_id].gst) {\
4133 LOGE("failed to create %s \n", x_factory);\
4136 if (x_player->ini.set_dump_element_flag)\
4137 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4140 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4144 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4149 MMPLAYER_RETURN_IF_FAIL(player);
4151 if (player->audio_stream_buff_list) {
4152 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4153 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4156 LOGD("[%lld] send remained data.", tmp->channel_mask);
4157 __mmplayer_audio_stream_send_data(player, tmp);
4160 g_free(tmp->pcm_data);
4164 g_list_free(player->audio_stream_buff_list);
4165 player->audio_stream_buff_list = NULL;
4172 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4174 MMPlayerAudioStreamDataType audio_stream = { 0, };
4177 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4179 audio_stream.bitrate = a_buffer->bitrate;
4180 audio_stream.channel = a_buffer->channel;
4181 audio_stream.depth = a_buffer->depth;
4182 audio_stream.is_little_endian = a_buffer->is_little_endian;
4183 audio_stream.channel_mask = a_buffer->channel_mask;
4184 audio_stream.data_size = a_buffer->data_size;
4185 audio_stream.data = a_buffer->pcm_data;
4187 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4188 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4194 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4196 mm_player_t* player = (mm_player_t*) data;
4201 gint endianness = 0;
4202 guint64 channel_mask = 0;
4203 void *a_data = NULL;
4205 mm_player_audio_stream_buff_t *a_buffer = NULL;
4206 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4210 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4212 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4213 a_data = mapinfo.data;
4214 a_size = mapinfo.size;
4216 GstCaps *caps = gst_pad_get_current_caps(pad);
4217 GstStructure *structure = gst_caps_get_structure(caps, 0);
4219 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4220 gst_structure_get_int(structure, "rate", &rate);
4221 gst_structure_get_int(structure, "channels", &channel);
4222 gst_structure_get_int(structure, "depth", &depth);
4223 gst_structure_get_int(structure, "endianness", &endianness);
4224 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4225 gst_caps_unref(GST_CAPS(caps));
4227 /* In case of the sync is false, use buffer list. *
4228 * The num of buffer list depends on the num of audio channels */
4229 if (player->audio_stream_buff_list) {
4230 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4231 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4233 if (channel_mask == tmp->channel_mask) {
4234 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4235 if (tmp->data_size + a_size < tmp->buff_size) {
4236 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4237 tmp->data_size += a_size;
4239 /* send data to client */
4240 __mmplayer_audio_stream_send_data(player, tmp);
4242 if (a_size > tmp->buff_size) {
4243 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4244 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4245 if (tmp->pcm_data == NULL) {
4246 LOGE("failed to realloc data.");
4249 tmp->buff_size = a_size;
4251 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4252 memcpy(tmp->pcm_data, a_data, a_size);
4253 tmp->data_size = a_size;
4258 LOGE("data is empty in list.");
4264 /* create new audio stream data */
4265 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4266 if (a_buffer == NULL) {
4267 LOGE("failed to alloc data.");
4270 a_buffer->bitrate = rate;
4271 a_buffer->channel = channel;
4272 a_buffer->depth = depth;
4273 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4274 a_buffer->channel_mask = channel_mask;
4275 a_buffer->data_size = a_size;
4277 if (!player->audio_stream_sink_sync) {
4278 /* If sync is FALSE, use buffer list to reduce the IPC. */
4279 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4280 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4281 if (a_buffer->pcm_data == NULL) {
4282 LOGE("failed to alloc data.");
4286 memcpy(a_buffer->pcm_data, a_data, a_size);
4287 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4288 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4290 /* If sync is TRUE, send data directly. */
4291 a_buffer->pcm_data = a_data;
4292 __mmplayer_audio_stream_send_data(player, a_buffer);
4297 gst_buffer_unmap(buffer, &mapinfo);
4302 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4304 mm_player_t* player = (mm_player_t*)data;
4305 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4306 GstPad* sinkpad = NULL;
4307 GstElement *queue = NULL, *sink = NULL;
4310 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4312 queue = gst_element_factory_make("queue", NULL);
4313 if (queue == NULL) {
4314 LOGD("fail make queue\n");
4318 sink = gst_element_factory_make("fakesink", NULL);
4320 LOGD("fail make fakesink\n");
4324 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4326 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4327 LOGW("failed to link queue & sink\n");
4331 sinkpad = gst_element_get_static_pad(queue, "sink");
4333 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4334 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4338 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4340 gst_object_unref(sinkpad);
4341 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4342 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4344 gst_element_set_state(sink, GST_STATE_PAUSED);
4345 gst_element_set_state(queue, GST_STATE_PAUSED);
4347 MMPLAYER_SIGNAL_CONNECT(player,
4349 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4351 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4358 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4360 gst_object_unref(GST_OBJECT(queue));
4364 gst_object_unref(GST_OBJECT(sink));
4368 gst_object_unref(GST_OBJECT(sinkpad));
4375 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4377 #define MAX_PROPS_LEN 128
4378 gint latency_mode = 0;
4379 gchar *stream_type = NULL;
4380 gchar *latency = NULL;
4382 gchar stream_props[MAX_PROPS_LEN] = {0,};
4383 GstStructure *props = NULL;
4386 * It should be set after player creation through attribute.
4387 * But, it can not be changed during playing.
4390 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4391 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4394 LOGE("stream_type is null.\n");
4396 if (player->sound.focus_id)
4397 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4398 stream_type, stream_id, player->sound.focus_id);
4400 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4401 stream_type, stream_id);
4402 props = gst_structure_from_string(stream_props, NULL);
4403 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4404 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4405 stream_type, stream_id, player->sound.focus_id, stream_props);
4406 gst_structure_free(props);
4409 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4411 switch (latency_mode) {
4412 case AUDIO_LATENCY_MODE_LOW:
4413 latency = g_strndup("low", 3);
4415 case AUDIO_LATENCY_MODE_MID:
4416 latency = g_strndup("mid", 3);
4418 case AUDIO_LATENCY_MODE_HIGH:
4419 latency = g_strndup("high", 4);
4423 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4427 LOGD("audiosink property - latency=%s \n", latency);
4435 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4437 MMPlayerGstElement* first_element = NULL;
4438 MMPlayerGstElement* audiobin = NULL;
4439 MMHandleType attrs = 0;
4441 GstPad *ghostpad = NULL;
4442 GList* element_bucket = NULL;
4443 gboolean link_audio_sink_now = TRUE;
4449 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4452 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4454 LOGE("failed to allocate memory for audiobin\n");
4455 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4458 attrs = MMPLAYER_GET_ATTRS(player);
4461 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4462 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4463 if (!audiobin[MMPLAYER_A_BIN].gst) {
4464 LOGE("failed to create audiobin\n");
4469 player->pipeline->audiobin = audiobin;
4471 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4473 /* Adding audiotp plugin for reverse trickplay feature */
4474 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4477 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4479 /* replaygain volume */
4480 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4481 if (player->sound.rg_enable)
4482 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4484 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4487 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4489 if (player->set_mode.pcm_extraction) {
4490 // pcm extraction only and no sound output
4491 if (player->audio_stream_render_cb_ex) {
4492 char *caps_str = NULL;
4493 GstCaps* caps = NULL;
4494 gchar *format = NULL;
4497 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4499 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4501 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4503 caps = gst_caps_new_simple("audio/x-raw",
4504 "format", G_TYPE_STRING, format,
4505 "rate", G_TYPE_INT, player->pcm_samplerate,
4506 "channels", G_TYPE_INT, player->pcm_channel,
4508 caps_str = gst_caps_to_string(caps);
4509 LOGD("new caps : %s\n", caps_str);
4511 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4514 gst_caps_unref(caps);
4515 MMPLAYER_FREEIF(caps_str);
4517 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4519 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4520 /* raw pad handling signal */
4521 MMPLAYER_SIGNAL_CONNECT(player,
4522 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4523 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4524 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4526 int dst_samplerate = 0;
4527 int dst_channels = 0;
4529 char *caps_str = NULL;
4530 GstCaps* caps = NULL;
4532 /* get conf. values */
4533 mm_attrs_multiple_get(player->attrs,
4535 "pcm_extraction_samplerate", &dst_samplerate,
4536 "pcm_extraction_channels", &dst_channels,
4537 "pcm_extraction_depth", &dst_depth,
4541 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4542 caps = gst_caps_new_simple("audio/x-raw",
4543 "rate", G_TYPE_INT, dst_samplerate,
4544 "channels", G_TYPE_INT, dst_channels,
4545 "depth", G_TYPE_INT, dst_depth,
4547 caps_str = gst_caps_to_string(caps);
4548 LOGD("new caps : %s\n", caps_str);
4550 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4553 gst_caps_unref(caps);
4554 MMPLAYER_FREEIF(caps_str);
4557 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4560 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4564 //GstCaps* caps = NULL;
4567 /* for logical volume control */
4568 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4569 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4571 if (player->sound.mute) {
4572 LOGD("mute enabled\n");
4573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4578 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4579 caps = gst_caps_from_string("audio/x-raw-int, "
4580 "endianness = (int) LITTLE_ENDIAN, "
4581 "signed = (boolean) true, "
4582 "width = (int) 16, "
4583 "depth = (int) 16");
4584 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4585 gst_caps_unref(caps);
4588 /* check if multi-channels */
4589 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4590 GstPad *srcpad = NULL;
4591 GstCaps *caps = NULL;
4593 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4594 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4595 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4596 GstStructure *str = gst_caps_get_structure(caps, 0);
4598 gst_structure_get_int(str, "channels", &channels);
4599 gst_caps_unref(caps);
4601 gst_object_unref(srcpad);
4605 /* audio effect element. if audio effect is enabled */
4606 if ((strcmp(player->ini.audioeffect_element, ""))
4608 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4609 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4611 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4613 if ((!player->bypass_audio_effect)
4614 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4615 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4616 if (!_mmplayer_audio_effect_custom_apply(player))
4617 LOGI("apply audio effect(custom) setting success\n");
4621 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4622 && (player->set_mode.rich_audio))
4623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4626 /* create audio sink */
4627 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4628 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4629 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4631 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4632 if (player->is_content_spherical &&
4634 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4635 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4636 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4638 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4643 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4645 gst_caps_unref(acaps);
4647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4648 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4649 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4652 player->is_openal_plugin_used = TRUE;
4654 if (player->video360_yaw_radians <= M_PI &&
4655 player->video360_yaw_radians >= -M_PI &&
4656 player->video360_pitch_radians <= M_PI_2 &&
4657 player->video360_pitch_radians >= -M_PI_2) {
4658 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4659 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4660 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4661 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4663 "source-orientation-y", player->video360_metadata.init_view_heading,
4664 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4667 if (player->is_content_spherical)
4668 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4673 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4674 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4677 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4678 (player->videodec_linked && player->ini.use_system_clock)) {
4679 LOGD("system clock will be used.\n");
4680 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4683 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4684 __mmplayer_gst_set_audiosink_property(player, attrs);
4687 if (audiobin[MMPLAYER_A_SINK].gst) {
4688 GstPad *sink_pad = NULL;
4689 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4690 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4691 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4692 gst_object_unref(GST_OBJECT(sink_pad));
4695 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4697 /* adding created elements to bin */
4698 LOGD("adding created elements to bin\n");
4699 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4700 LOGE("failed to add elements\n");
4704 /* linking elements in the bucket by added order. */
4705 LOGD("Linking elements in the bucket by added order.\n");
4706 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4707 LOGE("failed to link elements\n");
4711 /* get first element's sinkpad for creating ghostpad */
4712 first_element = (MMPlayerGstElement *)element_bucket->data;
4713 if (!first_element) {
4714 LOGE("failed to get first elem\n");
4718 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4720 LOGE("failed to get pad from first element of audiobin\n");
4724 ghostpad = gst_ghost_pad_new("sink", pad);
4726 LOGE("failed to create ghostpad\n");
4730 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4731 LOGE("failed to add ghostpad to audiobin\n");
4735 gst_object_unref(pad);
4737 g_list_free(element_bucket);
4740 return MM_ERROR_NONE;
4744 LOGD("ERROR : releasing audiobin\n");
4747 gst_object_unref(GST_OBJECT(pad));
4750 gst_object_unref(GST_OBJECT(ghostpad));
4753 g_list_free(element_bucket);
4755 /* release element which are not added to bin */
4756 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4757 /* NOTE : skip bin */
4758 if (audiobin[i].gst) {
4759 GstObject* parent = NULL;
4760 parent = gst_element_get_parent(audiobin[i].gst);
4763 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4764 audiobin[i].gst = NULL;
4766 gst_object_unref(GST_OBJECT(parent));
4770 /* release audiobin with it's childs */
4771 if (audiobin[MMPLAYER_A_BIN].gst)
4772 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4774 MMPLAYER_FREEIF(audiobin);
4776 player->pipeline->audiobin = NULL;
4778 return MM_ERROR_PLAYER_INTERNAL;
4781 static GstPadProbeReturn
4782 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4784 mm_player_t* player = (mm_player_t*) u_data;
4785 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4786 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4788 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4790 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4791 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4793 return GST_PAD_PROBE_OK;
4796 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4798 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4801 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4803 int ret = MM_ERROR_NONE;
4805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4806 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4808 MMPLAYER_VIDEO_BO_LOCK(player);
4810 if (player->video_bo_list) {
4811 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4812 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4813 if (tmp && tmp->bo == bo) {
4815 LOGD("release bo %p", bo);
4816 tbm_bo_unref(tmp->bo);
4817 MMPLAYER_VIDEO_BO_UNLOCK(player);
4818 MMPLAYER_VIDEO_BO_SIGNAL(player);
4823 /* hw codec is running or the list was reset for DRC. */
4824 LOGW("there is no bo list.");
4826 MMPLAYER_VIDEO_BO_UNLOCK(player);
4828 LOGW("failed to find bo %p", bo);
4833 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4838 MMPLAYER_RETURN_IF_FAIL(player);
4840 MMPLAYER_VIDEO_BO_LOCK(player);
4841 if (player->video_bo_list) {
4842 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4843 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4844 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4847 tbm_bo_unref(tmp->bo);
4851 g_list_free(player->video_bo_list);
4852 player->video_bo_list = NULL;
4854 player->video_bo_size = 0;
4855 MMPLAYER_VIDEO_BO_UNLOCK(player);
4862 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4865 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4866 gboolean ret = TRUE;
4868 /* check DRC, if it is, destroy the prev bo list to create again */
4869 if (player->video_bo_size != size) {
4870 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4871 __mmplayer_video_stream_destroy_bo_list(player);
4872 player->video_bo_size = size;
4875 MMPLAYER_VIDEO_BO_LOCK(player);
4877 if ((!player->video_bo_list) ||
4878 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4880 /* create bo list */
4882 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4884 if (player->video_bo_list) {
4885 /* if bo list did not created all, try it again. */
4886 idx = g_list_length(player->video_bo_list);
4887 LOGD("bo list exist(len: %d)", idx);
4890 for (; idx < player->ini.num_of_video_bo; idx++) {
4891 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4893 LOGE("Fail to alloc bo_info.");
4896 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4898 LOGE("Fail to tbm_bo_alloc.");
4902 bo_info->using = FALSE;
4903 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4906 /* update video num buffers */
4907 player->video_num_buffers = idx;
4908 if (idx == player->ini.num_of_video_bo)
4909 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4912 MMPLAYER_VIDEO_BO_UNLOCK(player);
4916 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4920 /* get bo from list*/
4921 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4922 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4923 if (tmp && (tmp->using == FALSE)) {
4924 LOGD("found bo %p to use", tmp->bo);
4926 MMPLAYER_VIDEO_BO_UNLOCK(player);
4927 return tbm_bo_ref(tmp->bo);
4931 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4932 MMPLAYER_VIDEO_BO_UNLOCK(player);
4936 if (player->ini.video_bo_timeout <= 0) {
4937 MMPLAYER_VIDEO_BO_WAIT(player);
4939 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4940 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4947 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4949 mm_player_t* player = (mm_player_t*)data;
4951 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4953 /* send prerolled pkt */
4954 player->video_stream_prerolled = FALSE;
4956 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4958 /* not to send prerolled pkt again */
4959 player->video_stream_prerolled = TRUE;
4963 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4965 mm_player_t* player = (mm_player_t*)data;
4966 GstCaps *caps = NULL;
4967 MMPlayerVideoStreamDataType *stream = NULL;
4968 MMVideoBuffer *video_buffer = NULL;
4969 GstMemory *dataBlock = NULL;
4970 GstMemory *metaBlock = NULL;
4971 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4972 GstStructure *structure = NULL;
4973 const gchar *string_format = NULL;
4974 unsigned int fourcc = 0;
4977 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4979 if (player->video_stream_prerolled) {
4980 player->video_stream_prerolled = FALSE;
4981 LOGD("skip the prerolled pkt not to send it again");
4985 caps = gst_pad_get_current_caps(pad);
4987 LOGE("Caps is NULL.");
4991 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4993 /* clear stream data structure */
4994 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4996 LOGE("failed to alloc mem for video data");
5000 structure = gst_caps_get_structure(caps, 0);
5001 gst_structure_get_int(structure, "width", &(stream->width));
5002 gst_structure_get_int(structure, "height", &(stream->height));
5003 string_format = gst_structure_get_string(structure, "format");
5005 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5006 stream->format = util_get_pixtype(fourcc);
5007 gst_caps_unref(caps);
5011 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5012 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5015 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5016 LOGE("Wrong condition!!");
5020 /* set size and timestamp */
5021 dataBlock = gst_buffer_peek_memory(buffer, 0);
5022 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5023 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5025 /* check zero-copy */
5026 if (player->set_mode.video_zc &&
5027 player->set_mode.media_packet_video_stream &&
5028 gst_buffer_n_memory(buffer) > 1) {
5029 metaBlock = gst_buffer_peek_memory(buffer, 1);
5030 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5031 video_buffer = (MMVideoBuffer *)mapinfo.data;
5034 if (video_buffer) { /* hw codec */
5036 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5039 /* copy pointer of tbm bo, stride, elevation */
5040 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5041 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5045 LOGE("Not support video buffer format");
5048 memcpy(stream->stride, video_buffer->stride_width,
5049 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5050 memcpy(stream->elevation, video_buffer->stride_height,
5051 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5053 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5054 stream->internal_buffer = gst_buffer_ref(buffer);
5055 } else { /* sw codec */
5059 int ret = TBM_SURFACE_ERROR_NONE;
5060 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5061 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5063 unsigned char *src = NULL;
5064 unsigned char *dest = NULL;
5065 tbm_bo_handle thandle;
5066 tbm_surface_h surface;
5067 tbm_surface_info_s info;
5070 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5072 LOGE("fail to gst_memory_map");
5077 if (stream->format == MM_PIXEL_FORMAT_I420) {
5078 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5080 ret = tbm_surface_get_info(surface, &info);
5082 if (ret != TBM_SURFACE_ERROR_NONE) {
5083 tbm_surface_destroy(surface);
5086 tbm_surface_destroy(surface);
5088 src_stride[0] = GST_ROUND_UP_4(stream->width);
5089 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5090 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5091 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5092 stream->stride[0] = info.planes[0].stride;
5093 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5094 stream->stride[1] = info.planes[1].stride;
5095 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5096 stream->stride[2] = info.planes[2].stride;
5097 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5098 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5099 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5100 stream->stride[0] = stream->width * 4;
5101 stream->elevation[0] = stream->height;
5102 size = stream->stride[0] * stream->height;
5104 LOGE("Not support format %d", stream->format);
5108 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5109 if (!stream->bo[0]) {
5110 LOGE("Fail to tbm_bo_alloc!!");
5114 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5115 if (thandle.ptr && mapinfo.data) {
5116 if (stream->format == MM_PIXEL_FORMAT_I420) {
5117 for (i = 0; i < 3; i++) {
5118 src = mapinfo.data + src_offset[i];
5119 dest = thandle.ptr + info.planes[i].offset;
5122 for (j = 0; j < stream->height>>k; j++) {
5123 memcpy(dest, src, stream->width>>k);
5124 src += src_stride[i];
5125 dest += stream->stride[i];
5128 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5129 memcpy(thandle.ptr, mapinfo.data, size);
5131 LOGE("Not support format %d", stream->format);
5135 LOGE("data pointer is wrong. dest : %p, src : %p",
5136 thandle.ptr, mapinfo.data);
5139 tbm_bo_unmap(stream->bo[0]);
5142 if (player->video_stream_cb) { /* This has been already checked at the entry */
5143 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5144 LOGE("failed to send video stream data.");
5150 gst_memory_unmap(metaBlock, &mapinfo);
5152 gst_memory_unmap(dataBlock, &mapinfo);
5157 LOGE("release video stream resource.");
5160 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5162 tbm_bo_unref(stream->bo[i]);
5164 gst_memory_unmap(metaBlock, &mapinfo);
5166 /* unref gst buffer */
5167 if (stream->internal_buffer)
5168 gst_buffer_unref(stream->internal_buffer);
5169 } else if (dataBlock) {
5171 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5172 gst_memory_unmap(dataBlock, &mapinfo);
5180 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5182 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5183 GList* element_bucket = NULL;
5185 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5189 if (player->set_mode.video_zc || player->is_content_spherical) {
5190 LOGD("do not need to add video filters.");
5191 return MM_ERROR_NONE;
5194 /* in case of sw codec except 360 playback,
5195 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5196 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5197 LOGD("using video converter: %s", video_csc);
5199 /* set video rotator */
5200 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5202 *bucket = element_bucket;
5204 return MM_ERROR_NONE;
5206 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5207 g_list_free(element_bucket);
5211 return MM_ERROR_PLAYER_INTERNAL;
5215 * This function is to create video pipeline.
5217 * @param player [in] handle of player
5218 * caps [in] src caps of decoder
5219 * surface_type [in] surface type for video rendering
5221 * @return This function returns zero on success.
5223 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5227 * - video overlay surface(arm/x86) : tizenwlsink
5230 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5234 GList*element_bucket = NULL;
5235 MMPlayerGstElement* first_element = NULL;
5236 MMPlayerGstElement* videobin = NULL;
5237 gchar *videosink_element = NULL;
5241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5246 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5248 player->pipeline->videobin = videobin;
5250 attrs = MMPLAYER_GET_ATTRS(player);
5252 LOGE("cannot get content attribute");
5253 return MM_ERROR_PLAYER_INTERNAL;
5257 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5258 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5259 if (!videobin[MMPLAYER_V_BIN].gst) {
5260 LOGE("failed to create videobin");
5264 int enable_video_decoded_cb = 0;
5265 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5267 if (player->is_content_spherical) {
5268 LOGD("video360 elem will be added.");
5270 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5271 "video-360", TRUE, player);
5273 /* Set spatial media metadata and/or user settings to the element.
5275 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5276 "projection-type", player->video360_metadata.projection_type, NULL);
5278 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5279 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5281 if (player->video360_metadata.full_pano_width_pixels &&
5282 player->video360_metadata.full_pano_height_pixels &&
5283 player->video360_metadata.cropped_area_image_width &&
5284 player->video360_metadata.cropped_area_image_height) {
5285 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5286 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5287 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5288 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5289 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5290 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5291 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5295 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5296 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5297 "horizontal-fov", player->video360_horizontal_fov,
5298 "vertical-fov", player->video360_vertical_fov, NULL);
5301 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5302 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5303 "zoom", 1.0f / player->video360_zoom, NULL);
5306 if (player->video360_yaw_radians <= M_PI &&
5307 player->video360_yaw_radians >= -M_PI &&
5308 player->video360_pitch_radians <= M_PI_2 &&
5309 player->video360_pitch_radians >= -M_PI_2) {
5310 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5311 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5312 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5313 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5314 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5315 "pose-yaw", player->video360_metadata.init_view_heading,
5316 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5319 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5320 "passthrough", !player->is_video360_enabled, NULL);
5323 /* set video sink */
5324 switch (surface_type) {
5325 case MM_DISPLAY_SURFACE_OVERLAY:
5326 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5328 if (strlen(player->ini.videosink_element_overlay) > 0)
5329 videosink_element = player->ini.videosink_element_overlay;
5333 case MM_DISPLAY_SURFACE_NULL:
5334 if (strlen(player->ini.videosink_element_fake) > 0)
5335 videosink_element = player->ini.videosink_element_fake;
5339 case MM_DISPLAY_SURFACE_REMOTE:
5340 if (strlen(player->ini.videosink_element_fake) > 0)
5341 videosink_element = player->ini.videosink_element_fake;
5346 LOGE("unidentified surface type");
5349 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5351 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5353 /* additional setting for sink plug-in */
5354 switch (surface_type) {
5355 case MM_DISPLAY_SURFACE_OVERLAY:
5357 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5359 LOGD("selected videosink name: %s", videosink_element);
5361 /* support shard memory with S/W codec on HawkP */
5362 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5363 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5364 "use-tbm", use_tbm, NULL);
5370 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5373 LOGD("disable last-sample");
5374 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5378 if (player->set_mode.media_packet_video_stream) {
5380 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5382 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5384 MMPLAYER_SIGNAL_CONNECT(player,
5385 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5386 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5388 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5391 MMPLAYER_SIGNAL_CONNECT(player,
5392 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5395 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5400 case MM_DISPLAY_SURFACE_REMOTE:
5402 if (player->set_mode.media_packet_video_stream) {
5403 LOGE("add data probe at videosink");
5404 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5405 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5407 MMPLAYER_SIGNAL_CONNECT(player,
5408 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5409 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5411 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5414 MMPLAYER_SIGNAL_CONNECT(player,
5415 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5416 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5418 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5423 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5426 LOGD("disable last-sample");
5427 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5437 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5440 if (videobin[MMPLAYER_V_SINK].gst) {
5441 GstPad *sink_pad = NULL;
5442 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5444 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5445 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5446 gst_object_unref(GST_OBJECT(sink_pad));
5448 LOGW("failed to get sink pad from videosink\n");
5451 /* store it as it's sink element */
5452 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5454 /* adding created elements to bin */
5455 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5456 LOGE("failed to add elements\n");
5460 /* Linking elements in the bucket by added order */
5461 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5462 LOGE("failed to link elements\n");
5466 /* get first element's sinkpad for creating ghostpad */
5468 first_element = (MMPlayerGstElement *)element_bucket->data;
5469 if (!first_element) {
5470 LOGE("failed to get first element from bucket\n");
5474 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5476 LOGE("failed to get pad from first element\n");
5480 /* create ghostpad */
5481 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5482 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5483 LOGE("failed to add ghostpad to videobin\n");
5486 gst_object_unref(pad);
5488 /* done. free allocated variables */
5490 g_list_free(element_bucket);
5494 return MM_ERROR_NONE;
5497 LOGE("ERROR : releasing videobin\n");
5499 g_list_free(element_bucket);
5502 gst_object_unref(GST_OBJECT(pad));
5504 /* release videobin with it's childs */
5505 if (videobin[MMPLAYER_V_BIN].gst)
5506 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5509 MMPLAYER_FREEIF(videobin);
5511 player->pipeline->videobin = NULL;
5513 return MM_ERROR_PLAYER_INTERNAL;
5516 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5518 GList *element_bucket = NULL;
5519 MMPlayerGstElement *textbin = player->pipeline->textbin;
5521 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5522 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5523 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5524 "signal-handoffs", FALSE,
5527 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5528 MMPLAYER_SIGNAL_CONNECT(player,
5529 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5530 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5532 G_CALLBACK(__mmplayer_update_subtitle),
5535 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5536 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5537 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5539 if (!player->play_subtitle) {
5540 LOGD("add textbin sink as sink element of whole pipeline.\n");
5541 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5544 /* adding created elements to bin */
5545 LOGD("adding created elements to bin\n");
5546 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5547 LOGE("failed to add elements\n");
5551 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5552 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5553 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5555 /* linking elements in the bucket by added order. */
5556 LOGD("Linking elements in the bucket by added order.\n");
5557 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5558 LOGE("failed to link elements\n");
5562 /* done. free allocated variables */
5563 g_list_free(element_bucket);
5565 if (textbin[MMPLAYER_T_QUEUE].gst) {
5567 GstPad *ghostpad = NULL;
5569 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5571 LOGE("failed to get sink pad of text queue");
5575 ghostpad = gst_ghost_pad_new("text_sink", pad);
5576 gst_object_unref(pad);
5579 LOGE("failed to create ghostpad of textbin\n");
5583 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5584 LOGE("failed to add ghostpad to textbin\n");
5585 gst_object_unref(ghostpad);
5590 return MM_ERROR_NONE;
5593 g_list_free(element_bucket);
5595 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5596 LOGE("remove textbin sink from sink list");
5597 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5600 /* release element at __mmplayer_gst_create_text_sink_bin */
5601 return MM_ERROR_PLAYER_INTERNAL;
5604 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5606 MMPlayerGstElement *textbin = NULL;
5607 GList *element_bucket = NULL;
5608 int surface_type = 0;
5613 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5616 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5618 LOGE("failed to allocate memory for textbin\n");
5619 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5623 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5624 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5625 if (!textbin[MMPLAYER_T_BIN].gst) {
5626 LOGE("failed to create textbin\n");
5631 player->pipeline->textbin = textbin;
5634 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5635 LOGD("surface type for subtitle : %d", surface_type);
5636 switch (surface_type) {
5637 case MM_DISPLAY_SURFACE_OVERLAY:
5638 case MM_DISPLAY_SURFACE_NULL:
5639 case MM_DISPLAY_SURFACE_REMOTE:
5640 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5641 LOGE("failed to make plain text elements\n");
5652 return MM_ERROR_NONE;
5656 LOGD("ERROR : releasing textbin\n");
5658 g_list_free(element_bucket);
5660 /* release signal */
5661 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5663 /* release element which are not added to bin */
5664 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5665 /* NOTE : skip bin */
5666 if (textbin[i].gst) {
5667 GstObject* parent = NULL;
5668 parent = gst_element_get_parent(textbin[i].gst);
5671 gst_object_unref(GST_OBJECT(textbin[i].gst));
5672 textbin[i].gst = NULL;
5674 gst_object_unref(GST_OBJECT(parent));
5679 /* release textbin with it's childs */
5680 if (textbin[MMPLAYER_T_BIN].gst)
5681 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5683 MMPLAYER_FREEIF(player->pipeline->textbin);
5684 player->pipeline->textbin = NULL;
5687 return MM_ERROR_PLAYER_INTERNAL;
5692 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5694 MMPlayerGstElement* mainbin = NULL;
5695 MMPlayerGstElement* textbin = NULL;
5696 MMHandleType attrs = 0;
5697 GstElement *subsrc = NULL;
5698 GstElement *subparse = NULL;
5699 gchar *subtitle_uri = NULL;
5700 const gchar *charset = NULL;
5706 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5708 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5710 mainbin = player->pipeline->mainbin;
5712 attrs = MMPLAYER_GET_ATTRS(player);
5714 LOGE("cannot get content attribute\n");
5715 return MM_ERROR_PLAYER_INTERNAL;
5718 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5719 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5720 LOGE("subtitle uri is not proper filepath.\n");
5721 return MM_ERROR_PLAYER_INVALID_URI;
5724 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5725 LOGE("failed to get storage info of subtitle path");
5726 return MM_ERROR_PLAYER_INVALID_URI;
5729 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5731 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5732 player->subtitle_language_list = NULL;
5733 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5735 /* create the subtitle source */
5736 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5738 LOGE("failed to create filesrc element\n");
5741 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5743 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5744 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5746 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5747 LOGW("failed to add queue\n");
5748 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5749 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5750 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5755 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5757 LOGE("failed to create subparse element\n");
5761 charset = util_get_charset(subtitle_uri);
5763 LOGD("detected charset is %s\n", charset);
5764 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5767 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5768 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5770 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5771 LOGW("failed to add subparse\n");
5772 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5773 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5774 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5778 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5779 LOGW("failed to link subsrc and subparse\n");
5783 player->play_subtitle = TRUE;
5784 player->adjust_subtitle_pos = 0;
5786 LOGD("play subtitle using subtitle file\n");
5788 if (player->pipeline->textbin == NULL) {
5789 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5790 LOGE("failed to create text sink bin. continuing without text\n");
5794 textbin = player->pipeline->textbin;
5796 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5797 LOGW("failed to add textbin\n");
5799 /* release signal */
5800 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5802 /* release textbin with it's childs */
5803 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5804 MMPLAYER_FREEIF(player->pipeline->textbin);
5805 player->pipeline->textbin = textbin = NULL;
5809 LOGD("link text input selector and textbin ghost pad");
5811 player->textsink_linked = 1;
5812 player->external_text_idx = 0;
5813 LOGI("player->textsink_linked set to 1\n");
5815 textbin = player->pipeline->textbin;
5816 LOGD("text bin has been created. reuse it.");
5817 player->external_text_idx = 1;
5820 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5821 LOGW("failed to link subparse and textbin\n");
5825 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5827 LOGE("failed to get sink pad from textsink to probe data");
5831 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5832 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5834 gst_object_unref(pad);
5837 /* create dot. for debugging */
5838 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5841 return MM_ERROR_NONE;
5844 /* release text pipeline resource */
5845 player->textsink_linked = 0;
5847 /* release signal */
5848 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5850 if (player->pipeline->textbin) {
5851 LOGE("remove textbin");
5853 /* release textbin with it's childs */
5854 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5855 MMPLAYER_FREEIF(player->pipeline->textbin);
5856 player->pipeline->textbin = NULL;
5860 /* release subtitle elem */
5861 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5862 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5864 return MM_ERROR_PLAYER_INTERNAL;
5868 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5870 mm_player_t* player = (mm_player_t*) data;
5871 MMMessageParamType msg = {0, };
5872 GstClockTime duration = 0;
5873 gpointer text = NULL;
5874 guint text_size = 0;
5875 gboolean ret = TRUE;
5876 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5880 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5881 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5883 if (player->is_subtitle_force_drop) {
5884 LOGW("subtitle is dropped forcedly.");
5888 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5889 text = mapinfo.data;
5890 text_size = mapinfo.size;
5891 duration = GST_BUFFER_DURATION(buffer);
5893 if (player->set_mode.subtitle_off) {
5894 LOGD("subtitle is OFF.\n");
5898 if (!text || (text_size == 0)) {
5899 LOGD("There is no subtitle to be displayed.\n");
5903 msg.data = (void *) text;
5904 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5906 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5908 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5909 gst_buffer_unmap(buffer, &mapinfo);
5916 static GstPadProbeReturn
5917 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5919 mm_player_t *player = (mm_player_t *) u_data;
5920 GstClockTime cur_timestamp = 0;
5921 gint64 adjusted_timestamp = 0;
5922 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5924 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5926 if (player->set_mode.subtitle_off) {
5927 LOGD("subtitle is OFF.\n");
5931 if (player->adjust_subtitle_pos == 0) {
5932 LOGD("nothing to do");
5936 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5937 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5939 if (adjusted_timestamp < 0) {
5940 LOGD("adjusted_timestamp under zero");
5945 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5946 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5947 GST_TIME_ARGS(cur_timestamp),
5948 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5950 return GST_PAD_PROBE_OK;
5952 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5956 /* check player and subtitlebin are created */
5957 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5958 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5960 if (position == 0) {
5961 LOGD("nothing to do\n");
5963 return MM_ERROR_NONE;
5967 case MM_PLAYER_POS_FORMAT_TIME:
5969 /* check current postion */
5970 player->adjust_subtitle_pos = position;
5972 LOGD("save adjust_subtitle_pos in player") ;
5978 LOGW("invalid format.\n");
5980 return MM_ERROR_INVALID_ARGUMENT;
5986 return MM_ERROR_NONE;
5988 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5991 LOGD("adjusting video_pos in player") ;
5992 int current_pos = 0;
5993 /* check player and videobin are created */
5994 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5995 if (!player->pipeline->videobin ||
5996 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5997 LOGD("no video pipeline or sink is there");
5998 return MM_ERROR_PLAYER_INVALID_STATE ;
6001 LOGD("nothing to do\n");
6003 return MM_ERROR_NONE;
6005 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6006 LOGD("failed to get current position");
6007 return MM_ERROR_PLAYER_INTERNAL;
6009 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6010 LOGD("enter video delay is valid");
6012 LOGD("enter video delay is crossing content boundary");
6013 return MM_ERROR_INVALID_ARGUMENT ;
6015 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6016 LOGD("video delay has been done");
6019 return MM_ERROR_NONE;
6023 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6025 GstElement *appsrc = element;
6026 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6027 GstBuffer *buffer = NULL;
6028 GstFlowReturn ret = GST_FLOW_OK;
6031 MMPLAYER_RETURN_IF_FAIL(element);
6032 MMPLAYER_RETURN_IF_FAIL(buf);
6034 buffer = gst_buffer_new();
6036 if (buf->offset >= buf->len) {
6037 LOGD("call eos appsrc\n");
6038 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6042 if (buf->len - buf->offset < size)
6043 len = buf->len - buf->offset;
6045 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6046 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6047 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6049 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6050 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6056 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6058 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6060 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6062 buf->offset = (int)size;
6067 static GstBusSyncReply
6068 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6070 mm_player_t *player = (mm_player_t *)data;
6071 GstBusSyncReply reply = GST_BUS_DROP;
6073 if (!(player->pipeline && player->pipeline->mainbin)) {
6074 LOGE("player pipeline handle is null");
6075 return GST_BUS_PASS;
6078 if (!__mmplayer_check_useful_message(player, message)) {
6079 gst_message_unref(message);
6080 return GST_BUS_DROP;
6083 switch (GST_MESSAGE_TYPE(message)) {
6084 case GST_MESSAGE_STATE_CHANGED:
6085 /* post directly for fast launch */
6086 if (player->sync_handler) {
6087 __mmplayer_gst_callback(message, player);
6088 reply = GST_BUS_DROP;
6090 reply = GST_BUS_PASS;
6092 case GST_MESSAGE_TAG:
6093 __mmplayer_gst_extract_tag_from_msg(player, message);
6097 GstTagList *tags = NULL;
6099 gst_message_parse_tag(message, &tags);
6101 LOGE("TAGS received from element \"%s\".\n",
6102 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6104 gst_tag_list_foreach(tags, print_tag, NULL);
6105 gst_tag_list_free(tags);
6113 case GST_MESSAGE_DURATION_CHANGED:
6114 __mmplayer_gst_handle_duration(player, message);
6116 case GST_MESSAGE_ASYNC_DONE:
6117 /* NOTE:Don't call gst_callback directly
6118 * because previous frame can be showed even though this message is received for seek.
6121 reply = GST_BUS_PASS;
6125 if (reply == GST_BUS_DROP)
6126 gst_message_unref(message);
6132 __mmplayer_gst_create_decoder(mm_player_t *player,
6133 MMPlayerTrackType track,
6135 enum MainElementID elemId,
6138 gboolean ret = TRUE;
6139 GstPad *sinkpad = NULL;
6143 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6145 player->pipeline->mainbin, FALSE);
6146 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6147 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6148 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6150 GstElement *decodebin = NULL;
6151 GstCaps *dec_caps = NULL;
6153 /* create decodebin */
6154 decodebin = gst_element_factory_make("decodebin", name);
6157 LOGE("error : fail to create decodebin for %d decoder\n", track);
6162 /* raw pad handling signal */
6163 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6164 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6166 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6167 before looking for any elements that can handle that stream.*/
6168 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6169 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6171 /* This signal is emitted when a element is added to the bin.*/
6172 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6173 G_CALLBACK(__mmplayer_gst_element_added), player);
6175 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6176 LOGE("failed to add new decodebin\n");
6181 dec_caps = gst_pad_query_caps(srcpad, NULL);
6183 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6184 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6185 gst_caps_unref(dec_caps);
6188 player->pipeline->mainbin[elemId].id = elemId;
6189 player->pipeline->mainbin[elemId].gst = decodebin;
6191 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6193 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6194 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6195 gst_object_unref(GST_OBJECT(decodebin));
6198 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6199 LOGE("failed to sync second level decodebin state with parent\n");
6201 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6205 gst_object_unref(GST_OBJECT(sinkpad));
6214 * This function is to create audio or video pipeline for playing.
6216 * @param player [in] handle of player
6218 * @return This function returns zero on success.
6223 __mmplayer_gst_create_pipeline(mm_player_t* player)
6226 MMPlayerGstElement *mainbin = NULL;
6227 MMHandleType attrs = 0;
6228 GstElement* element = NULL;
6229 GstElement* elem_src_audio = NULL;
6230 GstElement* elem_src_subtitle = NULL;
6231 GstElement* es_video_queue = NULL;
6232 GstElement* es_audio_queue = NULL;
6233 GstElement* es_subtitle_queue = NULL;
6234 GList* element_bucket = NULL;
6235 gboolean need_state_holder = TRUE;
6237 #ifdef SW_CODEC_ONLY
6238 int surface_type = 0;
6242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6244 /* get profile attribute */
6245 attrs = MMPLAYER_GET_ATTRS(player);
6247 LOGE("cannot get content attribute\n");
6251 /* create pipeline handles */
6252 if (player->pipeline) {
6253 LOGW("pipeline should be released before create new one\n");
6257 player->video360_metadata.is_spherical = -1;
6258 player->is_openal_plugin_used = FALSE;
6260 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6261 if (player->pipeline == NULL)
6264 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6266 /* create mainbin */
6267 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6268 if (mainbin == NULL)
6271 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6273 /* create pipeline */
6274 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6275 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6276 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6277 LOGE("failed to create pipeline\n");
6280 player->demux_pad_index = 0;
6281 player->subtitle_language_list = NULL;
6283 player->is_subtitle_force_drop = FALSE;
6284 player->last_multiwin_status = FALSE;
6286 _mmplayer_track_initialize(player);
6287 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6289 /* create source element */
6290 switch (player->profile.uri_type) {
6291 /* rtsp streamming */
6292 case MM_PLAYER_URI_TYPE_URL_RTSP:
6296 element = gst_element_factory_make("rtspsrc", "rtsp source");
6299 LOGE("failed to create streaming source element\n");
6307 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6309 SECURE_LOGD("user_agent : %s\n", user_agent);
6311 /* setting property to streaming source */
6312 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6314 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6316 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6317 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6318 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6319 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6324 case MM_PLAYER_URI_TYPE_URL_HTTP:
6326 gchar *user_agent, *cookies, **cookie_list;
6327 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6328 user_agent = cookies = NULL;
6330 gint mode = MM_PLAYER_PD_MODE_NONE;
6332 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6334 player->pd_mode = mode;
6336 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6338 if (!MMPLAYER_IS_HTTP_PD(player)) {
6339 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6341 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6344 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6347 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6348 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6350 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6351 LOGD("get timeout from ini\n");
6352 http_timeout = player->ini.http_timeout;
6356 SECURE_LOGD("location : %s\n", player->profile.uri);
6357 SECURE_LOGD("cookies : %s\n", cookies);
6358 SECURE_LOGD("user_agent : %s\n", user_agent);
6359 LOGD("timeout : %d\n", http_timeout);
6361 /* setting property to streaming source */
6362 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6363 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6364 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6366 /* parsing cookies */
6367 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6368 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6369 g_strfreev(cookie_list);
6372 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6374 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6375 LOGW("it's dash. and it's still experimental feature.");
6377 // progressive download
6378 gchar* location = NULL;
6380 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6383 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6385 MMPLAYER_FREEIF(player->pd_file_save_path);
6387 LOGD("PD Location : %s\n", path);
6390 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6391 LOGE("failed to get storage info");
6394 player->pd_file_save_path = g_strdup(path);
6396 LOGE("can't find pd location so, it should be set \n");
6401 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6403 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6407 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6408 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6410 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6411 g_object_get(element, "location", &location, NULL);
6412 LOGD("PD_LOCATION [%s].\n", location);
6420 case MM_PLAYER_URI_TYPE_FILE:
6422 LOGD("using filesrc for 'file://' handler.\n");
6423 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6424 LOGE("failed to get storage info");
6428 element = gst_element_factory_make("filesrc", "source");
6430 LOGE("failed to create filesrc\n");
6434 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6438 case MM_PLAYER_URI_TYPE_SS:
6440 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6441 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6443 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6447 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6448 LOGD("get timeout from ini\n");
6449 http_timeout = player->ini.http_timeout;
6452 /* setting property to streaming source */
6453 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6454 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6457 case MM_PLAYER_URI_TYPE_MS_BUFF:
6459 LOGD("MS buff src is selected\n");
6461 if (player->v_stream_caps) {
6462 element = gst_element_factory_make("appsrc", "video_appsrc");
6464 LOGF("failed to create video app source element[appsrc].\n");
6468 if (player->a_stream_caps) {
6469 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6470 if (!elem_src_audio) {
6471 LOGF("failed to create audio app source element[appsrc].\n");
6475 } else if (player->a_stream_caps) {
6476 /* no video, only audio pipeline*/
6477 element = gst_element_factory_make("appsrc", "audio_appsrc");
6479 LOGF("failed to create audio app source element[appsrc].\n");
6484 if (player->s_stream_caps) {
6485 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6486 if (!elem_src_subtitle) {
6487 LOGF("failed to create subtitle app source element[appsrc].\n");
6492 LOGD("setting app sources properties.\n");
6493 LOGD("location : %s\n", player->profile.uri);
6495 if (player->v_stream_caps && element) {
6496 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6497 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6498 "caps", player->v_stream_caps, NULL);
6500 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6501 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6502 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6503 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6505 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6506 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6507 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6508 G_CALLBACK(__gst_seek_video_data), player);
6510 if (player->a_stream_caps && elem_src_audio) {
6511 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6512 "caps", player->a_stream_caps, NULL);
6514 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6515 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6516 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6517 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6519 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6520 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6521 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6522 G_CALLBACK(__gst_seek_audio_data), player);
6524 } else if (player->a_stream_caps && element) {
6525 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6526 "caps", player->a_stream_caps, NULL);
6528 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6529 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6530 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6531 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6533 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6534 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6535 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6536 G_CALLBACK(__gst_seek_audio_data), player);
6539 if (player->s_stream_caps && elem_src_subtitle) {
6540 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6541 "caps", player->s_stream_caps, NULL);
6543 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6544 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6545 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6546 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6548 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6550 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6551 G_CALLBACK(__gst_seek_subtitle_data), player);
6554 if (player->v_stream_caps && element) {
6555 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6556 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6557 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6558 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6560 if (player->a_stream_caps && elem_src_audio) {
6561 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6562 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6563 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6564 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6566 } else if (player->a_stream_caps && element) {
6567 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6568 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6569 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6570 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6573 if (player->s_stream_caps && elem_src_subtitle)
6574 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6575 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6577 need_state_holder = FALSE;
6579 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6580 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6581 LOGE("failed to commit\n");
6585 case MM_PLAYER_URI_TYPE_MEM:
6587 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6589 LOGD("mem src is selected\n");
6591 element = gst_element_factory_make("appsrc", "mem-source");
6593 LOGE("failed to create appsrc element\n");
6597 g_object_set(element, "stream-type", stream_type, NULL);
6598 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6599 g_object_set(element, "blocksize", (guint64)20480, NULL);
6601 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6602 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6603 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6607 case MM_PLAYER_URI_TYPE_URL:
6610 case MM_PLAYER_URI_TYPE_TEMP:
6613 case MM_PLAYER_URI_TYPE_NONE:
6618 /* check source element is OK */
6620 LOGE("no source element was created.\n");
6624 /* take source element */
6625 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6626 mainbin[MMPLAYER_M_SRC].gst = element;
6627 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6629 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6630 player->streamer = __mm_player_streaming_create();
6631 __mm_player_streaming_initialize(player->streamer);
6634 if (MMPLAYER_IS_HTTP_PD(player)) {
6635 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6637 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6638 element = gst_element_factory_make("queue2", "queue2");
6640 LOGE("failed to create http streaming buffer element\n");
6645 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6646 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6647 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6649 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6651 __mm_player_streaming_set_queue2(player->streamer,
6654 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6657 player->ini.http_buffering_limit,
6658 MUXED_BUFFER_TYPE_MEM_QUEUE,
6662 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6663 if (player->v_stream_caps) {
6664 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6665 if (!es_video_queue) {
6666 LOGE("create es_video_queue for es player failed\n");
6669 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6670 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6671 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6672 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6674 /* Adding audio appsrc to bucket */
6675 if (player->a_stream_caps && elem_src_audio) {
6676 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6677 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6678 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6680 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6681 if (!es_audio_queue) {
6682 LOGE("create es_audio_queue for es player failed\n");
6685 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6687 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6688 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6689 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6691 } else if (player->a_stream_caps) {
6692 /* Only audio stream, no video */
6693 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6694 if (!es_audio_queue) {
6695 LOGE("create es_audio_queue for es player failed\n");
6698 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6699 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6700 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6703 if (player->s_stream_caps && elem_src_subtitle) {
6704 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6705 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6706 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6708 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6709 if (!es_subtitle_queue) {
6710 LOGE("create es_subtitle_queue for es player failed\n");
6713 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6714 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6715 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6719 /* create autoplugging element if src element is not a rtsp src */
6720 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6721 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6723 enum MainElementID elemId = MMPLAYER_M_NUM;
6725 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6726 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6727 elemId = MMPLAYER_M_AUTOPLUG;
6728 element = __mmplayer_create_decodebin(player);
6730 /* default size of mq in decodebin is 2M
6731 * but it can cause blocking issue during seeking depends on content. */
6732 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6734 need_state_holder = FALSE;
6736 elemId = MMPLAYER_M_TYPEFIND;
6737 element = gst_element_factory_make("typefind", "typefinder");
6738 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6739 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6743 /* check autoplug element is OK */
6745 LOGE("can not create element(%d)\n", elemId);
6749 mainbin[elemId].id = elemId;
6750 mainbin[elemId].gst = element;
6752 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6755 /* add elements to pipeline */
6756 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6757 LOGE("Failed to add elements to pipeline\n");
6762 /* linking elements in the bucket by added order. */
6763 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6764 LOGE("Failed to link some elements\n");
6769 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6770 if (need_state_holder) {
6772 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6773 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6775 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6776 LOGE("fakesink element could not be created\n");
6779 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6781 /* take ownership of fakesink. we are reusing it */
6782 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6785 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6786 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6787 LOGE("failed to add fakesink to bin\n");
6792 /* now we have completed mainbin. take it */
6793 player->pipeline->mainbin = mainbin;
6795 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6796 GstPad *srcpad = NULL;
6798 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6799 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6801 __mmplayer_gst_create_decoder(player,
6802 MM_PLAYER_TRACK_TYPE_VIDEO,
6804 MMPLAYER_M_AUTOPLUG_V_DEC,
6807 gst_object_unref(GST_OBJECT(srcpad));
6812 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6813 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6815 __mmplayer_gst_create_decoder(player,
6816 MM_PLAYER_TRACK_TYPE_AUDIO,
6818 MMPLAYER_M_AUTOPLUG_A_DEC,
6821 gst_object_unref(GST_OBJECT(srcpad));
6826 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6827 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6830 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6831 if (__mmplayer_check_subtitle(player)) {
6832 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6833 LOGE("fail to create text pipeline");
6836 /* connect bus callback */
6837 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6839 LOGE("cannot get bus from pipeline.\n");
6843 /* set sync handler to get tag synchronously */
6844 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6847 gst_object_unref(GST_OBJECT(bus));
6848 g_list_free(element_bucket);
6850 /* create gst bus_msb_cb thread */
6851 g_mutex_init(&player->bus_msg_thread_mutex);
6852 g_cond_init(&player->bus_msg_thread_cond);
6853 player->bus_msg_thread_exit = FALSE;
6854 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6855 player->bus_msg_thread =
6856 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6857 if (!player->bus_msg_thread) {
6858 LOGE("failed to create gst BUS msg thread");
6859 g_mutex_clear(&player->bus_msg_thread_mutex);
6860 g_cond_clear(&player->bus_msg_thread_cond);
6866 return MM_ERROR_NONE;
6869 __mmplayer_gst_destroy_pipeline(player);
6870 g_list_free(element_bucket);
6873 /* release element which are not added to bin */
6874 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6875 /* NOTE : skip pipeline */
6876 if (mainbin[i].gst) {
6877 GstObject* parent = NULL;
6878 parent = gst_element_get_parent(mainbin[i].gst);
6881 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6882 mainbin[i].gst = NULL;
6884 gst_object_unref(GST_OBJECT(parent));
6888 /* release pipeline with it's childs */
6889 if (mainbin[MMPLAYER_M_PIPE].gst)
6890 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6892 MMPLAYER_FREEIF(mainbin);
6895 MMPLAYER_FREEIF(player->pipeline);
6896 return MM_ERROR_PLAYER_INTERNAL;
6900 __mmplayer_reset_gapless_state(mm_player_t* player)
6903 MMPLAYER_RETURN_IF_FAIL(player
6905 && player->pipeline->audiobin
6906 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6908 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6915 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6918 int ret = MM_ERROR_NONE;
6922 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6924 /* cleanup stuffs */
6925 MMPLAYER_FREEIF(player->type);
6926 player->have_dynamic_pad = FALSE;
6927 player->no_more_pad = FALSE;
6928 player->num_dynamic_pad = 0;
6929 player->demux_pad_index = 0;
6930 player->use_deinterleave = FALSE;
6931 player->max_audio_channels = 0;
6932 player->video_share_api_delta = 0;
6933 player->video_share_clock_delta = 0;
6934 player->video_hub_download_mode = 0;
6936 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6937 player->subtitle_language_list = NULL;
6938 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6940 __mmplayer_reset_gapless_state(player);
6942 if (player->streamer) {
6943 __mm_player_streaming_deinitialize(player->streamer);
6944 __mm_player_streaming_destroy(player->streamer);
6945 player->streamer = NULL;
6948 /* cleanup unlinked mime type */
6949 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6950 MMPLAYER_FREEIF(player->unlinked_video_mime);
6951 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6953 /* cleanup running stuffs */
6954 __mmplayer_cancel_eos_timer(player);
6956 /* cleanup gst stuffs */
6957 if (player->pipeline) {
6958 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6959 GstTagList* tag_list = player->pipeline->tag_list;
6961 /* first we need to disconnect all signal hander */
6962 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6965 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6966 MMPlayerGstElement* videobin = player->pipeline->videobin;
6967 MMPlayerGstElement* textbin = player->pipeline->textbin;
6968 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6969 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6970 gst_object_unref(bus);
6972 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6973 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6974 if (ret != MM_ERROR_NONE) {
6975 LOGE("fail to change state to NULL\n");
6976 return MM_ERROR_PLAYER_INTERNAL;
6979 LOGW("succeeded in chaning state to NULL\n");
6981 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6984 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6985 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6987 /* free avsysaudiosink
6988 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6989 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6991 MMPLAYER_FREEIF(audiobin);
6992 MMPLAYER_FREEIF(videobin);
6993 MMPLAYER_FREEIF(textbin);
6994 MMPLAYER_FREEIF(mainbin);
6998 gst_tag_list_free(tag_list);
7000 MMPLAYER_FREEIF(player->pipeline);
7002 MMPLAYER_FREEIF(player->album_art);
7004 if (player->v_stream_caps) {
7005 gst_caps_unref(player->v_stream_caps);
7006 player->v_stream_caps = NULL;
7008 if (player->a_stream_caps) {
7009 gst_caps_unref(player->a_stream_caps);
7010 player->a_stream_caps = NULL;
7013 if (player->s_stream_caps) {
7014 gst_caps_unref(player->s_stream_caps);
7015 player->s_stream_caps = NULL;
7017 _mmplayer_track_destroy(player);
7019 if (player->sink_elements)
7020 g_list_free(player->sink_elements);
7021 player->sink_elements = NULL;
7023 if (player->bufmgr) {
7024 tbm_bufmgr_deinit(player->bufmgr);
7025 player->bufmgr = NULL;
7028 LOGW("finished destroy pipeline\n");
7035 static int __gst_realize(mm_player_t* player)
7038 int ret = MM_ERROR_NONE;
7042 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7044 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7046 ret = __mmplayer_gst_create_pipeline(player);
7048 LOGE("failed to create pipeline\n");
7052 /* set pipeline state to READY */
7053 /* NOTE : state change to READY must be performed sync. */
7054 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7055 ret = __mmplayer_gst_set_state(player,
7056 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7058 if (ret != MM_ERROR_NONE) {
7059 /* return error if failed to set state */
7060 LOGE("failed to set READY state");
7064 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7066 /* create dot before error-return. for debugging */
7067 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7074 static int __gst_unrealize(mm_player_t* player)
7076 int ret = MM_ERROR_NONE;
7080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7082 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7083 MMPLAYER_PRINT_STATE(player);
7085 /* release miscellaneous information */
7086 __mmplayer_release_misc(player);
7088 /* destroy pipeline */
7089 ret = __mmplayer_gst_destroy_pipeline(player);
7090 if (ret != MM_ERROR_NONE) {
7091 LOGE("failed to destory pipeline\n");
7095 /* release miscellaneous information.
7096 these info needs to be released after pipeline is destroyed. */
7097 __mmplayer_release_misc_post(player);
7099 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7106 static int __gst_pending_seek(mm_player_t* player)
7108 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7109 int ret = MM_ERROR_NONE;
7113 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7115 if (!player->pending_seek.is_pending) {
7116 LOGD("pending seek is not reserved. nothing to do.\n");
7120 /* check player state if player could pending seek or not. */
7121 current_state = MMPLAYER_CURRENT_STATE(player);
7123 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7124 LOGW("try to pending seek in %s state, try next time. \n",
7125 MMPLAYER_STATE_GET_NAME(current_state));
7129 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7131 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7133 if (MM_ERROR_NONE != ret)
7134 LOGE("failed to seek pending postion. just keep staying current position.\n");
7136 player->pending_seek.is_pending = FALSE;
7143 static int __gst_start(mm_player_t* player)
7145 gboolean sound_extraction = 0;
7146 int ret = MM_ERROR_NONE;
7147 gboolean async = FALSE;
7151 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7153 /* get sound_extraction property */
7154 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7156 /* NOTE : if SetPosition was called before Start. do it now */
7157 /* streaming doesn't support it. so it should be always sync */
7158 /* !!create one more api to check if there is pending seek rather than checking variables */
7159 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7160 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7161 ret = __gst_pause(player, FALSE);
7162 if (ret != MM_ERROR_NONE) {
7163 LOGE("failed to set state to PAUSED for pending seek\n");
7167 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7169 if (sound_extraction) {
7170 LOGD("setting pcm extraction\n");
7172 ret = __mmplayer_set_pcm_extraction(player);
7173 if (MM_ERROR_NONE != ret) {
7174 LOGW("failed to set pcm extraction\n");
7178 if (MM_ERROR_NONE != __gst_pending_seek(player))
7179 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7183 LOGD("current state before doing transition");
7184 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7185 MMPLAYER_PRINT_STATE(player);
7187 /* set pipeline state to PLAYING */
7188 if (player->es_player_push_mode)
7190 /* set pipeline state to PLAYING */
7191 ret = __mmplayer_gst_set_state(player,
7192 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7194 if (ret == MM_ERROR_NONE) {
7195 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7197 LOGE("failed to set state to PLAYING");
7201 /* generating debug info before returning error */
7202 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7209 static int __gst_stop(mm_player_t* player)
7211 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7212 MMHandleType attrs = 0;
7213 gboolean rewind = FALSE;
7215 int ret = MM_ERROR_NONE;
7216 gboolean async = FALSE;
7220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7221 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7223 LOGD("current state before doing transition");
7224 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7225 MMPLAYER_PRINT_STATE(player);
7227 attrs = MMPLAYER_GET_ATTRS(player);
7229 LOGE("cannot get content attribute\n");
7230 return MM_ERROR_PLAYER_INTERNAL;
7233 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7234 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7236 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7237 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7240 if (player->es_player_push_mode)
7243 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7245 /* return if set_state has failed */
7246 if (ret != MM_ERROR_NONE) {
7247 LOGE("failed to set state.\n");
7253 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7254 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7255 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7256 LOGW("failed to rewind\n");
7257 ret = MM_ERROR_PLAYER_SEEK;
7262 player->sent_bos = FALSE;
7264 if (player->es_player_push_mode) //for cloudgame
7267 /* wait for seek to complete */
7268 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7269 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7270 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7272 LOGE("fail to stop player.\n");
7273 ret = MM_ERROR_PLAYER_INTERNAL;
7274 __mmplayer_dump_pipeline_state(player);
7277 /* generate dot file if enabled */
7278 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7285 int __gst_pause(mm_player_t* player, gboolean async)
7287 int ret = MM_ERROR_NONE;
7291 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7292 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7294 LOGD("current state before doing transition");
7295 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7296 MMPLAYER_PRINT_STATE(player);
7298 /* set pipeline status to PAUSED */
7299 ret = __mmplayer_gst_set_state(player,
7300 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7302 if (FALSE == async) {
7303 if (ret != MM_ERROR_NONE) {
7304 GstMessage *msg = NULL;
7305 GTimer *timer = NULL;
7306 gdouble MAX_TIMEOUT_SEC = 3;
7308 LOGE("failed to set state to PAUSED");
7310 if (player->msg_posted) {
7311 LOGE("error msg is already posted.");
7315 timer = g_timer_new();
7316 g_timer_start(timer);
7318 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7321 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7323 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7324 GError *error = NULL;
7326 /* parse error code */
7327 gst_message_parse_error(msg, &error, NULL);
7329 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7330 /* Note : the streaming error from the streaming source is handled
7331 * using __mmplayer_handle_streaming_error.
7333 __mmplayer_handle_streaming_error(player, msg);
7336 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7338 if (error->domain == GST_STREAM_ERROR)
7339 ret = __gst_handle_stream_error(player, error, msg);
7340 else if (error->domain == GST_RESOURCE_ERROR)
7341 ret = __gst_handle_resource_error(player, error->code, NULL);
7342 else if (error->domain == GST_LIBRARY_ERROR)
7343 ret = __gst_handle_library_error(player, error->code);
7344 else if (error->domain == GST_CORE_ERROR)
7345 ret = __gst_handle_core_error(player, error->code);
7347 g_error_free(error);
7349 player->msg_posted = TRUE;
7351 gst_message_unref(msg);
7353 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7355 gst_object_unref(bus);
7356 g_timer_stop(timer);
7357 g_timer_destroy(timer);
7361 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7362 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7364 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7366 } else if (ret == MM_ERROR_NONE) {
7368 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7372 /* generate dot file before returning error */
7373 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7380 int __gst_resume(mm_player_t* player, gboolean async)
7382 int ret = MM_ERROR_NONE;
7387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7388 MM_ERROR_PLAYER_NOT_INITIALIZED);
7390 LOGD("current state before doing transition");
7391 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7392 MMPLAYER_PRINT_STATE(player);
7394 /* generate dot file before returning error */
7395 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7398 LOGD("do async state transition to PLAYING.\n");
7400 /* set pipeline state to PLAYING */
7401 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7403 ret = __mmplayer_gst_set_state(player,
7404 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7405 if (ret != MM_ERROR_NONE) {
7406 LOGE("failed to set state to PLAYING\n");
7409 if (async == FALSE) {
7410 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7411 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7412 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7416 /* generate dot file before returning error */
7417 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7425 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7427 unsigned long dur_msec = 0;
7428 gint64 dur_nsec = 0;
7429 gint64 pos_nsec = 0;
7430 gboolean ret = TRUE;
7431 gboolean accurated = FALSE;
7432 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7435 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7436 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7438 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7439 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7442 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7443 /* check duration */
7444 /* NOTE : duration cannot be zero except live streaming.
7445 * Since some element could have some timing problemn with quering duration, try again.
7447 if (!player->duration) {
7448 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7449 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7450 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7451 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7452 player->pending_seek.is_pending = TRUE;
7453 player->pending_seek.format = format;
7454 player->pending_seek.pos = position;
7455 player->doing_seek = FALSE;
7456 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7457 return MM_ERROR_NONE;
7462 player->duration = dur_nsec;
7465 if (player->duration) {
7466 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7468 LOGE("could not get the duration. fail to seek.\n");
7472 LOGD("playback rate: %f\n", player->playback_rate);
7474 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7476 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7478 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7482 case MM_PLAYER_POS_FORMAT_TIME:
7484 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7485 GstQuery *query = NULL;
7486 gboolean seekable = FALSE;
7488 /* check position is valid or not */
7489 if (position > dur_msec)
7492 query = gst_query_new_seeking(GST_FORMAT_TIME);
7493 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7494 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7495 gst_query_unref(query);
7498 LOGW("non-seekable content");
7499 player->doing_seek = FALSE;
7500 return MM_ERROR_PLAYER_NO_OP;
7503 LOGW("failed to get seeking query");
7504 gst_query_unref(query); /* keep seeking operation */
7507 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7509 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7510 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7511 This causes problem is position calculation during normal pause resume scenarios also.
7512 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7513 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7514 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7515 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7516 LOGW("getting current position failed in seek\n");
7518 player->last_position = pos_nsec;
7519 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7522 if (player->doing_seek) {
7523 LOGD("not completed seek");
7524 return MM_ERROR_PLAYER_DOING_SEEK;
7528 if (!internal_called)
7529 player->doing_seek = TRUE;
7531 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7533 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7534 gint64 cur_time = 0;
7536 /* get current position */
7537 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7540 GstEvent *event = gst_event_new_seek(1.0,
7542 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7543 GST_SEEK_TYPE_SET, cur_time,
7544 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7546 __gst_send_event_to_sink(player, event);
7548 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7549 __gst_pause(player, FALSE);
7552 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7553 that's why set position through property. */
7554 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7555 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7556 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7557 (!player->videodec_linked) && (!player->audiodec_linked)) {
7559 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7560 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7561 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7562 player->doing_seek = FALSE;
7563 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7565 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7566 GST_FORMAT_TIME, seek_flags,
7567 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7571 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7577 case MM_PLAYER_POS_FORMAT_PERCENT:
7579 LOGD("seeking to(%lu)%% \n", position);
7581 if (player->doing_seek) {
7582 LOGD("not completed seek");
7583 return MM_ERROR_PLAYER_DOING_SEEK;
7586 if (!internal_called)
7587 player->doing_seek = TRUE;
7589 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7590 pos_nsec = (gint64)((position * player->duration) / 100);
7591 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7592 GST_FORMAT_TIME, seek_flags,
7593 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7595 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7605 /* NOTE : store last seeking point to overcome some bad operation
7606 * (returning zero when getting current position) of some elements
7608 player->last_position = pos_nsec;
7610 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7611 if (player->playback_rate > 1.0)
7612 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7615 return MM_ERROR_NONE;
7618 player->pending_seek.is_pending = TRUE;
7619 player->pending_seek.format = format;
7620 player->pending_seek.pos = position;
7622 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7623 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7625 return MM_ERROR_NONE;
7628 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7629 return MM_ERROR_INVALID_ARGUMENT;
7632 player->doing_seek = FALSE;
7633 return MM_ERROR_PLAYER_SEEK;
7636 #define TRICKPLAY_OFFSET GST_MSECOND
7639 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7641 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7642 gint64 pos_msec = 0;
7643 gboolean ret = TRUE;
7645 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7646 MM_ERROR_PLAYER_NOT_INITIALIZED);
7648 current_state = MMPLAYER_CURRENT_STATE(player);
7650 /* NOTE : query position except paused state to overcome some bad operation
7651 * please refer to below comments in details
7653 if (current_state != MM_PLAYER_STATE_PAUSED)
7654 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7656 /* NOTE : get last point to overcome some bad operation of some elements
7657 *(returning zero when getting current position in paused state
7658 * and when failed to get postion during seeking
7660 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7661 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7663 if (player->playback_rate < 0.0)
7664 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7666 pos_msec = player->last_position;
7669 pos_msec = player->last_position;
7671 player->last_position = pos_msec;
7673 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7676 if (player->duration > 0 && pos_msec > player->duration)
7677 pos_msec = player->duration;
7679 player->last_position = pos_msec;
7683 case MM_PLAYER_POS_FORMAT_TIME:
7684 *position = GST_TIME_AS_MSECONDS(pos_msec);
7687 case MM_PLAYER_POS_FORMAT_PERCENT:
7689 if (player->duration <= 0) {
7690 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7693 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7694 *position = pos_msec * 100 / player->duration;
7699 return MM_ERROR_PLAYER_INTERNAL;
7702 return MM_ERROR_NONE;
7706 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7708 #define STREAMING_IS_FINISHED 0
7709 #define BUFFERING_MAX_PER 100
7710 #define DEFAULT_PER_VALUE -1
7711 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7713 MMPlayerGstElement *mainbin = NULL;
7714 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7715 gint64 buffered_total = 0;
7716 unsigned long position = 0;
7717 gint buffered_sec = -1;
7718 GstBufferingMode mode = GST_BUFFERING_STREAM;
7719 gint64 content_size_time = player->duration;
7720 guint64 content_size_bytes = player->http_content_size;
7722 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7724 player->pipeline->mainbin,
7725 MM_ERROR_PLAYER_NOT_INITIALIZED);
7727 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7732 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7733 /* and rtsp is not ready yet. */
7734 LOGW("it's only used for http streaming case.\n");
7735 return MM_ERROR_PLAYER_NO_OP;
7738 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7739 LOGW("Time format is not supported yet.\n");
7740 return MM_ERROR_INVALID_ARGUMENT;
7743 if (content_size_time <= 0 || content_size_bytes <= 0) {
7744 LOGW("there is no content size.");
7745 return MM_ERROR_NONE;
7748 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7749 LOGW("fail to get current position.");
7750 return MM_ERROR_NONE;
7753 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7754 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7756 mainbin = player->pipeline->mainbin;
7757 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7759 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7760 GstQuery *query = NULL;
7761 gint byte_in_rate = 0, byte_out_rate = 0;
7762 gint64 estimated_total = 0;
7764 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7765 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7766 LOGW("fail to get buffering query from queue2");
7768 gst_query_unref(query);
7769 return MM_ERROR_NONE;
7772 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7773 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7775 if (mode == GST_BUFFERING_STREAM) {
7776 /* using only queue in case of push mode(ts / mp3) */
7777 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7778 GST_FORMAT_BYTES, &buffered_total)) {
7779 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7780 stop_per = 100 * buffered_total / content_size_bytes;
7783 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7785 guint num_of_ranges = 0;
7786 gint64 start_byte = 0, stop_byte = 0;
7788 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7789 if (estimated_total != STREAMING_IS_FINISHED) {
7790 /* buffered size info from queue2 */
7791 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7792 for (idx = 0; idx < num_of_ranges; idx++) {
7793 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7794 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7796 buffered_total += (stop_byte - start_byte);
7799 stop_per = BUFFERING_MAX_PER;
7801 gst_query_unref(query);
7804 if (stop_per == DEFAULT_PER_VALUE) {
7805 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7807 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7809 /* buffered size info from multiqueue */
7810 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7811 guint curr_size_bytes = 0;
7812 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7813 "curr-size-bytes", &curr_size_bytes, NULL);
7814 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7815 buffered_total += curr_size_bytes;
7818 if (avg_byterate > 0)
7819 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7820 else if (player->total_maximum_bitrate > 0)
7821 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7822 else if (player->total_bitrate > 0)
7823 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7825 if (buffered_sec >= 0)
7826 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7830 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7831 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7833 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7834 buffered_total, buffered_sec, *start_pos, *stop_pos);
7836 return MM_ERROR_NONE;
7840 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7845 LOGW("set_message_callback is called with invalid player handle\n");
7846 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7849 player->msg_cb = callback;
7850 player->msg_cb_param = user_param;
7852 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7856 return MM_ERROR_NONE;
7859 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7861 int ret = MM_ERROR_PLAYER_INVALID_URI;
7866 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7867 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7868 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7870 memset(data, 0, sizeof(MMPlayerParseProfile));
7872 if ((path = strstr(uri, "es_buff://"))) {
7874 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7875 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7876 ret = MM_ERROR_NONE;
7878 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7880 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7881 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7882 ret = MM_ERROR_NONE;
7884 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7887 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7888 tmp = g_ascii_strdown(uri, strlen(uri));
7890 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7891 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7893 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7895 ret = MM_ERROR_NONE;
7898 } else if ((path = strstr(uri, "rtspu://"))) {
7900 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7901 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7902 ret = MM_ERROR_NONE;
7904 } else if ((path = strstr(uri, "rtspr://"))) {
7905 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7906 char *separater = strstr(path, "*");
7910 char *urgent = separater + strlen("*");
7912 if ((urgent_len = strlen(urgent))) {
7913 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7914 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7915 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7916 ret = MM_ERROR_NONE;
7919 } else if ((path = strstr(uri, "mms://"))) {
7921 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7922 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7923 ret = MM_ERROR_NONE;
7925 } else if ((path = strstr(uri, "mem://"))) {
7928 char *buffer = NULL;
7929 char *seperator = strchr(path, ',');
7930 char ext[100] = {0,}, size[100] = {0,};
7933 if ((buffer = strstr(path, "ext="))) {
7934 buffer += strlen("ext=");
7936 if (strlen(buffer)) {
7937 strncpy(ext, buffer, 99);
7939 if ((seperator = strchr(ext, ','))
7940 || (seperator = strchr(ext, ' '))
7941 || (seperator = strchr(ext, '\0'))) {
7942 seperator[0] = '\0';
7947 if ((buffer = strstr(path, "size="))) {
7948 buffer += strlen("size=");
7950 if (strlen(buffer) > 0) {
7951 strncpy(size, buffer, 99);
7953 if ((seperator = strchr(size, ','))
7954 || (seperator = strchr(size, ' '))
7955 || (seperator = strchr(size, '\0'))) {
7956 seperator[0] = '\0';
7959 mem_size = atoi(size);
7964 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7965 if (mem_size && param) {
7966 if (data->input_mem.buf)
7967 free(data->input_mem.buf);
7968 data->input_mem.buf = malloc(mem_size);
7970 if (data->input_mem.buf) {
7971 memcpy(data->input_mem.buf, param, mem_size);
7972 data->input_mem.len = mem_size;
7973 ret = MM_ERROR_NONE;
7975 LOGE("failed to alloc mem %d", mem_size);
7976 ret = MM_ERROR_PLAYER_INTERNAL;
7979 data->input_mem.offset = 0;
7980 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7984 gchar *location = NULL;
7987 if ((path = strstr(uri, "file://"))) {
7989 location = g_filename_from_uri(uri, NULL, &err);
7991 if (!location || (err != NULL)) {
7992 LOGE("Invalid URI '%s' for filesrc: %s", path,
7993 (err != NULL) ? err->message : "unknown error");
7995 if (err) g_error_free(err);
7996 if (location) g_free(location);
7998 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8002 LOGD("path from uri: %s", location);
8005 path = (location != NULL) ? (location) : ((char*)uri);
8006 int file_stat = MM_ERROR_NONE;
8008 file_stat = util_exist_file_path(path);
8010 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8011 if (file_stat == MM_ERROR_NONE) {
8012 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8014 if (util_is_sdp_file(path)) {
8015 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8016 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8018 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8020 ret = MM_ERROR_NONE;
8021 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8022 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8024 LOGE("invalid uri, could not play..\n");
8025 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8028 if (location) g_free(location);
8032 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8033 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8034 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8035 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8037 /* dump parse result */
8038 SECURE_LOGW("incomming uri : %s\n", uri);
8039 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8040 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8048 __mmplayer_can_do_interrupt(mm_player_t *player)
8050 if (!player || !player->pipeline || !player->attrs) {
8051 LOGW("not initialized");
8055 if (player->set_mode.pcm_extraction) {
8056 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8060 /* check if seeking */
8061 if (player->doing_seek) {
8062 MMMessageParamType msg_param;
8063 memset(&msg_param, 0, sizeof(MMMessageParamType));
8064 msg_param.code = MM_ERROR_PLAYER_SEEK;
8065 player->doing_seek = FALSE;
8066 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8070 /* check other thread */
8071 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8072 LOGW("locked already, cmd state : %d", player->cmd);
8074 /* check application command */
8075 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8076 LOGW("playing.. should wait cmd lock then, will be interrupted");
8078 /* lock will be released at mrp_resource_release_cb() */
8079 MMPLAYER_CMD_LOCK(player);
8082 LOGW("nothing to do");
8085 LOGW("can interrupt immediately");
8089 FAILED: /* with CMD UNLOCKED */
8092 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8097 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8100 mm_player_t *player = NULL;
8104 if (user_data == NULL) {
8105 LOGE("- user_data is null\n");
8108 player = (mm_player_t *)user_data;
8110 /* do something to release resource here.
8111 * player stop and interrupt forwarding */
8112 if (!__mmplayer_can_do_interrupt(player)) {
8113 LOGW("no need to interrupt, so leave");
8115 MMMessageParamType msg = {0, };
8116 unsigned long pos = 0;
8118 player->interrupted_by_resource = TRUE;
8120 /* get last play position */
8121 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8122 LOGW("failed to get play position.");
8124 msg.union_type = MM_MSG_UNION_TIME;
8125 msg.time.elapsed = (unsigned int)pos;
8126 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8128 LOGD("video resource conflict so, resource will be freed by unrealizing");
8129 if (_mmplayer_unrealize((MMHandleType)player))
8130 LOGW("failed to unrealize");
8132 /* lock is called in __mmplayer_can_do_interrupt() */
8133 MMPLAYER_CMD_UNLOCK(player);
8136 if (res == player->video_overlay_resource)
8137 player->video_overlay_resource = FALSE;
8139 player->video_decoder_resource = FALSE;
8147 _mmplayer_create_player(MMHandleType handle)
8149 int ret = MM_ERROR_PLAYER_INTERNAL;
8150 mm_player_t* player = MM_PLAYER_CAST(handle);
8154 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8156 /* initialize player state */
8157 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8158 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8159 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8160 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8162 /* check current state */
8163 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8165 /* construct attributes */
8166 player->attrs = _mmplayer_construct_attribute(handle);
8168 if (!player->attrs) {
8169 LOGE("Failed to construct attributes\n");
8173 /* initialize gstreamer with configured parameter */
8174 if (!__mmplayer_init_gstreamer(player)) {
8175 LOGE("Initializing gstreamer failed\n");
8176 _mmplayer_deconstruct_attribute(handle);
8180 /* create lock. note that g_tread_init() has already called in gst_init() */
8181 g_mutex_init(&player->fsink_lock);
8183 /* create update tag lock */
8184 g_mutex_init(&player->update_tag_lock);
8186 /* create next play mutex */
8187 g_mutex_init(&player->next_play_thread_mutex);
8189 /* create next play cond */
8190 g_cond_init(&player->next_play_thread_cond);
8192 /* create next play thread */
8193 player->next_play_thread =
8194 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8195 if (!player->next_play_thread) {
8196 LOGE("failed to create next play thread");
8197 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8198 g_mutex_clear(&player->next_play_thread_mutex);
8199 g_cond_clear(&player->next_play_thread_cond);
8203 ret = _mmplayer_initialize_video_capture(player);
8204 if (ret != MM_ERROR_NONE) {
8205 LOGE("failed to initialize video capture\n");
8209 /* initialize resource manager */
8210 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8211 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8212 &player->resource_manager)) {
8213 LOGE("failed to initialize resource manager\n");
8217 if (MMPLAYER_IS_HTTP_PD(player)) {
8218 player->pd_downloader = NULL;
8219 player->pd_file_save_path = NULL;
8222 /* create video bo lock and cond */
8223 g_mutex_init(&player->video_bo_mutex);
8224 g_cond_init(&player->video_bo_cond);
8226 /* create media stream callback mutex */
8227 g_mutex_init(&player->media_stream_cb_lock);
8229 /* create subtitle info lock and cond */
8230 g_mutex_init(&player->subtitle_info_mutex);
8231 g_cond_init(&player->subtitle_info_cond);
8233 player->streaming_type = STREAMING_SERVICE_NONE;
8235 /* give default value of audio effect setting */
8236 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8237 player->sound.rg_enable = false;
8238 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8240 player->play_subtitle = FALSE;
8241 player->use_deinterleave = FALSE;
8242 player->max_audio_channels = 0;
8243 player->video_share_api_delta = 0;
8244 player->video_share_clock_delta = 0;
8245 player->has_closed_caption = FALSE;
8246 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8247 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8248 player->pending_resume = FALSE;
8249 if (player->ini.dump_element_keyword[0][0] == '\0')
8250 player->ini.set_dump_element_flag = FALSE;
8252 player->ini.set_dump_element_flag = TRUE;
8254 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8255 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8256 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8258 /* Set video360 settings to their defaults for just-created player.
8260 player->is_content_spherical = FALSE;
8261 player->is_video360_enabled = TRUE;
8262 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8263 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8264 player->video360_yaw_radians = 4;
8265 player->video360_pitch_radians = 4;
8266 player->video360_zoom = 1.0f;
8267 player->video360_horizontal_fov = 0;
8268 player->video360_vertical_fov = 0;
8270 /* set player state to null */
8271 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8272 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8274 return MM_ERROR_NONE;
8278 g_mutex_clear(&player->fsink_lock);
8280 /* free update tag lock */
8281 g_mutex_clear(&player->update_tag_lock);
8283 /* free next play thread */
8284 if (player->next_play_thread) {
8285 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8286 player->next_play_thread_exit = TRUE;
8287 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8288 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8290 g_thread_join(player->next_play_thread);
8291 player->next_play_thread = NULL;
8293 g_mutex_clear(&player->next_play_thread_mutex);
8294 g_cond_clear(&player->next_play_thread_cond);
8297 /* release attributes */
8298 _mmplayer_deconstruct_attribute(handle);
8306 __mmplayer_init_gstreamer(mm_player_t* player)
8308 static gboolean initialized = FALSE;
8309 static const int max_argc = 50;
8311 gchar** argv = NULL;
8312 gchar** argv2 = NULL;
8318 LOGD("gstreamer already initialized.\n");
8323 argc = malloc(sizeof(int));
8324 argv = malloc(sizeof(gchar*) * max_argc);
8325 argv2 = malloc(sizeof(gchar*) * max_argc);
8327 if (!argc || !argv || !argv2)
8330 memset(argv, 0, sizeof(gchar*) * max_argc);
8331 memset(argv2, 0, sizeof(gchar*) * max_argc);
8335 argv[0] = g_strdup("mmplayer");
8338 for (i = 0; i < 5; i++) {
8339 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8340 if (strlen(player->ini.gst_param[i]) > 0) {
8341 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8346 /* we would not do fork for scanning plugins */
8347 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8350 /* check disable registry scan */
8351 if (player->ini.skip_rescan) {
8352 argv[*argc] = g_strdup("--gst-disable-registry-update");
8356 /* check disable segtrap */
8357 if (player->ini.disable_segtrap) {
8358 argv[*argc] = g_strdup("--gst-disable-segtrap");
8362 LOGD("initializing gstreamer with following parameter\n");
8363 LOGD("argc : %d\n", *argc);
8366 for (i = 0; i < arg_count; i++) {
8368 LOGD("argv[%d] : %s\n", i, argv2[i]);
8371 /* initializing gstreamer */
8372 if (!gst_init_check(argc, &argv, &err)) {
8373 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8380 for (i = 0; i < arg_count; i++) {
8381 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8382 MMPLAYER_FREEIF(argv2[i]);
8385 MMPLAYER_FREEIF(argv);
8386 MMPLAYER_FREEIF(argv2);
8387 MMPLAYER_FREEIF(argc);
8397 for (i = 0; i < arg_count; i++) {
8398 LOGD("free[%d] : %s\n", i, argv2[i]);
8399 MMPLAYER_FREEIF(argv2[i]);
8402 MMPLAYER_FREEIF(argv);
8403 MMPLAYER_FREEIF(argv2);
8404 MMPLAYER_FREEIF(argc);
8410 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8414 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8415 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8416 MMPLAYER_FREEIF(player->pd_file_save_path);
8419 return MM_ERROR_NONE;
8423 __mmplayer_check_async_state_transition(mm_player_t* player)
8425 GstState element_state = GST_STATE_VOID_PENDING;
8426 GstState element_pending_state = GST_STATE_VOID_PENDING;
8427 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8428 GstElement * element = NULL;
8429 gboolean async = FALSE;
8431 /* check player handle */
8432 MMPLAYER_RETURN_IF_FAIL(player &&
8434 player->pipeline->mainbin &&
8435 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8438 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8440 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8441 LOGD("don't need to check the pipeline state");
8445 MMPLAYER_PRINT_STATE(player);
8447 /* wait for state transition */
8448 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8449 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8451 if (ret == GST_STATE_CHANGE_FAILURE) {
8452 LOGE(" [%s] state : %s pending : %s \n",
8453 GST_ELEMENT_NAME(element),
8454 gst_element_state_get_name(element_state),
8455 gst_element_state_get_name(element_pending_state));
8457 /* dump state of all element */
8458 __mmplayer_dump_pipeline_state(player);
8463 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8468 _mmplayer_destroy(MMHandleType handle)
8470 mm_player_t* player = MM_PLAYER_CAST(handle);
8474 /* check player handle */
8475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8477 /* destroy can called at anytime */
8478 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8480 /* check async state transition */
8481 __mmplayer_check_async_state_transition(player);
8483 __mmplayer_destroy_streaming_ext(player);
8485 /* release next play thread */
8486 if (player->next_play_thread) {
8487 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8488 player->next_play_thread_exit = TRUE;
8489 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8490 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8492 LOGD("waitting for next play thread exit\n");
8493 g_thread_join(player->next_play_thread);
8494 g_mutex_clear(&player->next_play_thread_mutex);
8495 g_cond_clear(&player->next_play_thread_cond);
8496 LOGD("next play thread released\n");
8499 _mmplayer_release_video_capture(player);
8501 /* de-initialize resource manager */
8502 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8503 player->resource_manager))
8504 LOGE("failed to deinitialize resource manager\n");
8506 /* release pipeline */
8507 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8508 LOGE("failed to destory pipeline\n");
8509 return MM_ERROR_PLAYER_INTERNAL;
8512 /* release subtitle info lock and cond */
8513 g_mutex_clear(&player->subtitle_info_mutex);
8514 g_cond_clear(&player->subtitle_info_cond);
8516 __mmplayer_release_dump_list(player->dump_list);
8518 /* release miscellaneous information */
8519 __mmplayer_release_misc(player);
8521 /* release miscellaneous information.
8522 these info needs to be released after pipeline is destroyed. */
8523 __mmplayer_release_misc_post(player);
8525 /* release attributes */
8526 _mmplayer_deconstruct_attribute(handle);
8529 g_mutex_clear(&player->fsink_lock);
8532 g_mutex_clear(&player->update_tag_lock);
8534 /* release video bo lock and cond */
8535 g_mutex_clear(&player->video_bo_mutex);
8536 g_cond_clear(&player->video_bo_cond);
8538 /* release media stream callback lock */
8539 g_mutex_clear(&player->media_stream_cb_lock);
8543 return MM_ERROR_NONE;
8547 __mmplayer_realize_streaming_ext(mm_player_t* player)
8549 int ret = MM_ERROR_NONE;
8552 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554 if (MMPLAYER_IS_HTTP_PD(player)) {
8555 gboolean bret = FALSE;
8557 player->pd_downloader = _mmplayer_create_pd_downloader();
8558 if (!player->pd_downloader) {
8559 LOGE("Unable to create PD Downloader...");
8560 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8563 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8565 if (FALSE == bret) {
8566 LOGE("Unable to create PD Downloader...");
8567 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8576 _mmplayer_realize(MMHandleType hplayer)
8578 mm_player_t* player = (mm_player_t*)hplayer;
8581 MMHandleType attrs = 0;
8582 int ret = MM_ERROR_NONE;
8586 /* check player handle */
8587 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8589 /* check current state */
8590 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8592 attrs = MMPLAYER_GET_ATTRS(player);
8594 LOGE("fail to get attributes.\n");
8595 return MM_ERROR_PLAYER_INTERNAL;
8597 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8598 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8600 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8601 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8603 if (ret != MM_ERROR_NONE) {
8604 LOGE("failed to parse profile\n");
8609 if (uri && (strstr(uri, "es_buff://"))) {
8610 if (strstr(uri, "es_buff://push_mode"))
8611 player->es_player_push_mode = TRUE;
8613 player->es_player_push_mode = FALSE;
8616 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8617 LOGW("mms protocol is not supported format.\n");
8618 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8621 if (MMPLAYER_IS_STREAMING(player))
8622 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8624 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8626 player->smooth_streaming = FALSE;
8627 player->videodec_linked = 0;
8628 player->videosink_linked = 0;
8629 player->audiodec_linked = 0;
8630 player->audiosink_linked = 0;
8631 player->textsink_linked = 0;
8632 player->is_external_subtitle_present = FALSE;
8633 player->is_external_subtitle_added_now = FALSE;
8634 /* set the subtitle ON default */
8635 player->is_subtitle_off = FALSE;
8637 /* realize pipeline */
8638 ret = __gst_realize(player);
8639 if (ret != MM_ERROR_NONE)
8640 LOGE("fail to realize the player.\n");
8642 ret = __mmplayer_realize_streaming_ext(player);
8644 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8645 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8653 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658 /* destroy can called at anytime */
8659 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8660 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8663 return MM_ERROR_NONE;
8667 _mmplayer_unrealize(MMHandleType hplayer)
8669 mm_player_t* player = (mm_player_t*)hplayer;
8670 int ret = MM_ERROR_NONE;
8674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676 MMPLAYER_CMD_UNLOCK(player);
8677 /* destroy the gst bus msg thread which is created during realize.
8678 this funct have to be called before getting cmd lock. */
8679 _mmplayer_bus_msg_thread_destroy(player);
8680 MMPLAYER_CMD_LOCK(player);
8682 /* check current state */
8683 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8685 /* check async state transition */
8686 __mmplayer_check_async_state_transition(player);
8688 __mmplayer_unrealize_streaming_ext(player);
8690 /* unrealize pipeline */
8691 ret = __gst_unrealize(player);
8693 /* set asm stop if success */
8694 if (MM_ERROR_NONE == ret) {
8695 if (!player->interrupted_by_resource) {
8696 if (player->video_decoder_resource != NULL) {
8697 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8698 player->video_decoder_resource);
8699 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8700 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8702 player->video_decoder_resource = NULL;
8705 if (player->video_overlay_resource != NULL) {
8706 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8707 player->video_overlay_resource);
8708 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8709 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8711 player->video_overlay_resource = NULL;
8714 ret = mm_resource_manager_commit(player->resource_manager);
8715 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8716 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8719 LOGE("failed and don't change asm state to stop");
8727 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8729 mm_player_t* player = (mm_player_t*)hplayer;
8731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 return __gst_set_message_callback(player, callback, user_param);
8737 _mmplayer_get_state(MMHandleType hplayer, int* state)
8739 mm_player_t *player = (mm_player_t*)hplayer;
8741 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8743 *state = MMPLAYER_CURRENT_STATE(player);
8745 return MM_ERROR_NONE;
8750 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8752 mm_player_t* player = (mm_player_t*) hplayer;
8753 GstElement* vol_element = NULL;
8758 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8760 LOGD("volume [L]=%f:[R]=%f\n",
8761 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8763 /* invalid factor range or not */
8764 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8765 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8766 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8767 return MM_ERROR_INVALID_ARGUMENT;
8771 /* not support to set other value into each channel */
8772 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8773 return MM_ERROR_INVALID_ARGUMENT;
8775 /* Save volume to handle. Currently the first array element will be saved. */
8776 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8778 /* check pipeline handle */
8779 if (!player->pipeline || !player->pipeline->audiobin) {
8780 LOGD("audiobin is not created yet\n");
8781 LOGD("but, current stored volume will be set when it's created.\n");
8783 /* NOTE : stored volume will be used in create_audiobin
8784 * returning MM_ERROR_NONE here makes application to able to
8785 * set volume at anytime.
8787 return MM_ERROR_NONE;
8790 /* setting volume to volume element */
8791 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8794 LOGD("volume is set [%f]\n", player->sound.volume);
8795 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8800 return MM_ERROR_NONE;
8805 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8807 mm_player_t* player = (mm_player_t*) hplayer;
8812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8813 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8815 /* returning stored volume */
8816 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8817 volume->level[i] = player->sound.volume;
8821 return MM_ERROR_NONE;
8825 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8827 mm_player_t* player = (mm_player_t*) hplayer;
8828 GstElement* vol_element = NULL;
8832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834 /* mute value shoud 0 or 1 */
8835 if (mute != 0 && mute != 1) {
8836 LOGE("bad mute value\n");
8838 /* FIXIT : definitly, we need _BAD_PARAM error code */
8839 return MM_ERROR_INVALID_ARGUMENT;
8842 player->sound.mute = mute;
8844 /* just hold mute value if pipeline is not ready */
8845 if (!player->pipeline || !player->pipeline->audiobin) {
8846 LOGD("pipeline is not ready. holding mute value\n");
8847 return MM_ERROR_NONE;
8850 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8852 /* NOTE : volume will only created when the bt is enabled */
8854 LOGD("mute : %d\n", mute);
8855 g_object_set(vol_element, "mute", mute, NULL);
8857 LOGD("volume elemnet is not created. using volume in audiosink\n");
8861 return MM_ERROR_NONE;
8865 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8867 mm_player_t* player = (mm_player_t*) hplayer;
8871 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8872 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8874 /* just hold mute value if pipeline is not ready */
8875 if (!player->pipeline || !player->pipeline->audiobin) {
8876 LOGD("pipeline is not ready. returning stored value\n");
8877 *pmute = player->sound.mute;
8878 return MM_ERROR_NONE;
8881 *pmute = player->sound.mute;
8885 return MM_ERROR_NONE;
8889 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8891 mm_player_t* player = (mm_player_t*) hplayer;
8895 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8897 player->video_stream_changed_cb = callback;
8898 player->video_stream_changed_cb_user_param = user_param;
8899 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8903 return MM_ERROR_NONE;
8907 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8909 mm_player_t* player = (mm_player_t*) hplayer;
8913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8915 player->audio_stream_changed_cb = callback;
8916 player->audio_stream_changed_cb_user_param = user_param;
8917 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8921 return MM_ERROR_NONE;
8925 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8927 mm_player_t* player = (mm_player_t*) hplayer;
8931 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8933 player->audio_stream_render_cb_ex = callback;
8934 player->audio_stream_cb_user_param = user_param;
8935 player->audio_stream_sink_sync = sync;
8936 LOGD("Audio Stream cb Handle value is %p : %p audio_stream_sink_sync : %d\n", player, player->audio_stream_render_cb_ex, player->audio_stream_sink_sync);
8940 return MM_ERROR_NONE;
8944 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8946 mm_player_t* player = (mm_player_t*) hplayer;
8950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8952 if (callback && !player->bufmgr)
8953 player->bufmgr = tbm_bufmgr_init(-1);
8955 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8956 player->video_stream_cb = callback;
8957 player->video_stream_cb_user_param = user_param;
8959 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8963 return MM_ERROR_NONE;
8967 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8969 mm_player_t* player = (mm_player_t*) hplayer;
8973 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8975 player->audio_stream_cb = callback;
8976 player->audio_stream_cb_user_param = user_param;
8977 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8981 return MM_ERROR_NONE;
8985 __mmplayer_start_streaming_ext(mm_player_t *player)
8987 gint ret = MM_ERROR_NONE;
8990 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8992 if (MMPLAYER_IS_HTTP_PD(player)) {
8993 if (!player->pd_downloader) {
8994 ret = __mmplayer_realize_streaming_ext(player);
8996 if (ret != MM_ERROR_NONE) {
8997 LOGE("failed to realize streaming ext\n");
9002 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9003 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9005 LOGE("ERROR while starting PD...\n");
9006 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9008 ret = MM_ERROR_NONE;
9017 _mmplayer_start(MMHandleType hplayer)
9019 mm_player_t* player = (mm_player_t*) hplayer;
9020 gint ret = MM_ERROR_NONE;
9024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9026 /* check current state */
9027 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9029 /* NOTE : we should check and create pipeline again if not created as we destroy
9030 * whole pipeline when stopping in streamming playback
9032 if (!player->pipeline) {
9033 ret = __gst_realize(player);
9034 if (MM_ERROR_NONE != ret) {
9035 LOGE("failed to realize before starting. only in streamming\n");
9041 ret = __mmplayer_start_streaming_ext(player);
9042 if (ret != MM_ERROR_NONE) {
9043 LOGE("failed to start streaming ext 0x%X", ret);
9047 /* start pipeline */
9048 ret = __gst_start(player);
9049 if (ret != MM_ERROR_NONE)
9050 LOGE("failed to start player.\n");
9057 /* NOTE: post "not supported codec message" to application
9058 * when one codec is not found during AUTOPLUGGING in MSL.
9059 * So, it's separated with error of __mmplayer_gst_callback().
9060 * And, if any codec is not found, don't send message here.
9061 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9064 __mmplayer_handle_missed_plugin(mm_player_t* player)
9066 MMMessageParamType msg_param;
9067 memset(&msg_param, 0, sizeof(MMMessageParamType));
9068 gboolean post_msg_direct = FALSE;
9072 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9074 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9075 player->not_supported_codec, player->can_support_codec);
9077 if (player->not_found_demuxer) {
9078 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9079 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9081 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9082 MMPLAYER_FREEIF(msg_param.data);
9084 return MM_ERROR_NONE;
9087 if (player->not_supported_codec) {
9088 if (player->can_support_codec) {
9089 // There is one codec to play
9090 post_msg_direct = TRUE;
9092 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9093 post_msg_direct = TRUE;
9096 if (post_msg_direct) {
9097 MMMessageParamType msg_param;
9098 memset(&msg_param, 0, sizeof(MMMessageParamType));
9100 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9101 LOGW("not found AUDIO codec, posting error code to application.\n");
9103 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9104 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9105 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9106 LOGW("not found VIDEO codec, posting error code to application.\n");
9108 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9109 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9112 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9114 MMPLAYER_FREEIF(msg_param.data);
9116 return MM_ERROR_NONE;
9118 // no any supported codec case
9119 LOGW("not found any codec, posting error code to application.\n");
9121 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9122 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9123 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9125 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9126 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9129 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9131 MMPLAYER_FREEIF(msg_param.data);
9137 return MM_ERROR_NONE;
9140 static void __mmplayer_check_pipeline(mm_player_t* player)
9142 GstState element_state = GST_STATE_VOID_PENDING;
9143 GstState element_pending_state = GST_STATE_VOID_PENDING;
9145 int ret = MM_ERROR_NONE;
9147 if (player->gapless.reconfigure) {
9148 LOGW("pipeline is under construction.\n");
9150 MMPLAYER_PLAYBACK_LOCK(player);
9151 MMPLAYER_PLAYBACK_UNLOCK(player);
9153 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9155 /* wait for state transition */
9156 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9158 if (ret == GST_STATE_CHANGE_FAILURE)
9159 LOGE("failed to change pipeline state within %d sec\n", timeout);
9163 /* NOTE : it should be able to call 'stop' anytime*/
9165 _mmplayer_stop(MMHandleType hplayer)
9167 mm_player_t* player = (mm_player_t*)hplayer;
9168 int ret = MM_ERROR_NONE;
9172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9174 /* check current state */
9175 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9177 /* check pipline building state */
9178 __mmplayer_check_pipeline(player);
9179 __mmplayer_reset_gapless_state(player);
9181 /* NOTE : application should not wait for EOS after calling STOP */
9182 __mmplayer_cancel_eos_timer(player);
9184 __mmplayer_unrealize_streaming_ext(player);
9187 player->doing_seek = FALSE;
9190 ret = __gst_stop(player);
9192 if (ret != MM_ERROR_NONE)
9193 LOGE("failed to stop player.\n");
9201 _mmplayer_pause(MMHandleType hplayer)
9203 mm_player_t* player = (mm_player_t*)hplayer;
9204 gint64 pos_msec = 0;
9205 gboolean async = FALSE;
9206 gint ret = MM_ERROR_NONE;
9210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9212 /* check current state */
9213 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9215 /* check pipline building state */
9216 __mmplayer_check_pipeline(player);
9218 switch (MMPLAYER_CURRENT_STATE(player)) {
9219 case MM_PLAYER_STATE_READY:
9221 /* check prepare async or not.
9222 * In the case of streaming playback, it's recommned to avoid blocking wait.
9224 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9225 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9227 /* Changing back sync of rtspsrc to async */
9228 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9229 LOGD("async prepare working mode for rtsp");
9235 case MM_PLAYER_STATE_PLAYING:
9237 /* NOTE : store current point to overcome some bad operation
9238 *(returning zero when getting current position in paused state) of some
9241 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9242 LOGW("getting current position failed in paused\n");
9244 player->last_position = pos_msec;
9246 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9247 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9248 This causes problem is position calculation during normal pause resume scenarios also.
9249 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9250 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9251 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9252 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9258 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9259 LOGD("doing async pause in case of ms buff src");
9263 /* pause pipeline */
9264 ret = __gst_pause(player, async);
9266 if (ret != MM_ERROR_NONE)
9267 LOGE("failed to pause player. ret : 0x%x\n", ret);
9269 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9270 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9271 LOGE("failed to update display_rotation");
9280 _mmplayer_resume(MMHandleType hplayer)
9282 mm_player_t* player = (mm_player_t*)hplayer;
9283 int ret = MM_ERROR_NONE;
9284 gboolean async = FALSE;
9288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9290 /* Changing back sync mode rtspsrc to async */
9291 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9292 LOGD("async resume for rtsp case");
9296 /* check current state */
9297 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9299 ret = __gst_resume(player, async);
9301 if (ret != MM_ERROR_NONE)
9302 LOGE("failed to resume player.\n");
9310 __mmplayer_set_pcm_extraction(mm_player_t* player)
9312 gint64 start_nsec = 0;
9313 gint64 end_nsec = 0;
9314 gint64 dur_nsec = 0;
9315 gint64 dur_msec = 0;
9316 int required_start = 0;
9317 int required_end = 0;
9322 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9324 mm_attrs_multiple_get(player->attrs,
9326 "pcm_extraction_start_msec", &required_start,
9327 "pcm_extraction_end_msec", &required_end,
9330 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9332 if (required_start == 0 && required_end == 0) {
9333 LOGD("extracting entire stream");
9334 return MM_ERROR_NONE;
9335 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9336 LOGD("invalid range for pcm extraction");
9337 return MM_ERROR_INVALID_ARGUMENT;
9341 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9343 LOGE("failed to get duration");
9344 return MM_ERROR_PLAYER_INTERNAL;
9346 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9348 if (dur_msec < required_end) {
9350 LOGD("invalid end pos for pcm extraction");
9351 return MM_ERROR_INVALID_ARGUMENT;
9354 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9355 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9357 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9360 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9361 GST_SEEK_TYPE_SET, start_nsec,
9362 GST_SEEK_TYPE_SET, end_nsec))) {
9363 LOGE("failed to seek for pcm extraction\n");
9365 return MM_ERROR_PLAYER_SEEK;
9368 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9372 return MM_ERROR_NONE;
9376 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9378 mm_player_t* player = (mm_player_t*)hplayer;
9379 gint64 pos_msec = 0;
9380 int ret = MM_ERROR_NONE;
9382 signed long long start = 0, stop = 0;
9383 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9386 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9387 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9389 /* The sound of video is not supported under 0.0 and over 2.0. */
9390 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9391 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9394 _mmplayer_set_mute(hplayer, mute);
9396 if (player->playback_rate == rate)
9397 return MM_ERROR_NONE;
9399 /* If the position is reached at start potion during fast backward, EOS is posted.
9400 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9402 player->playback_rate = rate;
9404 current_state = MMPLAYER_CURRENT_STATE(player);
9406 if (current_state != MM_PLAYER_STATE_PAUSED)
9407 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9409 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9411 if ((current_state == MM_PLAYER_STATE_PAUSED)
9412 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9413 LOGW("returning last point : %lld\n", player->last_position);
9414 pos_msec = player->last_position;
9419 stop = GST_CLOCK_TIME_NONE;
9421 start = GST_CLOCK_TIME_NONE;
9425 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9426 player->playback_rate,
9428 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9429 GST_SEEK_TYPE_SET, start,
9430 GST_SEEK_TYPE_SET, stop)) {
9431 LOGE("failed to set speed playback\n");
9432 return MM_ERROR_PLAYER_SEEK;
9435 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9439 return MM_ERROR_NONE;;
9443 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9445 mm_player_t* player = (mm_player_t*)hplayer;
9446 int ret = MM_ERROR_NONE;
9450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9452 /* check pipline building state */
9453 __mmplayer_check_pipeline(player);
9455 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9463 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9465 mm_player_t* player = (mm_player_t*)hplayer;
9466 int ret = MM_ERROR_NONE;
9468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9470 ret = __gst_get_position(player, format, position);
9476 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9478 mm_player_t* player = (mm_player_t*)hplayer;
9479 int ret = MM_ERROR_NONE;
9481 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9483 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9489 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9491 mm_player_t* player = (mm_player_t*)hplayer;
9492 int ret = MM_ERROR_NONE;
9496 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9498 ret = __gst_adjust_subtitle_position(player, format, position);
9505 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9507 mm_player_t* player = (mm_player_t*)hplayer;
9508 int ret = MM_ERROR_NONE;
9512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9514 ret = __gst_adjust_video_position(player, offset);
9522 __mmplayer_is_midi_type(gchar* str_caps)
9524 if ((g_strrstr(str_caps, "audio/midi")) ||
9525 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9526 (g_strrstr(str_caps, "application/x-smaf")) ||
9527 (g_strrstr(str_caps, "audio/x-imelody")) ||
9528 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9529 (g_strrstr(str_caps, "audio/xmf")) ||
9530 (g_strrstr(str_caps, "audio/mxmf"))) {
9539 __mmplayer_is_only_mp3_type(gchar *str_caps)
9541 if (g_strrstr(str_caps, "application/x-id3") ||
9542 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9548 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9550 GstStructure* caps_structure = NULL;
9551 gint samplerate = 0;
9555 MMPLAYER_RETURN_IF_FAIL(player && caps);
9557 caps_structure = gst_caps_get_structure(caps, 0);
9559 /* set stream information */
9560 gst_structure_get_int(caps_structure, "rate", &samplerate);
9561 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9563 gst_structure_get_int(caps_structure, "channels", &channels);
9564 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9566 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9570 __mmplayer_update_content_type_info(mm_player_t* player)
9573 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9575 if (__mmplayer_is_midi_type(player->type)) {
9576 player->bypass_audio_effect = TRUE;
9577 } else if (g_strrstr(player->type, "application/x-hls")) {
9578 /* If it can't know exact type when it parses uri because of redirection case,
9579 * it will be fixed by typefinder or when doing autoplugging.
9581 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9582 if (player->streamer) {
9583 player->streamer->is_adaptive_streaming = TRUE;
9584 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9585 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9587 } else if (g_strrstr(player->type, "application/dash+xml")) {
9588 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9595 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9596 GstCaps *caps, gpointer data)
9598 mm_player_t* player = (mm_player_t*)data;
9603 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9605 /* store type string */
9606 MMPLAYER_FREEIF(player->type);
9607 player->type = gst_caps_to_string(caps);
9609 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9610 player, player->type, probability, gst_caps_get_size(caps));
9613 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9614 (g_strrstr(player->type, "audio/x-raw-int"))) {
9615 LOGE("not support media format\n");
9617 if (player->msg_posted == FALSE) {
9618 MMMessageParamType msg_param;
9619 memset(&msg_param, 0, sizeof(MMMessageParamType));
9621 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9622 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9624 /* don't post more if one was sent already */
9625 player->msg_posted = TRUE;
9630 __mmplayer_update_content_type_info(player);
9632 pad = gst_element_get_static_pad(tf, "src");
9634 LOGE("fail to get typefind src pad.\n");
9638 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9639 gboolean async = FALSE;
9640 LOGE("failed to autoplug %s\n", player->type);
9642 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9644 if (async && player->msg_posted == FALSE)
9645 __mmplayer_handle_missed_plugin(player);
9651 gst_object_unref(GST_OBJECT(pad));
9659 __mmplayer_create_decodebin(mm_player_t* player)
9661 GstElement *decodebin = NULL;
9665 /* create decodebin */
9666 decodebin = gst_element_factory_make("decodebin", NULL);
9669 LOGE("fail to create decodebin\n");
9673 /* raw pad handling signal */
9674 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9675 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9677 /* no-more-pad pad handling signal */
9678 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9679 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9681 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9682 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9684 /* This signal is emitted when a pad for which there is no further possible
9685 decoding is added to the decodebin.*/
9686 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9687 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9689 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9690 before looking for any elements that can handle that stream.*/
9691 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9692 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9694 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9695 before looking for any elements that can handle that stream.*/
9696 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9697 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9699 /* This signal is emitted once decodebin has finished decoding all the data.*/
9700 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9701 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9703 /* This signal is emitted when a element is added to the bin.*/
9704 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9705 G_CALLBACK(__mmplayer_gst_element_added), player);
9712 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9714 MMPlayerGstElement* mainbin = NULL;
9715 GstElement* decodebin = NULL;
9716 GstElement* queue2 = NULL;
9717 GstPad* sinkpad = NULL;
9718 GstPad* qsrcpad = NULL;
9719 gint64 dur_bytes = 0L;
9721 guint max_buffer_size_bytes = 0;
9722 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9727 mainbin = player->pipeline->mainbin;
9729 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9730 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9731 LOGD("creating http streaming buffering queue(queue2)\n");
9733 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9734 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9736 queue2 = gst_element_factory_make("queue2", "queue2");
9738 LOGE("failed to create buffering queue element\n");
9742 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9743 LOGE("failed to add buffering queue\n");
9747 sinkpad = gst_element_get_static_pad(queue2, "sink");
9748 qsrcpad = gst_element_get_static_pad(queue2, "src");
9750 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9751 LOGE("failed to link buffering queue\n");
9755 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9756 LOGE("fail to get duration.\n");
9758 LOGD("dur_bytes = %lld\n", dur_bytes);
9760 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9762 if (dur_bytes > 0) {
9763 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9764 type = MUXED_BUFFER_TYPE_FILE;
9766 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9767 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9773 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9774 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9775 if (!g_strrstr(player->type, "video/mpegts")) {
9776 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9777 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9779 // FIXME : pass ini setting directly. is this ok?
9780 __mm_player_streaming_set_queue2(player->streamer,
9783 max_buffer_size_bytes,
9784 player->ini.http_buffering_time,
9786 player->ini.http_buffering_limit, // no meaning
9788 player->http_file_buffering_path,
9789 (guint64)dur_bytes);
9792 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9793 LOGE("failed to sync queue2 state with parent\n");
9799 gst_object_unref(GST_OBJECT(sinkpad));
9801 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9802 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9806 /* create decodebin */
9807 decodebin = __mmplayer_create_decodebin(player);
9810 LOGE("can not create autoplug element\n");
9814 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9815 LOGE("failed to add decodebin\n");
9819 /* to force caps on the decodebin element and avoid reparsing stuff by
9820 * typefind. It also avoids a deadlock in the way typefind activates pads in
9821 * the state change */
9822 g_object_set(decodebin, "sink-caps", caps, NULL);
9824 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9826 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9827 LOGE("failed to link decodebin\n");
9831 gst_object_unref(GST_OBJECT(sinkpad));
9833 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9834 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9836 /* set decodebin property about buffer in streaming playback. *
9837 * in case of HLS/DASH, it does not need to have big buffer *
9838 * because it is kind of adaptive streaming. */
9839 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9840 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9841 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9842 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9844 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9845 || MMPLAYER_IS_DASH_STREAMING(player)) {
9846 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9847 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9850 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9851 "high-percent", (gint)player->ini.http_buffering_limit,
9852 "low-percent", 1, // 1%
9853 "max-size-bytes", max_size_bytes,
9854 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9855 "max-size-buffers", 0, NULL); // disable or automatic
9858 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9859 LOGE("failed to sync decodebin state with parent\n");
9870 gst_object_unref(GST_OBJECT(sinkpad));
9873 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9874 * You need to explicitly set elements to the NULL state before
9875 * dropping the final reference, to allow them to clean up.
9877 gst_element_set_state(queue2, GST_STATE_NULL);
9879 /* And, it still has a parent "player".
9880 * You need to let the parent manage the object instead of unreffing the object directly.
9882 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9883 gst_object_unref(queue2);
9888 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9889 * You need to explicitly set elements to the NULL state before
9890 * dropping the final reference, to allow them to clean up.
9892 gst_element_set_state(decodebin, GST_STATE_NULL);
9894 /* And, it still has a parent "player".
9895 * You need to let the parent manage the object instead of unreffing the object directly.
9898 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9899 gst_object_unref(decodebin);
9907 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9911 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9912 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9914 LOGD("class : %s, mime : %s \n", factory_class, mime);
9916 /* add missing plugin */
9917 /* NOTE : msl should check missing plugin for image mime type.
9918 * Some motion jpeg clips can have playable audio track.
9919 * So, msl have to play audio after displaying popup written video format not supported.
9921 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9922 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9923 LOGD("not found demuxer\n");
9924 player->not_found_demuxer = TRUE;
9925 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9931 if (!g_strrstr(factory_class, "Demuxer")) {
9932 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9933 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9934 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9936 /* check that clip have multi tracks or not */
9937 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9938 LOGD("video plugin is already linked\n");
9940 LOGW("add VIDEO to missing plugin\n");
9941 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9942 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9944 } else if (g_str_has_prefix(mime, "audio")) {
9945 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9946 LOGD("audio plugin is already linked\n");
9948 LOGW("add AUDIO to missing plugin\n");
9949 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9950 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9958 return MM_ERROR_NONE;
9963 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9965 mm_player_t* player = (mm_player_t*)data;
9969 MMPLAYER_RETURN_IF_FAIL(player);
9971 /* remove fakesink. */
9972 if (!__mmplayer_gst_remove_fakesink(player,
9973 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9974 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9975 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9976 * source element are not same. To overcome this situation, this function will called
9977 * several places and several times. Therefore, this is not an error case.
9982 LOGD("[handle: %p] pipeline has completely constructed", player);
9984 if ((player->ini.async_start) &&
9985 (player->msg_posted == FALSE) &&
9986 (player->cmd >= MMPLAYER_COMMAND_START))
9987 __mmplayer_handle_missed_plugin(player);
9989 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
9993 __mmplayer_verify_next_play_path(mm_player_t *player)
9995 MMHandleType attrs = 0;
9996 MMPlayerParseProfile profile;
9997 gint uri_idx = 0, check_cnt = 0;
9999 gint mode = MM_PLAYER_PD_MODE_NONE;
10003 guint num_of_list = 0;
10004 static int profile_tv = -1;
10008 LOGD("checking for gapless play");
10010 if (player->pipeline->textbin) {
10011 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10015 attrs = MMPLAYER_GET_ATTRS(player);
10017 LOGE("fail to get attributes.\n");
10021 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10023 if (__builtin_expect(profile_tv == -1, 0)) {
10025 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10026 switch (*profileName) {
10036 /* gapless playback is not supported in case of video at TV profile. */
10037 if (profile_tv && video) {
10038 LOGW("not support video gapless playback");
10042 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10043 if (mode == TRUE) {
10049 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10050 LOGE("can not get play count\n");
10052 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10053 LOGE("can not get gapless mode\n");
10055 if (video && !gapless) {
10056 LOGW("not enabled video gapless playback");
10060 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10064 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10068 num_of_list = g_list_length(player->uri_info.uri_list);
10070 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10072 if (num_of_list == 0) {
10073 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10074 LOGE("can not get profile_uri\n");
10079 LOGE("uri list is empty.\n");
10083 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10084 LOGD("add original path : %s ", uri);
10090 uri_idx = player->uri_info.uri_idx;
10095 if (check_cnt > num_of_list) {
10096 LOGE("there is no valid uri.");
10100 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10102 if (uri_idx < num_of_list-1) {
10105 if ((count <= 1) && (count != -1)) {
10106 LOGD("no repeat.");
10108 } else if (count > 1) {
10109 /* decrease play count */
10110 /* we succeeded to rewind. update play count and then wait for next EOS */
10113 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10115 /* commit attribute */
10116 if (mmf_attrs_commit(attrs))
10117 LOGE("failed to commit attribute\n");
10120 /* count < 0 : repeat continually */
10124 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10125 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10128 LOGW("next uri does not exist\n");
10132 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10133 LOGE("failed to parse profile\n");
10137 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10138 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10139 LOGW("uri type is not supported(%d).", profile.uri_type);
10146 player->uri_info.uri_idx = uri_idx;
10147 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10149 if (mmf_attrs_commit(player->attrs)) {
10150 LOGE("failed to commit.\n");
10154 LOGD("next uri %s(%d)\n", uri, uri_idx);
10160 LOGE("unable to play next path. EOS will be posted soon.\n");
10165 __mmplayer_initialize_next_play(mm_player_t *player)
10171 player->smooth_streaming = FALSE;
10172 player->videodec_linked = 0;
10173 player->audiodec_linked = 0;
10174 player->videosink_linked = 0;
10175 player->audiosink_linked = 0;
10176 player->textsink_linked = 0;
10177 player->is_external_subtitle_present = FALSE;
10178 player->is_external_subtitle_added_now = FALSE;
10179 player->not_supported_codec = MISSING_PLUGIN_NONE;
10180 player->can_support_codec = FOUND_PLUGIN_NONE;
10181 player->pending_seek.is_pending = FALSE;
10182 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10183 player->pending_seek.pos = 0;
10184 player->msg_posted = FALSE;
10185 player->has_many_types = FALSE;
10186 player->no_more_pad = FALSE;
10187 player->not_found_demuxer = 0;
10188 player->doing_seek = FALSE;
10189 player->max_audio_channels = 0;
10190 player->is_subtitle_force_drop = FALSE;
10191 player->play_subtitle = FALSE;
10192 player->adjust_subtitle_pos = 0;
10194 player->total_bitrate = 0;
10195 player->total_maximum_bitrate = 0;
10197 _mmplayer_track_initialize(player);
10198 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10200 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10201 player->bitrate[i] = 0;
10202 player->maximum_bitrate[i] = 0;
10205 if (player->v_stream_caps) {
10206 gst_caps_unref(player->v_stream_caps);
10207 player->v_stream_caps = NULL;
10210 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10212 /* clean found parsers */
10213 if (player->parsers) {
10214 GList *parsers = player->parsers;
10215 for (; parsers; parsers = g_list_next(parsers)) {
10216 gchar *name = parsers->data;
10217 MMPLAYER_FREEIF(name);
10219 g_list_free(player->parsers);
10220 player->parsers = NULL;
10223 /* clean found audio decoders */
10224 if (player->audio_decoders) {
10225 GList *a_dec = player->audio_decoders;
10226 for (; a_dec; a_dec = g_list_next(a_dec)) {
10227 gchar *name = a_dec->data;
10228 MMPLAYER_FREEIF(name);
10230 g_list_free(player->audio_decoders);
10231 player->audio_decoders = NULL;
10238 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10240 MMPlayerGstElement *mainbin = NULL;
10241 MMMessageParamType msg_param = {0,};
10242 GstElement *element = NULL;
10243 MMHandleType attrs = 0;
10245 enum MainElementID elemId = MMPLAYER_M_NUM;
10249 if ((player == NULL) ||
10250 (player->pipeline == NULL) ||
10251 (player->pipeline->mainbin == NULL)) {
10252 LOGE("player is null.\n");
10256 mainbin = player->pipeline->mainbin;
10257 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10259 attrs = MMPLAYER_GET_ATTRS(player);
10261 LOGE("fail to get attributes.\n");
10265 /* Initialize Player values */
10266 __mmplayer_initialize_next_play(player);
10268 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10270 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10271 LOGE("failed to parse profile\n");
10272 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10276 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10277 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10278 LOGE("it's dash or hls. not support.");
10279 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10284 switch (player->profile.uri_type) {
10286 case MM_PLAYER_URI_TYPE_FILE:
10288 LOGD("using filesrc for 'file://' handler.\n");
10289 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10290 LOGE("failed to get storage info");
10294 element = gst_element_factory_make("filesrc", "source");
10297 LOGE("failed to create filesrc\n");
10301 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10304 case MM_PLAYER_URI_TYPE_URL_HTTP:
10306 gchar *user_agent, *cookies, **cookie_list;
10307 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10308 user_agent = cookies = NULL;
10309 cookie_list = NULL;
10311 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10313 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10316 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10318 /* get attribute */
10319 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10320 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10322 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10323 LOGD("get timeout from ini\n");
10324 http_timeout = player->ini.http_timeout;
10327 /* get attribute */
10328 SECURE_LOGD("location : %s\n", player->profile.uri);
10329 SECURE_LOGD("cookies : %s\n", cookies);
10330 SECURE_LOGD("user_agent : %s\n", user_agent);
10331 LOGD("timeout : %d\n", http_timeout);
10333 /* setting property to streaming source */
10334 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10335 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10336 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10338 /* parsing cookies */
10339 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10340 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10342 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10346 LOGE("not support uri type %d\n", player->profile.uri_type);
10351 LOGE("no source element was created.\n");
10355 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10356 LOGE("failed to add source element to pipeline\n");
10357 gst_object_unref(GST_OBJECT(element));
10362 /* take source element */
10363 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10364 mainbin[MMPLAYER_M_SRC].gst = element;
10368 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10369 if (player->streamer == NULL) {
10370 player->streamer = __mm_player_streaming_create();
10371 __mm_player_streaming_initialize(player->streamer);
10374 elemId = MMPLAYER_M_TYPEFIND;
10375 element = gst_element_factory_make("typefind", "typefinder");
10376 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10377 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10379 elemId = MMPLAYER_M_AUTOPLUG;
10380 element = __mmplayer_create_decodebin(player);
10383 /* check autoplug element is OK */
10385 LOGE("can not create element(%d)\n", elemId);
10389 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10390 LOGE("failed to add sinkbin to pipeline\n");
10391 gst_object_unref(GST_OBJECT(element));
10396 mainbin[elemId].id = elemId;
10397 mainbin[elemId].gst = element;
10399 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10400 LOGE("Failed to link src - autoplug(or typefind)\n");
10404 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10405 LOGE("Failed to change state of src element\n");
10409 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10410 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10411 LOGE("Failed to change state of decodebin\n");
10415 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10416 LOGE("Failed to change state of src element\n");
10421 player->gapless.stream_changed = TRUE;
10422 player->gapless.running = TRUE;
10428 MMPLAYER_PLAYBACK_UNLOCK(player);
10430 if (!player->msg_posted) {
10431 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10432 player->msg_posted = TRUE;
10439 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10441 mm_player_selector_t *selector = &player->selector[type];
10442 MMPlayerGstElement *sinkbin = NULL;
10443 enum MainElementID selectorId = MMPLAYER_M_NUM;
10444 enum MainElementID sinkId = MMPLAYER_M_NUM;
10445 GstPad *srcpad = NULL;
10446 GstPad *sinkpad = NULL;
10447 gboolean send_notice = FALSE;
10450 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10452 LOGD("type %d", type);
10455 case MM_PLAYER_TRACK_TYPE_AUDIO:
10456 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10457 sinkId = MMPLAYER_A_BIN;
10458 sinkbin = player->pipeline->audiobin;
10460 case MM_PLAYER_TRACK_TYPE_VIDEO:
10461 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10462 sinkId = MMPLAYER_V_BIN;
10463 sinkbin = player->pipeline->videobin;
10464 send_notice = TRUE;
10466 case MM_PLAYER_TRACK_TYPE_TEXT:
10467 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10468 sinkId = MMPLAYER_T_BIN;
10469 sinkbin = player->pipeline->textbin;
10472 LOGE("requested type is not supportable");
10477 if (player->pipeline->mainbin[selectorId].gst) {
10480 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10482 if (selector->event_probe_id != 0)
10483 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10484 selector->event_probe_id = 0;
10486 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10487 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10489 if (srcpad && sinkpad) {
10490 /* after getting drained signal there is no data flows, so no need to do pad_block */
10491 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10492 gst_pad_unlink(srcpad, sinkpad);
10494 /* send custom event to sink pad to handle it at video sink */
10496 LOGD("send custom event to sinkpad");
10497 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10498 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10499 gst_pad_send_event(sinkpad, event);
10503 gst_object_unref(sinkpad);
10506 gst_object_unref(srcpad);
10509 LOGD("selector release");
10511 /* release and unref requests pad from the selector */
10512 for (n = 0; n < selector->channels->len; n++) {
10513 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10514 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10516 g_ptr_array_set_size(selector->channels, 0);
10518 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10519 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10521 player->pipeline->mainbin[selectorId].gst = NULL;
10529 __mmplayer_deactivate_old_path(mm_player_t *player)
10532 MMPLAYER_RETURN_IF_FAIL(player);
10534 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10535 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10536 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10537 LOGE("deactivate selector error");
10541 _mmplayer_track_destroy(player);
10542 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10544 if (player->streamer) {
10545 __mm_player_streaming_deinitialize(player->streamer);
10546 __mm_player_streaming_destroy(player->streamer);
10547 player->streamer = NULL;
10550 MMPLAYER_PLAYBACK_LOCK(player);
10551 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10558 if (!player->msg_posted) {
10559 MMMessageParamType msg = {0,};
10562 msg.code = MM_ERROR_PLAYER_INTERNAL;
10563 LOGE("next_uri_play> deactivate error");
10565 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10566 player->msg_posted = TRUE;
10571 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10573 int result = MM_ERROR_NONE;
10574 mm_player_t* player = (mm_player_t*) hplayer;
10577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10580 player->http_file_buffering_path = (gchar*)file_path;
10581 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10587 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10589 int result = MM_ERROR_NONE;
10590 mm_player_t* player = (mm_player_t*) hplayer;
10593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10595 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10596 if (mmf_attrs_commit(player->attrs)) {
10597 LOGE("failed to commit the original uri.\n");
10598 result = MM_ERROR_PLAYER_INTERNAL;
10600 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10601 LOGE("failed to add the original uri in the uri list.\n");
10608 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10610 mm_player_t* player = (mm_player_t*) hplayer;
10611 guint num_of_list = 0;
10615 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10616 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10618 if (player->pipeline && player->pipeline->textbin) {
10619 LOGE("subtitle path is enabled.\n");
10620 return MM_ERROR_PLAYER_INVALID_STATE;
10623 num_of_list = g_list_length(player->uri_info.uri_list);
10625 if (is_first_path == TRUE) {
10626 if (num_of_list == 0) {
10627 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10628 LOGD("add original path : %s", uri);
10630 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10631 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10633 LOGD("change original path : %s", uri);
10636 MMHandleType attrs = 0;
10637 attrs = MMPLAYER_GET_ATTRS(player);
10639 if (num_of_list == 0) {
10640 char *original_uri = NULL;
10643 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10645 if (!original_uri) {
10646 LOGE("there is no original uri.");
10647 return MM_ERROR_PLAYER_INVALID_STATE;
10650 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10651 player->uri_info.uri_idx = 0;
10653 LOGD("add original path at first : %s(%d)", original_uri);
10657 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10658 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10662 return MM_ERROR_NONE;
10665 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10667 mm_player_t* player = (mm_player_t*) hplayer;
10668 char *next_uri = NULL;
10669 guint num_of_list = 0;
10672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10674 num_of_list = g_list_length(player->uri_info.uri_list);
10676 if (num_of_list > 0) {
10677 gint uri_idx = player->uri_info.uri_idx;
10679 if (uri_idx < num_of_list-1)
10684 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10685 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10687 *uri = g_strdup(next_uri);
10691 return MM_ERROR_NONE;
10695 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10696 GstCaps *caps, gpointer data)
10698 mm_player_t* player = (mm_player_t*)data;
10699 const gchar* klass = NULL;
10700 const gchar* mime = NULL;
10701 gchar* caps_str = NULL;
10703 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10704 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10705 caps_str = gst_caps_to_string(caps);
10707 LOGW("unknown type of caps : %s from %s",
10708 caps_str, GST_ELEMENT_NAME(elem));
10710 MMPLAYER_FREEIF(caps_str);
10712 /* There is no available codec. */
10713 __mmplayer_check_not_supported_codec(player, klass, mime);
10717 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10718 GstCaps * caps, gpointer data)
10720 mm_player_t* player = (mm_player_t*)data;
10721 const char* mime = NULL;
10722 gboolean ret = TRUE;
10724 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10725 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10727 if (g_str_has_prefix(mime, "audio")) {
10728 GstStructure* caps_structure = NULL;
10729 gint samplerate = 0;
10731 gchar *caps_str = NULL;
10733 caps_structure = gst_caps_get_structure(caps, 0);
10734 gst_structure_get_int(caps_structure, "rate", &samplerate);
10735 gst_structure_get_int(caps_structure, "channels", &channels);
10737 if ((channels > 0 && samplerate == 0)) {
10738 LOGD("exclude audio...");
10742 caps_str = gst_caps_to_string(caps);
10743 /* set it directly because not sent by TAG */
10744 if (g_strrstr(caps_str, "mobile-xmf"))
10745 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10746 MMPLAYER_FREEIF(caps_str);
10747 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10748 MMMessageParamType msg_param;
10749 memset(&msg_param, 0, sizeof(MMMessageParamType));
10750 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10751 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10752 LOGD("video file is not supported on this device");
10754 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10755 LOGD("already video linked");
10758 LOGD("found new stream");
10765 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10767 int ret = MM_ERROR_NONE;
10769 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10771 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10772 GstStructure* str = NULL;
10774 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10776 LOGD("audio codec type: %d", codec_type);
10777 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10778 /* sw codec will be skipped */
10779 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10780 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10781 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10782 ret = MM_ERROR_PLAYER_INTERNAL;
10786 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10787 /* hw codec will be skipped */
10788 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10789 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10790 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10791 ret = MM_ERROR_PLAYER_INTERNAL;
10796 str = gst_caps_get_structure(caps, 0);
10798 gst_structure_get_int(str, "channels", &channels);
10800 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10801 if (player->max_audio_channels < channels)
10802 player->max_audio_channels = channels;
10804 /* set stream information */
10805 if (!player->audiodec_linked)
10806 __mmplayer_set_audio_attrs(player, caps);
10808 /* update codec info */
10809 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10810 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10811 player->audiodec_linked = 1;
10813 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10815 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10817 LOGD("video codec type: %d", codec_type);
10818 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10819 /* sw codec is skipped */
10820 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10821 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10822 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10823 ret = MM_ERROR_PLAYER_INTERNAL;
10827 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10828 /* hw codec is skipped */
10829 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10830 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10831 ret = MM_ERROR_PLAYER_INTERNAL;
10836 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10837 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10839 /* mark video decoder for acquire */
10840 if (player->video_decoder_resource == NULL) {
10841 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10842 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10843 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10844 &player->video_decoder_resource)
10845 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10846 LOGE("could not mark video_decoder resource for acquire");
10847 ret = MM_ERROR_PLAYER_INTERNAL;
10851 LOGW("video decoder resource is already acquired, skip it.");
10852 ret = MM_ERROR_PLAYER_INTERNAL;
10856 player->interrupted_by_resource = FALSE;
10857 /* acquire resources for video playing */
10858 if (mm_resource_manager_commit(player->resource_manager)
10859 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10860 LOGE("could not acquire resources for video decoding\n");
10861 ret = MM_ERROR_PLAYER_INTERNAL;
10866 /* update codec info */
10867 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10868 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10869 player->videodec_linked = 1;
10877 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10878 GstCaps* caps, GstElementFactory* factory, gpointer data)
10880 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10881 We are defining our own and will be removed when it actually exposed */
10883 GST_AUTOPLUG_SELECT_TRY,
10884 GST_AUTOPLUG_SELECT_EXPOSE,
10885 GST_AUTOPLUG_SELECT_SKIP
10886 } GstAutoplugSelectResult;
10888 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10889 mm_player_t* player = (mm_player_t*)data;
10891 gchar* factory_name = NULL;
10892 gchar* caps_str = NULL;
10893 const gchar* klass = NULL;
10896 factory_name = GST_OBJECT_NAME(factory);
10897 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10898 caps_str = gst_caps_to_string(caps);
10900 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10902 /* store type string */
10903 if (player->type == NULL) {
10904 player->type = gst_caps_to_string(caps);
10905 __mmplayer_update_content_type_info(player);
10908 /* filtering exclude keyword */
10909 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10910 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10911 LOGW("skipping [%s] by exculde keyword [%s]\n",
10912 factory_name, player->ini.exclude_element_keyword[idx]);
10914 result = GST_AUTOPLUG_SELECT_SKIP;
10919 /* exclude webm format */
10920 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10921 * because webm format is not supportable.
10922 * If webm is disabled in "autoplug-continue", there is no state change
10923 * failure or error because the decodebin will expose the pad directly.
10924 * It make MSL invoke _prepare_async_callback.
10925 * So, we need to disable webm format in "autoplug-select" */
10926 if (caps_str && strstr(caps_str, "webm")) {
10927 LOGW("webm is not supported");
10928 result = GST_AUTOPLUG_SELECT_SKIP;
10932 /* check factory class for filtering */
10933 /* NOTE : msl don't need to use image plugins.
10934 * So, those plugins should be skipped for error handling.
10936 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10937 LOGD("skipping [%s] by not required\n", factory_name);
10938 result = GST_AUTOPLUG_SELECT_SKIP;
10942 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10943 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10944 // TO CHECK : subtitle if needed, add subparse exception.
10945 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10946 result = GST_AUTOPLUG_SELECT_SKIP;
10950 if (g_strrstr(factory_name, "mpegpsdemux")) {
10951 LOGD("skipping PS container - not support\n");
10952 result = GST_AUTOPLUG_SELECT_SKIP;
10956 if (g_strrstr(factory_name, "mssdemux"))
10957 player->smooth_streaming = TRUE;
10959 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10960 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10963 GstStructure *str = NULL;
10964 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10966 /* don't make video because of not required */
10967 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10968 (player->set_mode.media_packet_video_stream == FALSE)) {
10969 LOGD("no video because it's not required. -> return expose");
10970 result = GST_AUTOPLUG_SELECT_EXPOSE;
10974 /* get w/h for omx state-tune */
10975 /* FIXME: deprecated? */
10976 str = gst_caps_get_structure(caps, 0);
10977 gst_structure_get_int(str, "width", &width);
10980 if (player->v_stream_caps) {
10981 gst_caps_unref(player->v_stream_caps);
10982 player->v_stream_caps = NULL;
10985 player->v_stream_caps = gst_caps_copy(caps);
10986 LOGD("take caps for video state tune");
10987 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
10991 if (g_strrstr(klass, "Codec/Decoder")) {
10992 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
10993 LOGD("skipping %s codec", factory_name);
10994 result = GST_AUTOPLUG_SELECT_SKIP;
11000 MMPLAYER_FREEIF(caps_str);
11006 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11009 //mm_player_t* player = (mm_player_t*)data;
11010 GstCaps* caps = NULL;
11012 LOGD("[Decodebin2] pad-removed signal\n");
11014 caps = gst_pad_query_caps(new_pad, NULL);
11016 gchar* caps_str = NULL;
11017 caps_str = gst_caps_to_string(caps);
11019 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11021 MMPLAYER_FREEIF(caps_str);
11022 gst_caps_unref(caps);
11027 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11029 mm_player_t* player = (mm_player_t*)data;
11030 GstIterator *iter = NULL;
11031 GValue item = { 0, };
11032 GstPad *pad = NULL;
11033 gboolean done = FALSE;
11034 gboolean is_all_drained = TRUE;
11037 MMPLAYER_RETURN_IF_FAIL(player);
11039 LOGD("__mmplayer_gst_decode_drained");
11041 if (player->use_deinterleave == TRUE) {
11042 LOGD("group playing mode.");
11046 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11047 LOGW("Fail to get cmd lock");
11051 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11052 !__mmplayer_verify_next_play_path(player)) {
11053 LOGD("decoding is finished.");
11054 __mmplayer_reset_gapless_state(player);
11055 MMPLAYER_CMD_UNLOCK(player);
11059 player->gapless.reconfigure = TRUE;
11061 /* check decodebin src pads whether they received EOS or not */
11062 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11065 switch (gst_iterator_next(iter, &item)) {
11066 case GST_ITERATOR_OK:
11067 pad = g_value_get_object(&item);
11068 if (pad && !GST_PAD_IS_EOS(pad)) {
11069 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11070 is_all_drained = FALSE;
11073 g_value_reset(&item);
11075 case GST_ITERATOR_RESYNC:
11076 gst_iterator_resync(iter);
11078 case GST_ITERATOR_ERROR:
11079 case GST_ITERATOR_DONE:
11084 g_value_unset(&item);
11085 gst_iterator_free(iter);
11087 if (!is_all_drained) {
11088 LOGD("Wait util the all pads get EOS.");
11089 MMPLAYER_CMD_UNLOCK(player);
11094 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11095 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11097 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11098 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11099 __mmplayer_deactivate_old_path(player);
11100 MMPLAYER_CMD_UNLOCK(player);
11106 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11108 mm_player_t* player = (mm_player_t*)data;
11109 const gchar* klass = NULL;
11110 gchar* factory_name = NULL;
11112 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11113 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11115 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11117 if (__mmplayer_add_dump_buffer_probe(player, element))
11118 LOGD("add buffer probe");
11121 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11122 gchar* selected = NULL;
11123 selected = g_strdup(GST_ELEMENT_NAME(element));
11124 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11128 if (g_strrstr(klass, "Parser")) {
11129 gchar* selected = NULL;
11131 selected = g_strdup(factory_name);
11132 player->parsers = g_list_append(player->parsers, selected);
11135 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11136 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11137 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11139 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11140 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11142 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11143 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11144 "max-video-width", player->adaptive_info.limit.width,
11145 "max-video-height", player->adaptive_info.limit.height, NULL);
11147 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11148 /* FIXIT : first value will be overwritten if there's more
11149 * than 1 demuxer/parser
11152 //LOGD("plugged element is demuxer. take it\n");
11153 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11154 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11156 /*Added for multi audio support */ // Q. del?
11157 if (g_strrstr(klass, "Demux")) {
11158 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11159 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11163 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11164 int surface_type = 0;
11166 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11169 // to support trust-zone only
11170 if (g_strrstr(factory_name, "asfdemux")) {
11171 LOGD("set file-location %s\n", player->profile.uri);
11172 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11174 if (player->video_hub_download_mode == TRUE)
11175 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11176 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11177 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11178 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11179 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11180 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11181 (__mmplayer_is_only_mp3_type(player->type))) {
11182 LOGD("[mpegaudioparse] set streaming pull mode.");
11183 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11185 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11186 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11189 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11190 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11191 LOGD("plugged element is multiqueue. take it\n");
11193 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11194 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11196 if (!MMPLAYER_IS_HTTP_PD(player) &&
11197 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11198 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11199 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11200 __mm_player_streaming_set_multiqueue(player->streamer,
11203 player->ini.http_buffering_time,
11205 player->ini.http_buffering_limit);
11207 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11214 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11217 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11219 if (MMPLAYER_IS_STREAMING(player))
11222 /* This callback can be set to music player only. */
11223 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11224 LOGW("audio callback is not supported for video");
11228 if (player->audio_stream_cb) {
11229 GstPad *pad = NULL;
11231 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11234 LOGE("failed to get sink pad from audiosink to probe data\n");
11237 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11238 __mmplayer_audio_stream_probe, player, NULL);
11240 gst_object_unref(pad);
11244 LOGE("There is no audio callback to configure.\n");
11254 __mmplayer_release_misc(mm_player_t* player)
11257 bool cur_mode = player->set_mode.rich_audio;
11260 MMPLAYER_RETURN_IF_FAIL(player);
11262 player->video_stream_cb = NULL;
11263 player->video_stream_cb_user_param = NULL;
11264 player->video_stream_prerolled = FALSE;
11266 player->audio_stream_cb = NULL;
11267 player->audio_stream_render_cb_ex = NULL;
11268 player->audio_stream_cb_user_param = NULL;
11269 player->audio_stream_sink_sync = false;
11271 player->video_stream_changed_cb = NULL;
11272 player->video_stream_changed_cb_user_param = NULL;
11274 player->audio_stream_changed_cb = NULL;
11275 player->audio_stream_changed_cb_user_param = NULL;
11277 player->sent_bos = FALSE;
11278 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11280 player->doing_seek = FALSE;
11282 player->total_bitrate = 0;
11283 player->total_maximum_bitrate = 0;
11285 player->not_found_demuxer = 0;
11287 player->last_position = 0;
11288 player->duration = 0;
11289 player->http_content_size = 0;
11290 player->not_supported_codec = MISSING_PLUGIN_NONE;
11291 player->can_support_codec = FOUND_PLUGIN_NONE;
11292 player->pending_seek.is_pending = FALSE;
11293 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11294 player->pending_seek.pos = 0;
11295 player->msg_posted = FALSE;
11296 player->has_many_types = FALSE;
11297 player->max_audio_channels = 0;
11298 player->video_share_api_delta = 0;
11299 player->video_share_clock_delta = 0;
11300 player->is_subtitle_force_drop = FALSE;
11301 player->play_subtitle = FALSE;
11302 player->adjust_subtitle_pos = 0;
11303 player->last_multiwin_status = FALSE;
11304 player->has_closed_caption = FALSE;
11305 player->set_mode.media_packet_video_stream = FALSE;
11306 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11307 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11309 player->set_mode.rich_audio = cur_mode;
11311 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11312 player->bitrate[i] = 0;
11313 player->maximum_bitrate[i] = 0;
11316 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11318 /* remove media stream cb(appsrc cb) */
11319 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11320 player->media_stream_buffer_status_cb[i] = NULL;
11321 player->media_stream_seek_data_cb[i] = NULL;
11322 player->buffer_cb_user_param[i] = NULL;
11323 player->seek_cb_user_param[i] = NULL;
11325 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11327 /* free memory related to audio effect */
11328 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11330 if (player->adaptive_info.var_list) {
11331 g_list_free_full(player->adaptive_info.var_list, g_free);
11332 player->adaptive_info.var_list = NULL;
11335 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11336 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11337 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11339 /* Reset video360 settings to their defaults in case if the pipeline is to be
11342 player->video360_metadata.is_spherical = -1;
11343 player->is_openal_plugin_used = FALSE;
11345 player->is_content_spherical = FALSE;
11346 player->is_video360_enabled = TRUE;
11347 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11348 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11349 player->video360_yaw_radians = 4;
11350 player->video360_pitch_radians = 4;
11351 player->video360_zoom = 1.0f;
11352 player->video360_horizontal_fov = 0;
11353 player->video360_vertical_fov = 0;
11355 player->sound.rg_enable = false;
11361 __mmplayer_release_misc_post(mm_player_t* player)
11363 char *original_uri = NULL;
11366 /* player->pipeline is already released before. */
11368 MMPLAYER_RETURN_IF_FAIL(player);
11370 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11372 /* clean found parsers */
11373 if (player->parsers) {
11374 GList *parsers = player->parsers;
11375 for (; parsers; parsers = g_list_next(parsers)) {
11376 gchar *name = parsers->data;
11377 MMPLAYER_FREEIF(name);
11379 g_list_free(player->parsers);
11380 player->parsers = NULL;
11383 /* clean found audio decoders */
11384 if (player->audio_decoders) {
11385 GList *a_dec = player->audio_decoders;
11386 for (; a_dec; a_dec = g_list_next(a_dec)) {
11387 gchar *name = a_dec->data;
11388 MMPLAYER_FREEIF(name);
11390 g_list_free(player->audio_decoders);
11391 player->audio_decoders = NULL;
11394 /* clean the uri list except original uri */
11395 if (player->uri_info.uri_list) {
11396 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11398 if (player->attrs) {
11399 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11400 LOGD("restore original uri = %s\n", original_uri);
11402 if (mmf_attrs_commit(player->attrs))
11403 LOGE("failed to commit the original uri.\n");
11406 GList *uri_list = player->uri_info.uri_list;
11407 for (; uri_list; uri_list = g_list_next(uri_list)) {
11408 gchar *uri = uri_list->data;
11409 MMPLAYER_FREEIF(uri);
11411 g_list_free(player->uri_info.uri_list);
11412 player->uri_info.uri_list = NULL;
11415 /* clear the audio stream buffer list */
11416 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11418 /* clear the video stream bo list */
11419 __mmplayer_video_stream_destroy_bo_list(player);
11420 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11422 if (player->profile.input_mem.buf) {
11423 free(player->profile.input_mem.buf);
11424 player->profile.input_mem.buf = NULL;
11426 player->profile.input_mem.len = 0;
11427 player->profile.input_mem.offset = 0;
11429 player->uri_info.uri_idx = 0;
11433 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11435 GstElement *element = NULL;
11438 LOGD("creating %s to plug\n", name);
11440 element = gst_element_factory_make(name, NULL);
11442 LOGE("failed to create queue\n");
11446 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11447 LOGE("failed to set state READY to %s\n", name);
11448 gst_object_unref(element);
11452 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11453 LOGE("failed to add %s\n", name);
11454 gst_object_unref(element);
11458 sinkpad = gst_element_get_static_pad(element, "sink");
11460 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11461 LOGE("failed to link %s\n", name);
11462 gst_object_unref(sinkpad);
11463 gst_object_unref(element);
11467 LOGD("linked %s to pipeline successfully\n", name);
11469 gst_object_unref(sinkpad);
11475 __mmplayer_check_subtitle(mm_player_t* player)
11477 MMHandleType attrs = 0;
11478 char *subtitle_uri = NULL;
11482 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11484 /* get subtitle attribute */
11485 attrs = MMPLAYER_GET_ATTRS(player);
11489 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11490 if (!subtitle_uri || !strlen(subtitle_uri))
11493 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11494 player->is_external_subtitle_present = TRUE;
11502 __mmplayer_can_extract_pcm(mm_player_t* player)
11504 MMHandleType attrs = 0;
11505 gboolean sound_extraction = FALSE;
11507 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11509 attrs = MMPLAYER_GET_ATTRS(player);
11511 LOGE("fail to get attributes.");
11515 /* get sound_extraction property */
11516 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11518 if (!sound_extraction) {
11519 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11527 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11530 MMMessageParamType msg_param;
11531 gchar *msg_src_element = NULL;
11532 GstStructure *s = NULL;
11533 guint error_id = 0;
11534 gchar *error_string = NULL;
11538 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11539 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11541 s = gst_structure_copy(gst_message_get_structure(message));
11544 if (!gst_structure_get_uint(s, "error_id", &error_id))
11545 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11547 switch (error_id) {
11548 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11549 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11551 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11552 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11554 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11555 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11557 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11558 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11560 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11561 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11563 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11564 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11566 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11567 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11569 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11570 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11572 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11573 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11575 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11576 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11578 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11579 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11581 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11582 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11584 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11585 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11587 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11588 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11590 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11591 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11593 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11594 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11596 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11597 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11599 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11600 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11602 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11603 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11605 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11606 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11608 case MMPLAYER_STREAMING_ERROR_GONE:
11609 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11611 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11612 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11614 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11615 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11617 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11618 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11620 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11621 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11623 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11624 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11626 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11627 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11629 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11630 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11632 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11633 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11635 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11636 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11638 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11639 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11641 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11642 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11644 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11645 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11647 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11648 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11650 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11651 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11653 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11654 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11656 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11657 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11659 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11660 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11662 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11663 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11665 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11666 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11668 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11669 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11671 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11672 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11674 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11675 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11677 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11678 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11680 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11681 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11685 gst_structure_free(s);
11686 return MM_ERROR_PLAYER_STREAMING_FAIL;
11690 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11692 msg_param.data = (void *) error_string;
11694 if (message->src) {
11695 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11697 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11698 msg_src_element, msg_param.code, (char*)msg_param.data);
11701 /* post error to application */
11702 if (!player->msg_posted) {
11703 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11705 /* don't post more if one was sent already */
11706 player->msg_posted = TRUE;
11708 LOGD("skip error post because it's sent already.\n");
11710 gst_structure_free(s);
11712 g_free(error_string);
11719 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11721 MMPLAYER_RETURN_IF_FAIL(player);
11723 /* post now if delay is zero */
11724 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11725 LOGD("eos delay is zero. posting EOS now\n");
11726 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11728 if (player->set_mode.pcm_extraction)
11729 __mmplayer_cancel_eos_timer(player);
11734 /* cancel if existing */
11735 __mmplayer_cancel_eos_timer(player);
11737 /* init new timeout */
11738 /* NOTE : consider give high priority to this timer */
11739 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11741 player->eos_timer = g_timeout_add(delay_in_ms,
11742 __mmplayer_eos_timer_cb, player);
11744 player->global_default = g_main_context_default();
11745 LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11747 /* check timer is valid. if not, send EOS now */
11748 if (player->eos_timer == 0) {
11749 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11750 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11755 __mmplayer_cancel_eos_timer(mm_player_t* player)
11757 MMPLAYER_RETURN_IF_FAIL(player);
11759 if (player->eos_timer) {
11760 LOGD("cancel eos timer");
11761 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11762 player->eos_timer = 0;
11769 __mmplayer_eos_timer_cb(gpointer u_data)
11771 mm_player_t* player = NULL;
11772 MMHandleType attrs = 0;
11775 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11777 player = (mm_player_t*) u_data;
11778 attrs = MMPLAYER_GET_ATTRS(player);
11780 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11783 gint ret_value = 0;
11784 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11785 if (ret_value != MM_ERROR_NONE)
11786 LOGE("seeking to 0 failed in repeat play");
11789 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11792 /* we are returning FALSE as we need only one posting */
11796 /* sending event to one of sinkelements */
11798 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11800 GstEvent * event2 = NULL;
11801 GList *sinks = NULL;
11802 gboolean res = FALSE;
11805 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11806 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11808 /* While adding subtitles in live feeds seek is getting called.
11809 Adding defensive check in framework layer.*/
11810 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11811 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11812 LOGE("Should not send seek event during live playback");
11817 if (player->play_subtitle)
11818 event2 = gst_event_copy((const GstEvent *)event);
11820 sinks = player->sink_elements;
11822 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11824 if (GST_IS_ELEMENT(sink)) {
11825 /* keep ref to the event */
11826 gst_event_ref(event);
11828 if ((res = gst_element_send_event(sink, event))) {
11829 LOGD("sending event[%s] to sink element [%s] success!\n",
11830 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11832 /* rtsp case, asyn_done is not called after seek during pause state */
11833 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11834 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11835 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11836 LOGD("RTSP seek completed, after pause state..\n");
11837 player->doing_seek = FALSE;
11838 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11844 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11845 sinks = g_list_next(sinks);
11852 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11853 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11856 sinks = g_list_next(sinks);
11859 /* Note : Textbin is not linked to the video or audio bin.
11860 * It needs to send the event to the text sink seperatelly.
11862 if (player->play_subtitle && player->pipeline) {
11863 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11865 if (GST_IS_ELEMENT(text_sink)) {
11866 /* keep ref to the event */
11867 gst_event_ref(event2);
11869 if ((res = gst_element_send_event(text_sink, event2)))
11870 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11871 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11873 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11874 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11876 gst_event_unref(event2);
11880 gst_event_unref(event);
11888 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11892 MMPLAYER_RETURN_IF_FAIL(player);
11893 MMPLAYER_RETURN_IF_FAIL(sink);
11895 player->sink_elements =
11896 g_list_append(player->sink_elements, sink);
11902 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11906 MMPLAYER_RETURN_IF_FAIL(player);
11907 MMPLAYER_RETURN_IF_FAIL(sink);
11909 player->sink_elements =
11910 g_list_remove(player->sink_elements, sink);
11916 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11917 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11918 gint64 cur, GstSeekType stop_type, gint64 stop)
11920 GstEvent* event = NULL;
11921 gboolean result = FALSE;
11925 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11927 if (player->pipeline && player->pipeline->textbin)
11928 __mmplayer_drop_subtitle(player, FALSE);
11930 event = gst_event_new_seek(rate, format, flags, cur_type,
11931 cur, stop_type, stop);
11933 result = __gst_send_event_to_sink(player, event);
11940 /* NOTE : be careful with calling this api. please refer to below glib comment
11941 * glib comment : Note that there is a bug in GObject that makes this function much
11942 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11943 * will no longer be called, but, the signal handler is not currently disconnected.
11944 * If the instance is itself being freed at the same time than this doesn't matter,
11945 * since the signal will automatically be removed, but if instance persists,
11946 * then the signal handler will leak. You should not remove the signal yourself
11947 * because in a future versions of GObject, the handler will automatically be
11950 * It's possible to work around this problem in a way that will continue to work
11951 * with future versions of GObject by checking that the signal handler is still
11952 * connected before disconnected it:
11954 * if (g_signal_handler_is_connected(instance, id))
11955 * g_signal_handler_disconnect(instance, id);
11958 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11960 GList* sig_list = NULL;
11961 MMPlayerSignalItem* item = NULL;
11965 MMPLAYER_RETURN_IF_FAIL(player);
11967 LOGD("release signals type : %d", type);
11969 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11970 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11971 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11972 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11973 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11978 sig_list = player->signals[type];
11980 for (; sig_list; sig_list = sig_list->next) {
11981 item = sig_list->data;
11983 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11984 if (g_signal_handler_is_connected(item->obj, item->sig))
11985 g_signal_handler_disconnect(item->obj, item->sig);
11988 MMPLAYER_FREEIF(item);
11991 g_list_free(player->signals[type]);
11992 player->signals[type] = NULL;
11999 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12001 mm_player_t* player = 0;
12002 int prev_display_surface_type = 0;
12003 void *prev_display_overlay = NULL;
12004 const gchar *klass = NULL;
12005 gchar *cur_videosink_name = NULL;
12008 int num_of_dec = 2; /* DEC1, DEC2 */
12012 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12013 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12015 player = MM_PLAYER_CAST(handle);
12017 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12018 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12020 return MM_ERROR_INVALID_ARGUMENT;
12023 /* load previous attributes */
12024 if (player->attrs) {
12025 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12026 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12027 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12028 if (prev_display_surface_type == surface_type) {
12029 LOGD("incoming display surface type is same as previous one, do nothing..");
12031 return MM_ERROR_NONE;
12034 LOGE("failed to load attributes");
12036 return MM_ERROR_PLAYER_INTERNAL;
12039 /* check videosink element is created */
12040 if (!player->pipeline || !player->pipeline->videobin ||
12041 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12042 LOGD("videosink element is not yet ready");
12044 /* videobin is not created yet, so we just set attributes related to display surface */
12045 LOGD("store display attribute for given surface type(%d)", surface_type);
12046 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12047 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12048 if (mmf_attrs_commit(player->attrs)) {
12049 LOGE("failed to commit attribute");
12051 return MM_ERROR_PLAYER_INTERNAL;
12054 return MM_ERROR_NONE;
12056 /* get player command status */
12057 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12058 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12060 return MM_ERROR_PLAYER_INVALID_STATE;
12063 /* surface change */
12064 for (i = 0 ; i < num_of_dec ; i++) {
12065 if (player->pipeline->mainbin &&
12066 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12067 GstElementFactory *decfactory;
12068 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12070 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12071 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12072 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12073 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12077 LOGW("success to changing display surface(%d)", surface_type);
12079 return MM_ERROR_NONE;
12081 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12082 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12086 LOGW("success to changing display surface(%d)", surface_type);
12088 return MM_ERROR_NONE;
12091 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12092 ret = MM_ERROR_PLAYER_INTERNAL;
12101 /* rollback to previous attributes */
12102 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12103 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12104 if (mmf_attrs_commit(player->attrs)) {
12105 LOGE("failed to commit attributes to rollback");
12107 return MM_ERROR_PLAYER_INTERNAL;
12113 /* NOTE : It does not support some use cases, eg using colorspace converter */
12115 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12117 GstPad *src_pad_dec = NULL;
12118 GstPad *sink_pad_videosink = NULL;
12119 GstPad *sink_pad_videobin = NULL;
12120 GstClock *clock = NULL;
12121 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12122 int ret = MM_ERROR_NONE;
12123 gboolean is_audiobin_created = TRUE;
12127 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12128 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12129 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12131 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12132 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12134 /* get information whether if audiobin is created */
12135 if (!player->pipeline->audiobin ||
12136 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12137 LOGW("audiobin is null, this video content may not have audio data");
12138 is_audiobin_created = FALSE;
12141 /* get current state of player */
12142 previous_state = MMPLAYER_CURRENT_STATE(player);
12143 LOGD("previous state(%d)", previous_state);
12146 /* get src pad of decoder and block it */
12147 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12148 if (!src_pad_dec) {
12149 LOGE("failed to get src pad from decode in mainbin");
12150 return MM_ERROR_PLAYER_INTERNAL;
12153 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12154 LOGW("trying to block pad(video)");
12155 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12156 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12159 LOGE("failed to set block pad(video)");
12160 return MM_ERROR_PLAYER_INTERNAL;
12162 LOGW("pad is blocked(video)");
12164 /* no data flows, so no need to do pad_block */
12165 if (player->doing_seek)
12166 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12168 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12172 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12173 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12174 LOGE("failed to remove previous ghost_pad for videobin");
12175 return MM_ERROR_PLAYER_INTERNAL;
12178 /* change state of videobin to NULL */
12179 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12180 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12181 if (ret != GST_STATE_CHANGE_SUCCESS) {
12182 LOGE("failed to change state of videobin to NULL");
12183 return MM_ERROR_PLAYER_INTERNAL;
12186 /* unlink between decoder and videobin and remove previous videosink from videobin */
12187 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12188 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12189 LOGE("failed to remove former videosink from videobin");
12190 return MM_ERROR_PLAYER_INTERNAL;
12193 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12195 /* create a new videosink and add it to videobin */
12196 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12197 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12198 LOGE("failed to create videosink element\n");
12200 return MM_ERROR_PLAYER_INTERNAL;
12202 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12203 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12204 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12206 /* save attributes */
12207 if (player->attrs) {
12208 /* set a new display surface type */
12209 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12210 /* set a new diplay overlay */
12211 switch (surface_type) {
12212 case MM_DISPLAY_SURFACE_OVERLAY:
12213 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12214 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12217 LOGE("invalid type(%d) for changing display surface", surface_type);
12219 return MM_ERROR_INVALID_ARGUMENT;
12221 if (mmf_attrs_commit(player->attrs)) {
12222 LOGE("failed to commit");
12224 return MM_ERROR_PLAYER_INTERNAL;
12227 LOGE("player->attrs is null, failed to save attributes");
12229 return MM_ERROR_PLAYER_INTERNAL;
12232 /* update video param */
12233 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12234 LOGE("failed to update video param");
12235 return MM_ERROR_PLAYER_INTERNAL;
12238 /* change state of videobin to READY */
12239 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12240 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12241 if (ret != GST_STATE_CHANGE_SUCCESS) {
12242 LOGE("failed to change state of videobin to READY");
12243 return MM_ERROR_PLAYER_INTERNAL;
12246 /* change ghostpad */
12247 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12248 if (!sink_pad_videosink) {
12249 LOGE("failed to get sink pad from videosink element");
12250 return MM_ERROR_PLAYER_INTERNAL;
12252 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12253 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12254 LOGE("failed to set active to ghost_pad");
12255 return MM_ERROR_PLAYER_INTERNAL;
12257 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12258 LOGE("failed to change ghostpad for videobin");
12259 return MM_ERROR_PLAYER_INTERNAL;
12261 gst_object_unref(sink_pad_videosink);
12263 /* link decoder with videobin */
12264 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12265 if (!sink_pad_videobin) {
12266 LOGE("failed to get sink pad from videobin");
12267 return MM_ERROR_PLAYER_INTERNAL;
12269 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12270 LOGE("failed to link");
12271 return MM_ERROR_PLAYER_INTERNAL;
12273 gst_object_unref(sink_pad_videobin);
12275 /* clock setting for a new videosink plugin */
12276 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12277 so we set it from audiosink plugin or pipeline(system clock) */
12278 if (!is_audiobin_created) {
12279 LOGW("audiobin is not created, get clock from pipeline..");
12280 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12282 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12286 GstClockTime base_time;
12287 LOGD("set the clock to videosink");
12288 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12289 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12291 LOGD("got clock of videosink");
12292 now = gst_clock_get_time(clock);
12293 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12294 LOGD("at time %" GST_TIME_FORMAT ", base %"
12295 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12297 LOGE("failed to get clock of videosink after setting clock");
12298 return MM_ERROR_PLAYER_INTERNAL;
12301 LOGW("failed to get clock, maybe it is the time before first playing");
12303 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12304 /* change state of videobin to PAUSED */
12305 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12306 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12307 if (ret != GST_STATE_CHANGE_FAILURE) {
12308 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12310 LOGE("failed to change state of videobin to PLAYING");
12311 return MM_ERROR_PLAYER_INTERNAL;
12314 /* release blocked and unref src pad of video decoder */
12316 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12317 LOGE("failed to set pad blocked FALSE(video)");
12318 return MM_ERROR_PLAYER_INTERNAL;
12321 LOGW("pad is unblocked(video)");
12323 if (player->doing_seek)
12324 LOGW("not completed seek(%d)", player->doing_seek);
12325 /* change state of videobin to PAUSED */
12326 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12327 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12328 if (ret != GST_STATE_CHANGE_FAILURE) {
12329 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12331 LOGE("failed to change state of videobin to PLAYING");
12332 return MM_ERROR_PLAYER_INTERNAL;
12335 /* already skipped pad block */
12336 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12339 /* do get/set position for new videosink plugin */
12341 unsigned long position = 0;
12342 gint64 pos_msec = 0;
12344 LOGD("do get/set position for new videosink plugin");
12345 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12346 LOGE("failed to get position");
12347 return MM_ERROR_PLAYER_INTERNAL;
12349 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12350 /* accurate seek */
12351 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12352 LOGE("failed to set position");
12353 return MM_ERROR_PLAYER_INTERNAL;
12356 /* key unit seek */
12357 pos_msec = position * G_GINT64_CONSTANT(1000000);
12358 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12359 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12360 GST_SEEK_TYPE_SET, pos_msec,
12361 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12363 LOGE("failed to set position");
12364 return MM_ERROR_PLAYER_INTERNAL;
12370 gst_object_unref(src_pad_dec);
12371 LOGD("success to change sink");
12375 return MM_ERROR_NONE;
12379 /* Note : if silent is true, then subtitle would not be displayed. :*/
12380 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12382 mm_player_t* player = (mm_player_t*) hplayer;
12386 /* check player handle */
12387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12389 player->set_mode.subtitle_off = silent;
12391 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12395 return MM_ERROR_NONE;
12398 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12400 MMPlayerGstElement* mainbin = NULL;
12401 MMPlayerGstElement* textbin = NULL;
12402 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12403 GstState current_state = GST_STATE_VOID_PENDING;
12404 GstState element_state = GST_STATE_VOID_PENDING;
12405 GstState element_pending_state = GST_STATE_VOID_PENDING;
12407 GstEvent *event = NULL;
12408 int result = MM_ERROR_NONE;
12410 GstClock *curr_clock = NULL;
12411 GstClockTime base_time, start_time, curr_time;
12416 /* check player handle */
12417 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12418 player->pipeline &&
12419 player->pipeline->mainbin &&
12420 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12422 mainbin = player->pipeline->mainbin;
12423 textbin = player->pipeline->textbin;
12425 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12427 // sync clock with current pipeline
12428 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12429 curr_time = gst_clock_get_time(curr_clock);
12431 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12432 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12434 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12435 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12437 if (current_state > GST_STATE_READY) {
12438 // sync state with current pipeline
12439 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12440 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12441 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12443 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12444 if (GST_STATE_CHANGE_FAILURE == ret) {
12445 LOGE("fail to state change.\n");
12446 result = MM_ERROR_PLAYER_INTERNAL;
12451 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12452 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12455 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12456 gst_object_unref(curr_clock);
12459 // seek to current position
12460 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12461 result = MM_ERROR_PLAYER_INVALID_STATE;
12462 LOGE("gst_element_query_position failed, invalid state\n");
12466 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12467 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);
12469 __gst_send_event_to_sink(player, event);
12471 result = MM_ERROR_PLAYER_INTERNAL;
12472 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12476 /* sync state with current pipeline */
12477 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12478 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12479 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12481 return MM_ERROR_NONE;
12484 /* release text pipeline resource */
12485 player->textsink_linked = 0;
12487 /* release signal */
12488 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12490 /* release textbin with it's childs */
12491 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12492 MMPLAYER_FREEIF(player->pipeline->textbin);
12493 player->pipeline->textbin = NULL;
12495 /* release subtitle elem */
12496 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12497 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12503 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12505 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12506 GstState current_state = GST_STATE_VOID_PENDING;
12508 MMHandleType attrs = 0;
12509 MMPlayerGstElement* mainbin = NULL;
12510 MMPlayerGstElement* textbin = NULL;
12512 gchar* subtitle_uri = NULL;
12513 int result = MM_ERROR_NONE;
12514 const gchar *charset = NULL;
12518 /* check player handle */
12519 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12520 player->pipeline &&
12521 player->pipeline->mainbin &&
12522 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12523 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12525 mainbin = player->pipeline->mainbin;
12526 textbin = player->pipeline->textbin;
12528 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12529 if (current_state < GST_STATE_READY) {
12530 result = MM_ERROR_PLAYER_INVALID_STATE;
12531 LOGE("Pipeline is not in proper state\n");
12535 attrs = MMPLAYER_GET_ATTRS(player);
12537 LOGE("cannot get content attribute\n");
12538 result = MM_ERROR_PLAYER_INTERNAL;
12542 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12543 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12544 LOGE("subtitle uri is not proper filepath\n");
12545 result = MM_ERROR_PLAYER_INVALID_URI;
12549 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12550 LOGE("failed to get storage info of subtitle path");
12551 result = MM_ERROR_PLAYER_INVALID_URI;
12555 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12556 LOGD("new subtitle file path is [%s]\n", filepath);
12558 if (!strcmp(filepath, subtitle_uri)) {
12559 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12562 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12563 if (mmf_attrs_commit(player->attrs)) {
12564 LOGE("failed to commit.\n");
12569 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12570 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12571 player->subtitle_language_list = NULL;
12572 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12574 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12575 if (ret != GST_STATE_CHANGE_SUCCESS) {
12576 LOGE("failed to change state of textbin to READY");
12577 result = MM_ERROR_PLAYER_INTERNAL;
12581 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12582 if (ret != GST_STATE_CHANGE_SUCCESS) {
12583 LOGE("failed to change state of subparse to READY");
12584 result = MM_ERROR_PLAYER_INTERNAL;
12588 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12589 if (ret != GST_STATE_CHANGE_SUCCESS) {
12590 LOGE("failed to change state of filesrc to READY");
12591 result = MM_ERROR_PLAYER_INTERNAL;
12595 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12597 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12599 charset = util_get_charset(filepath);
12601 LOGD("detected charset is %s\n", charset);
12602 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12605 result = _mmplayer_sync_subtitle_pipeline(player);
12612 /* API to switch between external subtitles */
12613 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12615 int result = MM_ERROR_NONE;
12616 mm_player_t* player = (mm_player_t*)hplayer;
12621 /* check player handle */
12622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12624 /* filepath can be null in idle state */
12626 /* check file path */
12627 if ((path = strstr(filepath, "file://")))
12628 result = util_exist_file_path(path + 7);
12630 result = util_exist_file_path(filepath);
12632 if (result != MM_ERROR_NONE) {
12633 LOGE("invalid subtitle path 0x%X", result);
12634 return result; /* file not found or permission denied */
12638 if (!player->pipeline) {
12640 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12641 if (mmf_attrs_commit(player->attrs)) {
12642 LOGE("failed to commit"); /* subtitle path will not be created */
12643 return MM_ERROR_PLAYER_INTERNAL;
12646 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12647 /* check filepath */
12648 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12650 if (!__mmplayer_check_subtitle(player)) {
12651 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12652 if (mmf_attrs_commit(player->attrs)) {
12653 LOGE("failed to commit");
12654 return MM_ERROR_PLAYER_INTERNAL;
12657 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12658 LOGE("fail to create text pipeline");
12659 return MM_ERROR_PLAYER_INTERNAL;
12662 result = _mmplayer_sync_subtitle_pipeline(player);
12664 result = __mmplayer_change_external_subtitle_language(player, filepath);
12667 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12668 player->is_external_subtitle_added_now = TRUE;
12670 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12671 if (!player->subtitle_language_list) {
12672 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12673 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12674 LOGW("subtitle language list is not updated yet");
12676 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12684 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12686 int result = MM_ERROR_NONE;
12687 gchar* change_pad_name = NULL;
12688 GstPad* sinkpad = NULL;
12689 MMPlayerGstElement* mainbin = NULL;
12690 enum MainElementID elemId = MMPLAYER_M_NUM;
12691 GstCaps* caps = NULL;
12692 gint total_track_num = 0;
12696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12697 MM_ERROR_PLAYER_NOT_INITIALIZED);
12699 LOGD("Change Track(%d) to %d\n", type, index);
12701 mainbin = player->pipeline->mainbin;
12703 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12704 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12705 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12706 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12708 /* Changing Video Track is not supported. */
12709 LOGE("Track Type Error\n");
12713 if (mainbin[elemId].gst == NULL) {
12714 result = MM_ERROR_PLAYER_NO_OP;
12715 LOGD("Req track doesn't exist\n");
12719 total_track_num = player->selector[type].total_track_num;
12720 if (total_track_num <= 0) {
12721 result = MM_ERROR_PLAYER_NO_OP;
12722 LOGD("Language list is not available \n");
12726 if ((index < 0) || (index >= total_track_num)) {
12727 result = MM_ERROR_INVALID_ARGUMENT;
12728 LOGD("Not a proper index : %d \n", index);
12732 /*To get the new pad from the selector*/
12733 change_pad_name = g_strdup_printf("sink_%u", index);
12734 if (change_pad_name == NULL) {
12735 result = MM_ERROR_PLAYER_INTERNAL;
12736 LOGD("Pad does not exists\n");
12740 LOGD("new active pad name: %s\n", change_pad_name);
12742 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12743 if (sinkpad == NULL) {
12744 LOGD("sinkpad is NULL");
12745 result = MM_ERROR_PLAYER_INTERNAL;
12749 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12750 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12752 caps = gst_pad_get_current_caps(sinkpad);
12753 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12756 gst_object_unref(sinkpad);
12758 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12759 __mmplayer_set_audio_attrs(player, caps);
12763 MMPLAYER_FREEIF(change_pad_name);
12767 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12769 int result = MM_ERROR_NONE;
12770 mm_player_t* player = NULL;
12771 MMPlayerGstElement* mainbin = NULL;
12773 gint current_active_index = 0;
12775 GstState current_state = GST_STATE_VOID_PENDING;
12776 GstEvent* event = NULL;
12781 player = (mm_player_t*)hplayer;
12782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12784 if (!player->pipeline) {
12785 LOGE("Track %d pre setting -> %d\n", type, index);
12787 player->selector[type].active_pad_index = index;
12791 mainbin = player->pipeline->mainbin;
12793 current_active_index = player->selector[type].active_pad_index;
12795 /*If index is same as running index no need to change the pad*/
12796 if (current_active_index == index)
12799 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12800 result = MM_ERROR_PLAYER_INVALID_STATE;
12804 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12805 if (current_state < GST_STATE_PAUSED) {
12806 result = MM_ERROR_PLAYER_INVALID_STATE;
12807 LOGW("Pipeline not in porper state\n");
12811 result = __mmplayer_change_selector_pad(player, type, index);
12812 if (result != MM_ERROR_NONE) {
12813 LOGE("change selector pad error\n");
12817 player->selector[type].active_pad_index = index;
12819 if (current_state == GST_STATE_PLAYING) {
12820 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
12822 __gst_send_event_to_sink(player, event);
12824 result = MM_ERROR_PLAYER_INTERNAL;
12833 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12835 mm_player_t* player = (mm_player_t*) hplayer;
12839 /* check player handle */
12840 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12842 *silent = player->set_mode.subtitle_off;
12844 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12848 return MM_ERROR_NONE;
12852 __is_ms_buff_src(mm_player_t* player)
12854 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12856 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12860 __has_suffix(mm_player_t* player, const gchar* suffix)
12862 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12863 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12865 gboolean ret = FALSE;
12866 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12867 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12869 if (g_str_has_suffix(player->profile.uri, suffix))
12872 MMPLAYER_FREEIF(t_url);
12873 MMPLAYER_FREEIF(t_suffix);
12879 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12881 mm_player_t* player = (mm_player_t*) hplayer;
12883 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12885 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12886 MMPLAYER_PRINT_STATE(player);
12887 LOGE("wrong-state : can't set the download mode to parse");
12888 return MM_ERROR_PLAYER_INVALID_STATE;
12891 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12892 player->video_hub_download_mode = mode;
12894 return MM_ERROR_NONE;
12898 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12900 mm_player_t* player = (mm_player_t*) hplayer;
12902 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12904 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12905 player->sync_handler = enable;
12907 return MM_ERROR_NONE;
12911 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12913 long long clock_delta,
12914 long long video_time,
12915 long long media_clock,
12916 long long audio_time)
12918 mm_player_t* player = (mm_player_t*) hplayer;
12919 MMPlayerGstElement* mainbin = NULL;
12920 GstClockTime start_time_audio = 0, start_time_video = 0;
12921 GstClockTimeDiff base_time = 0, new_base_time = 0;
12922 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12923 gint64 api_delta = 0;
12924 gint64 position = 0, position_delta = 0;
12925 gint64 adj_base_time = 0;
12926 GstClock *curr_clock = NULL;
12927 GstClockTime curr_time = 0;
12928 gboolean query_ret = TRUE;
12929 int result = MM_ERROR_NONE;
12933 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12934 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12935 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12937 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12939 if ((video_time < 0) || (player->doing_seek)) {
12940 LOGD("skip setting master clock. %lld", video_time);
12944 mainbin = player->pipeline->mainbin;
12946 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12947 curr_time = gst_clock_get_time(curr_clock);
12949 current_state = MMPLAYER_CURRENT_STATE(player);
12951 if (current_state == MM_PLAYER_STATE_PLAYING)
12952 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12954 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12956 position = player->last_position;
12957 LOGD("query fail. %lld", position);
12960 clock *= GST_USECOND;
12961 clock_delta *= GST_USECOND;
12963 api_delta = clock - curr_time;
12964 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12965 player->video_share_api_delta = api_delta;
12967 clock_delta += (api_delta - player->video_share_api_delta);
12969 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12970 player->video_share_clock_delta = (gint64)clock_delta;
12972 position_delta = (position/GST_USECOND) - video_time;
12973 position_delta *= GST_USECOND;
12975 adj_base_time = position_delta;
12976 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12979 gint64 new_play_time = 0;
12980 gint64 network_delay = 0;
12982 video_time *= GST_USECOND;
12984 network_delay = clock_delta - player->video_share_clock_delta;
12985 new_play_time = video_time + network_delay;
12987 adj_base_time = position - new_play_time;
12989 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
12990 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
12993 /* Adjust Current Stream Time with base_time of sink
12994 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
12995 * 2. Set new base time
12996 * if adj_base_time is positive value, the stream time will be decreased.
12997 * 3. If seek event is occurred, the start time will be reset. */
12998 if ((player->pipeline->audiobin) &&
12999 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13000 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13002 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13003 LOGD("audio sink : gst_element_set_start_time -> NONE");
13004 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13007 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13010 if ((player->pipeline->videobin) &&
13011 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13012 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13014 if (start_time_video != GST_CLOCK_TIME_NONE) {
13015 LOGD("video sink : gst_element_set_start_time -> NONE");
13016 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13019 // if videobin exist, get base_time from videobin.
13020 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13023 new_base_time = base_time + adj_base_time;
13025 if ((player->pipeline->audiobin) &&
13026 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13027 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13029 if ((player->pipeline->videobin) &&
13030 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13031 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13040 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13041 long long *video_time,
13042 long long *media_clock,
13043 long long *audio_time)
13045 mm_player_t* player = (mm_player_t*) hplayer;
13046 MMPlayerGstElement* mainbin = NULL;
13047 GstClock *curr_clock = NULL;
13048 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13049 gint64 position = 0;
13050 gboolean query_ret = TRUE;
13054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13055 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13056 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13058 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13059 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13060 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13062 mainbin = player->pipeline->mainbin;
13064 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13066 current_state = MMPLAYER_CURRENT_STATE(player);
13068 if (current_state != MM_PLAYER_STATE_PAUSED)
13069 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13071 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13073 position = player->last_position;
13075 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13077 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13080 gst_object_unref(curr_clock);
13084 return MM_ERROR_NONE;
13088 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13090 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13091 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13093 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13094 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13098 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13099 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13100 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13101 mm_player_dump_t *dump_s;
13102 dump_s = g_malloc(sizeof(mm_player_dump_t));
13104 if (dump_s == NULL) {
13105 LOGE("malloc fail");
13109 dump_s->dump_element_file = NULL;
13110 dump_s->dump_pad = NULL;
13111 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13113 if (dump_s->dump_pad) {
13114 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13115 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]);
13116 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13117 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);
13118 /* add list for removed buffer probe and close FILE */
13119 player->dump_list = g_list_append(player->dump_list, dump_s);
13120 LOGD("%s sink pad added buffer probe for dump", factory_name);
13125 LOGE("failed to get %s sink pad added", factory_name);
13134 static GstPadProbeReturn
13135 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13137 FILE *dump_data = (FILE *) u_data;
13138 // int written = 0;
13139 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13140 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13142 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13144 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13146 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13148 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13150 return GST_PAD_PROBE_OK;
13154 __mmplayer_release_dump_list(GList *dump_list)
13157 GList *d_list = dump_list;
13158 for (; d_list; d_list = g_list_next(d_list)) {
13159 mm_player_dump_t *dump_s = d_list->data;
13160 if (dump_s->dump_pad) {
13161 if (dump_s->probe_handle_id)
13162 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13164 if (dump_s->dump_element_file) {
13165 fclose(dump_s->dump_element_file);
13166 dump_s->dump_element_file = NULL;
13168 MMPLAYER_FREEIF(dump_s);
13170 g_list_free(dump_list);
13176 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13178 mm_player_t* player = (mm_player_t*) hplayer;
13182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13183 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13185 *exist = player->has_closed_caption;
13189 return MM_ERROR_NONE;
13192 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13196 // LOGD("unref internal gst buffer %p", buffer);
13197 gst_buffer_unref((GstBuffer *)buffer);
13204 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13206 mm_player_t *player = (mm_player_t*)user_data;
13207 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13208 guint64 current_level_bytes = 0;
13210 MMPLAYER_RETURN_IF_FAIL(player);
13212 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13214 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13215 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13217 if (player->media_stream_buffer_status_cb[type])
13218 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13219 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13224 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13226 mm_player_t *player = (mm_player_t*)user_data;
13227 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13228 guint64 current_level_bytes = 0;
13230 MMPLAYER_RETURN_IF_FAIL(player);
13232 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13234 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13236 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13237 if (player->media_stream_buffer_status_cb[type])
13238 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13239 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13243 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13245 mm_player_t *player = (mm_player_t*)user_data;
13246 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13247 guint64 current_level_bytes = 0;
13249 MMPLAYER_RETURN_IF_FAIL(player);
13251 LOGI("app-src: feed subtitle\n");
13253 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13255 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13256 if (player->media_stream_buffer_status_cb[type])
13257 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13259 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13263 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13265 mm_player_t *player = (mm_player_t*)user_data;
13266 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13267 guint64 current_level_bytes = 0;
13269 MMPLAYER_RETURN_IF_FAIL(player);
13271 LOGI("app-src: audio buffer is full.\n");
13273 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13275 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13277 if (player->media_stream_buffer_status_cb[type])
13278 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13280 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13284 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13286 mm_player_t *player = (mm_player_t*)user_data;
13287 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13288 guint64 current_level_bytes = 0;
13290 MMPLAYER_RETURN_IF_FAIL(player);
13292 LOGI("app-src: video buffer is full.\n");
13294 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13296 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13297 if (player->media_stream_buffer_status_cb[type])
13298 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13300 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13304 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13306 mm_player_t *player = (mm_player_t*)user_data;
13307 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13309 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13311 LOGD("app-src: seek audio data %llu\n", position);
13312 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13314 if (player->media_stream_seek_data_cb[type])
13315 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13316 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13322 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13324 mm_player_t *player = (mm_player_t*)user_data;
13325 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13327 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13329 LOGD("app-src: seek video data %llu\n", position);
13330 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13331 if (player->media_stream_seek_data_cb[type])
13332 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13333 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13339 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13341 mm_player_t *player = (mm_player_t*)user_data;
13342 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13344 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13346 LOGD("app-src: seek subtitle data\n");
13347 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13349 if (player->media_stream_seek_data_cb[type])
13350 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13351 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13357 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13359 mm_player_t* player = (mm_player_t*) hplayer;
13363 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13365 player->pcm_samplerate = samplerate;
13366 player->pcm_channel = channel;
13369 return MM_ERROR_NONE;
13372 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13374 mm_player_t* player = (mm_player_t*) hplayer;
13378 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13379 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13381 if (MMPLAYER_IS_STREAMING(player))
13382 *timeout = player->ini.live_state_change_timeout;
13384 *timeout = player->ini.localplayback_state_change_timeout;
13386 LOGD("timeout = %d\n", *timeout);
13389 return MM_ERROR_NONE;
13392 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13394 mm_player_t* player = (mm_player_t*) hplayer;
13398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13399 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13401 *num = player->video_num_buffers;
13402 *extra_num = player->video_extra_num_buffers;
13404 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13407 return MM_ERROR_NONE;
13411 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13415 MMPLAYER_RETURN_IF_FAIL(player);
13417 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13419 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13420 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13421 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13422 player->storage_info[i].id = -1;
13423 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13425 if (path_type != MMPLAYER_PATH_MAX)
13433 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13435 int ret = MM_ERROR_NONE;
13436 mm_player_t* player = (mm_player_t*)hplayer;
13437 MMMessageParamType msg_param = {0, };
13440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13442 LOGW("state changed storage %d:%d", id, state);
13444 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13445 return MM_ERROR_NONE;
13447 /* FIXME: text path should be handled seperately. */
13448 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13449 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13450 LOGW("external storage is removed");
13452 if (player->msg_posted == FALSE) {
13453 memset(&msg_param, 0, sizeof(MMMessageParamType));
13454 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13455 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13456 player->msg_posted = TRUE;
13459 /* unrealize the player */
13460 ret = _mmplayer_unrealize(hplayer);
13461 if (ret != MM_ERROR_NONE)
13462 LOGE("failed to unrealize");
13469 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13471 int ret = MM_ERROR_NONE;
13472 mm_player_t* player = (mm_player_t*) hplayer;
13473 int idx = 0, total = 0;
13474 gchar *result = NULL, *tmp = NULL;
13477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13478 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13480 total = *num = g_list_length(player->adaptive_info.var_list);
13482 LOGW("There is no stream variant info.");
13486 result = g_strdup("");
13487 for (idx = 0 ; idx < total ; idx++) {
13488 VariantData *v_data = NULL;
13489 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13492 gchar data[64] = {0};
13493 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13495 tmp = g_strconcat(result, data, NULL);
13499 LOGW("There is no variant data in %d", idx);
13504 *var_info = (char *)result;
13506 LOGD("variant info %d:%s", *num, *var_info);
13511 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13513 int ret = MM_ERROR_NONE;
13514 mm_player_t* player = (mm_player_t*) hplayer;
13517 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13519 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13521 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13522 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13523 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13525 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13526 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13527 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13528 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13530 /* FIXME: seek to current position for applying new variant limitation */
13538 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13540 int ret = MM_ERROR_NONE;
13541 mm_player_t* player = (mm_player_t*) hplayer;
13544 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13545 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13547 *bandwidth = player->adaptive_info.limit.bandwidth;
13548 *width = player->adaptive_info.limit.width;
13549 *height = player->adaptive_info.limit.height;
13551 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13557 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13559 int ret = MM_ERROR_NONE;
13560 mm_player_t* player = (mm_player_t*) hplayer;
13563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13565 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13566 LOGW("buffer_ms will not be applied.");
13569 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13571 if (player->streamer == NULL) {
13572 player->streamer = __mm_player_streaming_create();
13573 __mm_player_streaming_initialize(player->streamer);
13576 if (buffer_ms >= 0)
13577 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13579 if (rebuffer_ms >= 0)
13580 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13587 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13589 int ret = MM_ERROR_NONE;
13590 mm_player_t* player = (mm_player_t*) hplayer;
13593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13594 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13596 if (player->streamer == NULL) {
13597 player->streamer = __mm_player_streaming_create();
13598 __mm_player_streaming_initialize(player->streamer);
13601 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13602 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13604 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13610 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13612 #define IDX_FIRST_SW_CODEC 0
13613 mm_player_t* player = (mm_player_t*) hplayer;
13614 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13615 MMHandleType attrs = 0;
13618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13620 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13621 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13622 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13624 switch (stream_type) {
13625 case MM_PLAYER_STREAM_TYPE_AUDIO:
13626 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13627 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13628 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13629 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13630 LOGE("There is no a codec for codec_type %d", codec_type);
13631 return MM_ERROR_PLAYER_NO_OP;
13634 case MM_PLAYER_STREAM_TYPE_VIDEO:
13635 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13636 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13637 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13638 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13639 LOGE("There is no v codec for codec_type %d", codec_type);
13640 return MM_ERROR_PLAYER_NO_OP;
13645 LOGE("Invalid stream type %d", stream_type);
13646 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13650 LOGD("update %s codec_type to %d", attr_name, codec_type);
13652 attrs = MMPLAYER_GET_ATTRS(player);
13653 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13655 if (mmf_attrs_commit(player->attrs)) {
13656 LOGE("failed to commit codec_type attributes");
13657 return MM_ERROR_PLAYER_INTERNAL;
13661 return MM_ERROR_NONE;
13665 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13667 mm_player_t* player = (mm_player_t*) hplayer;
13668 GstElement* rg_vol_element = NULL;
13672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13674 player->sound.rg_enable = enabled;
13676 /* just hold rgvolume enable value if pipeline is not ready */
13677 if (!player->pipeline || !player->pipeline->audiobin) {
13678 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13679 return MM_ERROR_NONE;
13682 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13684 if (!rg_vol_element) {
13685 LOGD("rgvolume element is not created");
13686 return MM_ERROR_PLAYER_INTERNAL;
13690 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13692 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13696 return MM_ERROR_NONE;
13700 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13702 mm_player_t* player = (mm_player_t*) hplayer;
13703 GstElement* rg_vol_element = NULL;
13704 gboolean enable = FALSE;
13708 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13709 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13711 /* just hold enable_rg value if pipeline is not ready */
13712 if (!player->pipeline || !player->pipeline->audiobin) {
13713 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13714 *enabled = player->sound.rg_enable;
13715 return MM_ERROR_NONE;
13718 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13720 if (!rg_vol_element) {
13721 LOGD("rgvolume element is not created");
13722 return MM_ERROR_PLAYER_INTERNAL;
13725 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13730 return MM_ERROR_NONE;