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 100
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 tag_list_str = gst_tag_list_to_string(tag_list); \
1812 if (tag_list_str && strstr(tag_list_str, "audio")) \
1813 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1814 else if (tag_list_str && strstr(tag_list_str, "video")) \
1815 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1817 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1818 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1819 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1820 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1821 player->bitrate[track_type] = v_uint; \
1822 player->total_bitrate = 0; \
1823 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1824 player->total_bitrate += player->bitrate[i]; \
1825 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1826 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1827 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1828 player->maximum_bitrate[track_type] = v_uint; \
1829 player->total_maximum_bitrate = 0; \
1830 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1831 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1832 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1833 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1835 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1838 g_free(tag_list_str); \
1843 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1844 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1845 if (date != NULL) {\
1846 string = g_strdup_printf("%d", g_date_get_year(date));\
1847 mm_attrs_set_string_by_name(attribute, playertag, string);\
1848 SECURE_LOGD("metainfo year : %s\n", string);\
1849 MMPLAYER_FREEIF(string);\
1854 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1856 if (datetime != NULL) {\
1857 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1858 mm_attrs_set_string_by_name(attribute, playertag, string);\
1859 SECURE_LOGD("metainfo year : %s\n", string);\
1860 MMPLAYER_FREEIF(string);\
1861 gst_date_time_unref(datetime);\
1865 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1866 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1868 /* FIXIT : don't know how to store date */\
1874 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1875 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1877 /* FIXIT : don't know how to store date */\
1883 /* function start */
1884 GstTagList* tag_list = NULL;
1886 MMHandleType attrs = 0;
1888 char *string = NULL;
1891 GstDateTime *datetime = NULL;
1893 GstBuffer *buffer = NULL;
1895 MMMessageParamType msg_param = {0, };
1897 /* currently not used. but those are needed for above macro */
1898 //guint64 v_uint64 = 0;
1899 //gdouble v_double = 0;
1901 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1903 attrs = MMPLAYER_GET_ATTRS(player);
1905 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1907 /* get tag list from gst message */
1908 gst_message_parse_tag(msg, &tag_list);
1910 /* store tags to player attributes */
1911 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1912 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1913 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1915 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1916 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1917 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1918 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1919 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1920 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1923 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1924 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1925 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1926 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1927 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1929 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1930 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1931 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1932 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1933 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1940 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1941 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1942 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1943 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1944 MMPLAYER_UPDATE_TAG_LOCK(player);
1945 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1946 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1947 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1948 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1949 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1950 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1951 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1952 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1953 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1954 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1955 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1956 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1958 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1959 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1961 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1962 if (player->video360_metadata.is_spherical == -1) {
1963 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1964 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1965 player->video360_metadata.is_spherical);
1966 if (player->video360_metadata.is_spherical == 1) {
1967 LOGD("This is spherical content for 360 playback.");
1968 player->is_content_spherical = TRUE;
1970 LOGD("This is not spherical content");
1971 player->is_content_spherical = FALSE;
1974 if (player->video360_metadata.projection_type_string) {
1975 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1976 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1978 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1979 player->is_content_spherical = player->is_video360_enabled = FALSE;
1983 if (player->video360_metadata.stereo_mode_string) {
1984 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1985 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1986 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1987 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1988 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1989 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1991 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1992 player->is_content_spherical = player->is_video360_enabled = FALSE;
1998 if (mmf_attrs_commit(attrs))
1999 LOGE("failed to commit.\n");
2001 gst_tag_list_free(tag_list);
2007 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2009 mm_player_t* player = (mm_player_t*) data;
2013 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2014 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2015 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2016 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2018 * [1] audio and video will be dumped with filesink.
2019 * [2] autoplugging is done by just using pad caps.
2020 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2021 * and the video will be dumped via filesink.
2023 if (player->num_dynamic_pad == 0) {
2024 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2026 if (!__mmplayer_gst_remove_fakesink(player,
2027 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2028 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2029 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2030 * source element are not same. To overcome this situation, this function will called
2031 * several places and several times. Therefore, this is not an error case.
2036 /* create dot before error-return. for debugging */
2037 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2039 player->no_more_pad = TRUE;
2045 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2047 GstElement* parent = NULL;
2049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2051 /* if we have no fakesink. this meas we are using decodebin which doesn'
2052 t need to add extra fakesink */
2053 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2056 MMPLAYER_FSINK_LOCK(player);
2061 /* get parent of fakesink */
2062 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2064 LOGD("fakesink already removed\n");
2068 gst_element_set_locked_state(fakesink->gst, TRUE);
2070 /* setting the state to NULL never returns async
2071 * so no need to wait for completion of state transiton
2073 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2074 LOGE("fakesink state change failure!\n");
2075 /* FIXIT : should I return here? or try to proceed to next? */
2078 /* remove fakesink from it's parent */
2079 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2080 LOGE("failed to remove fakesink\n");
2082 gst_object_unref(parent);
2087 gst_object_unref(parent);
2089 LOGD("state-holder removed\n");
2091 gst_element_set_locked_state(fakesink->gst, FALSE);
2093 MMPLAYER_FSINK_UNLOCK(player);
2098 gst_element_set_locked_state(fakesink->gst, FALSE);
2100 MMPLAYER_FSINK_UNLOCK(player);
2106 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2108 GstPad *sinkpad = NULL;
2109 GstCaps* caps = NULL;
2110 GstElement* new_element = NULL;
2111 GstStructure* str = NULL;
2112 const gchar* name = NULL;
2114 mm_player_t* player = (mm_player_t*) data;
2118 MMPLAYER_RETURN_IF_FAIL(element && pad);
2119 MMPLAYER_RETURN_IF_FAIL(player &&
2121 player->pipeline->mainbin);
2124 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2125 * num_dynamic_pad will decreased after creating a sinkbin.
2127 player->num_dynamic_pad++;
2128 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2130 caps = gst_pad_query_caps(pad, NULL);
2132 MMPLAYER_CHECK_NULL(caps);
2134 /* clear previous result*/
2135 player->have_dynamic_pad = FALSE;
2137 str = gst_caps_get_structure(caps, 0);
2140 LOGE("cannot get structure from caps.\n");
2144 name = gst_structure_get_name(str);
2146 LOGE("cannot get mimetype from structure.\n");
2150 if (strstr(name, "video")) {
2152 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2154 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2155 if (player->v_stream_caps) {
2156 gst_caps_unref(player->v_stream_caps);
2157 player->v_stream_caps = NULL;
2160 new_element = gst_element_factory_make("fakesink", NULL);
2161 player->num_dynamic_pad--;
2166 /* clear previous result*/
2167 player->have_dynamic_pad = FALSE;
2169 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2170 LOGE("failed to autoplug for caps");
2174 /* check if there's dynamic pad*/
2175 if (player->have_dynamic_pad) {
2176 LOGE("using pad caps assums there's no dynamic pad !\n");
2180 gst_caps_unref(caps);
2185 /* excute new_element if created*/
2187 LOGD("adding new element to pipeline\n");
2189 /* set state to READY before add to bin */
2190 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2192 /* add new element to the pipeline */
2193 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2194 LOGE("failed to add autoplug element to bin\n");
2198 /* get pad from element */
2199 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2201 LOGE("failed to get sinkpad from autoplug element\n");
2206 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2207 LOGE("failed to link autoplug element\n");
2211 gst_object_unref(sinkpad);
2214 /* run. setting PLAYING here since streamming source is live source */
2215 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2219 gst_caps_unref(caps);
2225 STATE_CHANGE_FAILED:
2227 /* FIXIT : take care if new_element has already added to pipeline */
2229 gst_object_unref(GST_OBJECT(new_element));
2232 gst_object_unref(GST_OBJECT(sinkpad));
2235 gst_caps_unref(caps);
2237 /* FIXIT : how to inform this error to MSL ????? */
2238 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2239 * then post an error to application
2243 static GstPadProbeReturn
2244 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2246 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2247 return GST_PAD_PROBE_OK;
2250 static GstPadProbeReturn
2251 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2253 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2254 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2255 mm_player_t* player = (mm_player_t*)data;
2256 GstCaps* caps = NULL;
2257 GstStructure* str = NULL;
2258 const gchar* name = NULL;
2259 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2262 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2263 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2264 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2265 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2266 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2268 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2269 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2273 caps = gst_pad_query_caps(pad, NULL);
2275 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2279 str = gst_caps_get_structure(caps, 0);
2281 LOGE("failed to get structure from caps");
2285 name = gst_structure_get_name(str);
2287 LOGE("failed to get name from str");
2291 if (strstr(name, "audio")) {
2292 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2293 } else if (strstr(name, "video")) {
2294 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2296 /* text track is not supportable */
2297 LOGE("invalid name %s", name);
2301 switch (GST_EVENT_TYPE(event)) {
2304 /* in case of gapless, drop eos event not to send it to sink */
2305 if (player->gapless.reconfigure && !player->msg_posted) {
2306 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2307 ret = GST_PAD_PROBE_DROP;
2311 case GST_EVENT_STREAM_START:
2313 gint64 stop_running_time = 0;
2314 gint64 position_running_time = 0;
2315 gint64 position = 0;
2318 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2319 if ((player->gapless.update_segment[idx] == TRUE) ||
2320 !(player->selector[idx].event_probe_id)) {
2321 /* LOGW("[%d] skip", idx); */
2325 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2327 gst_segment_to_running_time(&player->gapless.segment[idx],
2328 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2329 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2331 gst_segment_to_running_time(&player->gapless.segment[idx],
2332 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2334 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2336 gst_segment_to_running_time(&player->gapless.segment[idx],
2337 GST_FORMAT_TIME, player->duration);
2340 position_running_time =
2341 gst_segment_to_running_time(&player->gapless.segment[idx],
2342 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2344 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2345 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2347 GST_TIME_ARGS(stop_running_time),
2348 GST_TIME_ARGS(position_running_time),
2349 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2350 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2352 position_running_time = MAX(position_running_time, stop_running_time);
2353 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2354 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2355 position_running_time = MAX(0, position_running_time);
2356 position = MAX(position, position_running_time);
2359 if (position != 0) {
2360 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2361 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2362 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2364 player->gapless.start_time[stream_type] += position;
2368 case GST_EVENT_FLUSH_STOP:
2370 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2371 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2372 player->gapless.start_time[stream_type] = 0;
2375 case GST_EVENT_SEGMENT:
2380 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2381 gst_event_copy_segment(event, &segment);
2383 if (segment.format == GST_FORMAT_TIME) {
2384 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2385 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2386 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2387 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2388 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2389 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2391 /* keep the all the segment ev to cover the seeking */
2392 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2393 player->gapless.update_segment[stream_type] = TRUE;
2395 if (!player->gapless.running)
2398 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2400 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2402 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2403 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2404 gst_event_unref(event);
2405 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2411 gdouble proportion = 0.0;
2412 GstClockTimeDiff diff = 0;
2413 GstClockTime timestamp = 0;
2414 gint64 running_time_diff = -1;
2415 GstQOSType type = 0;
2416 GstEvent *tmpev = NULL;
2418 running_time_diff = player->gapless.segment[stream_type].base;
2420 if (running_time_diff <= 0) /* don't need to adjust */
2423 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2424 gst_event_unref(event);
2426 if (timestamp < running_time_diff) {
2427 LOGW("QOS event from previous group");
2428 ret = GST_PAD_PROBE_DROP;
2432 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2433 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2434 stream_type, GST_TIME_ARGS(timestamp),
2435 GST_TIME_ARGS(running_time_diff),
2436 GST_TIME_ARGS(timestamp - running_time_diff));
2438 timestamp -= running_time_diff;
2440 /* That case is invalid for QoS events */
2441 if (diff < 0 && -diff > timestamp) {
2442 LOGW("QOS event from previous group");
2443 ret = GST_PAD_PROBE_DROP;
2447 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2448 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2458 gst_caps_unref(caps);
2463 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2465 mm_player_t* player = NULL;
2466 GstElement* pipeline = NULL;
2467 GstElement* selector = NULL;
2468 GstElement* fakesink = NULL;
2469 GstCaps* caps = NULL;
2470 GstStructure* str = NULL;
2471 const gchar* name = NULL;
2472 GstPad* sinkpad = NULL;
2473 GstPad* srcpad = NULL;
2474 gboolean first_track = FALSE;
2476 enum MainElementID elemId = MMPLAYER_M_NUM;
2477 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2480 player = (mm_player_t*)data;
2482 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2483 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2485 //LOGD("pad-added signal handling\n");
2487 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2489 /* get mimetype from caps */
2490 caps = gst_pad_query_caps(pad, NULL);
2492 LOGE("cannot get caps from pad.\n");
2496 str = gst_caps_get_structure(caps, 0);
2498 LOGE("cannot get structure from caps.\n");
2502 name = gst_structure_get_name(str);
2504 LOGE("cannot get mimetype from structure.\n");
2508 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2509 //LOGD("detected mimetype : %s\n", name);
2511 if (strstr(name, "video")) {
2514 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2515 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2517 /* don't make video because of not required, and not support multiple track */
2518 if (stype == MM_DISPLAY_SURFACE_NULL) {
2519 LOGD("no video sink by null surface");
2521 gchar *caps_str = gst_caps_to_string(caps);
2522 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2523 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2524 player->set_mode.video_zc = TRUE;
2526 MMPLAYER_FREEIF(caps_str);
2528 if (player->v_stream_caps) {
2529 gst_caps_unref(player->v_stream_caps);
2530 player->v_stream_caps = NULL;
2533 LOGD("create fakesink instead of videobin");
2536 fakesink = gst_element_factory_make("fakesink", NULL);
2537 if (fakesink == NULL) {
2538 LOGE("ERROR : fakesink create error\n");
2542 if (player->ini.set_dump_element_flag)
2543 __mmplayer_add_dump_buffer_probe(player, fakesink);
2545 player->video_fakesink = fakesink;
2547 /* store it as it's sink element */
2548 __mmplayer_add_sink(player, player->video_fakesink);
2550 gst_bin_add(GST_BIN(pipeline), fakesink);
2553 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2555 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2556 LOGW("failed to link fakesink\n");
2557 gst_object_unref(GST_OBJECT(fakesink));
2561 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2562 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2563 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2566 if (player->set_mode.media_packet_video_stream) {
2567 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2569 MMPLAYER_SIGNAL_CONNECT(player,
2571 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2573 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2576 MMPLAYER_SIGNAL_CONNECT(player,
2578 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2580 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2584 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2585 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2589 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2590 __mmplayer_gst_decode_callback(elem, pad, player);
2594 LOGD("video selector \n");
2595 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2596 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2598 if (strstr(name, "audio")) {
2599 gint samplerate = 0;
2602 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2603 __mmplayer_gst_decode_callback(elem, pad, player);
2607 LOGD("audio selector \n");
2608 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2609 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2611 gst_structure_get_int(str, "rate", &samplerate);
2612 gst_structure_get_int(str, "channels", &channels);
2614 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2616 fakesink = gst_element_factory_make("fakesink", NULL);
2617 if (fakesink == NULL) {
2618 LOGE("ERROR : fakesink create error\n");
2622 gst_bin_add(GST_BIN(pipeline), fakesink);
2625 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2627 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2628 LOGW("failed to link fakesink\n");
2629 gst_object_unref(GST_OBJECT(fakesink));
2633 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2634 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2635 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2639 } else if (strstr(name, "text")) {
2640 LOGD("text selector \n");
2641 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2642 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2644 LOGE("wrong elem id \n");
2649 selector = player->pipeline->mainbin[elemId].gst;
2650 if (selector == NULL) {
2651 selector = gst_element_factory_make("input-selector", NULL);
2652 LOGD("Creating input-selector\n");
2653 if (selector == NULL) {
2654 LOGE("ERROR : input-selector create error\n");
2657 g_object_set(selector, "sync-streams", TRUE, NULL);
2659 player->pipeline->mainbin[elemId].id = elemId;
2660 player->pipeline->mainbin[elemId].gst = selector;
2663 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2665 srcpad = gst_element_get_static_pad(selector, "src");
2667 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2668 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2669 __mmplayer_gst_selector_blocked, NULL, NULL);
2670 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2671 __mmplayer_gst_selector_event_probe, player, NULL);
2673 gst_element_set_state(selector, GST_STATE_PAUSED);
2674 gst_bin_add(GST_BIN(pipeline), selector);
2676 LOGD("input-selector is already created.\n");
2679 LOGD("Calling request pad with selector %p \n", selector);
2680 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2682 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2684 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2685 LOGW("failed to link selector\n");
2686 gst_object_unref(GST_OBJECT(selector));
2691 LOGD("this is first track --> active track \n");
2692 g_object_set(selector, "active-pad", sinkpad, NULL);
2695 _mmplayer_track_update_info(player, stream_type, sinkpad);
2702 gst_caps_unref(caps);
2705 gst_object_unref(GST_OBJECT(sinkpad));
2710 gst_object_unref(GST_OBJECT(srcpad));
2717 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2719 GstPad* srcpad = NULL;
2720 MMHandleType attrs = 0;
2721 gint active_index = 0;
2723 // [link] input-selector :: textbin
2724 srcpad = gst_element_get_static_pad(text_selector, "src");
2726 LOGE("failed to get srcpad from selector\n");
2730 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2732 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2733 if ((active_index != DEFAULT_TRACK) &&
2734 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2735 LOGW("failed to change text track\n");
2736 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2739 player->no_more_pad = TRUE;
2740 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2742 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2743 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2744 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2745 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2748 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2750 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2751 player->has_closed_caption = TRUE;
2753 attrs = MMPLAYER_GET_ATTRS(player);
2755 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2756 if (mmf_attrs_commit(attrs))
2757 LOGE("failed to commit.\n");
2759 LOGE("cannot get content attribute");
2762 gst_object_unref(GST_OBJECT(srcpad));
2768 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2770 mm_player_t* player = (mm_player_t*)data;
2771 GstElement* selector = NULL;
2772 GstElement* queue = NULL;
2774 GstPad* srcpad = NULL;
2775 GstPad* sinkpad = NULL;
2776 GstCaps* caps = NULL;
2777 gchar* caps_str = NULL;
2780 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2782 caps = gst_pad_get_current_caps(pad);
2783 caps_str = gst_caps_to_string(caps);
2784 LOGD("deinterleave new caps : %s\n", caps_str);
2785 MMPLAYER_FREEIF(caps_str);
2786 gst_caps_unref(caps);
2788 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2789 LOGE("ERROR : queue create error\n");
2793 g_object_set(G_OBJECT(queue),
2794 "max-size-buffers", 10,
2795 "max-size-bytes", 0,
2796 "max-size-time", (guint64)0,
2799 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2802 LOGE("there is no audio channel selector.\n");
2806 srcpad = gst_element_get_static_pad(queue, "src");
2807 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2809 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2811 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2812 LOGW("failed to link deinterleave - selector\n");
2816 gst_element_set_state(queue, GST_STATE_PAUSED);
2817 player->audio_mode.total_track_num++;
2822 gst_object_unref(GST_OBJECT(srcpad));
2827 gst_object_unref(GST_OBJECT(sinkpad));
2836 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2838 mm_player_t* player = NULL;
2839 GstElement* selector = NULL;
2840 GstPad* sinkpad = NULL;
2841 gint active_index = 0;
2842 gchar* change_pad_name = NULL;
2843 GstCaps* caps = NULL; // no need to unref
2844 gint default_audio_ch = 0;
2847 player = (mm_player_t*) data;
2849 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2852 LOGE("there is no audio channel selector.\n");
2856 active_index = player->audio_mode.active_pad_index;
2858 if (active_index != default_audio_ch) {
2859 gint audio_ch = default_audio_ch;
2861 /*To get the new pad from the selector*/
2862 change_pad_name = g_strdup_printf("sink%d", active_index);
2863 if (change_pad_name != NULL) {
2864 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2865 if (sinkpad != NULL) {
2866 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2867 g_object_set(selector, "active-pad", sinkpad, NULL);
2869 audio_ch = active_index;
2871 caps = gst_pad_get_current_caps(sinkpad);
2872 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2874 __mmplayer_set_audio_attrs(player, caps);
2875 gst_caps_unref(caps);
2877 MMPLAYER_FREEIF(change_pad_name);
2880 player->audio_mode.active_pad_index = audio_ch;
2881 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2887 gst_object_unref(sinkpad);
2894 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2896 mm_player_t* player = NULL;
2897 MMPlayerGstElement *mainbin = NULL;
2899 GstElement* tee = NULL;
2900 GstElement* stereo_queue = NULL;
2901 GstElement* mono_queue = NULL;
2902 GstElement* conv = NULL;
2903 GstElement* filter = NULL;
2904 GstElement* deinterleave = NULL;
2905 GstElement* selector = NULL;
2907 GstPad* srcpad = NULL;
2908 GstPad* selector_srcpad = NULL;
2909 GstPad* sinkpad = NULL;
2910 GstCaps* caps = NULL;
2911 gulong block_id = 0;
2916 player = (mm_player_t*) data;
2918 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2919 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2921 mainbin = player->pipeline->mainbin;
2924 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2925 LOGE("ERROR : tee create error\n");
2929 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2930 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2932 gst_element_set_state(tee, GST_STATE_PAUSED);
2935 srcpad = gst_element_get_request_pad(tee, "src_%u");
2936 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2937 LOGE("ERROR : stereo queue create error\n");
2941 g_object_set(G_OBJECT(stereo_queue),
2942 "max-size-buffers", 10,
2943 "max-size-bytes", 0,
2944 "max-size-time", (guint64)0,
2947 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2948 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2951 gst_object_unref(GST_OBJECT(srcpad));
2955 srcpad = gst_element_get_request_pad(tee, "src_%u");
2957 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2958 LOGE("ERROR : mono queue create error\n");
2962 g_object_set(G_OBJECT(mono_queue),
2963 "max-size-buffers", 10,
2964 "max-size-bytes", 0,
2965 "max-size-time", (guint64)0,
2968 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2969 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2971 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2972 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2975 srcpad = gst_element_get_static_pad(mono_queue, "src");
2976 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2977 LOGE("ERROR : audioconvert create error\n");
2981 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2982 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2986 gst_object_unref(GST_OBJECT(srcpad));
2989 srcpad = gst_element_get_static_pad(conv, "src");
2991 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2992 LOGE("ERROR : capsfilter create error\n");
2996 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2997 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2999 caps = gst_caps_from_string("audio/x-raw-int, "
3000 "width = (int) 16, "
3001 "depth = (int) 16, "
3002 "channels = (int) 2");
3004 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3005 gst_caps_unref(caps);
3007 gst_element_set_state(conv, GST_STATE_PAUSED);
3008 gst_element_set_state(filter, GST_STATE_PAUSED);
3012 gst_object_unref(GST_OBJECT(srcpad));
3015 srcpad = gst_element_get_static_pad(filter, "src");
3017 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3018 LOGE("ERROR : deinterleave create error\n");
3022 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3024 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3025 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3027 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3028 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3030 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3031 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3034 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3035 if (selector == NULL) {
3036 LOGE("ERROR : audio-selector create error\n");
3040 g_object_set(selector, "sync-streams", TRUE, NULL);
3041 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3043 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3044 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3046 selector_srcpad = gst_element_get_static_pad(selector, "src");
3048 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3050 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3051 __mmplayer_gst_selector_blocked, NULL, NULL);
3054 gst_object_unref(GST_OBJECT(srcpad));
3058 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3059 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3061 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3062 LOGW("failed to link queue_stereo - selector\n");
3066 player->audio_mode.total_track_num++;
3068 g_object_set(selector, "active-pad", sinkpad, NULL);
3069 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3070 gst_element_set_state(selector, GST_STATE_PAUSED);
3072 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3076 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3077 if (block_id != 0) {
3078 gst_pad_remove_probe(selector_srcpad, block_id);
3083 gst_object_unref(GST_OBJECT(sinkpad));
3088 gst_object_unref(GST_OBJECT(srcpad));
3092 if (selector_srcpad) {
3093 gst_object_unref(GST_OBJECT(selector_srcpad));
3094 selector_srcpad = NULL;
3102 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3104 mm_player_t* player = NULL;
3105 GstPad* srcpad = NULL;
3106 GstElement* video_selector = NULL;
3107 GstElement* audio_selector = NULL;
3108 GstElement* text_selector = NULL;
3109 MMHandleType attrs = 0;
3110 gint active_index = 0;
3111 gint64 dur_bytes = 0L;
3113 player = (mm_player_t*) data;
3115 LOGD("no-more-pad signal handling\n");
3117 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3118 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3119 LOGW("no need to go more");
3121 if (player->gapless.reconfigure) {
3122 player->gapless.reconfigure = FALSE;
3123 MMPLAYER_PLAYBACK_UNLOCK(player);
3129 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3130 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3131 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3132 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3133 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3135 if (NULL == player->streamer) {
3136 LOGW("invalid state for buffering");
3140 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3141 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3143 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3144 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3146 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3148 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3149 LOGE("fail to get duration.\n");
3151 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3152 // use file information was already set on Q2 when it was created.
3153 __mm_player_streaming_set_queue2(player->streamer,
3154 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3155 TRUE, // use_buffering
3157 init_buffering_time,
3159 player->ini.http_buffering_limit, // high percent
3160 MUXED_BUFFER_TYPE_MEM_QUEUE,
3162 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3165 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3166 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3167 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3168 if (video_selector) {
3169 // [link] input-selector :: videobin
3170 srcpad = gst_element_get_static_pad(video_selector, "src");
3172 LOGE("failed to get srcpad from video selector\n");
3176 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3177 if (!text_selector && !audio_selector)
3178 player->no_more_pad = TRUE;
3180 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3182 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3183 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3184 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3185 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3189 if (audio_selector) {
3190 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3191 if ((active_index != DEFAULT_TRACK) &&
3192 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3193 LOGW("failed to change audio track\n");
3194 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3197 // [link] input-selector :: audiobin
3198 srcpad = gst_element_get_static_pad(audio_selector, "src");
3200 LOGE("failed to get srcpad from selector\n");
3204 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3206 player->no_more_pad = TRUE;
3208 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3209 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3210 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3211 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3212 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3215 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3217 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3219 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3220 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3221 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3222 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3226 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3228 attrs = MMPLAYER_GET_ATTRS(player);
3230 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3231 if (mmf_attrs_commit(attrs))
3232 LOGE("failed to commit.\n");
3234 LOGE("cannot get content attribute");
3236 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3237 LOGD("There is no audio track : remove audiobin");
3239 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3240 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3242 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3243 MMPLAYER_FREEIF(player->pipeline->audiobin);
3246 if (player->num_dynamic_pad == 0)
3247 __mmplayer_pipeline_complete(NULL, player);
3250 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3252 __mmplayer_handle_text_decode_path(player, text_selector);
3259 gst_object_unref(GST_OBJECT(srcpad));
3263 if (player->gapless.reconfigure) {
3264 player->gapless.reconfigure = FALSE;
3265 MMPLAYER_PLAYBACK_UNLOCK(player);
3270 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3272 mm_player_t* player = NULL;
3273 MMHandleType attrs = 0;
3274 GstElement* pipeline = NULL;
3275 GstCaps* caps = NULL;
3276 gchar* caps_str = NULL;
3277 GstStructure* str = NULL;
3278 const gchar* name = NULL;
3279 GstPad* sinkpad = NULL;
3280 GstElement* sinkbin = NULL;
3281 gboolean reusing = FALSE;
3282 GstElement *text_selector = NULL;
3285 player = (mm_player_t*) data;
3287 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3288 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3290 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3292 attrs = MMPLAYER_GET_ATTRS(player);
3294 LOGE("cannot get content attribute\n");
3298 /* get mimetype from caps */
3299 caps = gst_pad_query_caps(pad, NULL);
3301 LOGE("cannot get caps from pad.\n");
3304 caps_str = gst_caps_to_string(caps);
3306 str = gst_caps_get_structure(caps, 0);
3308 LOGE("cannot get structure from caps.\n");
3312 name = gst_structure_get_name(str);
3314 LOGE("cannot get mimetype from structure.\n");
3318 //LOGD("detected mimetype : %s\n", name);
3320 if (strstr(name, "audio")) {
3321 if (player->pipeline->audiobin == NULL) {
3322 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3323 LOGE("failed to create audiobin. continuing without audio\n");
3327 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3328 LOGD("creating audiosink bin success\n");
3331 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3332 LOGD("reusing audiobin\n");
3333 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3336 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3337 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3339 player->audiosink_linked = 1;
3341 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3343 LOGE("failed to get pad from sinkbin\n");
3346 } else if (strstr(name, "video")) {
3347 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3348 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3349 player->set_mode.video_zc = TRUE;
3351 if (player->pipeline->videobin == NULL) {
3352 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3353 /* get video surface type */
3354 int surface_type = 0;
3355 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3356 LOGD("display_surface_type(%d)\n", surface_type);
3358 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3359 LOGD("not make videobin because it dose not want\n");
3363 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3364 /* mark video overlay for acquire */
3365 if (player->video_overlay_resource == NULL) {
3366 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3367 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3368 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3369 &player->video_overlay_resource)
3370 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3371 LOGE("could not mark video_overlay resource for acquire\n");
3377 player->interrupted_by_resource = FALSE;
3378 /* acquire resources for video overlay */
3379 if (mm_resource_manager_commit(player->resource_manager) !=
3380 MM_RESOURCE_MANAGER_ERROR_NONE) {
3381 LOGE("could not acquire resources for video playing\n");
3385 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3386 LOGE("failed to create videobin. continuing without video\n");
3390 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3391 LOGD("creating videosink bin success\n");
3394 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3395 LOGD("re-using videobin\n");
3396 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3399 player->videosink_linked = 1;
3401 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3403 LOGE("failed to get pad from sinkbin\n");
3406 } else if (strstr(name, "text")) {
3407 if (player->pipeline->textbin == NULL) {
3408 MMPlayerGstElement* mainbin = NULL;
3410 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3411 LOGE("failed to create text sink bin. continuing without text\n");
3415 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3416 LOGD("creating textsink bin success\n");
3418 /* FIXIT : track number shouldn't be hardcoded */
3419 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3421 player->textsink_linked = 1;
3422 LOGI("player->textsink_linked set to 1\n");
3424 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3426 LOGE("failed to get pad from sinkbin\n");
3430 mainbin = player->pipeline->mainbin;
3432 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3433 /* input selector */
3434 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3435 if (!text_selector) {
3436 LOGE("failed to create subtitle input selector element\n");
3439 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3441 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3442 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3445 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3446 LOGE("failed to set state(READY) to sinkbin\n");
3450 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3451 LOGW("failed to add subtitle input selector\n");
3455 LOGD("created element input-selector");
3458 LOGD("already having subtitle input selector");
3459 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3462 if (!player->textsink_linked) {
3463 LOGD("re-using textbin\n");
3466 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3468 player->textsink_linked = 1;
3469 LOGI("player->textsink_linked set to 1\n");
3471 LOGD("ignoring internal subtutle since external subtitle is available");
3474 LOGW("unknown type of elementary stream!ignoring it...\n");
3481 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3482 LOGE("failed to set state(READY) to sinkbin\n");
3486 /* Added for multi audio support to avoid adding audio bin again*/
3488 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3489 LOGE("failed to add sinkbin to pipeline\n");
3495 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3496 LOGE("failed to get pad from sinkbin\n");
3502 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3503 LOGE("failed to set state(PAUSED) to sinkbin\n");
3507 if (text_selector) {
3508 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3509 LOGE("failed to set state(PAUSED) to sinkbin\n");
3515 gst_object_unref(sinkpad);
3519 LOGD("[handle: %p] linking sink bin success", player);
3521 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3522 * streaming task. if the task blocked, then buffer will not flow to the next element
3523 *(autoplugging element). so this is special hack for streaming. please try to remove it
3525 /* dec stream count. we can remove fakesink if it's zero */
3526 if (player->num_dynamic_pad)
3527 player->num_dynamic_pad--;
3529 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3531 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3532 __mmplayer_pipeline_complete(NULL, player);
3536 MMPLAYER_FREEIF(caps_str);
3539 gst_caps_unref(caps);
3542 gst_object_unref(GST_OBJECT(sinkpad));
3544 /* flusing out new attributes */
3545 if (mmf_attrs_commit(attrs))
3546 LOGE("failed to comit attributes\n");
3552 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3554 int pro_value = 0; // in the case of expection, default will be returned.
3555 int dest_angle = rotation_angle;
3556 int rotation_type = -1;
3558 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3559 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3560 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3562 if (rotation_angle >= 360)
3563 dest_angle = rotation_angle - 360;
3565 /* chech if supported or not */
3566 if (dest_angle % 90) {
3567 LOGD("not supported rotation angle = %d", rotation_angle);
3573 * custom_convert - none (B)
3574 * videoflip - none (C)
3576 if (player->set_mode.video_zc) {
3577 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3578 rotation_type = ROTATION_USING_CUSTOM;
3580 rotation_type = ROTATION_USING_SINK;
3582 int surface_type = 0;
3583 rotation_type = ROTATION_USING_FLIP;
3585 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3586 LOGD("check display surface type attribute: %d", surface_type);
3588 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3589 rotation_type = ROTATION_USING_SINK;
3591 rotation_type = ROTATION_USING_FLIP; //C
3593 LOGD("using %d type for rotation", rotation_type);
3596 /* get property value for setting */
3597 switch (rotation_type) {
3598 case ROTATION_USING_SINK: // tizenwlsink
3600 switch (dest_angle) {
3604 pro_value = 3; // clockwise 90
3610 pro_value = 1; // counter-clockwise 90
3615 case ROTATION_USING_CUSTOM:
3617 gchar *ename = NULL;
3618 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3620 if (g_strrstr(ename, "fimcconvert")) {
3621 switch (dest_angle) {
3625 pro_value = 90; // clockwise 90
3631 pro_value = 270; // counter-clockwise 90
3637 case ROTATION_USING_FLIP: // videoflip
3639 switch (dest_angle) {
3643 pro_value = 1; // clockwise 90
3649 pro_value = 3; // counter-clockwise 90
3656 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3664 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3666 /* check video sinkbin is created */
3667 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3669 player->pipeline->videobin &&
3670 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3671 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3672 MM_ERROR_PLAYER_NOT_INITIALIZED);
3674 return MM_ERROR_NONE;
3678 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3680 int rotation_value = 0;
3681 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3685 /* check video sinkbin is created */
3686 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3689 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3691 /* get rotation value to set */
3692 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3693 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3694 LOGD("set video param : rotate %d", rotation_value);
3698 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3700 MMHandleType attrs = 0;
3704 /* check video sinkbin is created */
3705 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3708 attrs = MMPLAYER_GET_ATTRS(player);
3709 MMPLAYER_RETURN_IF_FAIL(attrs);
3711 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3712 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3713 LOGD("set video param : visible %d", visible);
3717 __mmplayer_video_param_set_display_method(mm_player_t* player)
3719 MMHandleType attrs = 0;
3720 int display_method = 0;
3723 /* check video sinkbin is created */
3724 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3727 attrs = MMPLAYER_GET_ATTRS(player);
3728 MMPLAYER_RETURN_IF_FAIL(attrs);
3730 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3731 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3732 LOGD("set video param : method %d", display_method);
3736 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3738 MMHandleType attrs = 0;
3739 void *handle = NULL;
3741 int wl_window_x = 0;
3742 int wl_window_y = 0;
3743 int wl_window_width = 0;
3744 int wl_window_height = 0;
3747 /* check video sinkbin is created */
3748 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3751 attrs = MMPLAYER_GET_ATTRS(player);
3752 MMPLAYER_RETURN_IF_FAIL(attrs);
3754 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3757 /*It should be set after setting window*/
3758 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3759 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3760 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3761 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3763 /* After setting window handle, set render rectangle */
3764 gst_video_overlay_set_render_rectangle(
3765 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3766 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3767 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3768 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3773 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3775 MMHandleType attrs = 0;
3776 void *handle = NULL;
3778 /* check video sinkbin is created */
3779 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3782 attrs = MMPLAYER_GET_ATTRS(player);
3783 MMPLAYER_RETURN_IF_FAIL(attrs);
3785 /* common case if using overlay surface */
3786 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3789 /* default is using wl_surface_id */
3790 unsigned int wl_surface_id = 0;
3791 wl_surface_id = *(int*)handle;
3792 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3793 gst_video_overlay_set_wl_window_wl_surface_id(
3794 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3797 /* FIXIT : is it error case? */
3798 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3803 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3805 bool update_all_param = FALSE;
3808 /* check video sinkbin is created */
3809 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3810 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3812 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3813 LOGE("can not find tizenwlsink");
3814 return MM_ERROR_PLAYER_INTERNAL;
3817 LOGD("param_name : %s", param_name);
3818 if (!g_strcmp0(param_name, "update_all_param"))
3819 update_all_param = TRUE;
3821 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3822 __mmplayer_video_param_set_display_overlay(player);
3823 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3824 __mmplayer_video_param_set_display_method(player);
3825 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3826 __mmplayer_video_param_set_render_rectangle(player);
3827 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3828 __mmplayer_video_param_set_display_visible(player);
3829 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3830 __mmplayer_video_param_set_display_rotation(player);
3832 return MM_ERROR_NONE;
3836 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3838 MMHandleType attrs = 0;
3839 int surface_type = 0;
3840 int ret = MM_ERROR_NONE;
3844 /* check video sinkbin is created */
3845 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3846 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3848 attrs = MMPLAYER_GET_ATTRS(player);
3850 LOGE("cannot get content attribute");
3851 return MM_ERROR_PLAYER_INTERNAL;
3853 LOGD("param_name : %s", param_name);
3855 /* update display surface */
3856 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3857 LOGD("check display surface type attribute: %d", surface_type);
3859 /* configuring display */
3860 switch (surface_type) {
3861 case MM_DISPLAY_SURFACE_OVERLAY:
3863 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3864 if (ret != MM_ERROR_NONE)
3872 return MM_ERROR_NONE;
3876 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3878 gboolean disable_overlay = FALSE;
3879 mm_player_t* player = (mm_player_t*) hplayer;
3880 int ret = MM_ERROR_NONE;
3883 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3885 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3886 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3888 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3889 LOGW("Display control is not supported");
3890 return MM_ERROR_PLAYER_INTERNAL;
3893 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3895 if (audio_only == (bool)disable_overlay) {
3896 LOGE("It's the same with current setting: (%d)", audio_only);
3897 return MM_ERROR_NONE;
3901 LOGE("disable overlay");
3902 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3904 /* release overlay resource */
3905 if (player->video_overlay_resource != NULL) {
3906 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3907 player->video_overlay_resource);
3908 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3909 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3912 player->video_overlay_resource = NULL;
3915 ret = mm_resource_manager_commit(player->resource_manager);
3916 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3917 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3921 /* mark video overlay for acquire */
3922 if (player->video_overlay_resource == NULL) {
3923 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3924 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3925 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3926 &player->video_overlay_resource);
3927 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3928 LOGE("could not prepare for video_overlay resource\n");
3933 player->interrupted_by_resource = FALSE;
3934 /* acquire resources for video overlay */
3935 ret = mm_resource_manager_commit(player->resource_manager);
3936 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3937 LOGE("could not acquire resources for video playing\n");
3941 LOGD("enable overlay");
3942 __mmplayer_video_param_set_display_overlay(player);
3943 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3948 return MM_ERROR_NONE;
3952 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3954 mm_player_t* player = (mm_player_t*) hplayer;
3955 gboolean disable_overlay = FALSE;
3959 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3960 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3961 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3962 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3963 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3965 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3966 LOGW("Display control is not supported");
3967 return MM_ERROR_PLAYER_INTERNAL;
3970 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3972 *paudio_only = (bool)(disable_overlay);
3974 LOGD("audio_only : %d", *paudio_only);
3978 return MM_ERROR_NONE;
3982 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3984 GList* bucket = element_bucket;
3985 MMPlayerGstElement* element = NULL;
3986 MMPlayerGstElement* prv_element = NULL;
3987 gint successful_link_count = 0;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3993 prv_element = (MMPlayerGstElement*)bucket->data;
3994 bucket = bucket->next;
3996 for (; bucket; bucket = bucket->next) {
3997 element = (MMPlayerGstElement*)bucket->data;
3999 if (element && element->gst) {
4000 /* If next element is audio appsrc then make a separate audio pipeline */
4001 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4002 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4003 prv_element = element;
4007 if (prv_element && prv_element->gst) {
4008 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4009 LOGD("linking [%s] to [%s] success\n",
4010 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4011 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4012 successful_link_count++;
4014 LOGD("linking [%s] to [%s] failed\n",
4015 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4022 prv_element = element;
4027 return successful_link_count;
4031 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4033 GList* bucket = element_bucket;
4034 MMPlayerGstElement* element = NULL;
4035 int successful_add_count = 0;
4039 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4040 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4042 for (; bucket; bucket = bucket->next) {
4043 element = (MMPlayerGstElement*)bucket->data;
4045 if (element && element->gst) {
4046 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4047 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4048 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4049 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4052 successful_add_count++;
4058 return successful_add_count;
4061 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4063 mm_player_t* player = (mm_player_t*) data;
4064 GstCaps *caps = NULL;
4065 GstStructure *str = NULL;
4070 MMPLAYER_RETURN_IF_FAIL(pad)
4071 MMPLAYER_RETURN_IF_FAIL(unused)
4072 MMPLAYER_RETURN_IF_FAIL(data)
4074 caps = gst_pad_get_current_caps(pad);
4078 str = gst_caps_get_structure(caps, 0);
4082 name = gst_structure_get_name(str);
4086 LOGD("name = %s\n", name);
4088 if (strstr(name, "audio")) {
4089 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4091 if (player->audio_stream_changed_cb) {
4092 LOGE("call the audio stream changed cb\n");
4093 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4095 } else if (strstr(name, "video")) {
4096 if ((name = gst_structure_get_string(str, "format")))
4097 player->set_mode.video_zc = name[0] == 'S';
4099 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4101 if (player->video_stream_changed_cb) {
4102 LOGE("call the video stream changed cb\n");
4103 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4110 gst_caps_unref(caps);
4120 * This function is to create audio pipeline for playing.
4122 * @param player [in] handle of player
4124 * @return This function returns zero on success.
4126 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4128 /* macro for code readability. just for sinkbin-creation functions */
4129 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4131 x_bin[x_id].id = x_id;\
4132 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4133 if (!x_bin[x_id].gst) {\
4134 LOGE("failed to create %s \n", x_factory);\
4137 if (x_player->ini.set_dump_element_flag)\
4138 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4141 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4145 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4150 MMPLAYER_RETURN_IF_FAIL(player);
4152 if (player->audio_stream_buff_list) {
4153 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4154 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4157 LOGD("[%lld] send remained data.", tmp->channel_mask);
4158 __mmplayer_audio_stream_send_data(player, tmp);
4161 g_free(tmp->pcm_data);
4165 g_list_free(player->audio_stream_buff_list);
4166 player->audio_stream_buff_list = NULL;
4173 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4175 MMPlayerAudioStreamDataType audio_stream = { 0, };
4178 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4180 audio_stream.bitrate = a_buffer->bitrate;
4181 audio_stream.channel = a_buffer->channel;
4182 audio_stream.depth = a_buffer->depth;
4183 audio_stream.is_little_endian = a_buffer->is_little_endian;
4184 audio_stream.channel_mask = a_buffer->channel_mask;
4185 audio_stream.data_size = a_buffer->data_size;
4186 audio_stream.data = a_buffer->pcm_data;
4188 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4189 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4195 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4197 mm_player_t* player = (mm_player_t*) data;
4202 gint endianness = 0;
4203 guint64 channel_mask = 0;
4204 void *a_data = NULL;
4206 mm_player_audio_stream_buff_t *a_buffer = NULL;
4207 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4211 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4213 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4214 a_data = mapinfo.data;
4215 a_size = mapinfo.size;
4217 GstCaps *caps = gst_pad_get_current_caps(pad);
4218 GstStructure *structure = gst_caps_get_structure(caps, 0);
4220 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4221 gst_structure_get_int(structure, "rate", &rate);
4222 gst_structure_get_int(structure, "channels", &channel);
4223 gst_structure_get_int(structure, "depth", &depth);
4224 gst_structure_get_int(structure, "endianness", &endianness);
4225 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4226 gst_caps_unref(GST_CAPS(caps));
4228 /* In case of the sync is false, use buffer list. *
4229 * The num of buffer list depends on the num of audio channels */
4230 if (player->audio_stream_buff_list) {
4231 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4232 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4234 if (channel_mask == tmp->channel_mask) {
4235 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4236 if (tmp->data_size + a_size < tmp->buff_size) {
4237 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4238 tmp->data_size += a_size;
4240 /* send data to client */
4241 __mmplayer_audio_stream_send_data(player, tmp);
4243 if (a_size > tmp->buff_size) {
4244 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4245 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4246 if (tmp->pcm_data == NULL) {
4247 LOGE("failed to realloc data.");
4250 tmp->buff_size = a_size;
4252 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4253 memcpy(tmp->pcm_data, a_data, a_size);
4254 tmp->data_size = a_size;
4259 LOGE("data is empty in list.");
4265 /* create new audio stream data */
4266 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4267 if (a_buffer == NULL) {
4268 LOGE("failed to alloc data.");
4271 a_buffer->bitrate = rate;
4272 a_buffer->channel = channel;
4273 a_buffer->depth = depth;
4274 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4275 a_buffer->channel_mask = channel_mask;
4276 a_buffer->data_size = a_size;
4278 if (!player->audio_stream_sink_sync) {
4279 /* If sync is FALSE, use buffer list to reduce the IPC. */
4280 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4281 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4282 if (a_buffer->pcm_data == NULL) {
4283 LOGE("failed to alloc data.");
4287 memcpy(a_buffer->pcm_data, a_data, a_size);
4288 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4289 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4291 /* If sync is TRUE, send data directly. */
4292 a_buffer->pcm_data = a_data;
4293 __mmplayer_audio_stream_send_data(player, a_buffer);
4298 gst_buffer_unmap(buffer, &mapinfo);
4303 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4305 mm_player_t* player = (mm_player_t*)data;
4306 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4307 GstPad* sinkpad = NULL;
4308 GstElement *queue = NULL, *sink = NULL;
4311 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4313 queue = gst_element_factory_make("queue", NULL);
4314 if (queue == NULL) {
4315 LOGD("fail make queue\n");
4319 sink = gst_element_factory_make("fakesink", NULL);
4321 LOGD("fail make fakesink\n");
4325 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4327 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4328 LOGW("failed to link queue & sink\n");
4332 sinkpad = gst_element_get_static_pad(queue, "sink");
4334 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4335 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4339 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4341 gst_object_unref(sinkpad);
4342 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4343 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4345 gst_element_set_state(sink, GST_STATE_PAUSED);
4346 gst_element_set_state(queue, GST_STATE_PAUSED);
4348 MMPLAYER_SIGNAL_CONNECT(player,
4350 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4352 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4359 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4361 gst_object_unref(GST_OBJECT(queue));
4365 gst_object_unref(GST_OBJECT(sink));
4369 gst_object_unref(GST_OBJECT(sinkpad));
4376 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4378 #define MAX_PROPS_LEN 128
4379 gint latency_mode = 0;
4380 gchar *stream_type = NULL;
4381 gchar *latency = NULL;
4383 gchar stream_props[MAX_PROPS_LEN] = {0,};
4384 GstStructure *props = NULL;
4387 * It should be set after player creation through attribute.
4388 * But, it can not be changed during playing.
4391 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4392 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4395 LOGE("stream_type is null.\n");
4397 if (player->sound.focus_id)
4398 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4399 stream_type, stream_id, player->sound.focus_id);
4401 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4402 stream_type, stream_id);
4403 props = gst_structure_from_string(stream_props, NULL);
4404 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4405 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4406 stream_type, stream_id, player->sound.focus_id, stream_props);
4407 gst_structure_free(props);
4410 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4412 switch (latency_mode) {
4413 case AUDIO_LATENCY_MODE_LOW:
4414 latency = g_strndup("low", 3);
4416 case AUDIO_LATENCY_MODE_MID:
4417 latency = g_strndup("mid", 3);
4419 case AUDIO_LATENCY_MODE_HIGH:
4420 latency = g_strndup("high", 4);
4424 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4428 LOGD("audiosink property - latency=%s \n", latency);
4436 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4438 MMPlayerGstElement* first_element = NULL;
4439 MMPlayerGstElement* audiobin = NULL;
4440 MMHandleType attrs = 0;
4442 GstPad *ghostpad = NULL;
4443 GList* element_bucket = NULL;
4444 gboolean link_audio_sink_now = TRUE;
4450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4453 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4455 LOGE("failed to allocate memory for audiobin\n");
4456 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4459 attrs = MMPLAYER_GET_ATTRS(player);
4462 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4463 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4464 if (!audiobin[MMPLAYER_A_BIN].gst) {
4465 LOGE("failed to create audiobin\n");
4470 player->pipeline->audiobin = audiobin;
4472 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4474 /* Adding audiotp plugin for reverse trickplay feature */
4475 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4478 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4480 /* replaygain volume */
4481 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4482 if (player->sound.rg_enable)
4483 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4485 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4488 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4490 if (player->set_mode.pcm_extraction) {
4491 // pcm extraction only and no sound output
4492 if (player->audio_stream_render_cb_ex) {
4493 char *caps_str = NULL;
4494 GstCaps* caps = NULL;
4495 gchar *format = NULL;
4498 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4500 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4502 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4504 caps = gst_caps_new_simple("audio/x-raw",
4505 "format", G_TYPE_STRING, format,
4506 "rate", G_TYPE_INT, player->pcm_samplerate,
4507 "channels", G_TYPE_INT, player->pcm_channel,
4509 caps_str = gst_caps_to_string(caps);
4510 LOGD("new caps : %s\n", caps_str);
4512 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4515 gst_caps_unref(caps);
4516 MMPLAYER_FREEIF(caps_str);
4518 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4520 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4521 /* raw pad handling signal */
4522 MMPLAYER_SIGNAL_CONNECT(player,
4523 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4524 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4525 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4527 int dst_samplerate = 0;
4528 int dst_channels = 0;
4530 char *caps_str = NULL;
4531 GstCaps* caps = NULL;
4533 /* get conf. values */
4534 mm_attrs_multiple_get(player->attrs,
4536 "pcm_extraction_samplerate", &dst_samplerate,
4537 "pcm_extraction_channels", &dst_channels,
4538 "pcm_extraction_depth", &dst_depth,
4542 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4543 caps = gst_caps_new_simple("audio/x-raw",
4544 "rate", G_TYPE_INT, dst_samplerate,
4545 "channels", G_TYPE_INT, dst_channels,
4546 "depth", G_TYPE_INT, dst_depth,
4548 caps_str = gst_caps_to_string(caps);
4549 LOGD("new caps : %s\n", caps_str);
4551 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4554 gst_caps_unref(caps);
4555 MMPLAYER_FREEIF(caps_str);
4558 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4561 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4565 //GstCaps* caps = NULL;
4568 /* for logical volume control */
4569 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4572 if (player->sound.mute) {
4573 LOGD("mute enabled\n");
4574 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4579 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4580 caps = gst_caps_from_string("audio/x-raw-int, "
4581 "endianness = (int) LITTLE_ENDIAN, "
4582 "signed = (boolean) true, "
4583 "width = (int) 16, "
4584 "depth = (int) 16");
4585 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4586 gst_caps_unref(caps);
4589 /* check if multi-channels */
4590 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4591 GstPad *srcpad = NULL;
4592 GstCaps *caps = NULL;
4594 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4595 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4596 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4597 GstStructure *str = gst_caps_get_structure(caps, 0);
4599 gst_structure_get_int(str, "channels", &channels);
4600 gst_caps_unref(caps);
4602 gst_object_unref(srcpad);
4606 /* audio effect element. if audio effect is enabled */
4607 if ((strcmp(player->ini.audioeffect_element, ""))
4609 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4610 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4612 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4614 if ((!player->bypass_audio_effect)
4615 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4616 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4617 if (!_mmplayer_audio_effect_custom_apply(player))
4618 LOGI("apply audio effect(custom) setting success\n");
4622 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4623 && (player->set_mode.rich_audio))
4624 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4627 /* create audio sink */
4628 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4629 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4630 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4632 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4633 if (player->is_content_spherical &&
4635 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4636 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4637 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4639 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4644 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4645 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4646 gst_caps_unref(acaps);
4648 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4650 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4653 player->is_openal_plugin_used = TRUE;
4655 if (player->video360_yaw_radians <= M_PI &&
4656 player->video360_yaw_radians >= -M_PI &&
4657 player->video360_pitch_radians <= M_PI_2 &&
4658 player->video360_pitch_radians >= -M_PI_2) {
4659 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4660 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4661 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4662 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4664 "source-orientation-y", player->video360_metadata.init_view_heading,
4665 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4668 if (player->is_content_spherical)
4669 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4674 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4678 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4679 (player->videodec_linked && player->ini.use_system_clock)) {
4680 LOGD("system clock will be used.\n");
4681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4684 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4685 __mmplayer_gst_set_audiosink_property(player, attrs);
4688 if (audiobin[MMPLAYER_A_SINK].gst) {
4689 GstPad *sink_pad = NULL;
4690 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4691 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4692 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4693 gst_object_unref(GST_OBJECT(sink_pad));
4696 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4698 /* adding created elements to bin */
4699 LOGD("adding created elements to bin\n");
4700 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4701 LOGE("failed to add elements\n");
4705 /* linking elements in the bucket by added order. */
4706 LOGD("Linking elements in the bucket by added order.\n");
4707 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4708 LOGE("failed to link elements\n");
4712 /* get first element's sinkpad for creating ghostpad */
4713 first_element = (MMPlayerGstElement *)element_bucket->data;
4714 if (!first_element) {
4715 LOGE("failed to get first elem\n");
4719 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4721 LOGE("failed to get pad from first element of audiobin\n");
4725 ghostpad = gst_ghost_pad_new("sink", pad);
4727 LOGE("failed to create ghostpad\n");
4731 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4732 LOGE("failed to add ghostpad to audiobin\n");
4736 gst_object_unref(pad);
4738 g_list_free(element_bucket);
4741 return MM_ERROR_NONE;
4745 LOGD("ERROR : releasing audiobin\n");
4748 gst_object_unref(GST_OBJECT(pad));
4751 gst_object_unref(GST_OBJECT(ghostpad));
4754 g_list_free(element_bucket);
4756 /* release element which are not added to bin */
4757 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4758 /* NOTE : skip bin */
4759 if (audiobin[i].gst) {
4760 GstObject* parent = NULL;
4761 parent = gst_element_get_parent(audiobin[i].gst);
4764 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4765 audiobin[i].gst = NULL;
4767 gst_object_unref(GST_OBJECT(parent));
4771 /* release audiobin with it's childs */
4772 if (audiobin[MMPLAYER_A_BIN].gst)
4773 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4775 MMPLAYER_FREEIF(audiobin);
4777 player->pipeline->audiobin = NULL;
4779 return MM_ERROR_PLAYER_INTERNAL;
4782 static GstPadProbeReturn
4783 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4785 mm_player_t* player = (mm_player_t*) u_data;
4786 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4787 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4789 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4791 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4792 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4794 return GST_PAD_PROBE_OK;
4797 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4799 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4802 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4804 int ret = MM_ERROR_NONE;
4806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4807 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4809 MMPLAYER_VIDEO_BO_LOCK(player);
4811 if (player->video_bo_list) {
4812 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4813 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4814 if (tmp && tmp->bo == bo) {
4816 LOGD("release bo %p", bo);
4817 tbm_bo_unref(tmp->bo);
4818 MMPLAYER_VIDEO_BO_UNLOCK(player);
4819 MMPLAYER_VIDEO_BO_SIGNAL(player);
4824 /* hw codec is running or the list was reset for DRC. */
4825 LOGW("there is no bo list.");
4827 MMPLAYER_VIDEO_BO_UNLOCK(player);
4829 LOGW("failed to find bo %p", bo);
4834 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4839 MMPLAYER_RETURN_IF_FAIL(player);
4841 MMPLAYER_VIDEO_BO_LOCK(player);
4842 if (player->video_bo_list) {
4843 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4844 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4845 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4848 tbm_bo_unref(tmp->bo);
4852 g_list_free(player->video_bo_list);
4853 player->video_bo_list = NULL;
4855 player->video_bo_size = 0;
4856 MMPLAYER_VIDEO_BO_UNLOCK(player);
4863 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4866 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4867 gboolean ret = TRUE;
4869 /* check DRC, if it is, destroy the prev bo list to create again */
4870 if (player->video_bo_size != size) {
4871 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4872 __mmplayer_video_stream_destroy_bo_list(player);
4873 player->video_bo_size = size;
4876 MMPLAYER_VIDEO_BO_LOCK(player);
4878 if ((!player->video_bo_list) ||
4879 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4881 /* create bo list */
4883 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4885 if (player->video_bo_list) {
4886 /* if bo list did not created all, try it again. */
4887 idx = g_list_length(player->video_bo_list);
4888 LOGD("bo list exist(len: %d)", idx);
4891 for (; idx < player->ini.num_of_video_bo; idx++) {
4892 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4894 LOGE("Fail to alloc bo_info.");
4897 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4899 LOGE("Fail to tbm_bo_alloc.");
4903 bo_info->using = FALSE;
4904 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4907 /* update video num buffers */
4908 player->video_num_buffers = idx;
4909 if (idx == player->ini.num_of_video_bo)
4910 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4913 MMPLAYER_VIDEO_BO_UNLOCK(player);
4917 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4921 /* get bo from list*/
4922 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4923 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4924 if (tmp && (tmp->using == FALSE)) {
4925 LOGD("found bo %p to use", tmp->bo);
4927 MMPLAYER_VIDEO_BO_UNLOCK(player);
4928 return tbm_bo_ref(tmp->bo);
4932 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4933 MMPLAYER_VIDEO_BO_UNLOCK(player);
4937 if (player->ini.video_bo_timeout <= 0) {
4938 MMPLAYER_VIDEO_BO_WAIT(player);
4940 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4941 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4948 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4950 mm_player_t* player = (mm_player_t*)data;
4952 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4954 /* send prerolled pkt */
4955 player->video_stream_prerolled = FALSE;
4957 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4959 /* not to send prerolled pkt again */
4960 player->video_stream_prerolled = TRUE;
4964 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4966 mm_player_t* player = (mm_player_t*)data;
4967 GstCaps *caps = NULL;
4968 MMPlayerVideoStreamDataType *stream = NULL;
4969 MMVideoBuffer *video_buffer = NULL;
4970 GstMemory *dataBlock = NULL;
4971 GstMemory *metaBlock = NULL;
4972 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4973 GstStructure *structure = NULL;
4974 const gchar *string_format = NULL;
4975 unsigned int fourcc = 0;
4978 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4980 if (player->video_stream_prerolled) {
4981 player->video_stream_prerolled = FALSE;
4982 LOGD("skip the prerolled pkt not to send it again");
4986 caps = gst_pad_get_current_caps(pad);
4988 LOGE("Caps is NULL.");
4992 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4994 /* clear stream data structure */
4995 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4997 LOGE("failed to alloc mem for video data");
5001 structure = gst_caps_get_structure(caps, 0);
5002 gst_structure_get_int(structure, "width", &(stream->width));
5003 gst_structure_get_int(structure, "height", &(stream->height));
5004 string_format = gst_structure_get_string(structure, "format");
5006 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5007 stream->format = util_get_pixtype(fourcc);
5008 gst_caps_unref(caps);
5012 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5013 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5016 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5017 LOGE("Wrong condition!!");
5021 /* set size and timestamp */
5022 dataBlock = gst_buffer_peek_memory(buffer, 0);
5023 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5024 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5026 /* check zero-copy */
5027 if (player->set_mode.video_zc &&
5028 player->set_mode.media_packet_video_stream &&
5029 gst_buffer_n_memory(buffer) > 1) {
5030 metaBlock = gst_buffer_peek_memory(buffer, 1);
5031 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5032 video_buffer = (MMVideoBuffer *)mapinfo.data;
5035 if (video_buffer) { /* hw codec */
5037 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5040 /* copy pointer of tbm bo, stride, elevation */
5041 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5042 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5046 LOGE("Not support video buffer format");
5049 memcpy(stream->stride, video_buffer->stride_width,
5050 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5051 memcpy(stream->elevation, video_buffer->stride_height,
5052 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5054 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5055 stream->internal_buffer = gst_buffer_ref(buffer);
5056 } else { /* sw codec */
5060 int ret = TBM_SURFACE_ERROR_NONE;
5061 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5062 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5064 unsigned char *src = NULL;
5065 unsigned char *dest = NULL;
5066 tbm_bo_handle thandle;
5067 tbm_surface_h surface;
5068 tbm_surface_info_s info;
5071 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5073 LOGE("fail to gst_memory_map");
5078 if (stream->format == MM_PIXEL_FORMAT_I420) {
5079 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5081 ret = tbm_surface_get_info(surface, &info);
5083 if (ret != TBM_SURFACE_ERROR_NONE) {
5084 tbm_surface_destroy(surface);
5087 tbm_surface_destroy(surface);
5089 src_stride[0] = GST_ROUND_UP_4(stream->width);
5090 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5091 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5092 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5093 stream->stride[0] = info.planes[0].stride;
5094 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5095 stream->stride[1] = info.planes[1].stride;
5096 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5097 stream->stride[2] = info.planes[2].stride;
5098 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5099 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5100 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5101 stream->stride[0] = stream->width * 4;
5102 stream->elevation[0] = stream->height;
5103 size = stream->stride[0] * stream->height;
5105 LOGE("Not support format %d", stream->format);
5109 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5110 if (!stream->bo[0]) {
5111 LOGE("Fail to tbm_bo_alloc!!");
5115 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5116 if (thandle.ptr && mapinfo.data) {
5117 if (stream->format == MM_PIXEL_FORMAT_I420) {
5118 for (i = 0; i < 3; i++) {
5119 src = mapinfo.data + src_offset[i];
5120 dest = thandle.ptr + info.planes[i].offset;
5123 for (j = 0; j < stream->height>>k; j++) {
5124 memcpy(dest, src, stream->width>>k);
5125 src += src_stride[i];
5126 dest += stream->stride[i];
5129 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5130 memcpy(thandle.ptr, mapinfo.data, size);
5132 LOGE("Not support format %d", stream->format);
5136 LOGE("data pointer is wrong. dest : %p, src : %p",
5137 thandle.ptr, mapinfo.data);
5140 tbm_bo_unmap(stream->bo[0]);
5143 if (player->video_stream_cb) { /* This has been already checked at the entry */
5144 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5145 LOGE("failed to send video stream data.");
5151 gst_memory_unmap(metaBlock, &mapinfo);
5153 gst_memory_unmap(dataBlock, &mapinfo);
5158 LOGE("release video stream resource.");
5161 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5163 tbm_bo_unref(stream->bo[i]);
5165 gst_memory_unmap(metaBlock, &mapinfo);
5167 /* unref gst buffer */
5168 if (stream->internal_buffer)
5169 gst_buffer_unref(stream->internal_buffer);
5170 } else if (dataBlock) {
5172 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5173 gst_memory_unmap(dataBlock, &mapinfo);
5181 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5183 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5184 GList* element_bucket = NULL;
5186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5190 if (player->set_mode.video_zc || player->is_content_spherical) {
5191 LOGD("do not need to add video filters.");
5192 return MM_ERROR_NONE;
5195 /* in case of sw codec except 360 playback,
5196 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5197 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5198 LOGD("using video converter: %s", video_csc);
5200 /* set video rotator */
5201 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5203 *bucket = element_bucket;
5205 return MM_ERROR_NONE;
5207 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5208 g_list_free(element_bucket);
5212 return MM_ERROR_PLAYER_INTERNAL;
5216 * This function is to create video pipeline.
5218 * @param player [in] handle of player
5219 * caps [in] src caps of decoder
5220 * surface_type [in] surface type for video rendering
5222 * @return This function returns zero on success.
5224 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5228 * - video overlay surface(arm/x86) : tizenwlsink
5231 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5235 GList*element_bucket = NULL;
5236 MMPlayerGstElement* first_element = NULL;
5237 MMPlayerGstElement* videobin = NULL;
5238 gchar *videosink_element = NULL;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5247 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5249 player->pipeline->videobin = videobin;
5251 attrs = MMPLAYER_GET_ATTRS(player);
5253 LOGE("cannot get content attribute");
5254 return MM_ERROR_PLAYER_INTERNAL;
5258 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5259 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5260 if (!videobin[MMPLAYER_V_BIN].gst) {
5261 LOGE("failed to create videobin");
5265 int enable_video_decoded_cb = 0;
5266 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5268 if (player->is_content_spherical) {
5269 LOGD("video360 elem will be added.");
5271 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5272 "video-360", TRUE, player);
5274 /* Set spatial media metadata and/or user settings to the element.
5276 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5277 "projection-type", player->video360_metadata.projection_type, NULL);
5279 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5280 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5282 if (player->video360_metadata.full_pano_width_pixels &&
5283 player->video360_metadata.full_pano_height_pixels &&
5284 player->video360_metadata.cropped_area_image_width &&
5285 player->video360_metadata.cropped_area_image_height) {
5286 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5287 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5288 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5289 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5290 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5291 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5292 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5296 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5297 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5298 "horizontal-fov", player->video360_horizontal_fov,
5299 "vertical-fov", player->video360_vertical_fov, NULL);
5302 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5303 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5304 "zoom", 1.0f / player->video360_zoom, NULL);
5307 if (player->video360_yaw_radians <= M_PI &&
5308 player->video360_yaw_radians >= -M_PI &&
5309 player->video360_pitch_radians <= M_PI_2 &&
5310 player->video360_pitch_radians >= -M_PI_2) {
5311 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5312 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5313 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5314 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5315 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316 "pose-yaw", player->video360_metadata.init_view_heading,
5317 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5320 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5321 "passthrough", !player->is_video360_enabled, NULL);
5324 /* set video sink */
5325 switch (surface_type) {
5326 case MM_DISPLAY_SURFACE_OVERLAY:
5327 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5329 if (strlen(player->ini.videosink_element_overlay) > 0)
5330 videosink_element = player->ini.videosink_element_overlay;
5334 case MM_DISPLAY_SURFACE_NULL:
5335 if (strlen(player->ini.videosink_element_fake) > 0)
5336 videosink_element = player->ini.videosink_element_fake;
5340 case MM_DISPLAY_SURFACE_REMOTE:
5341 if (strlen(player->ini.videosink_element_fake) > 0)
5342 videosink_element = player->ini.videosink_element_fake;
5347 LOGE("unidentified surface type");
5350 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5352 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5354 /* additional setting for sink plug-in */
5355 switch (surface_type) {
5356 case MM_DISPLAY_SURFACE_OVERLAY:
5358 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5360 LOGD("selected videosink name: %s", videosink_element);
5362 /* support shard memory with S/W codec on HawkP */
5363 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5364 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5365 "use-tbm", use_tbm, NULL);
5371 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5374 LOGD("disable last-sample");
5375 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5379 if (player->set_mode.media_packet_video_stream) {
5381 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5383 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5385 MMPLAYER_SIGNAL_CONNECT(player,
5386 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5387 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5389 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5392 MMPLAYER_SIGNAL_CONNECT(player,
5393 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5394 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5396 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5401 case MM_DISPLAY_SURFACE_REMOTE:
5403 if (player->set_mode.media_packet_video_stream) {
5404 LOGE("add data probe at videosink");
5405 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5406 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5408 MMPLAYER_SIGNAL_CONNECT(player,
5409 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5410 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5412 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5415 MMPLAYER_SIGNAL_CONNECT(player,
5416 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5417 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5419 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5424 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5427 LOGD("disable last-sample");
5428 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5438 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5441 if (videobin[MMPLAYER_V_SINK].gst) {
5442 GstPad *sink_pad = NULL;
5443 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5445 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5446 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5447 gst_object_unref(GST_OBJECT(sink_pad));
5449 LOGW("failed to get sink pad from videosink\n");
5452 /* store it as it's sink element */
5453 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5455 /* adding created elements to bin */
5456 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5457 LOGE("failed to add elements\n");
5461 /* Linking elements in the bucket by added order */
5462 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5463 LOGE("failed to link elements\n");
5467 /* get first element's sinkpad for creating ghostpad */
5469 first_element = (MMPlayerGstElement *)element_bucket->data;
5470 if (!first_element) {
5471 LOGE("failed to get first element from bucket\n");
5475 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5477 LOGE("failed to get pad from first element\n");
5481 /* create ghostpad */
5482 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5483 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5484 LOGE("failed to add ghostpad to videobin\n");
5487 gst_object_unref(pad);
5489 /* done. free allocated variables */
5491 g_list_free(element_bucket);
5495 return MM_ERROR_NONE;
5498 LOGE("ERROR : releasing videobin\n");
5500 g_list_free(element_bucket);
5503 gst_object_unref(GST_OBJECT(pad));
5505 /* release videobin with it's childs */
5506 if (videobin[MMPLAYER_V_BIN].gst)
5507 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5510 MMPLAYER_FREEIF(videobin);
5512 player->pipeline->videobin = NULL;
5514 return MM_ERROR_PLAYER_INTERNAL;
5517 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5519 GList *element_bucket = NULL;
5520 MMPlayerGstElement *textbin = player->pipeline->textbin;
5522 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5523 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5524 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5525 "signal-handoffs", FALSE,
5528 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5529 MMPLAYER_SIGNAL_CONNECT(player,
5530 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5531 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5533 G_CALLBACK(__mmplayer_update_subtitle),
5536 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5537 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5538 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5540 if (!player->play_subtitle) {
5541 LOGD("add textbin sink as sink element of whole pipeline.\n");
5542 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5545 /* adding created elements to bin */
5546 LOGD("adding created elements to bin\n");
5547 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5548 LOGE("failed to add elements\n");
5552 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5553 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5554 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5556 /* linking elements in the bucket by added order. */
5557 LOGD("Linking elements in the bucket by added order.\n");
5558 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5559 LOGE("failed to link elements\n");
5563 /* done. free allocated variables */
5564 g_list_free(element_bucket);
5566 if (textbin[MMPLAYER_T_QUEUE].gst) {
5568 GstPad *ghostpad = NULL;
5570 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5572 LOGE("failed to get sink pad of text queue");
5576 ghostpad = gst_ghost_pad_new("text_sink", pad);
5577 gst_object_unref(pad);
5580 LOGE("failed to create ghostpad of textbin\n");
5584 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5585 LOGE("failed to add ghostpad to textbin\n");
5586 gst_object_unref(ghostpad);
5591 return MM_ERROR_NONE;
5594 g_list_free(element_bucket);
5596 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5597 LOGE("remove textbin sink from sink list");
5598 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5601 /* release element at __mmplayer_gst_create_text_sink_bin */
5602 return MM_ERROR_PLAYER_INTERNAL;
5605 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5607 MMPlayerGstElement *textbin = NULL;
5608 GList *element_bucket = NULL;
5609 int surface_type = 0;
5614 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5617 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5619 LOGE("failed to allocate memory for textbin\n");
5620 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5624 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5625 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5626 if (!textbin[MMPLAYER_T_BIN].gst) {
5627 LOGE("failed to create textbin\n");
5632 player->pipeline->textbin = textbin;
5635 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5636 LOGD("surface type for subtitle : %d", surface_type);
5637 switch (surface_type) {
5638 case MM_DISPLAY_SURFACE_OVERLAY:
5639 case MM_DISPLAY_SURFACE_NULL:
5640 case MM_DISPLAY_SURFACE_REMOTE:
5641 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5642 LOGE("failed to make plain text elements\n");
5653 return MM_ERROR_NONE;
5657 LOGD("ERROR : releasing textbin\n");
5659 g_list_free(element_bucket);
5661 /* release signal */
5662 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5664 /* release element which are not added to bin */
5665 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5666 /* NOTE : skip bin */
5667 if (textbin[i].gst) {
5668 GstObject* parent = NULL;
5669 parent = gst_element_get_parent(textbin[i].gst);
5672 gst_object_unref(GST_OBJECT(textbin[i].gst));
5673 textbin[i].gst = NULL;
5675 gst_object_unref(GST_OBJECT(parent));
5680 /* release textbin with it's childs */
5681 if (textbin[MMPLAYER_T_BIN].gst)
5682 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5684 MMPLAYER_FREEIF(player->pipeline->textbin);
5685 player->pipeline->textbin = NULL;
5688 return MM_ERROR_PLAYER_INTERNAL;
5693 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5695 MMPlayerGstElement* mainbin = NULL;
5696 MMPlayerGstElement* textbin = NULL;
5697 MMHandleType attrs = 0;
5698 GstElement *subsrc = NULL;
5699 GstElement *subparse = NULL;
5700 gchar *subtitle_uri = NULL;
5701 const gchar *charset = NULL;
5707 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5709 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5711 mainbin = player->pipeline->mainbin;
5713 attrs = MMPLAYER_GET_ATTRS(player);
5715 LOGE("cannot get content attribute\n");
5716 return MM_ERROR_PLAYER_INTERNAL;
5719 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5720 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5721 LOGE("subtitle uri is not proper filepath.\n");
5722 return MM_ERROR_PLAYER_INVALID_URI;
5725 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5726 LOGE("failed to get storage info of subtitle path");
5727 return MM_ERROR_PLAYER_INVALID_URI;
5730 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5732 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5733 player->subtitle_language_list = NULL;
5734 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5736 /* create the subtitle source */
5737 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5739 LOGE("failed to create filesrc element\n");
5742 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5744 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5745 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5747 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5748 LOGW("failed to add queue\n");
5749 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5750 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5751 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5756 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5758 LOGE("failed to create subparse element\n");
5762 charset = util_get_charset(subtitle_uri);
5764 LOGD("detected charset is %s\n", charset);
5765 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5768 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5769 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5771 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5772 LOGW("failed to add subparse\n");
5773 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5774 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5775 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5779 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5780 LOGW("failed to link subsrc and subparse\n");
5784 player->play_subtitle = TRUE;
5785 player->adjust_subtitle_pos = 0;
5787 LOGD("play subtitle using subtitle file\n");
5789 if (player->pipeline->textbin == NULL) {
5790 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5791 LOGE("failed to create text sink bin. continuing without text\n");
5795 textbin = player->pipeline->textbin;
5797 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5798 LOGW("failed to add textbin\n");
5800 /* release signal */
5801 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5803 /* release textbin with it's childs */
5804 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5805 MMPLAYER_FREEIF(player->pipeline->textbin);
5806 player->pipeline->textbin = textbin = NULL;
5810 LOGD("link text input selector and textbin ghost pad");
5812 player->textsink_linked = 1;
5813 player->external_text_idx = 0;
5814 LOGI("player->textsink_linked set to 1\n");
5816 textbin = player->pipeline->textbin;
5817 LOGD("text bin has been created. reuse it.");
5818 player->external_text_idx = 1;
5821 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5822 LOGW("failed to link subparse and textbin\n");
5826 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5828 LOGE("failed to get sink pad from textsink to probe data");
5832 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5833 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5835 gst_object_unref(pad);
5838 /* create dot. for debugging */
5839 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5842 return MM_ERROR_NONE;
5845 /* release text pipeline resource */
5846 player->textsink_linked = 0;
5848 /* release signal */
5849 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5851 if (player->pipeline->textbin) {
5852 LOGE("remove textbin");
5854 /* release textbin with it's childs */
5855 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5856 MMPLAYER_FREEIF(player->pipeline->textbin);
5857 player->pipeline->textbin = NULL;
5861 /* release subtitle elem */
5862 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5863 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5865 return MM_ERROR_PLAYER_INTERNAL;
5869 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5871 mm_player_t* player = (mm_player_t*) data;
5872 MMMessageParamType msg = {0, };
5873 GstClockTime duration = 0;
5874 gpointer text = NULL;
5875 guint text_size = 0;
5876 gboolean ret = TRUE;
5877 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5881 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5882 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5884 if (player->is_subtitle_force_drop) {
5885 LOGW("subtitle is dropped forcedly.");
5889 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5890 text = mapinfo.data;
5891 text_size = mapinfo.size;
5892 duration = GST_BUFFER_DURATION(buffer);
5894 if (player->set_mode.subtitle_off) {
5895 LOGD("subtitle is OFF.\n");
5899 if (!text || (text_size == 0)) {
5900 LOGD("There is no subtitle to be displayed.\n");
5904 msg.data = (void *) text;
5905 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5907 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5909 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5910 gst_buffer_unmap(buffer, &mapinfo);
5917 static GstPadProbeReturn
5918 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5920 mm_player_t *player = (mm_player_t *) u_data;
5921 GstClockTime cur_timestamp = 0;
5922 gint64 adjusted_timestamp = 0;
5923 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5925 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5927 if (player->set_mode.subtitle_off) {
5928 LOGD("subtitle is OFF.\n");
5932 if (player->adjust_subtitle_pos == 0) {
5933 LOGD("nothing to do");
5937 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5938 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5940 if (adjusted_timestamp < 0) {
5941 LOGD("adjusted_timestamp under zero");
5946 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5947 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5948 GST_TIME_ARGS(cur_timestamp),
5949 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5951 return GST_PAD_PROBE_OK;
5953 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5957 /* check player and subtitlebin are created */
5958 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5959 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5961 if (position == 0) {
5962 LOGD("nothing to do\n");
5964 return MM_ERROR_NONE;
5968 case MM_PLAYER_POS_FORMAT_TIME:
5970 /* check current postion */
5971 player->adjust_subtitle_pos = position;
5973 LOGD("save adjust_subtitle_pos in player") ;
5979 LOGW("invalid format.\n");
5981 return MM_ERROR_INVALID_ARGUMENT;
5987 return MM_ERROR_NONE;
5989 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5992 LOGD("adjusting video_pos in player") ;
5993 int current_pos = 0;
5994 /* check player and videobin are created */
5995 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5996 if (!player->pipeline->videobin ||
5997 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5998 LOGD("no video pipeline or sink is there");
5999 return MM_ERROR_PLAYER_INVALID_STATE ;
6002 LOGD("nothing to do\n");
6004 return MM_ERROR_NONE;
6006 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6007 LOGD("failed to get current position");
6008 return MM_ERROR_PLAYER_INTERNAL;
6010 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6011 LOGD("enter video delay is valid");
6013 LOGD("enter video delay is crossing content boundary");
6014 return MM_ERROR_INVALID_ARGUMENT ;
6016 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6017 LOGD("video delay has been done");
6020 return MM_ERROR_NONE;
6024 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6026 GstElement *appsrc = element;
6027 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6028 GstBuffer *buffer = NULL;
6029 GstFlowReturn ret = GST_FLOW_OK;
6032 MMPLAYER_RETURN_IF_FAIL(element);
6033 MMPLAYER_RETURN_IF_FAIL(buf);
6035 buffer = gst_buffer_new();
6037 if (buf->offset >= buf->len) {
6038 LOGD("call eos appsrc\n");
6039 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6043 if (buf->len - buf->offset < size)
6044 len = buf->len - buf->offset;
6046 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6047 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6048 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6050 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6051 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6057 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6059 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6061 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6063 buf->offset = (int)size;
6068 static GstBusSyncReply
6069 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6071 mm_player_t *player = (mm_player_t *)data;
6072 GstBusSyncReply reply = GST_BUS_DROP;
6074 if (!(player->pipeline && player->pipeline->mainbin)) {
6075 LOGE("player pipeline handle is null");
6076 return GST_BUS_PASS;
6079 if (!__mmplayer_check_useful_message(player, message)) {
6080 gst_message_unref(message);
6081 return GST_BUS_DROP;
6084 switch (GST_MESSAGE_TYPE(message)) {
6085 case GST_MESSAGE_STATE_CHANGED:
6086 /* post directly for fast launch */
6087 if (player->sync_handler) {
6088 __mmplayer_gst_callback(message, player);
6089 reply = GST_BUS_DROP;
6091 reply = GST_BUS_PASS;
6093 case GST_MESSAGE_TAG:
6094 __mmplayer_gst_extract_tag_from_msg(player, message);
6098 GstTagList *tags = NULL;
6100 gst_message_parse_tag(message, &tags);
6102 LOGE("TAGS received from element \"%s\".\n",
6103 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6105 gst_tag_list_foreach(tags, print_tag, NULL);
6106 gst_tag_list_free(tags);
6114 case GST_MESSAGE_DURATION_CHANGED:
6115 __mmplayer_gst_handle_duration(player, message);
6117 case GST_MESSAGE_ASYNC_DONE:
6118 /* NOTE:Don't call gst_callback directly
6119 * because previous frame can be showed even though this message is received for seek.
6122 reply = GST_BUS_PASS;
6126 if (reply == GST_BUS_DROP)
6127 gst_message_unref(message);
6133 __mmplayer_gst_create_decoder(mm_player_t *player,
6134 MMPlayerTrackType track,
6136 enum MainElementID elemId,
6139 gboolean ret = TRUE;
6140 GstPad *sinkpad = NULL;
6144 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6146 player->pipeline->mainbin, FALSE);
6147 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6148 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6149 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6151 GstElement *decodebin = NULL;
6152 GstCaps *dec_caps = NULL;
6154 /* create decodebin */
6155 decodebin = gst_element_factory_make("decodebin", name);
6158 LOGE("error : fail to create decodebin for %d decoder\n", track);
6163 /* raw pad handling signal */
6164 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6165 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6167 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6168 before looking for any elements that can handle that stream.*/
6169 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6170 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6172 /* This signal is emitted when a element is added to the bin.*/
6173 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6174 G_CALLBACK(__mmplayer_gst_element_added), player);
6176 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6177 LOGE("failed to add new decodebin\n");
6182 dec_caps = gst_pad_query_caps(srcpad, NULL);
6184 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6185 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6186 gst_caps_unref(dec_caps);
6189 player->pipeline->mainbin[elemId].id = elemId;
6190 player->pipeline->mainbin[elemId].gst = decodebin;
6192 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6194 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6195 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6196 gst_object_unref(GST_OBJECT(decodebin));
6199 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6200 LOGE("failed to sync second level decodebin state with parent\n");
6202 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6206 gst_object_unref(GST_OBJECT(sinkpad));
6215 * This function is to create audio or video pipeline for playing.
6217 * @param player [in] handle of player
6219 * @return This function returns zero on success.
6224 __mmplayer_gst_create_pipeline(mm_player_t* player)
6227 MMPlayerGstElement *mainbin = NULL;
6228 MMHandleType attrs = 0;
6229 GstElement* element = NULL;
6230 GstElement* elem_src_audio = NULL;
6231 GstElement* elem_src_subtitle = NULL;
6232 GstElement* es_video_queue = NULL;
6233 GstElement* es_audio_queue = NULL;
6234 GstElement* es_subtitle_queue = NULL;
6235 GList* element_bucket = NULL;
6236 gboolean need_state_holder = TRUE;
6238 #ifdef SW_CODEC_ONLY
6239 int surface_type = 0;
6243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6245 /* get profile attribute */
6246 attrs = MMPLAYER_GET_ATTRS(player);
6248 LOGE("cannot get content attribute\n");
6252 /* create pipeline handles */
6253 if (player->pipeline) {
6254 LOGW("pipeline should be released before create new one\n");
6258 player->video360_metadata.is_spherical = -1;
6259 player->is_openal_plugin_used = FALSE;
6261 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6262 if (player->pipeline == NULL)
6265 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6267 /* create mainbin */
6268 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6269 if (mainbin == NULL)
6272 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6274 /* create pipeline */
6275 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6276 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6277 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6278 LOGE("failed to create pipeline\n");
6281 player->demux_pad_index = 0;
6282 player->subtitle_language_list = NULL;
6284 player->is_subtitle_force_drop = FALSE;
6285 player->last_multiwin_status = FALSE;
6287 _mmplayer_track_initialize(player);
6288 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6290 /* create source element */
6291 switch (player->profile.uri_type) {
6292 /* rtsp streamming */
6293 case MM_PLAYER_URI_TYPE_URL_RTSP:
6297 element = gst_element_factory_make("rtspsrc", "rtsp source");
6300 LOGE("failed to create streaming source element\n");
6308 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6310 SECURE_LOGD("user_agent : %s\n", user_agent);
6312 /* setting property to streaming source */
6313 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6315 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6317 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6318 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6319 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6320 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6325 case MM_PLAYER_URI_TYPE_URL_HTTP:
6327 gchar *user_agent, *cookies, **cookie_list;
6328 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6329 user_agent = cookies = NULL;
6331 gint mode = MM_PLAYER_PD_MODE_NONE;
6333 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6335 player->pd_mode = mode;
6337 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6339 if (!MMPLAYER_IS_HTTP_PD(player)) {
6340 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6342 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6345 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6348 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6349 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6351 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6352 LOGD("get timeout from ini\n");
6353 http_timeout = player->ini.http_timeout;
6357 SECURE_LOGD("location : %s\n", player->profile.uri);
6358 SECURE_LOGD("cookies : %s\n", cookies);
6359 SECURE_LOGD("user_agent : %s\n", user_agent);
6360 LOGD("timeout : %d\n", http_timeout);
6362 /* setting property to streaming source */
6363 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6364 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6365 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6367 /* parsing cookies */
6368 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6369 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6370 g_strfreev(cookie_list);
6373 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6375 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6376 LOGW("it's dash. and it's still experimental feature.");
6378 // progressive download
6379 gchar* location = NULL;
6381 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6384 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6386 MMPLAYER_FREEIF(player->pd_file_save_path);
6388 LOGD("PD Location : %s\n", path);
6391 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6392 LOGE("failed to get storage info");
6395 player->pd_file_save_path = g_strdup(path);
6397 LOGE("can't find pd location so, it should be set \n");
6402 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6404 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6408 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6409 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6411 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6412 g_object_get(element, "location", &location, NULL);
6413 LOGD("PD_LOCATION [%s].\n", location);
6421 case MM_PLAYER_URI_TYPE_FILE:
6423 LOGD("using filesrc for 'file://' handler.\n");
6424 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6425 LOGE("failed to get storage info");
6429 element = gst_element_factory_make("filesrc", "source");
6431 LOGE("failed to create filesrc\n");
6435 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6439 case MM_PLAYER_URI_TYPE_SS:
6441 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6442 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6444 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6448 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6449 LOGD("get timeout from ini\n");
6450 http_timeout = player->ini.http_timeout;
6453 /* setting property to streaming source */
6454 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6455 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6458 case MM_PLAYER_URI_TYPE_MS_BUFF:
6460 LOGD("MS buff src is selected\n");
6462 if (player->v_stream_caps) {
6463 element = gst_element_factory_make("appsrc", "video_appsrc");
6465 LOGF("failed to create video app source element[appsrc].\n");
6469 if (player->a_stream_caps) {
6470 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6471 if (!elem_src_audio) {
6472 LOGF("failed to create audio app source element[appsrc].\n");
6476 } else if (player->a_stream_caps) {
6477 /* no video, only audio pipeline*/
6478 element = gst_element_factory_make("appsrc", "audio_appsrc");
6480 LOGF("failed to create audio app source element[appsrc].\n");
6485 if (player->s_stream_caps) {
6486 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6487 if (!elem_src_subtitle) {
6488 LOGF("failed to create subtitle app source element[appsrc].\n");
6493 LOGD("setting app sources properties.\n");
6494 LOGD("location : %s\n", player->profile.uri);
6496 if (player->v_stream_caps && element) {
6497 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6498 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6499 "caps", player->v_stream_caps, NULL);
6501 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6502 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6503 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6504 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6506 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6507 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6508 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6509 G_CALLBACK(__gst_seek_video_data), player);
6511 if (player->a_stream_caps && elem_src_audio) {
6512 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6513 "caps", player->a_stream_caps, NULL);
6515 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6516 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6517 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6518 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6520 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6521 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6522 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6523 G_CALLBACK(__gst_seek_audio_data), player);
6525 } else if (player->a_stream_caps && element) {
6526 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6527 "caps", player->a_stream_caps, NULL);
6529 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6530 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6531 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6532 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6534 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6535 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6536 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6537 G_CALLBACK(__gst_seek_audio_data), player);
6540 if (player->s_stream_caps && elem_src_subtitle) {
6541 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6542 "caps", player->s_stream_caps, NULL);
6544 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6545 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6546 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6547 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6549 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6551 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6552 G_CALLBACK(__gst_seek_subtitle_data), player);
6555 if (player->v_stream_caps && element) {
6556 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6557 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6558 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6559 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6561 if (player->a_stream_caps && elem_src_audio) {
6562 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6563 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6564 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6565 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6567 } else if (player->a_stream_caps && element) {
6568 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6569 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6570 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6571 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6574 if (player->s_stream_caps && elem_src_subtitle)
6575 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6576 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6578 need_state_holder = FALSE;
6580 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6581 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6582 LOGE("failed to commit\n");
6586 case MM_PLAYER_URI_TYPE_MEM:
6588 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6590 LOGD("mem src is selected\n");
6592 element = gst_element_factory_make("appsrc", "mem-source");
6594 LOGE("failed to create appsrc element\n");
6598 g_object_set(element, "stream-type", stream_type, NULL);
6599 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6600 g_object_set(element, "blocksize", (guint64)20480, NULL);
6602 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6603 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6604 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6605 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6608 case MM_PLAYER_URI_TYPE_URL:
6611 case MM_PLAYER_URI_TYPE_TEMP:
6614 case MM_PLAYER_URI_TYPE_NONE:
6619 /* check source element is OK */
6621 LOGE("no source element was created.\n");
6625 /* take source element */
6626 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6627 mainbin[MMPLAYER_M_SRC].gst = element;
6628 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6630 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6631 player->streamer = __mm_player_streaming_create();
6632 __mm_player_streaming_initialize(player->streamer);
6635 if (MMPLAYER_IS_HTTP_PD(player)) {
6636 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6638 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6639 element = gst_element_factory_make("queue2", "queue2");
6641 LOGE("failed to create http streaming buffer element\n");
6646 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6647 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6648 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6650 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6652 __mm_player_streaming_set_queue2(player->streamer,
6655 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6658 player->ini.http_buffering_limit,
6659 MUXED_BUFFER_TYPE_MEM_QUEUE,
6663 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6664 if (player->v_stream_caps) {
6665 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6666 if (!es_video_queue) {
6667 LOGE("create es_video_queue for es player failed\n");
6670 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6671 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6672 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6673 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6675 /* Adding audio appsrc to bucket */
6676 if (player->a_stream_caps && elem_src_audio) {
6677 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6678 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6679 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6681 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6682 if (!es_audio_queue) {
6683 LOGE("create es_audio_queue for es player failed\n");
6686 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6688 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6689 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6690 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6692 } else if (player->a_stream_caps) {
6693 /* Only audio stream, no video */
6694 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6695 if (!es_audio_queue) {
6696 LOGE("create es_audio_queue for es player failed\n");
6699 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6700 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6701 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6704 if (player->s_stream_caps && elem_src_subtitle) {
6705 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6706 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6707 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6709 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6710 if (!es_subtitle_queue) {
6711 LOGE("create es_subtitle_queue for es player failed\n");
6714 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6716 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6720 /* create autoplugging element if src element is not a rtsp src */
6721 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6722 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6724 enum MainElementID elemId = MMPLAYER_M_NUM;
6726 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6727 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6728 elemId = MMPLAYER_M_AUTOPLUG;
6729 element = __mmplayer_create_decodebin(player);
6731 /* default size of mq in decodebin is 2M
6732 * but it can cause blocking issue during seeking depends on content. */
6733 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6735 need_state_holder = FALSE;
6737 elemId = MMPLAYER_M_TYPEFIND;
6738 element = gst_element_factory_make("typefind", "typefinder");
6739 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6740 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6744 /* check autoplug element is OK */
6746 LOGE("can not create element(%d)\n", elemId);
6750 mainbin[elemId].id = elemId;
6751 mainbin[elemId].gst = element;
6753 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6756 /* add elements to pipeline */
6757 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6758 LOGE("Failed to add elements to pipeline\n");
6763 /* linking elements in the bucket by added order. */
6764 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6765 LOGE("Failed to link some elements\n");
6770 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6771 if (need_state_holder) {
6773 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6774 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6776 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6777 LOGE("fakesink element could not be created\n");
6780 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6782 /* take ownership of fakesink. we are reusing it */
6783 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6786 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6787 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6788 LOGE("failed to add fakesink to bin\n");
6793 /* now we have completed mainbin. take it */
6794 player->pipeline->mainbin = mainbin;
6796 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6797 GstPad *srcpad = NULL;
6799 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6800 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6802 __mmplayer_gst_create_decoder(player,
6803 MM_PLAYER_TRACK_TYPE_VIDEO,
6805 MMPLAYER_M_AUTOPLUG_V_DEC,
6808 gst_object_unref(GST_OBJECT(srcpad));
6813 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6814 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6816 __mmplayer_gst_create_decoder(player,
6817 MM_PLAYER_TRACK_TYPE_AUDIO,
6819 MMPLAYER_M_AUTOPLUG_A_DEC,
6822 gst_object_unref(GST_OBJECT(srcpad));
6827 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6828 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6831 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6832 if (__mmplayer_check_subtitle(player)) {
6833 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6834 LOGE("fail to create text pipeline");
6837 /* connect bus callback */
6838 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6840 LOGE("cannot get bus from pipeline.\n");
6844 /* set sync handler to get tag synchronously */
6845 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6848 gst_object_unref(GST_OBJECT(bus));
6849 g_list_free(element_bucket);
6851 /* create gst bus_msb_cb thread */
6852 g_mutex_init(&player->bus_msg_thread_mutex);
6853 g_cond_init(&player->bus_msg_thread_cond);
6854 player->bus_msg_thread_exit = FALSE;
6855 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6856 player->bus_msg_thread =
6857 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6858 if (!player->bus_msg_thread) {
6859 LOGE("failed to create gst BUS msg thread");
6860 g_mutex_clear(&player->bus_msg_thread_mutex);
6861 g_cond_clear(&player->bus_msg_thread_cond);
6867 return MM_ERROR_NONE;
6870 __mmplayer_gst_destroy_pipeline(player);
6871 g_list_free(element_bucket);
6874 /* release element which are not added to bin */
6875 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6876 /* NOTE : skip pipeline */
6877 if (mainbin[i].gst) {
6878 GstObject* parent = NULL;
6879 parent = gst_element_get_parent(mainbin[i].gst);
6882 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6883 mainbin[i].gst = NULL;
6885 gst_object_unref(GST_OBJECT(parent));
6889 /* release pipeline with it's childs */
6890 if (mainbin[MMPLAYER_M_PIPE].gst)
6891 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6893 MMPLAYER_FREEIF(mainbin);
6896 MMPLAYER_FREEIF(player->pipeline);
6897 return MM_ERROR_PLAYER_INTERNAL;
6901 __mmplayer_reset_gapless_state(mm_player_t* player)
6904 MMPLAYER_RETURN_IF_FAIL(player
6906 && player->pipeline->audiobin
6907 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6909 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6916 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6919 int ret = MM_ERROR_NONE;
6923 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6925 /* cleanup stuffs */
6926 MMPLAYER_FREEIF(player->type);
6927 player->have_dynamic_pad = FALSE;
6928 player->no_more_pad = FALSE;
6929 player->num_dynamic_pad = 0;
6930 player->demux_pad_index = 0;
6931 player->use_deinterleave = FALSE;
6932 player->max_audio_channels = 0;
6933 player->video_share_api_delta = 0;
6934 player->video_share_clock_delta = 0;
6935 player->video_hub_download_mode = 0;
6937 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6938 player->subtitle_language_list = NULL;
6939 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6941 __mmplayer_reset_gapless_state(player);
6943 if (player->streamer) {
6944 __mm_player_streaming_deinitialize(player->streamer);
6945 __mm_player_streaming_destroy(player->streamer);
6946 player->streamer = NULL;
6949 /* cleanup unlinked mime type */
6950 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6951 MMPLAYER_FREEIF(player->unlinked_video_mime);
6952 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6954 /* cleanup running stuffs */
6955 __mmplayer_cancel_eos_timer(player);
6957 /* cleanup gst stuffs */
6958 if (player->pipeline) {
6959 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6960 GstTagList* tag_list = player->pipeline->tag_list;
6962 /* first we need to disconnect all signal hander */
6963 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6966 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6967 MMPlayerGstElement* videobin = player->pipeline->videobin;
6968 MMPlayerGstElement* textbin = player->pipeline->textbin;
6969 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6970 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6971 gst_object_unref(bus);
6973 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6974 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6975 if (ret != MM_ERROR_NONE) {
6976 LOGE("fail to change state to NULL\n");
6977 return MM_ERROR_PLAYER_INTERNAL;
6980 LOGW("succeeded in chaning state to NULL\n");
6982 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6985 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6986 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6988 /* free avsysaudiosink
6989 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6990 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6992 MMPLAYER_FREEIF(audiobin);
6993 MMPLAYER_FREEIF(videobin);
6994 MMPLAYER_FREEIF(textbin);
6995 MMPLAYER_FREEIF(mainbin);
6999 gst_tag_list_free(tag_list);
7001 MMPLAYER_FREEIF(player->pipeline);
7003 MMPLAYER_FREEIF(player->album_art);
7005 if (player->v_stream_caps) {
7006 gst_caps_unref(player->v_stream_caps);
7007 player->v_stream_caps = NULL;
7009 if (player->a_stream_caps) {
7010 gst_caps_unref(player->a_stream_caps);
7011 player->a_stream_caps = NULL;
7014 if (player->s_stream_caps) {
7015 gst_caps_unref(player->s_stream_caps);
7016 player->s_stream_caps = NULL;
7018 _mmplayer_track_destroy(player);
7020 if (player->sink_elements)
7021 g_list_free(player->sink_elements);
7022 player->sink_elements = NULL;
7024 if (player->bufmgr) {
7025 tbm_bufmgr_deinit(player->bufmgr);
7026 player->bufmgr = NULL;
7029 LOGW("finished destroy pipeline\n");
7036 static int __gst_realize(mm_player_t* player)
7039 int ret = MM_ERROR_NONE;
7043 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7045 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7047 ret = __mmplayer_gst_create_pipeline(player);
7049 LOGE("failed to create pipeline\n");
7053 /* set pipeline state to READY */
7054 /* NOTE : state change to READY must be performed sync. */
7055 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7056 ret = __mmplayer_gst_set_state(player,
7057 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7059 if (ret != MM_ERROR_NONE) {
7060 /* return error if failed to set state */
7061 LOGE("failed to set READY state");
7065 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7067 /* create dot before error-return. for debugging */
7068 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7075 static int __gst_unrealize(mm_player_t* player)
7077 int ret = MM_ERROR_NONE;
7081 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7083 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7084 MMPLAYER_PRINT_STATE(player);
7086 /* release miscellaneous information */
7087 __mmplayer_release_misc(player);
7089 /* destroy pipeline */
7090 ret = __mmplayer_gst_destroy_pipeline(player);
7091 if (ret != MM_ERROR_NONE) {
7092 LOGE("failed to destory pipeline\n");
7096 /* release miscellaneous information.
7097 these info needs to be released after pipeline is destroyed. */
7098 __mmplayer_release_misc_post(player);
7100 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7107 static int __gst_pending_seek(mm_player_t* player)
7109 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7110 int ret = MM_ERROR_NONE;
7114 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7116 if (!player->pending_seek.is_pending) {
7117 LOGD("pending seek is not reserved. nothing to do.\n");
7121 /* check player state if player could pending seek or not. */
7122 current_state = MMPLAYER_CURRENT_STATE(player);
7124 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7125 LOGW("try to pending seek in %s state, try next time. \n",
7126 MMPLAYER_STATE_GET_NAME(current_state));
7130 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7132 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7134 if (MM_ERROR_NONE != ret)
7135 LOGE("failed to seek pending postion. just keep staying current position.\n");
7137 player->pending_seek.is_pending = FALSE;
7144 static int __gst_start(mm_player_t* player)
7146 gboolean sound_extraction = 0;
7147 int ret = MM_ERROR_NONE;
7148 gboolean async = FALSE;
7152 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7154 /* get sound_extraction property */
7155 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7157 /* NOTE : if SetPosition was called before Start. do it now */
7158 /* streaming doesn't support it. so it should be always sync */
7159 /* !!create one more api to check if there is pending seek rather than checking variables */
7160 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7161 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7162 ret = __gst_pause(player, FALSE);
7163 if (ret != MM_ERROR_NONE) {
7164 LOGE("failed to set state to PAUSED for pending seek\n");
7168 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7170 if (sound_extraction) {
7171 LOGD("setting pcm extraction\n");
7173 ret = __mmplayer_set_pcm_extraction(player);
7174 if (MM_ERROR_NONE != ret) {
7175 LOGW("failed to set pcm extraction\n");
7179 if (MM_ERROR_NONE != __gst_pending_seek(player))
7180 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7184 LOGD("current state before doing transition");
7185 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7186 MMPLAYER_PRINT_STATE(player);
7188 /* set pipeline state to PLAYING */
7189 if (player->es_player_push_mode)
7191 /* set pipeline state to PLAYING */
7192 ret = __mmplayer_gst_set_state(player,
7193 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7195 if (ret == MM_ERROR_NONE) {
7196 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7198 LOGE("failed to set state to PLAYING");
7202 /* generating debug info before returning error */
7203 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7210 static int __gst_stop(mm_player_t* player)
7212 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7213 MMHandleType attrs = 0;
7214 gboolean rewind = FALSE;
7216 int ret = MM_ERROR_NONE;
7217 gboolean async = FALSE;
7221 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7222 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7224 LOGD("current state before doing transition");
7225 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7226 MMPLAYER_PRINT_STATE(player);
7228 attrs = MMPLAYER_GET_ATTRS(player);
7230 LOGE("cannot get content attribute\n");
7231 return MM_ERROR_PLAYER_INTERNAL;
7234 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7235 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7237 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7238 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7241 if (player->es_player_push_mode)
7244 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7246 /* return if set_state has failed */
7247 if (ret != MM_ERROR_NONE) {
7248 LOGE("failed to set state.\n");
7254 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7255 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7256 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7257 LOGW("failed to rewind\n");
7258 ret = MM_ERROR_PLAYER_SEEK;
7263 player->sent_bos = FALSE;
7265 if (player->es_player_push_mode) //for cloudgame
7268 /* wait for seek to complete */
7269 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7270 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7271 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7273 LOGE("fail to stop player.\n");
7274 ret = MM_ERROR_PLAYER_INTERNAL;
7275 __mmplayer_dump_pipeline_state(player);
7278 /* generate dot file if enabled */
7279 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7286 int __gst_pause(mm_player_t* player, gboolean async)
7288 int ret = MM_ERROR_NONE;
7292 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7293 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7295 LOGD("current state before doing transition");
7296 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7297 MMPLAYER_PRINT_STATE(player);
7299 /* set pipeline status to PAUSED */
7300 ret = __mmplayer_gst_set_state(player,
7301 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7303 if (FALSE == async) {
7304 if (ret != MM_ERROR_NONE) {
7305 GstMessage *msg = NULL;
7306 GTimer *timer = NULL;
7307 gdouble MAX_TIMEOUT_SEC = 3;
7309 LOGE("failed to set state to PAUSED");
7311 if (player->msg_posted) {
7312 LOGE("error msg is already posted.");
7316 timer = g_timer_new();
7317 g_timer_start(timer);
7319 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7322 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7324 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7325 GError *error = NULL;
7327 /* parse error code */
7328 gst_message_parse_error(msg, &error, NULL);
7330 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7331 /* Note : the streaming error from the streaming source is handled
7332 * using __mmplayer_handle_streaming_error.
7334 __mmplayer_handle_streaming_error(player, msg);
7337 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7339 if (error->domain == GST_STREAM_ERROR)
7340 ret = __gst_handle_stream_error(player, error, msg);
7341 else if (error->domain == GST_RESOURCE_ERROR)
7342 ret = __gst_handle_resource_error(player, error->code, NULL);
7343 else if (error->domain == GST_LIBRARY_ERROR)
7344 ret = __gst_handle_library_error(player, error->code);
7345 else if (error->domain == GST_CORE_ERROR)
7346 ret = __gst_handle_core_error(player, error->code);
7348 g_error_free(error);
7350 player->msg_posted = TRUE;
7352 gst_message_unref(msg);
7354 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7356 gst_object_unref(bus);
7357 g_timer_stop(timer);
7358 g_timer_destroy(timer);
7362 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7363 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7365 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7367 } else if (ret == MM_ERROR_NONE) {
7369 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7373 /* generate dot file before returning error */
7374 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7381 int __gst_resume(mm_player_t* player, gboolean async)
7383 int ret = MM_ERROR_NONE;
7388 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7389 MM_ERROR_PLAYER_NOT_INITIALIZED);
7391 LOGD("current state before doing transition");
7392 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7393 MMPLAYER_PRINT_STATE(player);
7395 /* generate dot file before returning error */
7396 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7399 LOGD("do async state transition to PLAYING.\n");
7401 /* set pipeline state to PLAYING */
7402 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7404 ret = __mmplayer_gst_set_state(player,
7405 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7406 if (ret != MM_ERROR_NONE) {
7407 LOGE("failed to set state to PLAYING\n");
7410 if (async == FALSE) {
7411 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7412 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7413 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7417 /* generate dot file before returning error */
7418 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7426 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7428 unsigned long dur_msec = 0;
7429 gint64 dur_nsec = 0;
7430 gint64 pos_nsec = 0;
7431 gboolean ret = TRUE;
7432 gboolean accurated = FALSE;
7433 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7436 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7437 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7439 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7440 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7443 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7444 /* check duration */
7445 /* NOTE : duration cannot be zero except live streaming.
7446 * Since some element could have some timing problemn with quering duration, try again.
7448 if (!player->duration) {
7449 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7450 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7451 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7452 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7453 player->pending_seek.is_pending = TRUE;
7454 player->pending_seek.format = format;
7455 player->pending_seek.pos = position;
7456 player->doing_seek = FALSE;
7457 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7458 return MM_ERROR_NONE;
7463 player->duration = dur_nsec;
7466 if (player->duration) {
7467 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7469 LOGE("could not get the duration. fail to seek.\n");
7473 LOGD("playback rate: %f\n", player->playback_rate);
7475 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7477 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7479 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7483 case MM_PLAYER_POS_FORMAT_TIME:
7485 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7486 GstQuery *query = NULL;
7487 gboolean seekable = FALSE;
7489 /* check position is valid or not */
7490 if (position > dur_msec)
7493 query = gst_query_new_seeking(GST_FORMAT_TIME);
7494 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7495 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7496 gst_query_unref(query);
7499 LOGW("non-seekable content");
7500 player->doing_seek = FALSE;
7501 return MM_ERROR_PLAYER_NO_OP;
7504 LOGW("failed to get seeking query");
7505 gst_query_unref(query); /* keep seeking operation */
7508 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7510 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7511 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7512 This causes problem is position calculation during normal pause resume scenarios also.
7513 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7514 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7515 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7516 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7517 LOGW("getting current position failed in seek\n");
7519 player->last_position = pos_nsec;
7520 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7523 if (player->doing_seek) {
7524 LOGD("not completed seek");
7525 return MM_ERROR_PLAYER_DOING_SEEK;
7529 if (!internal_called)
7530 player->doing_seek = TRUE;
7532 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7534 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7535 gint64 cur_time = 0;
7537 /* get current position */
7538 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7541 GstEvent *event = gst_event_new_seek(1.0,
7543 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7544 GST_SEEK_TYPE_SET, cur_time,
7545 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7547 __gst_send_event_to_sink(player, event);
7549 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7550 __gst_pause(player, FALSE);
7553 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7554 that's why set position through property. */
7555 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7556 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7557 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7558 (!player->videodec_linked) && (!player->audiodec_linked)) {
7560 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7561 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7562 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7563 player->doing_seek = FALSE;
7564 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7566 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7567 GST_FORMAT_TIME, seek_flags,
7568 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7572 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7578 case MM_PLAYER_POS_FORMAT_PERCENT:
7580 LOGD("seeking to(%lu)%% \n", position);
7582 if (player->doing_seek) {
7583 LOGD("not completed seek");
7584 return MM_ERROR_PLAYER_DOING_SEEK;
7587 if (!internal_called)
7588 player->doing_seek = TRUE;
7590 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7591 pos_nsec = (gint64)((position * player->duration) / 100);
7592 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7593 GST_FORMAT_TIME, seek_flags,
7594 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7596 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7606 /* NOTE : store last seeking point to overcome some bad operation
7607 * (returning zero when getting current position) of some elements
7609 player->last_position = pos_nsec;
7611 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7612 if (player->playback_rate > 1.0)
7613 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7616 return MM_ERROR_NONE;
7619 player->pending_seek.is_pending = TRUE;
7620 player->pending_seek.format = format;
7621 player->pending_seek.pos = position;
7623 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7624 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7626 return MM_ERROR_NONE;
7629 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7630 return MM_ERROR_INVALID_ARGUMENT;
7633 player->doing_seek = FALSE;
7634 return MM_ERROR_PLAYER_SEEK;
7637 #define TRICKPLAY_OFFSET GST_MSECOND
7640 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7642 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7643 gint64 pos_msec = 0;
7644 gboolean ret = TRUE;
7646 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7647 MM_ERROR_PLAYER_NOT_INITIALIZED);
7649 current_state = MMPLAYER_CURRENT_STATE(player);
7651 /* NOTE : query position except paused state to overcome some bad operation
7652 * please refer to below comments in details
7654 if (current_state != MM_PLAYER_STATE_PAUSED)
7655 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7657 /* NOTE : get last point to overcome some bad operation of some elements
7658 *(returning zero when getting current position in paused state
7659 * and when failed to get postion during seeking
7661 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7662 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7664 if (player->playback_rate < 0.0)
7665 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7667 pos_msec = player->last_position;
7670 pos_msec = player->last_position;
7672 player->last_position = pos_msec;
7674 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7677 if (player->duration > 0 && pos_msec > player->duration)
7678 pos_msec = player->duration;
7680 player->last_position = pos_msec;
7684 case MM_PLAYER_POS_FORMAT_TIME:
7685 *position = GST_TIME_AS_MSECONDS(pos_msec);
7688 case MM_PLAYER_POS_FORMAT_PERCENT:
7690 if (player->duration <= 0) {
7691 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7694 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7695 *position = pos_msec * 100 / player->duration;
7700 return MM_ERROR_PLAYER_INTERNAL;
7703 return MM_ERROR_NONE;
7707 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7709 #define STREAMING_IS_FINISHED 0
7710 #define BUFFERING_MAX_PER 100
7711 #define DEFAULT_PER_VALUE -1
7712 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7714 MMPlayerGstElement *mainbin = NULL;
7715 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7716 gint64 buffered_total = 0;
7717 unsigned long position = 0;
7718 gint buffered_sec = -1;
7719 GstBufferingMode mode = GST_BUFFERING_STREAM;
7720 gint64 content_size_time = player->duration;
7721 guint64 content_size_bytes = player->http_content_size;
7723 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7725 player->pipeline->mainbin,
7726 MM_ERROR_PLAYER_NOT_INITIALIZED);
7728 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7733 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7734 /* and rtsp is not ready yet. */
7735 LOGW("it's only used for http streaming case.\n");
7736 return MM_ERROR_PLAYER_NO_OP;
7739 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7740 LOGW("Time format is not supported yet.\n");
7741 return MM_ERROR_INVALID_ARGUMENT;
7744 if (content_size_time <= 0 || content_size_bytes <= 0) {
7745 LOGW("there is no content size.");
7746 return MM_ERROR_NONE;
7749 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7750 LOGW("fail to get current position.");
7751 return MM_ERROR_NONE;
7754 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7755 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7757 mainbin = player->pipeline->mainbin;
7758 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7760 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7761 GstQuery *query = NULL;
7762 gint byte_in_rate = 0, byte_out_rate = 0;
7763 gint64 estimated_total = 0;
7765 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7766 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7767 LOGW("fail to get buffering query from queue2");
7769 gst_query_unref(query);
7770 return MM_ERROR_NONE;
7773 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7774 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7776 if (mode == GST_BUFFERING_STREAM) {
7777 /* using only queue in case of push mode(ts / mp3) */
7778 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7779 GST_FORMAT_BYTES, &buffered_total)) {
7780 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7781 stop_per = 100 * buffered_total / content_size_bytes;
7784 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7786 guint num_of_ranges = 0;
7787 gint64 start_byte = 0, stop_byte = 0;
7789 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7790 if (estimated_total != STREAMING_IS_FINISHED) {
7791 /* buffered size info from queue2 */
7792 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7793 for (idx = 0; idx < num_of_ranges; idx++) {
7794 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7795 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7797 buffered_total += (stop_byte - start_byte);
7800 stop_per = BUFFERING_MAX_PER;
7802 gst_query_unref(query);
7805 if (stop_per == DEFAULT_PER_VALUE) {
7806 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7808 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7810 /* buffered size info from multiqueue */
7811 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7812 guint curr_size_bytes = 0;
7813 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7814 "curr-size-bytes", &curr_size_bytes, NULL);
7815 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7816 buffered_total += curr_size_bytes;
7819 if (avg_byterate > 0)
7820 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7821 else if (player->total_maximum_bitrate > 0)
7822 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7823 else if (player->total_bitrate > 0)
7824 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7826 if (buffered_sec >= 0)
7827 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7831 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7832 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7834 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7835 buffered_total, buffered_sec, *start_pos, *stop_pos);
7837 return MM_ERROR_NONE;
7841 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7846 LOGW("set_message_callback is called with invalid player handle\n");
7847 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7850 player->msg_cb = callback;
7851 player->msg_cb_param = user_param;
7853 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7857 return MM_ERROR_NONE;
7860 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7862 int ret = MM_ERROR_PLAYER_INVALID_URI;
7867 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7868 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7869 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7871 memset(data, 0, sizeof(MMPlayerParseProfile));
7873 if ((path = strstr(uri, "es_buff://"))) {
7875 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7876 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7877 ret = MM_ERROR_NONE;
7879 } else if ((path = strstr(uri, "rtsp://"))) {
7881 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7883 ret = MM_ERROR_NONE;
7885 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7888 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7889 tmp = g_ascii_strdown(uri, strlen(uri));
7891 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7892 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7894 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7896 ret = MM_ERROR_NONE;
7899 } else if ((path = strstr(uri, "rtspu://"))) {
7901 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7902 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7903 ret = MM_ERROR_NONE;
7905 } else if ((path = strstr(uri, "rtspr://"))) {
7906 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7907 char *separater = strstr(path, "*");
7911 char *urgent = separater + strlen("*");
7913 if ((urgent_len = strlen(urgent))) {
7914 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7915 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7916 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7917 ret = MM_ERROR_NONE;
7920 } else if ((path = strstr(uri, "mms://"))) {
7922 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7923 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7924 ret = MM_ERROR_NONE;
7926 } else if ((path = strstr(uri, "mem://"))) {
7929 char *buffer = NULL;
7930 char *seperator = strchr(path, ',');
7931 char ext[100] = {0,}, size[100] = {0,};
7934 if ((buffer = strstr(path, "ext="))) {
7935 buffer += strlen("ext=");
7937 if (strlen(buffer)) {
7938 strncpy(ext, buffer, 99);
7940 if ((seperator = strchr(ext, ','))
7941 || (seperator = strchr(ext, ' '))
7942 || (seperator = strchr(ext, '\0'))) {
7943 seperator[0] = '\0';
7948 if ((buffer = strstr(path, "size="))) {
7949 buffer += strlen("size=");
7951 if (strlen(buffer) > 0) {
7952 strncpy(size, buffer, 99);
7954 if ((seperator = strchr(size, ','))
7955 || (seperator = strchr(size, ' '))
7956 || (seperator = strchr(size, '\0'))) {
7957 seperator[0] = '\0';
7960 mem_size = atoi(size);
7965 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7966 if (mem_size && param) {
7967 if (data->input_mem.buf)
7968 free(data->input_mem.buf);
7969 data->input_mem.buf = malloc(mem_size);
7971 if (data->input_mem.buf) {
7972 memcpy(data->input_mem.buf, param, mem_size);
7973 data->input_mem.len = mem_size;
7974 ret = MM_ERROR_NONE;
7976 LOGE("failed to alloc mem %d", mem_size);
7977 ret = MM_ERROR_PLAYER_INTERNAL;
7980 data->input_mem.offset = 0;
7981 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7985 gchar *location = NULL;
7988 if ((path = strstr(uri, "file://"))) {
7990 location = g_filename_from_uri(uri, NULL, &err);
7992 if (!location || (err != NULL)) {
7993 LOGE("Invalid URI '%s' for filesrc: %s", path,
7994 (err != NULL) ? err->message : "unknown error");
7996 if (err) g_error_free(err);
7997 if (location) g_free(location);
7999 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8003 LOGD("path from uri: %s", location);
8006 path = (location != NULL) ? (location) : ((char*)uri);
8007 int file_stat = MM_ERROR_NONE;
8009 file_stat = util_exist_file_path(path);
8011 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8012 if (file_stat == MM_ERROR_NONE) {
8013 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8015 if (util_is_sdp_file(path)) {
8016 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8017 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8019 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8021 ret = MM_ERROR_NONE;
8022 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8023 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8025 LOGE("invalid uri, could not play..\n");
8026 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8029 if (location) g_free(location);
8033 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8034 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8035 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8036 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8038 /* dump parse result */
8039 SECURE_LOGW("incomming uri : %s\n", uri);
8040 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8041 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8049 __mmplayer_can_do_interrupt(mm_player_t *player)
8051 if (!player || !player->pipeline || !player->attrs) {
8052 LOGW("not initialized");
8056 if (player->set_mode.pcm_extraction) {
8057 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8061 /* check if seeking */
8062 if (player->doing_seek) {
8063 MMMessageParamType msg_param;
8064 memset(&msg_param, 0, sizeof(MMMessageParamType));
8065 msg_param.code = MM_ERROR_PLAYER_SEEK;
8066 player->doing_seek = FALSE;
8067 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8071 /* check other thread */
8072 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8073 LOGW("locked already, cmd state : %d", player->cmd);
8075 /* check application command */
8076 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8077 LOGW("playing.. should wait cmd lock then, will be interrupted");
8079 /* lock will be released at mrp_resource_release_cb() */
8080 MMPLAYER_CMD_LOCK(player);
8083 LOGW("nothing to do");
8086 LOGW("can interrupt immediately");
8090 FAILED: /* with CMD UNLOCKED */
8093 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8098 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8101 mm_player_t *player = NULL;
8105 if (user_data == NULL) {
8106 LOGE("- user_data is null\n");
8109 player = (mm_player_t *)user_data;
8111 /* do something to release resource here.
8112 * player stop and interrupt forwarding */
8113 if (!__mmplayer_can_do_interrupt(player)) {
8114 LOGW("no need to interrupt, so leave");
8116 MMMessageParamType msg = {0, };
8117 unsigned long pos = 0;
8119 player->interrupted_by_resource = TRUE;
8121 /* get last play position */
8122 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8123 LOGW("failed to get play position.");
8125 msg.union_type = MM_MSG_UNION_TIME;
8126 msg.time.elapsed = (unsigned int)pos;
8127 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8129 LOGD("video resource conflict so, resource will be freed by unrealizing");
8130 if (_mmplayer_unrealize((MMHandleType)player))
8131 LOGW("failed to unrealize");
8133 /* lock is called in __mmplayer_can_do_interrupt() */
8134 MMPLAYER_CMD_UNLOCK(player);
8137 if (res == player->video_overlay_resource)
8138 player->video_overlay_resource = FALSE;
8140 player->video_decoder_resource = FALSE;
8148 _mmplayer_create_player(MMHandleType handle)
8150 int ret = MM_ERROR_PLAYER_INTERNAL;
8151 mm_player_t* player = MM_PLAYER_CAST(handle);
8155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8157 /* initialize player state */
8158 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8159 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8160 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8161 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8163 /* check current state */
8164 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8166 /* construct attributes */
8167 player->attrs = _mmplayer_construct_attribute(handle);
8169 if (!player->attrs) {
8170 LOGE("Failed to construct attributes\n");
8174 /* initialize gstreamer with configured parameter */
8175 if (!__mmplayer_init_gstreamer(player)) {
8176 LOGE("Initializing gstreamer failed\n");
8177 _mmplayer_deconstruct_attribute(handle);
8181 /* create lock. note that g_tread_init() has already called in gst_init() */
8182 g_mutex_init(&player->fsink_lock);
8184 /* create update tag lock */
8185 g_mutex_init(&player->update_tag_lock);
8187 /* create next play mutex */
8188 g_mutex_init(&player->next_play_thread_mutex);
8190 /* create next play cond */
8191 g_cond_init(&player->next_play_thread_cond);
8193 /* create next play thread */
8194 player->next_play_thread =
8195 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8196 if (!player->next_play_thread) {
8197 LOGE("failed to create next play thread");
8198 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8199 g_mutex_clear(&player->next_play_thread_mutex);
8200 g_cond_clear(&player->next_play_thread_cond);
8204 ret = _mmplayer_initialize_video_capture(player);
8205 if (ret != MM_ERROR_NONE) {
8206 LOGE("failed to initialize video capture\n");
8210 /* initialize resource manager */
8211 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8212 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8213 &player->resource_manager)) {
8214 LOGE("failed to initialize resource manager\n");
8218 if (MMPLAYER_IS_HTTP_PD(player)) {
8219 player->pd_downloader = NULL;
8220 player->pd_file_save_path = NULL;
8223 /* create video bo lock and cond */
8224 g_mutex_init(&player->video_bo_mutex);
8225 g_cond_init(&player->video_bo_cond);
8227 /* create media stream callback mutex */
8228 g_mutex_init(&player->media_stream_cb_lock);
8230 /* create subtitle info lock and cond */
8231 g_mutex_init(&player->subtitle_info_mutex);
8232 g_cond_init(&player->subtitle_info_cond);
8234 player->streaming_type = STREAMING_SERVICE_NONE;
8236 /* give default value of audio effect setting */
8237 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8238 player->sound.rg_enable = false;
8239 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8241 player->play_subtitle = FALSE;
8242 player->use_deinterleave = FALSE;
8243 player->max_audio_channels = 0;
8244 player->video_share_api_delta = 0;
8245 player->video_share_clock_delta = 0;
8246 player->has_closed_caption = FALSE;
8247 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8248 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8249 player->pending_resume = FALSE;
8250 if (player->ini.dump_element_keyword[0][0] == '\0')
8251 player->ini.set_dump_element_flag = FALSE;
8253 player->ini.set_dump_element_flag = TRUE;
8255 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8256 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8257 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8259 /* Set video360 settings to their defaults for just-created player.
8261 player->is_content_spherical = FALSE;
8262 player->is_video360_enabled = TRUE;
8263 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8264 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8265 player->video360_yaw_radians = 4;
8266 player->video360_pitch_radians = 4;
8267 player->video360_zoom = 1.0f;
8268 player->video360_horizontal_fov = 0;
8269 player->video360_vertical_fov = 0;
8271 /* set player state to null */
8272 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8273 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8275 return MM_ERROR_NONE;
8279 g_mutex_clear(&player->fsink_lock);
8281 /* free update tag lock */
8282 g_mutex_clear(&player->update_tag_lock);
8284 /* free next play thread */
8285 if (player->next_play_thread) {
8286 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8287 player->next_play_thread_exit = TRUE;
8288 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8289 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8291 g_thread_join(player->next_play_thread);
8292 player->next_play_thread = NULL;
8294 g_mutex_clear(&player->next_play_thread_mutex);
8295 g_cond_clear(&player->next_play_thread_cond);
8298 /* release attributes */
8299 _mmplayer_deconstruct_attribute(handle);
8307 __mmplayer_init_gstreamer(mm_player_t* player)
8309 static gboolean initialized = FALSE;
8310 static const int max_argc = 50;
8312 gchar** argv = NULL;
8313 gchar** argv2 = NULL;
8319 LOGD("gstreamer already initialized.\n");
8324 argc = malloc(sizeof(int));
8325 argv = malloc(sizeof(gchar*) * max_argc);
8326 argv2 = malloc(sizeof(gchar*) * max_argc);
8328 if (!argc || !argv || !argv2)
8331 memset(argv, 0, sizeof(gchar*) * max_argc);
8332 memset(argv2, 0, sizeof(gchar*) * max_argc);
8336 argv[0] = g_strdup("mmplayer");
8339 for (i = 0; i < 5; i++) {
8340 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8341 if (strlen(player->ini.gst_param[i]) > 0) {
8342 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8347 /* we would not do fork for scanning plugins */
8348 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8351 /* check disable registry scan */
8352 if (player->ini.skip_rescan) {
8353 argv[*argc] = g_strdup("--gst-disable-registry-update");
8357 /* check disable segtrap */
8358 if (player->ini.disable_segtrap) {
8359 argv[*argc] = g_strdup("--gst-disable-segtrap");
8363 LOGD("initializing gstreamer with following parameter\n");
8364 LOGD("argc : %d\n", *argc);
8367 for (i = 0; i < arg_count; i++) {
8369 LOGD("argv[%d] : %s\n", i, argv2[i]);
8372 /* initializing gstreamer */
8373 if (!gst_init_check(argc, &argv, &err)) {
8374 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8381 for (i = 0; i < arg_count; i++) {
8382 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8383 MMPLAYER_FREEIF(argv2[i]);
8386 MMPLAYER_FREEIF(argv);
8387 MMPLAYER_FREEIF(argv2);
8388 MMPLAYER_FREEIF(argc);
8398 for (i = 0; i < arg_count; i++) {
8399 LOGD("free[%d] : %s\n", i, argv2[i]);
8400 MMPLAYER_FREEIF(argv2[i]);
8403 MMPLAYER_FREEIF(argv);
8404 MMPLAYER_FREEIF(argv2);
8405 MMPLAYER_FREEIF(argc);
8411 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8413 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8415 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8416 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8417 MMPLAYER_FREEIF(player->pd_file_save_path);
8420 return MM_ERROR_NONE;
8424 __mmplayer_check_async_state_transition(mm_player_t* player)
8426 GstState element_state = GST_STATE_VOID_PENDING;
8427 GstState element_pending_state = GST_STATE_VOID_PENDING;
8428 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8429 GstElement * element = NULL;
8430 gboolean async = FALSE;
8432 /* check player handle */
8433 MMPLAYER_RETURN_IF_FAIL(player &&
8435 player->pipeline->mainbin &&
8436 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8439 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8441 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8442 LOGD("don't need to check the pipeline state");
8446 MMPLAYER_PRINT_STATE(player);
8448 /* wait for state transition */
8449 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8450 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8452 if (ret == GST_STATE_CHANGE_FAILURE) {
8453 LOGE(" [%s] state : %s pending : %s \n",
8454 GST_ELEMENT_NAME(element),
8455 gst_element_state_get_name(element_state),
8456 gst_element_state_get_name(element_pending_state));
8458 /* dump state of all element */
8459 __mmplayer_dump_pipeline_state(player);
8464 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8469 _mmplayer_destroy(MMHandleType handle)
8471 mm_player_t* player = MM_PLAYER_CAST(handle);
8475 /* check player handle */
8476 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8478 /* destroy can called at anytime */
8479 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8481 /* check async state transition */
8482 __mmplayer_check_async_state_transition(player);
8484 __mmplayer_destroy_streaming_ext(player);
8486 /* release next play thread */
8487 if (player->next_play_thread) {
8488 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8489 player->next_play_thread_exit = TRUE;
8490 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8491 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8493 LOGD("waitting for next play thread exit\n");
8494 g_thread_join(player->next_play_thread);
8495 g_mutex_clear(&player->next_play_thread_mutex);
8496 g_cond_clear(&player->next_play_thread_cond);
8497 LOGD("next play thread released\n");
8500 _mmplayer_release_video_capture(player);
8502 /* de-initialize resource manager */
8503 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8504 player->resource_manager))
8505 LOGE("failed to deinitialize resource manager\n");
8507 /* release pipeline */
8508 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8509 LOGE("failed to destory pipeline\n");
8510 return MM_ERROR_PLAYER_INTERNAL;
8513 /* release subtitle info lock and cond */
8514 g_mutex_clear(&player->subtitle_info_mutex);
8515 g_cond_clear(&player->subtitle_info_cond);
8517 __mmplayer_release_dump_list(player->dump_list);
8519 /* release miscellaneous information */
8520 __mmplayer_release_misc(player);
8522 /* release miscellaneous information.
8523 these info needs to be released after pipeline is destroyed. */
8524 __mmplayer_release_misc_post(player);
8526 /* release attributes */
8527 _mmplayer_deconstruct_attribute(handle);
8530 g_mutex_clear(&player->fsink_lock);
8533 g_mutex_clear(&player->update_tag_lock);
8535 /* release video bo lock and cond */
8536 g_mutex_clear(&player->video_bo_mutex);
8537 g_cond_clear(&player->video_bo_cond);
8539 /* release media stream callback lock */
8540 g_mutex_clear(&player->media_stream_cb_lock);
8544 return MM_ERROR_NONE;
8548 __mmplayer_realize_streaming_ext(mm_player_t* player)
8550 int ret = MM_ERROR_NONE;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 if (MMPLAYER_IS_HTTP_PD(player)) {
8556 gboolean bret = FALSE;
8558 player->pd_downloader = _mmplayer_create_pd_downloader();
8559 if (!player->pd_downloader) {
8560 LOGE("Unable to create PD Downloader...");
8561 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8564 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8566 if (FALSE == bret) {
8567 LOGE("Unable to create PD Downloader...");
8568 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8577 _mmplayer_realize(MMHandleType hplayer)
8579 mm_player_t* player = (mm_player_t*)hplayer;
8582 MMHandleType attrs = 0;
8583 int ret = MM_ERROR_NONE;
8587 /* check player handle */
8588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8590 /* check current state */
8591 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8593 attrs = MMPLAYER_GET_ATTRS(player);
8595 LOGE("fail to get attributes.\n");
8596 return MM_ERROR_PLAYER_INTERNAL;
8598 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8599 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8601 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8602 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8604 if (ret != MM_ERROR_NONE) {
8605 LOGE("failed to parse profile\n");
8610 if (uri && (strstr(uri, "es_buff://"))) {
8611 if (strstr(uri, "es_buff://push_mode"))
8612 player->es_player_push_mode = TRUE;
8614 player->es_player_push_mode = FALSE;
8617 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8618 LOGW("mms protocol is not supported format.\n");
8619 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8622 if (MMPLAYER_IS_STREAMING(player))
8623 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8625 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8627 player->smooth_streaming = FALSE;
8628 player->videodec_linked = 0;
8629 player->videosink_linked = 0;
8630 player->audiodec_linked = 0;
8631 player->audiosink_linked = 0;
8632 player->textsink_linked = 0;
8633 player->is_external_subtitle_present = FALSE;
8634 player->is_external_subtitle_added_now = FALSE;
8635 /* set the subtitle ON default */
8636 player->is_subtitle_off = FALSE;
8638 /* realize pipeline */
8639 ret = __gst_realize(player);
8640 if (ret != MM_ERROR_NONE)
8641 LOGE("fail to realize the player.\n");
8643 ret = __mmplayer_realize_streaming_ext(player);
8645 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8646 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8654 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8657 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8659 /* destroy can called at anytime */
8660 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8661 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8664 return MM_ERROR_NONE;
8668 _mmplayer_unrealize(MMHandleType hplayer)
8670 mm_player_t* player = (mm_player_t*)hplayer;
8671 int ret = MM_ERROR_NONE;
8675 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8677 MMPLAYER_CMD_UNLOCK(player);
8678 /* destroy the gst bus msg thread which is created during realize.
8679 this funct have to be called before getting cmd lock. */
8680 _mmplayer_bus_msg_thread_destroy(player);
8681 MMPLAYER_CMD_LOCK(player);
8683 /* check current state */
8684 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8686 /* check async state transition */
8687 __mmplayer_check_async_state_transition(player);
8689 __mmplayer_unrealize_streaming_ext(player);
8691 /* unrealize pipeline */
8692 ret = __gst_unrealize(player);
8694 /* set asm stop if success */
8695 if (MM_ERROR_NONE == ret) {
8696 if (!player->interrupted_by_resource) {
8697 if (player->video_decoder_resource != NULL) {
8698 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8699 player->video_decoder_resource);
8700 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8701 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8703 player->video_decoder_resource = NULL;
8706 if (player->video_overlay_resource != NULL) {
8707 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8708 player->video_overlay_resource);
8709 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8710 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8712 player->video_overlay_resource = NULL;
8715 ret = mm_resource_manager_commit(player->resource_manager);
8716 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8717 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8720 LOGE("failed and don't change asm state to stop");
8728 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8730 mm_player_t* player = (mm_player_t*)hplayer;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8734 return __gst_set_message_callback(player, callback, user_param);
8738 _mmplayer_get_state(MMHandleType hplayer, int* state)
8740 mm_player_t *player = (mm_player_t*)hplayer;
8742 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8744 *state = MMPLAYER_CURRENT_STATE(player);
8746 return MM_ERROR_NONE;
8751 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8753 mm_player_t* player = (mm_player_t*) hplayer;
8754 GstElement* vol_element = NULL;
8759 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8761 LOGD("volume [L]=%f:[R]=%f\n",
8762 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8764 /* invalid factor range or not */
8765 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8766 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8767 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8768 return MM_ERROR_INVALID_ARGUMENT;
8772 /* not support to set other value into each channel */
8773 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8774 return MM_ERROR_INVALID_ARGUMENT;
8776 /* Save volume to handle. Currently the first array element will be saved. */
8777 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8779 /* check pipeline handle */
8780 if (!player->pipeline || !player->pipeline->audiobin) {
8781 LOGD("audiobin is not created yet\n");
8782 LOGD("but, current stored volume will be set when it's created.\n");
8784 /* NOTE : stored volume will be used in create_audiobin
8785 * returning MM_ERROR_NONE here makes application to able to
8786 * set volume at anytime.
8788 return MM_ERROR_NONE;
8791 /* setting volume to volume element */
8792 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8795 LOGD("volume is set [%f]\n", player->sound.volume);
8796 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8801 return MM_ERROR_NONE;
8806 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8808 mm_player_t* player = (mm_player_t*) hplayer;
8813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8814 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8816 /* returning stored volume */
8817 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8818 volume->level[i] = player->sound.volume;
8822 return MM_ERROR_NONE;
8826 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8828 mm_player_t* player = (mm_player_t*) hplayer;
8829 GstElement* vol_element = NULL;
8833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8835 /* mute value shoud 0 or 1 */
8836 if (mute != 0 && mute != 1) {
8837 LOGE("bad mute value\n");
8839 /* FIXIT : definitly, we need _BAD_PARAM error code */
8840 return MM_ERROR_INVALID_ARGUMENT;
8843 player->sound.mute = mute;
8845 /* just hold mute value if pipeline is not ready */
8846 if (!player->pipeline || !player->pipeline->audiobin) {
8847 LOGD("pipeline is not ready. holding mute value\n");
8848 return MM_ERROR_NONE;
8851 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8853 /* NOTE : volume will only created when the bt is enabled */
8855 LOGD("mute : %d\n", mute);
8856 g_object_set(vol_element, "mute", mute, NULL);
8858 LOGD("volume elemnet is not created. using volume in audiosink\n");
8862 return MM_ERROR_NONE;
8866 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8868 mm_player_t* player = (mm_player_t*) hplayer;
8872 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8873 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8875 /* just hold mute value if pipeline is not ready */
8876 if (!player->pipeline || !player->pipeline->audiobin) {
8877 LOGD("pipeline is not ready. returning stored value\n");
8878 *pmute = player->sound.mute;
8879 return MM_ERROR_NONE;
8882 *pmute = player->sound.mute;
8886 return MM_ERROR_NONE;
8890 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8892 mm_player_t* player = (mm_player_t*) hplayer;
8896 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8898 player->video_stream_changed_cb = callback;
8899 player->video_stream_changed_cb_user_param = user_param;
8900 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8904 return MM_ERROR_NONE;
8908 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8910 mm_player_t* player = (mm_player_t*) hplayer;
8914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916 player->audio_stream_changed_cb = callback;
8917 player->audio_stream_changed_cb_user_param = user_param;
8918 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8922 return MM_ERROR_NONE;
8926 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8928 mm_player_t* player = (mm_player_t*) hplayer;
8932 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8934 player->audio_stream_render_cb_ex = callback;
8935 player->audio_stream_cb_user_param = user_param;
8936 player->audio_stream_sink_sync = sync;
8937 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);
8941 return MM_ERROR_NONE;
8945 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8947 mm_player_t* player = (mm_player_t*) hplayer;
8951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8953 if (callback && !player->bufmgr)
8954 player->bufmgr = tbm_bufmgr_init(-1);
8956 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8957 player->video_stream_cb = callback;
8958 player->video_stream_cb_user_param = user_param;
8960 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8964 return MM_ERROR_NONE;
8968 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8970 mm_player_t* player = (mm_player_t*) hplayer;
8974 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8976 player->audio_stream_cb = callback;
8977 player->audio_stream_cb_user_param = user_param;
8978 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8982 return MM_ERROR_NONE;
8986 __mmplayer_start_streaming_ext(mm_player_t *player)
8988 gint ret = MM_ERROR_NONE;
8991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8993 if (MMPLAYER_IS_HTTP_PD(player)) {
8994 if (!player->pd_downloader) {
8995 ret = __mmplayer_realize_streaming_ext(player);
8997 if (ret != MM_ERROR_NONE) {
8998 LOGE("failed to realize streaming ext\n");
9003 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9004 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9006 LOGE("ERROR while starting PD...\n");
9007 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9009 ret = MM_ERROR_NONE;
9018 _mmplayer_start(MMHandleType hplayer)
9020 mm_player_t* player = (mm_player_t*) hplayer;
9021 gint ret = MM_ERROR_NONE;
9025 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9027 /* check current state */
9028 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9030 /* NOTE : we should check and create pipeline again if not created as we destroy
9031 * whole pipeline when stopping in streamming playback
9033 if (!player->pipeline) {
9034 ret = __gst_realize(player);
9035 if (MM_ERROR_NONE != ret) {
9036 LOGE("failed to realize before starting. only in streamming\n");
9042 ret = __mmplayer_start_streaming_ext(player);
9043 if (ret != MM_ERROR_NONE) {
9044 LOGE("failed to start streaming ext 0x%X", ret);
9048 /* start pipeline */
9049 ret = __gst_start(player);
9050 if (ret != MM_ERROR_NONE)
9051 LOGE("failed to start player.\n");
9058 /* NOTE: post "not supported codec message" to application
9059 * when one codec is not found during AUTOPLUGGING in MSL.
9060 * So, it's separated with error of __mmplayer_gst_callback().
9061 * And, if any codec is not found, don't send message here.
9062 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9065 __mmplayer_handle_missed_plugin(mm_player_t* player)
9067 MMMessageParamType msg_param;
9068 memset(&msg_param, 0, sizeof(MMMessageParamType));
9069 gboolean post_msg_direct = FALSE;
9073 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9075 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9076 player->not_supported_codec, player->can_support_codec);
9078 if (player->not_found_demuxer) {
9079 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9080 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9082 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9083 MMPLAYER_FREEIF(msg_param.data);
9085 return MM_ERROR_NONE;
9088 if (player->not_supported_codec) {
9089 if (player->can_support_codec) {
9090 // There is one codec to play
9091 post_msg_direct = TRUE;
9093 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9094 post_msg_direct = TRUE;
9097 if (post_msg_direct) {
9098 MMMessageParamType msg_param;
9099 memset(&msg_param, 0, sizeof(MMMessageParamType));
9101 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9102 LOGW("not found AUDIO codec, posting error code to application.\n");
9104 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9105 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9106 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9107 LOGW("not found VIDEO codec, posting error code to application.\n");
9109 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9110 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9113 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9115 MMPLAYER_FREEIF(msg_param.data);
9117 return MM_ERROR_NONE;
9119 // no any supported codec case
9120 LOGW("not found any codec, posting error code to application.\n");
9122 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9123 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9124 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9126 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9127 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9130 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9132 MMPLAYER_FREEIF(msg_param.data);
9138 return MM_ERROR_NONE;
9141 static void __mmplayer_check_pipeline(mm_player_t* player)
9143 GstState element_state = GST_STATE_VOID_PENDING;
9144 GstState element_pending_state = GST_STATE_VOID_PENDING;
9146 int ret = MM_ERROR_NONE;
9148 if (player->gapless.reconfigure) {
9149 LOGW("pipeline is under construction.\n");
9151 MMPLAYER_PLAYBACK_LOCK(player);
9152 MMPLAYER_PLAYBACK_UNLOCK(player);
9154 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9156 /* wait for state transition */
9157 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9159 if (ret == GST_STATE_CHANGE_FAILURE)
9160 LOGE("failed to change pipeline state within %d sec\n", timeout);
9164 /* NOTE : it should be able to call 'stop' anytime*/
9166 _mmplayer_stop(MMHandleType hplayer)
9168 mm_player_t* player = (mm_player_t*)hplayer;
9169 int ret = MM_ERROR_NONE;
9173 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9175 /* check current state */
9176 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9178 /* check pipline building state */
9179 __mmplayer_check_pipeline(player);
9180 __mmplayer_reset_gapless_state(player);
9182 /* NOTE : application should not wait for EOS after calling STOP */
9183 __mmplayer_cancel_eos_timer(player);
9185 __mmplayer_unrealize_streaming_ext(player);
9188 player->doing_seek = FALSE;
9191 ret = __gst_stop(player);
9193 if (ret != MM_ERROR_NONE)
9194 LOGE("failed to stop player.\n");
9202 _mmplayer_pause(MMHandleType hplayer)
9204 mm_player_t* player = (mm_player_t*)hplayer;
9205 gint64 pos_msec = 0;
9206 gboolean async = FALSE;
9207 gint ret = MM_ERROR_NONE;
9211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9213 /* check current state */
9214 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9216 /* check pipline building state */
9217 __mmplayer_check_pipeline(player);
9219 switch (MMPLAYER_CURRENT_STATE(player)) {
9220 case MM_PLAYER_STATE_READY:
9222 /* check prepare async or not.
9223 * In the case of streaming playback, it's recommned to avoid blocking wait.
9225 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9226 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9228 /* Changing back sync of rtspsrc to async */
9229 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9230 LOGD("async prepare working mode for rtsp");
9236 case MM_PLAYER_STATE_PLAYING:
9238 /* NOTE : store current point to overcome some bad operation
9239 *(returning zero when getting current position in paused state) of some
9242 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9243 LOGW("getting current position failed in paused\n");
9245 player->last_position = pos_msec;
9247 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9248 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9249 This causes problem is position calculation during normal pause resume scenarios also.
9250 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9251 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9252 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9253 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9259 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9260 LOGD("doing async pause in case of ms buff src");
9264 /* pause pipeline */
9265 ret = __gst_pause(player, async);
9267 if (ret != MM_ERROR_NONE)
9268 LOGE("failed to pause player. ret : 0x%x\n", ret);
9270 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9271 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9272 LOGE("failed to update display_rotation");
9281 _mmplayer_resume(MMHandleType hplayer)
9283 mm_player_t* player = (mm_player_t*)hplayer;
9284 int ret = MM_ERROR_NONE;
9285 gboolean async = FALSE;
9289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9291 /* Changing back sync mode rtspsrc to async */
9292 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9293 LOGD("async resume for rtsp case");
9297 /* check current state */
9298 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9300 ret = __gst_resume(player, async);
9302 if (ret != MM_ERROR_NONE)
9303 LOGE("failed to resume player.\n");
9311 __mmplayer_set_pcm_extraction(mm_player_t* player)
9313 gint64 start_nsec = 0;
9314 gint64 end_nsec = 0;
9315 gint64 dur_nsec = 0;
9316 gint64 dur_msec = 0;
9317 int required_start = 0;
9318 int required_end = 0;
9323 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9325 mm_attrs_multiple_get(player->attrs,
9327 "pcm_extraction_start_msec", &required_start,
9328 "pcm_extraction_end_msec", &required_end,
9331 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9333 if (required_start == 0 && required_end == 0) {
9334 LOGD("extracting entire stream");
9335 return MM_ERROR_NONE;
9336 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9337 LOGD("invalid range for pcm extraction");
9338 return MM_ERROR_INVALID_ARGUMENT;
9342 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9344 LOGE("failed to get duration");
9345 return MM_ERROR_PLAYER_INTERNAL;
9347 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9349 if (dur_msec < required_end) {
9351 LOGD("invalid end pos for pcm extraction");
9352 return MM_ERROR_INVALID_ARGUMENT;
9355 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9356 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9358 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9361 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9362 GST_SEEK_TYPE_SET, start_nsec,
9363 GST_SEEK_TYPE_SET, end_nsec))) {
9364 LOGE("failed to seek for pcm extraction\n");
9366 return MM_ERROR_PLAYER_SEEK;
9369 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9373 return MM_ERROR_NONE;
9377 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9379 mm_player_t* player = (mm_player_t*)hplayer;
9380 gint64 pos_msec = 0;
9381 int ret = MM_ERROR_NONE;
9383 signed long long start = 0, stop = 0;
9384 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9388 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9390 /* The sound of video is not supported under 0.0 and over 2.0. */
9391 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9392 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9395 _mmplayer_set_mute(hplayer, mute);
9397 if (player->playback_rate == rate)
9398 return MM_ERROR_NONE;
9400 /* If the position is reached at start potion during fast backward, EOS is posted.
9401 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9403 player->playback_rate = rate;
9405 current_state = MMPLAYER_CURRENT_STATE(player);
9407 if (current_state != MM_PLAYER_STATE_PAUSED)
9408 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9410 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9412 if ((current_state == MM_PLAYER_STATE_PAUSED)
9413 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9414 LOGW("returning last point : %lld\n", player->last_position);
9415 pos_msec = player->last_position;
9420 stop = GST_CLOCK_TIME_NONE;
9422 start = GST_CLOCK_TIME_NONE;
9426 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9427 player->playback_rate,
9429 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9430 GST_SEEK_TYPE_SET, start,
9431 GST_SEEK_TYPE_SET, stop)) {
9432 LOGE("failed to set speed playback\n");
9433 return MM_ERROR_PLAYER_SEEK;
9436 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9440 return MM_ERROR_NONE;;
9444 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9446 mm_player_t* player = (mm_player_t*)hplayer;
9447 int ret = MM_ERROR_NONE;
9451 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9453 /* check pipline building state */
9454 __mmplayer_check_pipeline(player);
9456 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9464 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9466 mm_player_t* player = (mm_player_t*)hplayer;
9467 int ret = MM_ERROR_NONE;
9469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9471 ret = __gst_get_position(player, format, position);
9477 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9479 mm_player_t* player = (mm_player_t*)hplayer;
9480 int ret = MM_ERROR_NONE;
9482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9484 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9490 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9492 mm_player_t* player = (mm_player_t*)hplayer;
9493 int ret = MM_ERROR_NONE;
9497 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9499 ret = __gst_adjust_subtitle_position(player, format, position);
9506 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9508 mm_player_t* player = (mm_player_t*)hplayer;
9509 int ret = MM_ERROR_NONE;
9513 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9515 ret = __gst_adjust_video_position(player, offset);
9523 __mmplayer_is_midi_type(gchar* str_caps)
9525 if ((g_strrstr(str_caps, "audio/midi")) ||
9526 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9527 (g_strrstr(str_caps, "application/x-smaf")) ||
9528 (g_strrstr(str_caps, "audio/x-imelody")) ||
9529 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9530 (g_strrstr(str_caps, "audio/xmf")) ||
9531 (g_strrstr(str_caps, "audio/mxmf"))) {
9540 __mmplayer_is_only_mp3_type(gchar *str_caps)
9542 if (g_strrstr(str_caps, "application/x-id3") ||
9543 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9549 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9551 GstStructure* caps_structure = NULL;
9552 gint samplerate = 0;
9556 MMPLAYER_RETURN_IF_FAIL(player && caps);
9558 caps_structure = gst_caps_get_structure(caps, 0);
9560 /* set stream information */
9561 gst_structure_get_int(caps_structure, "rate", &samplerate);
9562 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9564 gst_structure_get_int(caps_structure, "channels", &channels);
9565 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9567 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9571 __mmplayer_update_content_type_info(mm_player_t* player)
9574 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9576 if (__mmplayer_is_midi_type(player->type)) {
9577 player->bypass_audio_effect = TRUE;
9578 } else if (g_strrstr(player->type, "application/x-hls")) {
9579 /* If it can't know exact type when it parses uri because of redirection case,
9580 * it will be fixed by typefinder or when doing autoplugging.
9582 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9583 if (player->streamer) {
9584 player->streamer->is_adaptive_streaming = TRUE;
9585 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9586 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9588 } else if (g_strrstr(player->type, "application/dash+xml")) {
9589 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9596 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9597 GstCaps *caps, gpointer data)
9599 mm_player_t* player = (mm_player_t*)data;
9604 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9606 /* store type string */
9607 MMPLAYER_FREEIF(player->type);
9608 player->type = gst_caps_to_string(caps);
9610 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9611 player, player->type, probability, gst_caps_get_size(caps));
9614 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9615 (g_strrstr(player->type, "audio/x-raw-int"))) {
9616 LOGE("not support media format\n");
9618 if (player->msg_posted == FALSE) {
9619 MMMessageParamType msg_param;
9620 memset(&msg_param, 0, sizeof(MMMessageParamType));
9622 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9623 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9625 /* don't post more if one was sent already */
9626 player->msg_posted = TRUE;
9631 __mmplayer_update_content_type_info(player);
9633 pad = gst_element_get_static_pad(tf, "src");
9635 LOGE("fail to get typefind src pad.\n");
9639 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9640 gboolean async = FALSE;
9641 LOGE("failed to autoplug %s\n", player->type);
9643 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9645 if (async && player->msg_posted == FALSE)
9646 __mmplayer_handle_missed_plugin(player);
9652 gst_object_unref(GST_OBJECT(pad));
9660 __mmplayer_create_decodebin(mm_player_t* player)
9662 GstElement *decodebin = NULL;
9666 /* create decodebin */
9667 decodebin = gst_element_factory_make("decodebin", NULL);
9670 LOGE("fail to create decodebin\n");
9674 /* raw pad handling signal */
9675 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9676 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9678 /* no-more-pad pad handling signal */
9679 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9680 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9682 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9683 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9685 /* This signal is emitted when a pad for which there is no further possible
9686 decoding is added to the decodebin.*/
9687 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9688 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9690 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9691 before looking for any elements that can handle that stream.*/
9692 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9693 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9695 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9696 before looking for any elements that can handle that stream.*/
9697 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9698 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9700 /* This signal is emitted once decodebin has finished decoding all the data.*/
9701 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9702 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9704 /* This signal is emitted when a element is added to the bin.*/
9705 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9706 G_CALLBACK(__mmplayer_gst_element_added), player);
9713 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9715 MMPlayerGstElement* mainbin = NULL;
9716 GstElement* decodebin = NULL;
9717 GstElement* queue2 = NULL;
9718 GstPad* sinkpad = NULL;
9719 GstPad* qsrcpad = NULL;
9720 gint64 dur_bytes = 0L;
9722 guint max_buffer_size_bytes = 0;
9723 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9726 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9728 mainbin = player->pipeline->mainbin;
9730 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9731 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9732 LOGD("creating http streaming buffering queue(queue2)\n");
9734 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9735 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9737 queue2 = gst_element_factory_make("queue2", "queue2");
9739 LOGE("failed to create buffering queue element\n");
9743 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9744 LOGE("failed to add buffering queue\n");
9748 sinkpad = gst_element_get_static_pad(queue2, "sink");
9749 qsrcpad = gst_element_get_static_pad(queue2, "src");
9751 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9752 LOGE("failed to link buffering queue\n");
9756 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9757 LOGE("fail to get duration.\n");
9759 LOGD("dur_bytes = %lld\n", dur_bytes);
9761 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9763 if (dur_bytes > 0) {
9764 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9765 type = MUXED_BUFFER_TYPE_FILE;
9767 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9768 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9774 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9775 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9776 if (!g_strrstr(player->type, "video/mpegts")) {
9777 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9778 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9780 // FIXME : pass ini setting directly. is this ok?
9781 __mm_player_streaming_set_queue2(player->streamer,
9784 max_buffer_size_bytes,
9785 player->ini.http_buffering_time,
9787 player->ini.http_buffering_limit, // no meaning
9789 player->http_file_buffering_path,
9790 (guint64)dur_bytes);
9793 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9794 LOGE("failed to sync queue2 state with parent\n");
9800 gst_object_unref(GST_OBJECT(sinkpad));
9802 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9803 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9807 /* create decodebin */
9808 decodebin = __mmplayer_create_decodebin(player);
9811 LOGE("can not create autoplug element\n");
9815 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9816 LOGE("failed to add decodebin\n");
9820 /* to force caps on the decodebin element and avoid reparsing stuff by
9821 * typefind. It also avoids a deadlock in the way typefind activates pads in
9822 * the state change */
9823 g_object_set(decodebin, "sink-caps", caps, NULL);
9825 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9827 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9828 LOGE("failed to link decodebin\n");
9832 gst_object_unref(GST_OBJECT(sinkpad));
9834 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9835 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9837 /* set decodebin property about buffer in streaming playback. *
9838 * in case of HLS/DASH, it does not need to have big buffer *
9839 * because it is kind of adaptive streaming. */
9840 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9841 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9842 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9843 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9845 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9846 || MMPLAYER_IS_DASH_STREAMING(player)) {
9847 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9848 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9851 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9852 "high-percent", (gint)player->ini.http_buffering_limit,
9853 "low-percent", 1, // 1%
9854 "max-size-bytes", max_size_bytes,
9855 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9856 "max-size-buffers", 0, NULL); // disable or automatic
9859 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9860 LOGE("failed to sync decodebin state with parent\n");
9871 gst_object_unref(GST_OBJECT(sinkpad));
9874 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9875 * You need to explicitly set elements to the NULL state before
9876 * dropping the final reference, to allow them to clean up.
9878 gst_element_set_state(queue2, GST_STATE_NULL);
9880 /* And, it still has a parent "player".
9881 * You need to let the parent manage the object instead of unreffing the object directly.
9883 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9884 gst_object_unref(queue2);
9889 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9890 * You need to explicitly set elements to the NULL state before
9891 * dropping the final reference, to allow them to clean up.
9893 gst_element_set_state(decodebin, GST_STATE_NULL);
9895 /* And, it still has a parent "player".
9896 * You need to let the parent manage the object instead of unreffing the object directly.
9899 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9900 gst_object_unref(decodebin);
9908 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9912 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9913 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9915 LOGD("class : %s, mime : %s \n", factory_class, mime);
9917 /* add missing plugin */
9918 /* NOTE : msl should check missing plugin for image mime type.
9919 * Some motion jpeg clips can have playable audio track.
9920 * So, msl have to play audio after displaying popup written video format not supported.
9922 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9923 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9924 LOGD("not found demuxer\n");
9925 player->not_found_demuxer = TRUE;
9926 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9932 if (!g_strrstr(factory_class, "Demuxer")) {
9933 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9934 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9935 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9937 /* check that clip have multi tracks or not */
9938 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9939 LOGD("video plugin is already linked\n");
9941 LOGW("add VIDEO to missing plugin\n");
9942 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9943 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9945 } else if (g_str_has_prefix(mime, "audio")) {
9946 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9947 LOGD("audio plugin is already linked\n");
9949 LOGW("add AUDIO to missing plugin\n");
9950 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9951 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9959 return MM_ERROR_NONE;
9964 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9966 mm_player_t* player = (mm_player_t*)data;
9970 MMPLAYER_RETURN_IF_FAIL(player);
9972 /* remove fakesink. */
9973 if (!__mmplayer_gst_remove_fakesink(player,
9974 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9975 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9976 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9977 * source element are not same. To overcome this situation, this function will called
9978 * several places and several times. Therefore, this is not an error case.
9983 LOGD("[handle: %p] pipeline has completely constructed", player);
9985 if ((player->ini.async_start) &&
9986 (player->msg_posted == FALSE) &&
9987 (player->cmd >= MMPLAYER_COMMAND_START))
9988 __mmplayer_handle_missed_plugin(player);
9990 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
9994 __mmplayer_verify_next_play_path(mm_player_t *player)
9996 MMHandleType attrs = 0;
9997 MMPlayerParseProfile profile;
9998 gint uri_idx = 0, check_cnt = 0;
10000 gint mode = MM_PLAYER_PD_MODE_NONE;
10004 guint num_of_list = 0;
10005 static int profile_tv = -1;
10009 LOGD("checking for gapless play");
10011 if (player->pipeline->textbin) {
10012 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10016 attrs = MMPLAYER_GET_ATTRS(player);
10018 LOGE("fail to get attributes.\n");
10022 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10024 if (__builtin_expect(profile_tv == -1, 0)) {
10026 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10027 switch (*profileName) {
10037 /* gapless playback is not supported in case of video at TV profile. */
10038 if (profile_tv && video) {
10039 LOGW("not support video gapless playback");
10043 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10044 if (mode == TRUE) {
10050 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10051 LOGE("can not get play count\n");
10053 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10054 LOGE("can not get gapless mode\n");
10056 if (video && !gapless) {
10057 LOGW("not enabled video gapless playback");
10061 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10065 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10069 num_of_list = g_list_length(player->uri_info.uri_list);
10071 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10073 if (num_of_list == 0) {
10074 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10075 LOGE("can not get profile_uri\n");
10080 LOGE("uri list is empty.\n");
10084 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10085 LOGD("add original path : %s ", uri);
10091 uri_idx = player->uri_info.uri_idx;
10096 if (check_cnt > num_of_list) {
10097 LOGE("there is no valid uri.");
10101 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10103 if (uri_idx < num_of_list-1) {
10106 if ((count <= 1) && (count != -1)) {
10107 LOGD("no repeat.");
10109 } else if (count > 1) {
10110 /* decrease play count */
10111 /* we succeeded to rewind. update play count and then wait for next EOS */
10114 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10116 /* commit attribute */
10117 if (mmf_attrs_commit(attrs))
10118 LOGE("failed to commit attribute\n");
10121 /* count < 0 : repeat continually */
10125 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10126 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10129 LOGW("next uri does not exist\n");
10133 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10134 LOGE("failed to parse profile\n");
10138 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10139 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10140 LOGW("uri type is not supported(%d).", profile.uri_type);
10147 player->uri_info.uri_idx = uri_idx;
10148 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10150 if (mmf_attrs_commit(player->attrs)) {
10151 LOGE("failed to commit.\n");
10155 LOGD("next uri %s(%d)\n", uri, uri_idx);
10161 LOGE("unable to play next path. EOS will be posted soon.\n");
10166 __mmplayer_initialize_next_play(mm_player_t *player)
10172 player->smooth_streaming = FALSE;
10173 player->videodec_linked = 0;
10174 player->audiodec_linked = 0;
10175 player->videosink_linked = 0;
10176 player->audiosink_linked = 0;
10177 player->textsink_linked = 0;
10178 player->is_external_subtitle_present = FALSE;
10179 player->is_external_subtitle_added_now = FALSE;
10180 player->not_supported_codec = MISSING_PLUGIN_NONE;
10181 player->can_support_codec = FOUND_PLUGIN_NONE;
10182 player->pending_seek.is_pending = FALSE;
10183 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10184 player->pending_seek.pos = 0;
10185 player->msg_posted = FALSE;
10186 player->has_many_types = FALSE;
10187 player->no_more_pad = FALSE;
10188 player->not_found_demuxer = 0;
10189 player->doing_seek = FALSE;
10190 player->max_audio_channels = 0;
10191 player->is_subtitle_force_drop = FALSE;
10192 player->play_subtitle = FALSE;
10193 player->adjust_subtitle_pos = 0;
10195 player->total_bitrate = 0;
10196 player->total_maximum_bitrate = 0;
10198 _mmplayer_track_initialize(player);
10199 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10201 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10202 player->bitrate[i] = 0;
10203 player->maximum_bitrate[i] = 0;
10206 if (player->v_stream_caps) {
10207 gst_caps_unref(player->v_stream_caps);
10208 player->v_stream_caps = NULL;
10211 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10213 /* clean found parsers */
10214 if (player->parsers) {
10215 GList *parsers = player->parsers;
10216 for (; parsers; parsers = g_list_next(parsers)) {
10217 gchar *name = parsers->data;
10218 MMPLAYER_FREEIF(name);
10220 g_list_free(player->parsers);
10221 player->parsers = NULL;
10224 /* clean found audio decoders */
10225 if (player->audio_decoders) {
10226 GList *a_dec = player->audio_decoders;
10227 for (; a_dec; a_dec = g_list_next(a_dec)) {
10228 gchar *name = a_dec->data;
10229 MMPLAYER_FREEIF(name);
10231 g_list_free(player->audio_decoders);
10232 player->audio_decoders = NULL;
10239 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10241 MMPlayerGstElement *mainbin = NULL;
10242 MMMessageParamType msg_param = {0,};
10243 GstElement *element = NULL;
10244 MMHandleType attrs = 0;
10246 enum MainElementID elemId = MMPLAYER_M_NUM;
10250 if ((player == NULL) ||
10251 (player->pipeline == NULL) ||
10252 (player->pipeline->mainbin == NULL)) {
10253 LOGE("player is null.\n");
10257 mainbin = player->pipeline->mainbin;
10258 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10260 attrs = MMPLAYER_GET_ATTRS(player);
10262 LOGE("fail to get attributes.\n");
10266 /* Initialize Player values */
10267 __mmplayer_initialize_next_play(player);
10269 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10271 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10272 LOGE("failed to parse profile\n");
10273 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10277 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10278 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10279 LOGE("it's dash or hls. not support.");
10280 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10285 switch (player->profile.uri_type) {
10287 case MM_PLAYER_URI_TYPE_FILE:
10289 LOGD("using filesrc for 'file://' handler.\n");
10290 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10291 LOGE("failed to get storage info");
10295 element = gst_element_factory_make("filesrc", "source");
10298 LOGE("failed to create filesrc\n");
10302 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10305 case MM_PLAYER_URI_TYPE_URL_HTTP:
10307 gchar *user_agent, *cookies, **cookie_list;
10308 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10309 user_agent = cookies = NULL;
10310 cookie_list = NULL;
10312 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10314 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10317 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10319 /* get attribute */
10320 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10321 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10323 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10324 LOGD("get timeout from ini\n");
10325 http_timeout = player->ini.http_timeout;
10328 /* get attribute */
10329 SECURE_LOGD("location : %s\n", player->profile.uri);
10330 SECURE_LOGD("cookies : %s\n", cookies);
10331 SECURE_LOGD("user_agent : %s\n", user_agent);
10332 LOGD("timeout : %d\n", http_timeout);
10334 /* setting property to streaming source */
10335 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10336 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10337 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10339 /* parsing cookies */
10340 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10341 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10343 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10347 LOGE("not support uri type %d\n", player->profile.uri_type);
10352 LOGE("no source element was created.\n");
10356 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10357 LOGE("failed to add source element to pipeline\n");
10358 gst_object_unref(GST_OBJECT(element));
10363 /* take source element */
10364 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10365 mainbin[MMPLAYER_M_SRC].gst = element;
10369 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10370 if (player->streamer == NULL) {
10371 player->streamer = __mm_player_streaming_create();
10372 __mm_player_streaming_initialize(player->streamer);
10375 elemId = MMPLAYER_M_TYPEFIND;
10376 element = gst_element_factory_make("typefind", "typefinder");
10377 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10378 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10380 elemId = MMPLAYER_M_AUTOPLUG;
10381 element = __mmplayer_create_decodebin(player);
10384 /* check autoplug element is OK */
10386 LOGE("can not create element(%d)\n", elemId);
10390 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10391 LOGE("failed to add sinkbin to pipeline\n");
10392 gst_object_unref(GST_OBJECT(element));
10397 mainbin[elemId].id = elemId;
10398 mainbin[elemId].gst = element;
10400 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10401 LOGE("Failed to link src - autoplug(or typefind)\n");
10405 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10406 LOGE("Failed to change state of src element\n");
10410 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10411 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10412 LOGE("Failed to change state of decodebin\n");
10416 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10417 LOGE("Failed to change state of src element\n");
10422 player->gapless.stream_changed = TRUE;
10423 player->gapless.running = TRUE;
10429 MMPLAYER_PLAYBACK_UNLOCK(player);
10431 if (!player->msg_posted) {
10432 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10433 player->msg_posted = TRUE;
10440 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10442 mm_player_selector_t *selector = &player->selector[type];
10443 MMPlayerGstElement *sinkbin = NULL;
10444 enum MainElementID selectorId = MMPLAYER_M_NUM;
10445 enum MainElementID sinkId = MMPLAYER_M_NUM;
10446 GstPad *srcpad = NULL;
10447 GstPad *sinkpad = NULL;
10448 gboolean send_notice = FALSE;
10451 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10453 LOGD("type %d", type);
10456 case MM_PLAYER_TRACK_TYPE_AUDIO:
10457 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10458 sinkId = MMPLAYER_A_BIN;
10459 sinkbin = player->pipeline->audiobin;
10461 case MM_PLAYER_TRACK_TYPE_VIDEO:
10462 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10463 sinkId = MMPLAYER_V_BIN;
10464 sinkbin = player->pipeline->videobin;
10465 send_notice = TRUE;
10467 case MM_PLAYER_TRACK_TYPE_TEXT:
10468 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10469 sinkId = MMPLAYER_T_BIN;
10470 sinkbin = player->pipeline->textbin;
10473 LOGE("requested type is not supportable");
10478 if (player->pipeline->mainbin[selectorId].gst) {
10481 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10483 if (selector->event_probe_id != 0)
10484 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10485 selector->event_probe_id = 0;
10487 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10488 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10490 if (srcpad && sinkpad) {
10491 /* after getting drained signal there is no data flows, so no need to do pad_block */
10492 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10493 gst_pad_unlink(srcpad, sinkpad);
10495 /* send custom event to sink pad to handle it at video sink */
10497 LOGD("send custom event to sinkpad");
10498 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10499 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10500 gst_pad_send_event(sinkpad, event);
10504 gst_object_unref(sinkpad);
10507 gst_object_unref(srcpad);
10510 LOGD("selector release");
10512 /* release and unref requests pad from the selector */
10513 for (n = 0; n < selector->channels->len; n++) {
10514 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10515 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10517 g_ptr_array_set_size(selector->channels, 0);
10519 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10520 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10522 player->pipeline->mainbin[selectorId].gst = NULL;
10530 __mmplayer_deactivate_old_path(mm_player_t *player)
10533 MMPLAYER_RETURN_IF_FAIL(player);
10535 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10536 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10537 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10538 LOGE("deactivate selector error");
10542 _mmplayer_track_destroy(player);
10543 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10545 if (player->streamer) {
10546 __mm_player_streaming_deinitialize(player->streamer);
10547 __mm_player_streaming_destroy(player->streamer);
10548 player->streamer = NULL;
10551 MMPLAYER_PLAYBACK_LOCK(player);
10552 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10559 if (!player->msg_posted) {
10560 MMMessageParamType msg = {0,};
10563 msg.code = MM_ERROR_PLAYER_INTERNAL;
10564 LOGE("next_uri_play> deactivate error");
10566 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10567 player->msg_posted = TRUE;
10572 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10574 int result = MM_ERROR_NONE;
10575 mm_player_t* player = (mm_player_t*) hplayer;
10578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10581 player->http_file_buffering_path = (gchar*)file_path;
10582 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10588 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10590 int result = MM_ERROR_NONE;
10591 mm_player_t* player = (mm_player_t*) hplayer;
10594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10596 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10597 if (mmf_attrs_commit(player->attrs)) {
10598 LOGE("failed to commit the original uri.\n");
10599 result = MM_ERROR_PLAYER_INTERNAL;
10601 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10602 LOGE("failed to add the original uri in the uri list.\n");
10609 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10611 mm_player_t* player = (mm_player_t*) hplayer;
10612 guint num_of_list = 0;
10616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10617 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10619 if (player->pipeline && player->pipeline->textbin) {
10620 LOGE("subtitle path is enabled.\n");
10621 return MM_ERROR_PLAYER_INVALID_STATE;
10624 num_of_list = g_list_length(player->uri_info.uri_list);
10626 if (is_first_path == TRUE) {
10627 if (num_of_list == 0) {
10628 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10629 LOGD("add original path : %s", uri);
10631 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10632 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10634 LOGD("change original path : %s", uri);
10637 MMHandleType attrs = 0;
10638 attrs = MMPLAYER_GET_ATTRS(player);
10640 if (num_of_list == 0) {
10641 char *original_uri = NULL;
10644 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10646 if (!original_uri) {
10647 LOGE("there is no original uri.");
10648 return MM_ERROR_PLAYER_INVALID_STATE;
10651 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10652 player->uri_info.uri_idx = 0;
10654 LOGD("add original path at first : %s(%d)", original_uri);
10658 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10659 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10663 return MM_ERROR_NONE;
10666 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10668 mm_player_t* player = (mm_player_t*) hplayer;
10669 char *next_uri = NULL;
10670 guint num_of_list = 0;
10673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10675 num_of_list = g_list_length(player->uri_info.uri_list);
10677 if (num_of_list > 0) {
10678 gint uri_idx = player->uri_info.uri_idx;
10680 if (uri_idx < num_of_list-1)
10685 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10686 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10688 *uri = g_strdup(next_uri);
10692 return MM_ERROR_NONE;
10696 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10697 GstCaps *caps, gpointer data)
10699 mm_player_t* player = (mm_player_t*)data;
10700 const gchar* klass = NULL;
10701 const gchar* mime = NULL;
10702 gchar* caps_str = NULL;
10704 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10705 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10706 caps_str = gst_caps_to_string(caps);
10708 LOGW("unknown type of caps : %s from %s",
10709 caps_str, GST_ELEMENT_NAME(elem));
10711 MMPLAYER_FREEIF(caps_str);
10713 /* There is no available codec. */
10714 __mmplayer_check_not_supported_codec(player, klass, mime);
10718 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10719 GstCaps * caps, gpointer data)
10721 mm_player_t* player = (mm_player_t*)data;
10722 const char* mime = NULL;
10723 gboolean ret = TRUE;
10725 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10726 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10728 if (g_str_has_prefix(mime, "audio")) {
10729 GstStructure* caps_structure = NULL;
10730 gint samplerate = 0;
10732 gchar *caps_str = NULL;
10734 caps_structure = gst_caps_get_structure(caps, 0);
10735 gst_structure_get_int(caps_structure, "rate", &samplerate);
10736 gst_structure_get_int(caps_structure, "channels", &channels);
10738 if ((channels > 0 && samplerate == 0)) {
10739 LOGD("exclude audio...");
10743 caps_str = gst_caps_to_string(caps);
10744 /* set it directly because not sent by TAG */
10745 if (g_strrstr(caps_str, "mobile-xmf"))
10746 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10747 MMPLAYER_FREEIF(caps_str);
10748 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10749 MMMessageParamType msg_param;
10750 memset(&msg_param, 0, sizeof(MMMessageParamType));
10751 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10752 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10753 LOGD("video file is not supported on this device");
10755 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10756 LOGD("already video linked");
10759 LOGD("found new stream");
10766 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10768 int ret = MM_ERROR_NONE;
10770 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10772 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10773 GstStructure* str = NULL;
10775 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10777 LOGD("audio codec type: %d", codec_type);
10778 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10779 /* sw codec will be skipped */
10780 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10781 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10782 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10783 ret = MM_ERROR_PLAYER_INTERNAL;
10787 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10788 /* hw codec will be skipped */
10789 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10790 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10791 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10792 ret = MM_ERROR_PLAYER_INTERNAL;
10797 str = gst_caps_get_structure(caps, 0);
10799 gst_structure_get_int(str, "channels", &channels);
10801 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10802 if (player->max_audio_channels < channels)
10803 player->max_audio_channels = channels;
10805 /* set stream information */
10806 if (!player->audiodec_linked)
10807 __mmplayer_set_audio_attrs(player, caps);
10809 /* update codec info */
10810 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10811 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10812 player->audiodec_linked = 1;
10814 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10816 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10818 LOGD("video codec type: %d", codec_type);
10819 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10820 /* sw codec is skipped */
10821 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10822 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10823 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10824 ret = MM_ERROR_PLAYER_INTERNAL;
10828 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10829 /* hw codec is skipped */
10830 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10831 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10832 ret = MM_ERROR_PLAYER_INTERNAL;
10837 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10838 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10840 /* mark video decoder for acquire */
10841 if (player->video_decoder_resource == NULL) {
10842 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10843 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10844 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10845 &player->video_decoder_resource)
10846 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10847 LOGE("could not mark video_decoder resource for acquire");
10848 ret = MM_ERROR_PLAYER_INTERNAL;
10852 LOGW("video decoder resource is already acquired, skip it.");
10853 ret = MM_ERROR_PLAYER_INTERNAL;
10857 player->interrupted_by_resource = FALSE;
10858 /* acquire resources for video playing */
10859 if (mm_resource_manager_commit(player->resource_manager)
10860 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10861 LOGE("could not acquire resources for video decoding\n");
10862 ret = MM_ERROR_PLAYER_INTERNAL;
10867 /* update codec info */
10868 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10869 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10870 player->videodec_linked = 1;
10878 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10879 GstCaps* caps, GstElementFactory* factory, gpointer data)
10881 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10882 We are defining our own and will be removed when it actually exposed */
10884 GST_AUTOPLUG_SELECT_TRY,
10885 GST_AUTOPLUG_SELECT_EXPOSE,
10886 GST_AUTOPLUG_SELECT_SKIP
10887 } GstAutoplugSelectResult;
10889 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10890 mm_player_t* player = (mm_player_t*)data;
10892 gchar* factory_name = NULL;
10893 gchar* caps_str = NULL;
10894 const gchar* klass = NULL;
10897 factory_name = GST_OBJECT_NAME(factory);
10898 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10899 caps_str = gst_caps_to_string(caps);
10901 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10903 /* store type string */
10904 if (player->type == NULL) {
10905 player->type = gst_caps_to_string(caps);
10906 __mmplayer_update_content_type_info(player);
10909 /* filtering exclude keyword */
10910 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10911 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10912 LOGW("skipping [%s] by exculde keyword [%s]\n",
10913 factory_name, player->ini.exclude_element_keyword[idx]);
10915 result = GST_AUTOPLUG_SELECT_SKIP;
10920 /* exclude webm format */
10921 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10922 * because webm format is not supportable.
10923 * If webm is disabled in "autoplug-continue", there is no state change
10924 * failure or error because the decodebin will expose the pad directly.
10925 * It make MSL invoke _prepare_async_callback.
10926 * So, we need to disable webm format in "autoplug-select" */
10927 if (caps_str && strstr(caps_str, "webm")) {
10928 LOGW("webm is not supported");
10929 result = GST_AUTOPLUG_SELECT_SKIP;
10933 /* check factory class for filtering */
10934 /* NOTE : msl don't need to use image plugins.
10935 * So, those plugins should be skipped for error handling.
10937 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10938 LOGD("skipping [%s] by not required\n", factory_name);
10939 result = GST_AUTOPLUG_SELECT_SKIP;
10943 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10944 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10945 // TO CHECK : subtitle if needed, add subparse exception.
10946 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10947 result = GST_AUTOPLUG_SELECT_SKIP;
10951 if (g_strrstr(factory_name, "mpegpsdemux")) {
10952 LOGD("skipping PS container - not support\n");
10953 result = GST_AUTOPLUG_SELECT_SKIP;
10957 if (g_strrstr(factory_name, "mssdemux"))
10958 player->smooth_streaming = TRUE;
10960 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10961 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10964 GstStructure *str = NULL;
10965 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10967 /* don't make video because of not required */
10968 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10969 (player->set_mode.media_packet_video_stream == FALSE)) {
10970 LOGD("no video because it's not required. -> return expose");
10971 result = GST_AUTOPLUG_SELECT_EXPOSE;
10975 /* get w/h for omx state-tune */
10976 /* FIXME: deprecated? */
10977 str = gst_caps_get_structure(caps, 0);
10978 gst_structure_get_int(str, "width", &width);
10981 if (player->v_stream_caps) {
10982 gst_caps_unref(player->v_stream_caps);
10983 player->v_stream_caps = NULL;
10986 player->v_stream_caps = gst_caps_copy(caps);
10987 LOGD("take caps for video state tune");
10988 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
10992 if (g_strrstr(klass, "Codec/Decoder")) {
10993 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
10994 LOGD("skipping %s codec", factory_name);
10995 result = GST_AUTOPLUG_SELECT_SKIP;
11001 MMPLAYER_FREEIF(caps_str);
11007 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11010 //mm_player_t* player = (mm_player_t*)data;
11011 GstCaps* caps = NULL;
11013 LOGD("[Decodebin2] pad-removed signal\n");
11015 caps = gst_pad_query_caps(new_pad, NULL);
11017 gchar* caps_str = NULL;
11018 caps_str = gst_caps_to_string(caps);
11020 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11022 MMPLAYER_FREEIF(caps_str);
11023 gst_caps_unref(caps);
11028 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11030 mm_player_t* player = (mm_player_t*)data;
11031 GstIterator *iter = NULL;
11032 GValue item = { 0, };
11033 GstPad *pad = NULL;
11034 gboolean done = FALSE;
11035 gboolean is_all_drained = TRUE;
11038 MMPLAYER_RETURN_IF_FAIL(player);
11040 LOGD("__mmplayer_gst_decode_drained");
11042 if (player->use_deinterleave == TRUE) {
11043 LOGD("group playing mode.");
11047 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11048 LOGW("Fail to get cmd lock");
11052 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11053 !__mmplayer_verify_next_play_path(player)) {
11054 LOGD("decoding is finished.");
11055 __mmplayer_reset_gapless_state(player);
11056 MMPLAYER_CMD_UNLOCK(player);
11060 player->gapless.reconfigure = TRUE;
11062 /* check decodebin src pads whether they received EOS or not */
11063 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11066 switch (gst_iterator_next(iter, &item)) {
11067 case GST_ITERATOR_OK:
11068 pad = g_value_get_object(&item);
11069 if (pad && !GST_PAD_IS_EOS(pad)) {
11070 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11071 is_all_drained = FALSE;
11074 g_value_reset(&item);
11076 case GST_ITERATOR_RESYNC:
11077 gst_iterator_resync(iter);
11079 case GST_ITERATOR_ERROR:
11080 case GST_ITERATOR_DONE:
11085 g_value_unset(&item);
11086 gst_iterator_free(iter);
11088 if (!is_all_drained) {
11089 LOGD("Wait util the all pads get EOS.");
11090 MMPLAYER_CMD_UNLOCK(player);
11095 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11096 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11098 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11099 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11100 __mmplayer_deactivate_old_path(player);
11101 MMPLAYER_CMD_UNLOCK(player);
11107 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11109 mm_player_t* player = (mm_player_t*)data;
11110 const gchar* klass = NULL;
11111 gchar* factory_name = NULL;
11113 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11114 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11116 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11118 if (__mmplayer_add_dump_buffer_probe(player, element))
11119 LOGD("add buffer probe");
11122 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11123 gchar* selected = NULL;
11124 selected = g_strdup(GST_ELEMENT_NAME(element));
11125 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11129 if (g_strrstr(klass, "Parser")) {
11130 gchar* selected = NULL;
11132 selected = g_strdup(factory_name);
11133 player->parsers = g_list_append(player->parsers, selected);
11136 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11137 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11138 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11140 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11141 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11143 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11144 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11145 "max-video-width", player->adaptive_info.limit.width,
11146 "max-video-height", player->adaptive_info.limit.height, NULL);
11148 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11149 /* FIXIT : first value will be overwritten if there's more
11150 * than 1 demuxer/parser
11153 //LOGD("plugged element is demuxer. take it\n");
11154 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11155 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11157 /*Added for multi audio support */ // Q. del?
11158 if (g_strrstr(klass, "Demux")) {
11159 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11160 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11164 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11165 int surface_type = 0;
11167 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11170 // to support trust-zone only
11171 if (g_strrstr(factory_name, "asfdemux")) {
11172 LOGD("set file-location %s\n", player->profile.uri);
11173 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11175 if (player->video_hub_download_mode == TRUE)
11176 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11177 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11178 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11179 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11180 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11181 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11182 (__mmplayer_is_only_mp3_type(player->type))) {
11183 LOGD("[mpegaudioparse] set streaming pull mode.");
11184 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11186 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11187 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11190 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11191 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11192 LOGD("plugged element is multiqueue. take it\n");
11194 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11195 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11197 if (!MMPLAYER_IS_HTTP_PD(player) &&
11198 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11199 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11200 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11201 __mm_player_streaming_set_multiqueue(player->streamer,
11204 player->ini.http_buffering_time,
11206 player->ini.http_buffering_limit);
11208 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11215 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11218 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11220 if (MMPLAYER_IS_STREAMING(player))
11223 /* This callback can be set to music player only. */
11224 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11225 LOGW("audio callback is not supported for video");
11229 if (player->audio_stream_cb) {
11230 GstPad *pad = NULL;
11232 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11235 LOGE("failed to get sink pad from audiosink to probe data\n");
11238 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11239 __mmplayer_audio_stream_probe, player, NULL);
11241 gst_object_unref(pad);
11245 LOGE("There is no audio callback to configure.\n");
11255 __mmplayer_release_misc(mm_player_t* player)
11258 bool cur_mode = player->set_mode.rich_audio;
11261 MMPLAYER_RETURN_IF_FAIL(player);
11263 player->video_stream_cb = NULL;
11264 player->video_stream_cb_user_param = NULL;
11265 player->video_stream_prerolled = FALSE;
11267 player->audio_stream_cb = NULL;
11268 player->audio_stream_render_cb_ex = NULL;
11269 player->audio_stream_cb_user_param = NULL;
11270 player->audio_stream_sink_sync = false;
11272 player->video_stream_changed_cb = NULL;
11273 player->video_stream_changed_cb_user_param = NULL;
11275 player->audio_stream_changed_cb = NULL;
11276 player->audio_stream_changed_cb_user_param = NULL;
11278 player->sent_bos = FALSE;
11279 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11281 player->doing_seek = FALSE;
11283 player->total_bitrate = 0;
11284 player->total_maximum_bitrate = 0;
11286 player->not_found_demuxer = 0;
11288 player->last_position = 0;
11289 player->duration = 0;
11290 player->http_content_size = 0;
11291 player->not_supported_codec = MISSING_PLUGIN_NONE;
11292 player->can_support_codec = FOUND_PLUGIN_NONE;
11293 player->pending_seek.is_pending = FALSE;
11294 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11295 player->pending_seek.pos = 0;
11296 player->msg_posted = FALSE;
11297 player->has_many_types = FALSE;
11298 player->max_audio_channels = 0;
11299 player->video_share_api_delta = 0;
11300 player->video_share_clock_delta = 0;
11301 player->is_subtitle_force_drop = FALSE;
11302 player->play_subtitle = FALSE;
11303 player->adjust_subtitle_pos = 0;
11304 player->last_multiwin_status = FALSE;
11305 player->has_closed_caption = FALSE;
11306 player->set_mode.media_packet_video_stream = FALSE;
11307 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11308 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11310 player->set_mode.rich_audio = cur_mode;
11312 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11313 player->bitrate[i] = 0;
11314 player->maximum_bitrate[i] = 0;
11317 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11319 /* remove media stream cb(appsrc cb) */
11320 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11321 player->media_stream_buffer_status_cb[i] = NULL;
11322 player->media_stream_seek_data_cb[i] = NULL;
11323 player->buffer_cb_user_param[i] = NULL;
11324 player->seek_cb_user_param[i] = NULL;
11326 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11328 /* free memory related to audio effect */
11329 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11331 if (player->adaptive_info.var_list) {
11332 g_list_free_full(player->adaptive_info.var_list, g_free);
11333 player->adaptive_info.var_list = NULL;
11336 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11337 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11338 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11340 /* Reset video360 settings to their defaults in case if the pipeline is to be
11343 player->video360_metadata.is_spherical = -1;
11344 player->is_openal_plugin_used = FALSE;
11346 player->is_content_spherical = FALSE;
11347 player->is_video360_enabled = TRUE;
11348 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11349 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11350 player->video360_yaw_radians = 4;
11351 player->video360_pitch_radians = 4;
11352 player->video360_zoom = 1.0f;
11353 player->video360_horizontal_fov = 0;
11354 player->video360_vertical_fov = 0;
11356 player->sound.rg_enable = false;
11362 __mmplayer_release_misc_post(mm_player_t* player)
11364 char *original_uri = NULL;
11367 /* player->pipeline is already released before. */
11369 MMPLAYER_RETURN_IF_FAIL(player);
11371 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11373 /* clean found parsers */
11374 if (player->parsers) {
11375 GList *parsers = player->parsers;
11376 for (; parsers; parsers = g_list_next(parsers)) {
11377 gchar *name = parsers->data;
11378 MMPLAYER_FREEIF(name);
11380 g_list_free(player->parsers);
11381 player->parsers = NULL;
11384 /* clean found audio decoders */
11385 if (player->audio_decoders) {
11386 GList *a_dec = player->audio_decoders;
11387 for (; a_dec; a_dec = g_list_next(a_dec)) {
11388 gchar *name = a_dec->data;
11389 MMPLAYER_FREEIF(name);
11391 g_list_free(player->audio_decoders);
11392 player->audio_decoders = NULL;
11395 /* clean the uri list except original uri */
11396 if (player->uri_info.uri_list) {
11397 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11399 if (player->attrs) {
11400 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11401 LOGD("restore original uri = %s\n", original_uri);
11403 if (mmf_attrs_commit(player->attrs))
11404 LOGE("failed to commit the original uri.\n");
11407 GList *uri_list = player->uri_info.uri_list;
11408 for (; uri_list; uri_list = g_list_next(uri_list)) {
11409 gchar *uri = uri_list->data;
11410 MMPLAYER_FREEIF(uri);
11412 g_list_free(player->uri_info.uri_list);
11413 player->uri_info.uri_list = NULL;
11416 /* clear the audio stream buffer list */
11417 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11419 /* clear the video stream bo list */
11420 __mmplayer_video_stream_destroy_bo_list(player);
11421 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11423 if (player->profile.input_mem.buf) {
11424 free(player->profile.input_mem.buf);
11425 player->profile.input_mem.buf = NULL;
11427 player->profile.input_mem.len = 0;
11428 player->profile.input_mem.offset = 0;
11430 player->uri_info.uri_idx = 0;
11434 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11436 GstElement *element = NULL;
11439 LOGD("creating %s to plug\n", name);
11441 element = gst_element_factory_make(name, NULL);
11443 LOGE("failed to create queue\n");
11447 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11448 LOGE("failed to set state READY to %s\n", name);
11449 gst_object_unref(element);
11453 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11454 LOGE("failed to add %s\n", name);
11455 gst_object_unref(element);
11459 sinkpad = gst_element_get_static_pad(element, "sink");
11461 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11462 LOGE("failed to link %s\n", name);
11463 gst_object_unref(sinkpad);
11464 gst_object_unref(element);
11468 LOGD("linked %s to pipeline successfully\n", name);
11470 gst_object_unref(sinkpad);
11476 __mmplayer_check_subtitle(mm_player_t* player)
11478 MMHandleType attrs = 0;
11479 char *subtitle_uri = NULL;
11483 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11485 /* get subtitle attribute */
11486 attrs = MMPLAYER_GET_ATTRS(player);
11490 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11491 if (!subtitle_uri || !strlen(subtitle_uri))
11494 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11495 player->is_external_subtitle_present = TRUE;
11503 __mmplayer_can_extract_pcm(mm_player_t* player)
11505 MMHandleType attrs = 0;
11506 gboolean sound_extraction = FALSE;
11508 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11510 attrs = MMPLAYER_GET_ATTRS(player);
11512 LOGE("fail to get attributes.");
11516 /* get sound_extraction property */
11517 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11519 if (!sound_extraction) {
11520 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11528 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11531 MMMessageParamType msg_param;
11532 gchar *msg_src_element = NULL;
11533 GstStructure *s = NULL;
11534 guint error_id = 0;
11535 gchar *error_string = NULL;
11539 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11540 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11542 s = gst_structure_copy(gst_message_get_structure(message));
11545 if (!gst_structure_get_uint(s, "error_id", &error_id))
11546 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11548 switch (error_id) {
11549 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11550 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11552 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11553 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11555 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11556 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11558 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11559 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11561 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11562 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11564 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11565 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11567 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11568 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11570 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11571 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11573 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11574 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11576 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11577 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11579 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11580 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11582 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11583 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11585 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11586 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11588 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11589 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11591 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11592 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11594 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11595 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11597 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11598 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11600 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11601 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11603 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11604 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11606 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11607 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11609 case MMPLAYER_STREAMING_ERROR_GONE:
11610 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11612 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11613 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11615 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11616 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11618 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11619 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11621 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11622 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11624 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11625 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11627 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11628 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11630 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11631 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11633 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11634 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11636 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11637 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11639 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11640 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11642 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11643 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11645 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11646 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11648 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11649 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11651 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11652 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11654 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11655 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11657 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11658 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11660 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11661 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11663 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11664 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11666 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11667 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11669 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11670 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11672 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11673 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11675 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11676 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11678 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11679 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11681 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11682 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11686 gst_structure_free(s);
11687 return MM_ERROR_PLAYER_STREAMING_FAIL;
11691 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11693 msg_param.data = (void *) error_string;
11695 if (message->src) {
11696 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11698 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11699 msg_src_element, msg_param.code, (char*)msg_param.data);
11702 /* post error to application */
11703 if (!player->msg_posted) {
11704 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11706 /* don't post more if one was sent already */
11707 player->msg_posted = TRUE;
11709 LOGD("skip error post because it's sent already.\n");
11711 gst_structure_free(s);
11713 g_free(error_string);
11720 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11722 MMPLAYER_RETURN_IF_FAIL(player);
11724 /* post now if delay is zero */
11725 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11726 LOGD("eos delay is zero. posting EOS now\n");
11727 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11729 if (player->set_mode.pcm_extraction)
11730 __mmplayer_cancel_eos_timer(player);
11735 /* cancel if existing */
11736 __mmplayer_cancel_eos_timer(player);
11738 /* init new timeout */
11739 /* NOTE : consider give high priority to this timer */
11740 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11742 player->eos_timer = g_timeout_add(delay_in_ms,
11743 __mmplayer_eos_timer_cb, player);
11745 player->global_default = g_main_context_default();
11746 LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11748 /* check timer is valid. if not, send EOS now */
11749 if (player->eos_timer == 0) {
11750 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11751 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11756 __mmplayer_cancel_eos_timer(mm_player_t* player)
11758 MMPLAYER_RETURN_IF_FAIL(player);
11760 if (player->eos_timer) {
11761 LOGD("cancel eos timer");
11762 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11763 player->eos_timer = 0;
11770 __mmplayer_eos_timer_cb(gpointer u_data)
11772 mm_player_t* player = NULL;
11773 MMHandleType attrs = 0;
11776 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11778 player = (mm_player_t*) u_data;
11779 attrs = MMPLAYER_GET_ATTRS(player);
11781 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11784 gint ret_value = 0;
11785 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11786 if (ret_value != MM_ERROR_NONE) {
11787 LOGE("seeking to 0 failed in repeat play");
11791 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11794 /* we are returning FALSE as we need only one posting */
11798 /* sending event to one of sinkelements */
11800 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11802 GstEvent * event2 = NULL;
11803 GList *sinks = NULL;
11804 gboolean res = FALSE;
11807 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11808 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11810 /* While adding subtitles in live feeds seek is getting called.
11811 Adding defensive check in framework layer.*/
11812 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11813 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11814 LOGE("Should not send seek event during live playback");
11819 if (player->play_subtitle)
11820 event2 = gst_event_copy((const GstEvent *)event);
11822 sinks = player->sink_elements;
11824 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11826 if (GST_IS_ELEMENT(sink)) {
11827 /* keep ref to the event */
11828 gst_event_ref(event);
11830 if ((res = gst_element_send_event(sink, event))) {
11831 LOGD("sending event[%s] to sink element [%s] success!\n",
11832 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11834 /* rtsp case, asyn_done is not called after seek during pause state */
11835 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11836 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11837 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11838 LOGD("RTSP seek completed, after pause state..\n");
11839 player->doing_seek = FALSE;
11840 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11846 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11847 sinks = g_list_next(sinks);
11854 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11855 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11858 sinks = g_list_next(sinks);
11861 /* Note : Textbin is not linked to the video or audio bin.
11862 * It needs to send the event to the text sink seperatelly.
11864 if (player->play_subtitle && player->pipeline) {
11865 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11867 if (GST_IS_ELEMENT(text_sink)) {
11868 /* keep ref to the event */
11869 gst_event_ref(event2);
11871 if ((res = gst_element_send_event(text_sink, event2)))
11872 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11873 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11875 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11876 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11878 gst_event_unref(event2);
11882 gst_event_unref(event);
11890 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11894 MMPLAYER_RETURN_IF_FAIL(player);
11895 MMPLAYER_RETURN_IF_FAIL(sink);
11897 player->sink_elements =
11898 g_list_append(player->sink_elements, sink);
11904 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11908 MMPLAYER_RETURN_IF_FAIL(player);
11909 MMPLAYER_RETURN_IF_FAIL(sink);
11911 player->sink_elements =
11912 g_list_remove(player->sink_elements, sink);
11918 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11919 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11920 gint64 cur, GstSeekType stop_type, gint64 stop)
11922 GstEvent* event = NULL;
11923 gboolean result = FALSE;
11927 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11929 if (player->pipeline && player->pipeline->textbin)
11930 __mmplayer_drop_subtitle(player, FALSE);
11932 event = gst_event_new_seek(rate, format, flags, cur_type,
11933 cur, stop_type, stop);
11935 result = __gst_send_event_to_sink(player, event);
11942 /* NOTE : be careful with calling this api. please refer to below glib comment
11943 * glib comment : Note that there is a bug in GObject that makes this function much
11944 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11945 * will no longer be called, but, the signal handler is not currently disconnected.
11946 * If the instance is itself being freed at the same time than this doesn't matter,
11947 * since the signal will automatically be removed, but if instance persists,
11948 * then the signal handler will leak. You should not remove the signal yourself
11949 * because in a future versions of GObject, the handler will automatically be
11952 * It's possible to work around this problem in a way that will continue to work
11953 * with future versions of GObject by checking that the signal handler is still
11954 * connected before disconnected it:
11956 * if (g_signal_handler_is_connected(instance, id))
11957 * g_signal_handler_disconnect(instance, id);
11960 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11962 GList* sig_list = NULL;
11963 MMPlayerSignalItem* item = NULL;
11967 MMPLAYER_RETURN_IF_FAIL(player);
11969 LOGD("release signals type : %d", type);
11971 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11972 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11973 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11975 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11976 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11980 sig_list = player->signals[type];
11982 for (; sig_list; sig_list = sig_list->next) {
11983 item = sig_list->data;
11985 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11986 if (g_signal_handler_is_connected(item->obj, item->sig))
11987 g_signal_handler_disconnect(item->obj, item->sig);
11990 MMPLAYER_FREEIF(item);
11993 g_list_free(player->signals[type]);
11994 player->signals[type] = NULL;
12001 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12003 mm_player_t* player = 0;
12004 int prev_display_surface_type = 0;
12005 void *prev_display_overlay = NULL;
12006 const gchar *klass = NULL;
12007 gchar *cur_videosink_name = NULL;
12010 int num_of_dec = 2; /* DEC1, DEC2 */
12014 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12015 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12017 player = MM_PLAYER_CAST(handle);
12019 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12020 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12022 return MM_ERROR_INVALID_ARGUMENT;
12025 /* load previous attributes */
12026 if (player->attrs) {
12027 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12028 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12029 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12030 if (prev_display_surface_type == surface_type) {
12031 LOGD("incoming display surface type is same as previous one, do nothing..");
12033 return MM_ERROR_NONE;
12036 LOGE("failed to load attributes");
12038 return MM_ERROR_PLAYER_INTERNAL;
12041 /* check videosink element is created */
12042 if (!player->pipeline || !player->pipeline->videobin ||
12043 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12044 LOGD("videosink element is not yet ready");
12046 /* videobin is not created yet, so we just set attributes related to display surface */
12047 LOGD("store display attribute for given surface type(%d)", surface_type);
12048 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12049 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12050 if (mmf_attrs_commit(player->attrs)) {
12051 LOGE("failed to commit attribute");
12053 return MM_ERROR_PLAYER_INTERNAL;
12056 return MM_ERROR_NONE;
12058 /* get player command status */
12059 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12060 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12062 return MM_ERROR_PLAYER_INVALID_STATE;
12065 /* surface change */
12066 for (i = 0 ; i < num_of_dec ; i++) {
12067 if (player->pipeline->mainbin &&
12068 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12069 GstElementFactory *decfactory;
12070 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12072 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12073 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12074 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12075 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12079 LOGW("success to changing display surface(%d)", surface_type);
12081 return MM_ERROR_NONE;
12083 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12084 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12088 LOGW("success to changing display surface(%d)", surface_type);
12090 return MM_ERROR_NONE;
12093 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12094 ret = MM_ERROR_PLAYER_INTERNAL;
12103 /* rollback to previous attributes */
12104 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12105 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12106 if (mmf_attrs_commit(player->attrs)) {
12107 LOGE("failed to commit attributes to rollback");
12109 return MM_ERROR_PLAYER_INTERNAL;
12115 /* NOTE : It does not support some use cases, eg using colorspace converter */
12117 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12119 GstPad *src_pad_dec = NULL;
12120 GstPad *sink_pad_videosink = NULL;
12121 GstPad *sink_pad_videobin = NULL;
12122 GstClock *clock = NULL;
12123 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12124 int ret = MM_ERROR_NONE;
12125 gboolean is_audiobin_created = TRUE;
12129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12130 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12131 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12133 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12134 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12136 /* get information whether if audiobin is created */
12137 if (!player->pipeline->audiobin ||
12138 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12139 LOGW("audiobin is null, this video content may not have audio data");
12140 is_audiobin_created = FALSE;
12143 /* get current state of player */
12144 previous_state = MMPLAYER_CURRENT_STATE(player);
12145 LOGD("previous state(%d)", previous_state);
12148 /* get src pad of decoder and block it */
12149 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12150 if (!src_pad_dec) {
12151 LOGE("failed to get src pad from decode in mainbin");
12152 return MM_ERROR_PLAYER_INTERNAL;
12155 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12156 LOGW("trying to block pad(video)");
12157 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12158 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12161 LOGE("failed to set block pad(video)");
12162 return MM_ERROR_PLAYER_INTERNAL;
12164 LOGW("pad is blocked(video)");
12166 /* no data flows, so no need to do pad_block */
12167 if (player->doing_seek)
12168 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12170 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12174 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12175 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12176 LOGE("failed to remove previous ghost_pad for videobin");
12177 return MM_ERROR_PLAYER_INTERNAL;
12180 /* change state of videobin to NULL */
12181 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12182 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12183 if (ret != GST_STATE_CHANGE_SUCCESS) {
12184 LOGE("failed to change state of videobin to NULL");
12185 return MM_ERROR_PLAYER_INTERNAL;
12188 /* unlink between decoder and videobin and remove previous videosink from videobin */
12189 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12190 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12191 LOGE("failed to remove former videosink from videobin");
12192 return MM_ERROR_PLAYER_INTERNAL;
12195 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12197 /* create a new videosink and add it to videobin */
12198 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
12199 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12200 LOGE("failed to create videosink element\n");
12202 return MM_ERROR_PLAYER_INTERNAL;
12204 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12205 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12206 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12208 /* save attributes */
12209 if (player->attrs) {
12210 /* set a new display surface type */
12211 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12212 /* set a new diplay overlay */
12213 switch (surface_type) {
12214 case MM_DISPLAY_SURFACE_OVERLAY:
12215 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12216 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12219 LOGE("invalid type(%d) for changing display surface", surface_type);
12221 return MM_ERROR_INVALID_ARGUMENT;
12223 if (mmf_attrs_commit(player->attrs)) {
12224 LOGE("failed to commit");
12226 return MM_ERROR_PLAYER_INTERNAL;
12229 LOGE("player->attrs is null, failed to save attributes");
12231 return MM_ERROR_PLAYER_INTERNAL;
12234 /* update video param */
12235 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12236 LOGE("failed to update video param");
12237 return MM_ERROR_PLAYER_INTERNAL;
12240 /* change state of videobin to READY */
12241 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12242 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12243 if (ret != GST_STATE_CHANGE_SUCCESS) {
12244 LOGE("failed to change state of videobin to READY");
12245 return MM_ERROR_PLAYER_INTERNAL;
12248 /* change ghostpad */
12249 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12250 if (!sink_pad_videosink) {
12251 LOGE("failed to get sink pad from videosink element");
12252 return MM_ERROR_PLAYER_INTERNAL;
12254 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12255 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12256 LOGE("failed to set active to ghost_pad");
12257 return MM_ERROR_PLAYER_INTERNAL;
12259 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12260 LOGE("failed to change ghostpad for videobin");
12261 return MM_ERROR_PLAYER_INTERNAL;
12263 gst_object_unref(sink_pad_videosink);
12265 /* link decoder with videobin */
12266 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12267 if (!sink_pad_videobin) {
12268 LOGE("failed to get sink pad from videobin");
12269 return MM_ERROR_PLAYER_INTERNAL;
12271 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12272 LOGE("failed to link");
12273 return MM_ERROR_PLAYER_INTERNAL;
12275 gst_object_unref(sink_pad_videobin);
12277 /* clock setting for a new videosink plugin */
12278 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12279 so we set it from audiosink plugin or pipeline(system clock) */
12280 if (!is_audiobin_created) {
12281 LOGW("audiobin is not created, get clock from pipeline..");
12282 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12284 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12288 GstClockTime base_time;
12289 LOGD("set the clock to videosink");
12290 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12291 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12293 LOGD("got clock of videosink");
12294 now = gst_clock_get_time(clock);
12295 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12296 LOGD("at time %" GST_TIME_FORMAT ", base %"
12297 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12299 LOGE("failed to get clock of videosink after setting clock");
12300 return MM_ERROR_PLAYER_INTERNAL;
12303 LOGW("failed to get clock, maybe it is the time before first playing");
12305 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12306 /* change state of videobin to PAUSED */
12307 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12308 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12309 if (ret != GST_STATE_CHANGE_FAILURE) {
12310 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12312 LOGE("failed to change state of videobin to PLAYING");
12313 return MM_ERROR_PLAYER_INTERNAL;
12316 /* release blocked and unref src pad of video decoder */
12318 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12319 LOGE("failed to set pad blocked FALSE(video)");
12320 return MM_ERROR_PLAYER_INTERNAL;
12323 LOGW("pad is unblocked(video)");
12325 if (player->doing_seek)
12326 LOGW("not completed seek(%d)", player->doing_seek);
12327 /* change state of videobin to PAUSED */
12328 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12329 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12330 if (ret != GST_STATE_CHANGE_FAILURE) {
12331 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12333 LOGE("failed to change state of videobin to PLAYING");
12334 return MM_ERROR_PLAYER_INTERNAL;
12337 /* already skipped pad block */
12338 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12341 /* do get/set position for new videosink plugin */
12343 unsigned long position = 0;
12344 gint64 pos_msec = 0;
12346 LOGD("do get/set position for new videosink plugin");
12347 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12348 LOGE("failed to get position");
12349 return MM_ERROR_PLAYER_INTERNAL;
12351 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12352 /* accurate seek */
12353 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12354 LOGE("failed to set position");
12355 return MM_ERROR_PLAYER_INTERNAL;
12358 /* key unit seek */
12359 pos_msec = position * G_GINT64_CONSTANT(1000000);
12360 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12361 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12362 GST_SEEK_TYPE_SET, pos_msec,
12363 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12365 LOGE("failed to set position");
12366 return MM_ERROR_PLAYER_INTERNAL;
12372 gst_object_unref(src_pad_dec);
12373 LOGD("success to change sink");
12377 return MM_ERROR_NONE;
12381 /* Note : if silent is true, then subtitle would not be displayed. :*/
12382 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12384 mm_player_t* player = (mm_player_t*) hplayer;
12388 /* check player handle */
12389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12391 player->set_mode.subtitle_off = silent;
12393 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12397 return MM_ERROR_NONE;
12400 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12402 MMPlayerGstElement* mainbin = NULL;
12403 MMPlayerGstElement* textbin = NULL;
12404 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12405 GstState current_state = GST_STATE_VOID_PENDING;
12406 GstState element_state = GST_STATE_VOID_PENDING;
12407 GstState element_pending_state = GST_STATE_VOID_PENDING;
12409 GstEvent *event = NULL;
12410 int result = MM_ERROR_NONE;
12412 GstClock *curr_clock = NULL;
12413 GstClockTime base_time, start_time, curr_time;
12418 /* check player handle */
12419 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12420 player->pipeline &&
12421 player->pipeline->mainbin &&
12422 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12424 mainbin = player->pipeline->mainbin;
12425 textbin = player->pipeline->textbin;
12427 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12429 // sync clock with current pipeline
12430 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12431 curr_time = gst_clock_get_time(curr_clock);
12433 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12434 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12436 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12437 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12439 if (current_state > GST_STATE_READY) {
12440 // sync state with current pipeline
12441 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12442 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12443 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12445 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12446 if (GST_STATE_CHANGE_FAILURE == ret) {
12447 LOGE("fail to state change.\n");
12448 result = MM_ERROR_PLAYER_INTERNAL;
12453 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12454 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12457 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12458 gst_object_unref(curr_clock);
12461 // seek to current position
12462 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12463 result = MM_ERROR_PLAYER_INVALID_STATE;
12464 LOGE("gst_element_query_position failed, invalid state\n");
12468 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12469 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);
12471 __gst_send_event_to_sink(player, event);
12473 result = MM_ERROR_PLAYER_INTERNAL;
12474 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12478 /* sync state with current pipeline */
12479 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12480 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12481 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12483 return MM_ERROR_NONE;
12486 /* release text pipeline resource */
12487 player->textsink_linked = 0;
12489 /* release signal */
12490 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12492 /* release textbin with it's childs */
12493 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12494 MMPLAYER_FREEIF(player->pipeline->textbin);
12495 player->pipeline->textbin = NULL;
12497 /* release subtitle elem */
12498 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12499 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12505 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12507 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12508 GstState current_state = GST_STATE_VOID_PENDING;
12510 MMHandleType attrs = 0;
12511 MMPlayerGstElement* mainbin = NULL;
12512 MMPlayerGstElement* textbin = NULL;
12514 gchar* subtitle_uri = NULL;
12515 int result = MM_ERROR_NONE;
12516 const gchar *charset = NULL;
12520 /* check player handle */
12521 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12522 player->pipeline &&
12523 player->pipeline->mainbin &&
12524 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12525 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12527 mainbin = player->pipeline->mainbin;
12528 textbin = player->pipeline->textbin;
12530 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12531 if (current_state < GST_STATE_READY) {
12532 result = MM_ERROR_PLAYER_INVALID_STATE;
12533 LOGE("Pipeline is not in proper state\n");
12537 attrs = MMPLAYER_GET_ATTRS(player);
12539 LOGE("cannot get content attribute\n");
12540 result = MM_ERROR_PLAYER_INTERNAL;
12544 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12545 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12546 LOGE("subtitle uri is not proper filepath\n");
12547 result = MM_ERROR_PLAYER_INVALID_URI;
12551 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12552 LOGE("failed to get storage info of subtitle path");
12553 result = MM_ERROR_PLAYER_INVALID_URI;
12557 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12558 LOGD("new subtitle file path is [%s]\n", filepath);
12560 if (!strcmp(filepath, subtitle_uri)) {
12561 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12564 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12565 if (mmf_attrs_commit(player->attrs)) {
12566 LOGE("failed to commit.\n");
12571 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12572 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12573 player->subtitle_language_list = NULL;
12574 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12576 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12577 if (ret != GST_STATE_CHANGE_SUCCESS) {
12578 LOGE("failed to change state of textbin to READY");
12579 result = MM_ERROR_PLAYER_INTERNAL;
12583 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12584 if (ret != GST_STATE_CHANGE_SUCCESS) {
12585 LOGE("failed to change state of subparse to READY");
12586 result = MM_ERROR_PLAYER_INTERNAL;
12590 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12591 if (ret != GST_STATE_CHANGE_SUCCESS) {
12592 LOGE("failed to change state of filesrc to READY");
12593 result = MM_ERROR_PLAYER_INTERNAL;
12597 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12599 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12601 charset = util_get_charset(filepath);
12603 LOGD("detected charset is %s\n", charset);
12604 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12607 result = _mmplayer_sync_subtitle_pipeline(player);
12614 /* API to switch between external subtitles */
12615 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12617 int result = MM_ERROR_NONE;
12618 mm_player_t* player = (mm_player_t*)hplayer;
12623 /* check player handle */
12624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12626 /* filepath can be null in idle state */
12628 /* check file path */
12629 if ((path = strstr(filepath, "file://")))
12630 result = util_exist_file_path(path + 7);
12632 result = util_exist_file_path(filepath);
12634 if (result != MM_ERROR_NONE) {
12635 LOGE("invalid subtitle path 0x%X", result);
12636 return result; /* file not found or permission denied */
12640 if (!player->pipeline) {
12642 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12643 if (mmf_attrs_commit(player->attrs)) {
12644 LOGE("failed to commit"); /* subtitle path will not be created */
12645 return MM_ERROR_PLAYER_INTERNAL;
12648 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12649 /* check filepath */
12650 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12652 if (!__mmplayer_check_subtitle(player)) {
12653 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12654 if (mmf_attrs_commit(player->attrs)) {
12655 LOGE("failed to commit");
12656 return MM_ERROR_PLAYER_INTERNAL;
12659 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12660 LOGE("fail to create text pipeline");
12661 return MM_ERROR_PLAYER_INTERNAL;
12664 result = _mmplayer_sync_subtitle_pipeline(player);
12666 result = __mmplayer_change_external_subtitle_language(player, filepath);
12669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12670 player->is_external_subtitle_added_now = TRUE;
12672 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12673 if (!player->subtitle_language_list) {
12674 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12675 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12676 LOGW("subtitle language list is not updated yet");
12678 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12686 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12688 int result = MM_ERROR_NONE;
12689 gchar* change_pad_name = NULL;
12690 GstPad* sinkpad = NULL;
12691 MMPlayerGstElement* mainbin = NULL;
12692 enum MainElementID elemId = MMPLAYER_M_NUM;
12693 GstCaps* caps = NULL;
12694 gint total_track_num = 0;
12698 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12699 MM_ERROR_PLAYER_NOT_INITIALIZED);
12701 LOGD("Change Track(%d) to %d\n", type, index);
12703 mainbin = player->pipeline->mainbin;
12705 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12706 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12707 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12708 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12710 /* Changing Video Track is not supported. */
12711 LOGE("Track Type Error\n");
12715 if (mainbin[elemId].gst == NULL) {
12716 result = MM_ERROR_PLAYER_NO_OP;
12717 LOGD("Req track doesn't exist\n");
12721 total_track_num = player->selector[type].total_track_num;
12722 if (total_track_num <= 0) {
12723 result = MM_ERROR_PLAYER_NO_OP;
12724 LOGD("Language list is not available \n");
12728 if ((index < 0) || (index >= total_track_num)) {
12729 result = MM_ERROR_INVALID_ARGUMENT;
12730 LOGD("Not a proper index : %d \n", index);
12734 /*To get the new pad from the selector*/
12735 change_pad_name = g_strdup_printf("sink_%u", index);
12736 if (change_pad_name == NULL) {
12737 result = MM_ERROR_PLAYER_INTERNAL;
12738 LOGD("Pad does not exists\n");
12742 LOGD("new active pad name: %s\n", change_pad_name);
12744 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12745 if (sinkpad == NULL) {
12746 LOGD("sinkpad is NULL");
12747 result = MM_ERROR_PLAYER_INTERNAL;
12751 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12752 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12754 caps = gst_pad_get_current_caps(sinkpad);
12755 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12758 gst_object_unref(sinkpad);
12760 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12761 __mmplayer_set_audio_attrs(player, caps);
12765 MMPLAYER_FREEIF(change_pad_name);
12769 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12771 int result = MM_ERROR_NONE;
12772 mm_player_t* player = NULL;
12773 MMPlayerGstElement* mainbin = NULL;
12775 gint current_active_index = 0;
12777 GstState current_state = GST_STATE_VOID_PENDING;
12778 GstEvent* event = NULL;
12783 player = (mm_player_t*)hplayer;
12784 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12786 if (!player->pipeline) {
12787 LOGE("Track %d pre setting -> %d\n", type, index);
12789 player->selector[type].active_pad_index = index;
12793 mainbin = player->pipeline->mainbin;
12795 current_active_index = player->selector[type].active_pad_index;
12797 /*If index is same as running index no need to change the pad*/
12798 if (current_active_index == index)
12801 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12802 result = MM_ERROR_PLAYER_INVALID_STATE;
12806 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12807 if (current_state < GST_STATE_PAUSED) {
12808 result = MM_ERROR_PLAYER_INVALID_STATE;
12809 LOGW("Pipeline not in porper state\n");
12813 result = __mmplayer_change_selector_pad(player, type, index);
12814 if (result != MM_ERROR_NONE) {
12815 LOGE("change selector pad error\n");
12819 player->selector[type].active_pad_index = index;
12821 if (current_state == GST_STATE_PLAYING) {
12822 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);
12824 __gst_send_event_to_sink(player, event);
12826 result = MM_ERROR_PLAYER_INTERNAL;
12835 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12837 mm_player_t* player = (mm_player_t*) hplayer;
12841 /* check player handle */
12842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12844 *silent = player->set_mode.subtitle_off;
12846 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12850 return MM_ERROR_NONE;
12854 __is_ms_buff_src(mm_player_t* player)
12856 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12858 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12862 __has_suffix(mm_player_t* player, const gchar* suffix)
12864 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12865 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12867 gboolean ret = FALSE;
12868 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12869 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12871 if (g_str_has_suffix(player->profile.uri, suffix))
12874 MMPLAYER_FREEIF(t_url);
12875 MMPLAYER_FREEIF(t_suffix);
12881 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12883 mm_player_t* player = (mm_player_t*) hplayer;
12885 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12887 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12888 MMPLAYER_PRINT_STATE(player);
12889 LOGE("wrong-state : can't set the download mode to parse");
12890 return MM_ERROR_PLAYER_INVALID_STATE;
12893 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12894 player->video_hub_download_mode = mode;
12896 return MM_ERROR_NONE;
12900 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12902 mm_player_t* player = (mm_player_t*) hplayer;
12904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12906 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12907 player->sync_handler = enable;
12909 return MM_ERROR_NONE;
12913 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12915 long long clock_delta,
12916 long long video_time,
12917 long long media_clock,
12918 long long audio_time)
12920 mm_player_t* player = (mm_player_t*) hplayer;
12921 MMPlayerGstElement* mainbin = NULL;
12922 GstClockTime start_time_audio = 0, start_time_video = 0;
12923 GstClockTimeDiff base_time = 0, new_base_time = 0;
12924 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12925 gint64 api_delta = 0;
12926 gint64 position = 0, position_delta = 0;
12927 gint64 adj_base_time = 0;
12928 GstClock *curr_clock = NULL;
12929 GstClockTime curr_time = 0;
12930 gboolean query_ret = TRUE;
12931 int result = MM_ERROR_NONE;
12935 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12936 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12937 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12939 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12941 if ((video_time < 0) || (player->doing_seek)) {
12942 LOGD("skip setting master clock. %lld", video_time);
12946 mainbin = player->pipeline->mainbin;
12948 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12949 curr_time = gst_clock_get_time(curr_clock);
12951 current_state = MMPLAYER_CURRENT_STATE(player);
12953 if (current_state == MM_PLAYER_STATE_PLAYING)
12954 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12956 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12958 position = player->last_position;
12959 LOGD("query fail. %lld", position);
12962 clock *= GST_USECOND;
12963 clock_delta *= GST_USECOND;
12965 api_delta = clock - curr_time;
12966 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12967 player->video_share_api_delta = api_delta;
12969 clock_delta += (api_delta - player->video_share_api_delta);
12971 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12972 player->video_share_clock_delta = (gint64)clock_delta;
12974 position_delta = (position/GST_USECOND) - video_time;
12975 position_delta *= GST_USECOND;
12977 adj_base_time = position_delta;
12978 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12981 gint64 new_play_time = 0;
12982 gint64 network_delay = 0;
12984 video_time *= GST_USECOND;
12986 network_delay = clock_delta - player->video_share_clock_delta;
12987 new_play_time = video_time + network_delay;
12989 adj_base_time = position - new_play_time;
12991 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
12992 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
12995 /* Adjust Current Stream Time with base_time of sink
12996 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
12997 * 2. Set new base time
12998 * if adj_base_time is positive value, the stream time will be decreased.
12999 * 3. If seek event is occurred, the start time will be reset. */
13000 if ((player->pipeline->audiobin) &&
13001 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13002 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13004 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13005 LOGD("audio sink : gst_element_set_start_time -> NONE");
13006 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13009 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13012 if ((player->pipeline->videobin) &&
13013 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13014 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13016 if (start_time_video != GST_CLOCK_TIME_NONE) {
13017 LOGD("video sink : gst_element_set_start_time -> NONE");
13018 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13021 // if videobin exist, get base_time from videobin.
13022 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13025 new_base_time = base_time + adj_base_time;
13027 if ((player->pipeline->audiobin) &&
13028 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13029 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13031 if ((player->pipeline->videobin) &&
13032 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13033 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13042 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13043 long long *video_time,
13044 long long *media_clock,
13045 long long *audio_time)
13047 mm_player_t* player = (mm_player_t*) hplayer;
13048 MMPlayerGstElement* mainbin = NULL;
13049 GstClock *curr_clock = NULL;
13050 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13051 gint64 position = 0;
13052 gboolean query_ret = TRUE;
13056 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13057 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13058 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13060 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13061 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13062 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13064 mainbin = player->pipeline->mainbin;
13066 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13068 current_state = MMPLAYER_CURRENT_STATE(player);
13070 if (current_state != MM_PLAYER_STATE_PAUSED)
13071 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13073 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13075 position = player->last_position;
13077 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13079 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13082 gst_object_unref(curr_clock);
13086 return MM_ERROR_NONE;
13090 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13092 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13093 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13095 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13096 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13100 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13101 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13102 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13103 mm_player_dump_t *dump_s;
13104 dump_s = g_malloc(sizeof(mm_player_dump_t));
13106 if (dump_s == NULL) {
13107 LOGE("malloc fail");
13111 dump_s->dump_element_file = NULL;
13112 dump_s->dump_pad = NULL;
13113 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13115 if (dump_s->dump_pad) {
13116 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13117 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]);
13118 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13119 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);
13120 /* add list for removed buffer probe and close FILE */
13121 player->dump_list = g_list_append(player->dump_list, dump_s);
13122 LOGD("%s sink pad added buffer probe for dump", factory_name);
13127 LOGE("failed to get %s sink pad added", factory_name);
13136 static GstPadProbeReturn
13137 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13139 FILE *dump_data = (FILE *) u_data;
13140 // int written = 0;
13141 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13142 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13144 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13146 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13148 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13150 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13152 return GST_PAD_PROBE_OK;
13156 __mmplayer_release_dump_list(GList *dump_list)
13159 GList *d_list = dump_list;
13160 for (; d_list; d_list = g_list_next(d_list)) {
13161 mm_player_dump_t *dump_s = d_list->data;
13162 if (dump_s->dump_pad) {
13163 if (dump_s->probe_handle_id)
13164 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13166 if (dump_s->dump_element_file) {
13167 fclose(dump_s->dump_element_file);
13168 dump_s->dump_element_file = NULL;
13170 MMPLAYER_FREEIF(dump_s);
13172 g_list_free(dump_list);
13178 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13180 mm_player_t* player = (mm_player_t*) hplayer;
13184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13185 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13187 *exist = player->has_closed_caption;
13191 return MM_ERROR_NONE;
13194 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13198 // LOGD("unref internal gst buffer %p", buffer);
13199 gst_buffer_unref((GstBuffer *)buffer);
13206 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13208 mm_player_t *player = (mm_player_t*)user_data;
13209 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13210 guint64 current_level_bytes = 0;
13212 MMPLAYER_RETURN_IF_FAIL(player);
13214 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13216 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13217 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13219 if (player->media_stream_buffer_status_cb[type])
13220 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13221 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13226 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13228 mm_player_t *player = (mm_player_t*)user_data;
13229 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13230 guint64 current_level_bytes = 0;
13232 MMPLAYER_RETURN_IF_FAIL(player);
13234 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13236 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13238 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13239 if (player->media_stream_buffer_status_cb[type])
13240 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13241 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13245 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13247 mm_player_t *player = (mm_player_t*)user_data;
13248 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13249 guint64 current_level_bytes = 0;
13251 MMPLAYER_RETURN_IF_FAIL(player);
13253 LOGI("app-src: feed subtitle\n");
13255 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13257 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13258 if (player->media_stream_buffer_status_cb[type])
13259 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13261 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13265 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13267 mm_player_t *player = (mm_player_t*)user_data;
13268 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13269 guint64 current_level_bytes = 0;
13271 MMPLAYER_RETURN_IF_FAIL(player);
13273 LOGI("app-src: audio buffer is full.\n");
13275 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13277 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13279 if (player->media_stream_buffer_status_cb[type])
13280 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13282 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13286 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13288 mm_player_t *player = (mm_player_t*)user_data;
13289 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13290 guint64 current_level_bytes = 0;
13292 MMPLAYER_RETURN_IF_FAIL(player);
13294 LOGI("app-src: video buffer is full.\n");
13296 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13298 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13299 if (player->media_stream_buffer_status_cb[type])
13300 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13302 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13306 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13308 mm_player_t *player = (mm_player_t*)user_data;
13309 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13311 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13313 LOGD("app-src: seek audio data %llu\n", position);
13314 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13316 if (player->media_stream_seek_data_cb[type])
13317 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13318 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13324 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13326 mm_player_t *player = (mm_player_t*)user_data;
13327 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13329 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13331 LOGD("app-src: seek video data %llu\n", position);
13332 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13333 if (player->media_stream_seek_data_cb[type])
13334 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13335 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13341 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13343 mm_player_t *player = (mm_player_t*)user_data;
13344 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13346 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13348 LOGD("app-src: seek subtitle data\n");
13349 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13351 if (player->media_stream_seek_data_cb[type])
13352 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13353 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13359 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13361 mm_player_t* player = (mm_player_t*) hplayer;
13365 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13367 player->pcm_samplerate = samplerate;
13368 player->pcm_channel = channel;
13371 return MM_ERROR_NONE;
13374 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13376 mm_player_t* player = (mm_player_t*) hplayer;
13380 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13381 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13383 if (MMPLAYER_IS_STREAMING(player))
13384 *timeout = player->ini.live_state_change_timeout;
13386 *timeout = player->ini.localplayback_state_change_timeout;
13388 LOGD("timeout = %d\n", *timeout);
13391 return MM_ERROR_NONE;
13394 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13396 mm_player_t* player = (mm_player_t*) hplayer;
13400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13401 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13403 *num = player->video_num_buffers;
13404 *extra_num = player->video_extra_num_buffers;
13406 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13409 return MM_ERROR_NONE;
13413 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13417 MMPLAYER_RETURN_IF_FAIL(player);
13419 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13421 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13422 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13423 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13424 player->storage_info[i].id = -1;
13425 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13427 if (path_type != MMPLAYER_PATH_MAX)
13435 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13437 int ret = MM_ERROR_NONE;
13438 mm_player_t* player = (mm_player_t*)hplayer;
13439 MMMessageParamType msg_param = {0, };
13442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13444 LOGW("state changed storage %d:%d", id, state);
13446 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13447 return MM_ERROR_NONE;
13449 /* FIXME: text path should be handled seperately. */
13450 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13451 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13452 LOGW("external storage is removed");
13454 if (player->msg_posted == FALSE) {
13455 memset(&msg_param, 0, sizeof(MMMessageParamType));
13456 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13457 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13458 player->msg_posted = TRUE;
13461 /* unrealize the player */
13462 ret = _mmplayer_unrealize(hplayer);
13463 if (ret != MM_ERROR_NONE)
13464 LOGE("failed to unrealize");
13471 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13473 int ret = MM_ERROR_NONE;
13474 mm_player_t* player = (mm_player_t*) hplayer;
13475 int idx = 0, total = 0;
13476 gchar *result = NULL, *tmp = NULL;
13479 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13480 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13482 total = *num = g_list_length(player->adaptive_info.var_list);
13484 LOGW("There is no stream variant info.");
13488 result = g_strdup("");
13489 for (idx = 0 ; idx < total ; idx++) {
13490 VariantData *v_data = NULL;
13491 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13494 gchar data[64] = {0};
13495 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13497 tmp = g_strconcat(result, data, NULL);
13501 LOGW("There is no variant data in %d", idx);
13506 *var_info = (char *)result;
13508 LOGD("variant info %d:%s", *num, *var_info);
13513 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13515 int ret = MM_ERROR_NONE;
13516 mm_player_t* player = (mm_player_t*) hplayer;
13519 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13521 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13523 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13524 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13525 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13527 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13528 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13529 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13530 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13532 /* FIXME: seek to current position for applying new variant limitation */
13540 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13542 int ret = MM_ERROR_NONE;
13543 mm_player_t* player = (mm_player_t*) hplayer;
13546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13547 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13549 *bandwidth = player->adaptive_info.limit.bandwidth;
13550 *width = player->adaptive_info.limit.width;
13551 *height = player->adaptive_info.limit.height;
13553 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13559 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13561 int ret = MM_ERROR_NONE;
13562 mm_player_t* player = (mm_player_t*) hplayer;
13565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13567 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13568 LOGW("buffer_ms will not be applied.");
13571 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13573 if (player->streamer == NULL) {
13574 player->streamer = __mm_player_streaming_create();
13575 __mm_player_streaming_initialize(player->streamer);
13578 if (buffer_ms >= 0)
13579 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13581 if (rebuffer_ms >= 0)
13582 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13589 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13591 int ret = MM_ERROR_NONE;
13592 mm_player_t* player = (mm_player_t*) hplayer;
13595 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13596 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13598 if (player->streamer == NULL) {
13599 player->streamer = __mm_player_streaming_create();
13600 __mm_player_streaming_initialize(player->streamer);
13603 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13604 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13606 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13612 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13614 #define IDX_FIRST_SW_CODEC 0
13615 mm_player_t* player = (mm_player_t*) hplayer;
13616 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13617 MMHandleType attrs = 0;
13620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13622 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13623 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13624 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13626 switch (stream_type) {
13627 case MM_PLAYER_STREAM_TYPE_AUDIO:
13628 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13629 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13630 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13631 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13632 LOGE("There is no a codec for codec_type %d", codec_type);
13633 return MM_ERROR_PLAYER_NO_OP;
13636 case MM_PLAYER_STREAM_TYPE_VIDEO:
13637 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13638 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13639 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13640 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13641 LOGE("There is no v codec for codec_type %d", codec_type);
13642 return MM_ERROR_PLAYER_NO_OP;
13647 LOGE("Invalid stream type %d", stream_type);
13648 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13652 LOGD("update %s codec_type to %d", attr_name, codec_type);
13654 attrs = MMPLAYER_GET_ATTRS(player);
13655 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13657 if (mmf_attrs_commit(player->attrs)) {
13658 LOGE("failed to commit codec_type attributes");
13659 return MM_ERROR_PLAYER_INTERNAL;
13663 return MM_ERROR_NONE;
13667 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13669 mm_player_t* player = (mm_player_t*) hplayer;
13670 GstElement* rg_vol_element = NULL;
13674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13676 player->sound.rg_enable = enabled;
13678 /* just hold rgvolume enable value if pipeline is not ready */
13679 if (!player->pipeline || !player->pipeline->audiobin) {
13680 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13681 return MM_ERROR_NONE;
13684 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13686 if (!rg_vol_element) {
13687 LOGD("rgvolume element is not created");
13688 return MM_ERROR_PLAYER_INTERNAL;
13692 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13694 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13698 return MM_ERROR_NONE;
13702 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13704 mm_player_t* player = (mm_player_t*) hplayer;
13705 GstElement* rg_vol_element = NULL;
13706 gboolean enable = FALSE;
13710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13711 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13713 /* just hold enable_rg value if pipeline is not ready */
13714 if (!player->pipeline || !player->pipeline->audiobin) {
13715 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13716 *enabled = player->sound.rg_enable;
13717 return MM_ERROR_NONE;
13720 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13722 if (!rg_vol_element) {
13723 LOGD("rgvolume element is not created");
13724 return MM_ERROR_PLAYER_INTERNAL;
13727 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13732 return MM_ERROR_NONE;