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 */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
104 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
105 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
107 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
108 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
109 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
110 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
112 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
113 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
115 /*---------------------------------------------------------------------------
116 | LOCAL CONSTANT DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | LOCAL DATA TYPE DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------
124 | GLOBAL VARIABLE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | LOCAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
130 static sound_stream_info_h stream_info;
132 /*---------------------------------------------------------------------------
133 | LOCAL FUNCTION PROTOTYPES: |
134 ---------------------------------------------------------------------------*/
135 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
138 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
140 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
141 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
143 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
144 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
146 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
149 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
153 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
154 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
155 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
161 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
162 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
164 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
165 static void __mmplayer_release_misc(mm_player_t* player);
166 static void __mmplayer_release_misc_post(mm_player_t* player);
167 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
168 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
169 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
170 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
171 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
172 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
173 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
175 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
176 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
177 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
179 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
180 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
181 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
182 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
183 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
184 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
185 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
186 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
187 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
188 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
189 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
190 static gpointer __mmplayer_next_play_thread(gpointer data);
191 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
193 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
194 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
195 static void __mmplayer_release_dump_list(GList *dump_list);
197 static int __gst_realize(mm_player_t* player);
198 static int __gst_unrealize(mm_player_t* player);
199 static int __gst_start(mm_player_t* player);
200 static int __gst_stop(mm_player_t* player);
201 static int __gst_pause(mm_player_t* player, gboolean async);
202 static int __gst_resume(mm_player_t* player, gboolean async);
203 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
204 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
205 gint64 cur, GstSeekType stop_type, gint64 stop);
206 static int __gst_pending_seek(mm_player_t* player);
208 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
209 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
210 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
211 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
212 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
214 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
216 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
217 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
220 static gboolean __is_ms_buff_src(mm_player_t* player);
221 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
223 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
224 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
225 static int __mmplayer_start_streaming_ext(mm_player_t *player);
226 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
227 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
229 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
230 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
231 static void __mmplayer_check_pipeline(mm_player_t* player);
232 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
233 static void __mmplayer_deactivate_old_path(mm_player_t *player);
235 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
236 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
238 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
239 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
240 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
241 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
242 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
243 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
244 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
245 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
247 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
248 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
249 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
250 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
251 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
252 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
253 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
255 /*===========================================================================================
257 | FUNCTION DEFINITIONS |
259 ========================================================================================== */
263 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
267 count = gst_tag_list_get_tag_size(list, tag);
269 LOGD("count = %d", count);
271 for (i = 0; i < count; i++) {
274 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
275 if (!gst_tag_list_get_string_index(list, tag, i, &str))
276 g_assert_not_reached();
278 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
281 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
283 g_print(" : %s\n", str);
290 /* This function should be called after the pipeline goes PAUSED or higher
293 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
295 static gboolean has_duration = FALSE;
296 static gboolean has_video_attrs = FALSE;
297 static gboolean has_audio_attrs = FALSE;
298 static gboolean has_bitrate = FALSE;
299 gboolean missing_only = FALSE;
300 gboolean all = FALSE;
302 GstStructure* p = NULL;
303 MMHandleType attrs = 0;
309 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
311 /* check player state here */
312 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
313 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
314 /* give warning now only */
315 LOGW("be careful. content attributes may not available in this state ");
318 /* get content attribute first */
319 attrs = MMPLAYER_GET_ATTRS(player);
321 LOGE("cannot get content attribute");
325 /* get update flag */
327 if (flag & ATTR_MISSING_ONLY) {
329 LOGD("updating missed attr only");
332 if (flag & ATTR_ALL) {
334 has_duration = FALSE;
335 has_video_attrs = FALSE;
336 has_audio_attrs = FALSE;
339 LOGD("updating all attrs");
342 if (missing_only && all) {
343 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
344 missing_only = FALSE;
347 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
348 LOGD("try to update duration");
349 has_duration = FALSE;
351 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
352 player->duration = dur_nsec;
353 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
356 if (player->duration < 0) {
357 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
358 player->duration = 0;
361 /* update streaming service type */
362 player->streaming_type = __mmplayer_get_stream_service_type(player);
364 /* check duration is OK */
365 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
366 /* FIXIT : find another way to get duration here. */
367 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
370 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
375 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
376 /* update audio params
377 NOTE : We need original audio params and it can be only obtained from src pad of audio
378 decoder. Below code only valid when we are not using 'resampler' just before
381 LOGD("try to update audio attrs");
382 has_audio_attrs = FALSE;
384 if (player->pipeline->audiobin &&
385 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
386 GstCaps *caps_a = NULL;
388 gint samplerate = 0, channels = 0;
390 pad = gst_element_get_static_pad(
391 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
394 caps_a = gst_pad_get_current_caps(pad);
397 p = gst_caps_get_structure(caps_a, 0);
399 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
401 gst_structure_get_int(p, "rate", &samplerate);
402 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
404 gst_structure_get_int(p, "channels", &channels);
405 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
407 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
409 gst_caps_unref(caps_a);
412 has_audio_attrs = TRUE;
414 LOGW("not ready to get audio caps");
416 gst_object_unref(pad);
418 LOGW("failed to get pad from audiosink");
422 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
423 LOGD("try to update video attrs");
424 has_video_attrs = FALSE;
426 if (player->pipeline->videobin &&
427 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
428 GstCaps *caps_v = NULL;
433 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
435 caps_v = gst_pad_get_current_caps(pad);
437 /* Use v_stream_caps, if fail to get video_sink sink pad*/
438 if (!caps_v && player->v_stream_caps) {
439 caps_v = player->v_stream_caps;
440 gst_caps_ref(caps_v);
444 p = gst_caps_get_structure(caps_v, 0);
445 gst_structure_get_int(p, "width", &width);
446 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
448 gst_structure_get_int(p, "height", &height);
449 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
451 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
453 SECURE_LOGD("width : %d height : %d", width, height);
455 gst_caps_unref(caps_v);
459 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
460 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
463 has_video_attrs = TRUE;
465 LOGD("no negitiated caps from videosink");
466 gst_object_unref(pad);
469 LOGD("no videosink sink pad");
474 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
477 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
478 if (player->duration) {
479 guint64 data_size = 0;
481 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
482 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
484 if (stat(path, &sb) == 0)
485 data_size = (guint64)sb.st_size;
486 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
487 data_size = player->http_content_size;
489 LOGD("try to update bitrate : data_size = %lld", data_size);
493 guint64 msec_dur = 0;
495 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
497 bitrate = data_size * 8 * 1000 / msec_dur;
498 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
499 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
503 LOGD("player duration is less than 0");
507 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
508 if (player->total_bitrate) {
509 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
517 if (mmf_attrs_commit(attrs)) {
518 LOGE("failed to update attributes\n");
527 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
529 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
533 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
535 player->pipeline->mainbin &&
536 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
537 STREAMING_SERVICE_NONE);
539 /* streaming service type if streaming */
540 if (!MMPLAYER_IS_STREAMING(player))
541 return STREAMING_SERVICE_NONE;
543 if (MMPLAYER_IS_HTTP_STREAMING(player))
544 streaming_type = (player->duration == 0) ?
545 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
547 switch (streaming_type) {
548 case STREAMING_SERVICE_LIVE:
549 LOGD("it's live streaming");
551 case STREAMING_SERVICE_VOD:
552 LOGD("it's vod streaming");
555 LOGE("should not get here");
561 return streaming_type;
565 /* this function sets the player state and also report
566 * it to applicaton by calling callback function
569 __mmplayer_set_state(mm_player_t* player, int state)
571 MMMessageParamType msg = {0, };
572 gboolean post_bos = FALSE;
574 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
576 if (MMPLAYER_CURRENT_STATE(player) == state) {
577 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
578 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
579 return MM_ERROR_NONE;
582 /* update player states */
583 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
584 MMPLAYER_CURRENT_STATE(player) = state;
586 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
587 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
590 MMPLAYER_PRINT_STATE(player);
592 switch (MMPLAYER_CURRENT_STATE(player)) {
593 case MM_PLAYER_STATE_NULL:
594 case MM_PLAYER_STATE_READY:
597 case MM_PLAYER_STATE_PAUSED:
599 if (!player->sent_bos) {
600 /* rtsp case, get content attrs by GstMessage */
601 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
602 /* it's first time to update all content attrs. */
603 _mmplayer_update_content_attrs(player, ATTR_ALL);
607 /* add audio callback probe if condition is satisfied */
608 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
609 __mmplayer_configure_audio_callback(player);
611 /* FIXIT : handle return value */
615 case MM_PLAYER_STATE_PLAYING:
617 /* try to get content metadata */
618 if (!player->sent_bos) {
619 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
620 * c-api since c-api doesn't use _start() anymore. It may not work propery with
621 * legacy mmfw-player api */
622 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
625 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
626 if (!player->sent_bos)
627 __mmplayer_handle_missed_plugin(player);
630 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
631 /* initialize because auto resume is done well. */
632 player->resumed_by_rewind = FALSE;
633 player->playback_rate = 1.0;
636 if (!player->sent_bos) {
637 /* check audio codec field is set or not
638 * we can get it from typefinder or codec's caps.
640 gchar *audio_codec = NULL;
641 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
643 /* The codec format can't be sent for audio only case like amr, mid etc.
644 * Because, parser don't make related TAG.
645 * So, if it's not set yet, fill it with found data.
648 if (g_strrstr(player->type, "audio/midi"))
649 audio_codec = g_strdup("MIDI");
650 else if (g_strrstr(player->type, "audio/x-amr"))
651 audio_codec = g_strdup("AMR");
652 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
653 audio_codec = g_strdup("AAC");
655 audio_codec = g_strdup("unknown");
656 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
658 MMPLAYER_FREEIF(audio_codec);
659 if (mmf_attrs_commit(player->attrs))
660 LOGE("failed to update attributes\n");
662 LOGD("set audio codec type with caps\n");
670 case MM_PLAYER_STATE_NONE:
672 LOGW("invalid target state, there is nothing to do.\n");
677 /* post message to application */
678 if (MMPLAYER_TARGET_STATE(player) == state) {
679 /* fill the message with state of player */
680 msg.union_type = MM_MSG_UNION_STATE;
681 msg.state.previous = MMPLAYER_PREV_STATE(player);
682 msg.state.current = MMPLAYER_CURRENT_STATE(player);
684 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
686 /* state changed by resource callback */
687 if (player->interrupted_by_resource) {
688 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
689 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
690 } else { /* state changed by usecase */
691 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
694 LOGD("intermediate state, do nothing.\n");
695 MMPLAYER_PRINT_STATE(player);
696 return MM_ERROR_NONE;
700 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
701 player->sent_bos = TRUE;
704 return MM_ERROR_NONE;
707 static gpointer __mmplayer_next_play_thread(gpointer data)
709 mm_player_t* player = (mm_player_t*) data;
710 MMPlayerGstElement *mainbin = NULL;
712 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
714 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
715 while (!player->next_play_thread_exit) {
716 LOGD("next play thread started. waiting for signal.\n");
717 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
719 LOGD("reconfigure pipeline for gapless play.\n");
721 if (player->next_play_thread_exit) {
722 if (player->gapless.reconfigure) {
723 player->gapless.reconfigure = false;
724 MMPLAYER_PLAYBACK_UNLOCK(player);
726 LOGD("exiting gapless play thread\n");
730 mainbin = player->pipeline->mainbin;
732 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
733 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
734 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
735 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
736 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
738 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
740 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
746 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
748 MMHandleType attrs = 0;
749 guint64 data_size = 0;
751 unsigned long pos_msec = 0;
754 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
756 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
758 attrs = MMPLAYER_GET_ATTRS(player);
760 LOGE("fail to get attributes.\n");
764 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
765 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
767 if (stat(path, &sb) == 0)
768 data_size = (guint64)sb.st_size;
769 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
770 data_size = player->http_content_size;
772 __mm_player_streaming_buffering(player->streamer,
775 player->last_position,
778 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
784 __mmplayer_handle_buffering_message(mm_player_t* player)
786 int ret = MM_ERROR_NONE;
787 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
788 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
789 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
790 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
792 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
793 LOGW("do nothing for buffering msg\n");
794 ret = MM_ERROR_PLAYER_INVALID_STATE;
798 prev_state = MMPLAYER_PREV_STATE(player);
799 current_state = MMPLAYER_CURRENT_STATE(player);
800 target_state = MMPLAYER_TARGET_STATE(player);
801 pending_state = MMPLAYER_PENDING_STATE(player);
803 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
804 MMPLAYER_STATE_GET_NAME(prev_state),
805 MMPLAYER_STATE_GET_NAME(current_state),
806 MMPLAYER_STATE_GET_NAME(pending_state),
807 MMPLAYER_STATE_GET_NAME(target_state),
808 player->streamer->is_buffering);
810 if (!player->streamer->is_buffering) {
811 /* NOTE : if buffering has done, player has to go to target state. */
812 switch (target_state) {
813 case MM_PLAYER_STATE_PAUSED:
815 switch (pending_state) {
816 case MM_PLAYER_STATE_PLAYING:
817 __gst_pause(player, TRUE);
820 case MM_PLAYER_STATE_PAUSED:
821 LOGD("player is already going to paused state, there is nothing to do.\n");
824 case MM_PLAYER_STATE_NONE:
825 case MM_PLAYER_STATE_NULL:
826 case MM_PLAYER_STATE_READY:
828 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
834 case MM_PLAYER_STATE_PLAYING:
836 switch (pending_state) {
837 case MM_PLAYER_STATE_NONE:
839 if (current_state != MM_PLAYER_STATE_PLAYING)
840 __gst_resume(player, TRUE);
844 case MM_PLAYER_STATE_PAUSED:
845 /* NOTE: It should be worked as asynchronously.
846 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
848 if (current_state == MM_PLAYER_STATE_PLAYING) {
849 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
850 * The current state should be changed to paused purposely to prevent state conflict.
852 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
854 __gst_resume(player, TRUE);
857 case MM_PLAYER_STATE_PLAYING:
858 LOGD("player is already going to playing state, there is nothing to do.\n");
861 case MM_PLAYER_STATE_NULL:
862 case MM_PLAYER_STATE_READY:
864 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
870 case MM_PLAYER_STATE_NULL:
871 case MM_PLAYER_STATE_READY:
872 case MM_PLAYER_STATE_NONE:
874 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
878 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
879 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
881 switch (pending_state) {
882 case MM_PLAYER_STATE_NONE:
884 if (current_state != MM_PLAYER_STATE_PAUSED) {
885 /* rtsp streaming pause makes rtsp server stop sending data. */
886 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
887 LOGD("set pause state during buffering\n");
888 __gst_pause(player, TRUE);
894 case MM_PLAYER_STATE_PLAYING:
895 /* rtsp streaming pause makes rtsp server stop sending data. */
896 if (!MMPLAYER_IS_RTSP_STREAMING(player))
897 __gst_pause(player, TRUE);
900 case MM_PLAYER_STATE_PAUSED:
903 case MM_PLAYER_STATE_NULL:
904 case MM_PLAYER_STATE_READY:
906 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
916 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
918 MMPlayerGstElement *textbin;
921 MMPLAYER_RETURN_IF_FAIL(player &&
923 player->pipeline->textbin);
925 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
927 textbin = player->pipeline->textbin;
930 LOGD("Drop subtitle text after getting EOS\n");
932 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
933 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
935 player->is_subtitle_force_drop = TRUE;
937 if (player->is_subtitle_force_drop == TRUE) {
938 LOGD("Enable subtitle data path without drop\n");
940 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
941 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
943 LOGD("non-connected with external display");
945 player->is_subtitle_force_drop = FALSE;
951 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
953 VariantData *var_info = NULL;
954 g_return_val_if_fail(self != NULL, NULL);
956 var_info = g_new0(VariantData, 1);
957 if (!var_info) return NULL;
958 var_info->bandwidth = self->bandwidth;
959 var_info->width = self->width;
960 var_info->height = self->height;
964 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
966 mm_player_t* player = (mm_player_t*)hplayer;
967 GstMessage *msg = NULL;
968 GQueue *queue = NULL;
971 MMPLAYER_RETURN_IF_FAIL(player);
973 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
975 /* destroy the gst bus msg thread */
976 if (player->bus_msg_thread) {
977 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
978 player->bus_msg_thread_exit = TRUE;
979 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
980 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
982 LOGD("gst bus msg thread exit.");
983 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
984 player->bus_msg_thread = NULL;
986 g_mutex_clear(&player->bus_msg_thread_mutex);
987 g_cond_clear(&player->bus_msg_thread_cond);
990 g_mutex_lock(&player->bus_msg_q_lock);
991 queue = player->bus_msg_q;
992 while (!g_queue_is_empty(queue)) {
993 msg = (GstMessage *)g_queue_pop_head(queue);
994 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
995 gst_message_unref(msg);
997 g_mutex_unlock(&player->bus_msg_q_lock);
1002 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1004 mm_player_t *player = (mm_player_t *) data;
1006 g_return_val_if_fail(player, FALSE);
1007 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1009 gst_message_ref(msg);
1011 g_mutex_lock(&player->bus_msg_q_lock);
1012 g_queue_push_tail(player->bus_msg_q, msg);
1013 g_mutex_unlock(&player->bus_msg_q_lock);
1015 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1017 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1021 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1023 mm_player_t *player = (mm_player_t*)(data);
1024 GstMessage *msg = NULL;
1028 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1030 player->pipeline->mainbin &&
1031 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1034 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1036 LOGE("cannot get BUS from the pipeline");
1040 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1042 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1043 while (!player->bus_msg_thread_exit) {
1044 g_mutex_lock(&player->bus_msg_q_lock);
1045 msg = g_queue_pop_head(player->bus_msg_q);
1046 g_mutex_unlock(&player->bus_msg_q_lock);
1048 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1051 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1052 /* handle the gst msg */
1053 __mmplayer_gst_callback(msg, player);
1054 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1055 gst_message_unref(msg);
1058 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1059 gst_object_unref(GST_OBJECT(bus));
1066 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1068 mm_player_t* player = (mm_player_t*)(data);
1069 static gboolean async_done = FALSE;
1071 MMPLAYER_RETURN_IF_FAIL(player);
1072 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1074 switch (GST_MESSAGE_TYPE(msg)) {
1075 case GST_MESSAGE_UNKNOWN:
1076 LOGD("unknown message received\n");
1079 case GST_MESSAGE_EOS:
1081 MMHandleType attrs = 0;
1084 LOGD("GST_MESSAGE_EOS received\n");
1086 /* NOTE : EOS event is comming multiple time. watch out it */
1087 /* check state. we only process EOS when pipeline state goes to PLAYING */
1088 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1089 LOGD("EOS received on non-playing state. ignoring it\n");
1093 if (player->pipeline) {
1094 if (player->pipeline->textbin)
1095 __mmplayer_drop_subtitle(player, TRUE);
1097 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1100 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1102 LOGD("release audio callback\n");
1104 /* release audio callback */
1105 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1106 player->audio_cb_probe_id = 0;
1107 /* audio callback should be free because it can be called even though probe remove.*/
1108 player->audio_stream_cb = NULL;
1109 player->audio_stream_cb_user_param = NULL;
1113 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1114 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1116 /* rewind if repeat count is greater then zero */
1117 /* get play count */
1118 attrs = MMPLAYER_GET_ATTRS(player);
1121 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1123 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1125 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1126 if (player->playback_rate < 0.0) {
1127 player->resumed_by_rewind = TRUE;
1128 _mmplayer_set_mute((MMHandleType)player, 0);
1129 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1132 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1135 player->sent_bos = FALSE;
1137 /* not posting eos when repeating */
1142 if (player->pipeline)
1143 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1145 /* post eos message to application */
1146 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1148 /* reset last position */
1149 player->last_position = 0;
1153 case GST_MESSAGE_ERROR:
1155 GError *error = NULL;
1156 gchar* debug = NULL;
1158 /* generating debug info before returning error */
1159 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1161 /* get error code */
1162 gst_message_parse_error(msg, &error, &debug);
1164 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1165 /* Note : the streaming error from the streaming source is handled
1166 * using __mmplayer_handle_streaming_error.
1168 __mmplayer_handle_streaming_error(player, msg);
1170 /* dump state of all element */
1171 __mmplayer_dump_pipeline_state(player);
1173 /* traslate gst error code to msl error code. then post it
1174 * to application if needed
1176 __mmplayer_handle_gst_error(player, msg, error);
1179 LOGE("error debug : %s", debug);
1182 if (MMPLAYER_IS_HTTP_PD(player))
1183 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1185 MMPLAYER_FREEIF(debug);
1186 g_error_free(error);
1190 case GST_MESSAGE_WARNING:
1193 GError* error = NULL;
1195 gst_message_parse_warning(msg, &error, &debug);
1197 LOGD("warning : %s\n", error->message);
1198 LOGD("debug : %s\n", debug);
1200 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1202 MMPLAYER_FREEIF(debug);
1203 g_error_free(error);
1207 case GST_MESSAGE_TAG:
1209 LOGD("GST_MESSAGE_TAG\n");
1210 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1211 LOGW("failed to extract tags from gstmessage\n");
1215 case GST_MESSAGE_BUFFERING:
1217 MMMessageParamType msg_param = {0, };
1218 int bRet = MM_ERROR_NONE;
1220 if (!(player->pipeline && player->pipeline->mainbin)) {
1221 LOGE("player pipeline handle is null");
1225 if (!MMPLAYER_IS_STREAMING(player))
1228 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1229 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1230 /* skip the playback control by buffering msg while user request is handled. */
1233 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1235 gst_message_parse_buffering(msg, &per);
1236 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1238 msg_param.connection.buffering = per;
1239 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1243 MMPLAYER_CMD_LOCK(player);
1246 /* ignore the prev buffering message */
1247 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1248 && (player->streamer->is_buffering_done == TRUE)) {
1249 gint buffer_percent = 0;
1251 gst_message_parse_buffering(msg, &buffer_percent);
1253 if (buffer_percent == MAX_BUFFER_PERCENT) {
1254 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1255 player->streamer->is_buffering_done = FALSE;
1257 MMPLAYER_CMD_UNLOCK(player);
1261 __mmplayer_update_buffer_setting(player, msg);
1263 bRet = __mmplayer_handle_buffering_message(player);
1265 if (bRet == MM_ERROR_NONE) {
1266 msg_param.connection.buffering = player->streamer->buffering_percent;
1267 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1269 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1270 player->pending_resume &&
1271 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1273 player->is_external_subtitle_added_now = FALSE;
1274 player->pending_resume = FALSE;
1275 _mmplayer_resume((MMHandleType)player);
1278 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1279 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1281 if (player->doing_seek) {
1282 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1283 player->doing_seek = FALSE;
1284 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1285 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1290 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1291 if (!player->streamer) {
1292 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1293 MMPLAYER_CMD_UNLOCK(player);
1297 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1299 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1300 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1302 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1303 msg_param.connection.buffering = player->streamer->buffering_percent;
1304 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1306 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1309 msg_param.connection.buffering = player->streamer->buffering_percent;
1310 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1313 MMPLAYER_CMD_UNLOCK(player);
1317 case GST_MESSAGE_STATE_CHANGED:
1319 MMPlayerGstElement *mainbin;
1320 const GValue *voldstate, *vnewstate, *vpending;
1321 GstState oldstate = GST_STATE_NULL;
1322 GstState newstate = GST_STATE_NULL;
1323 GstState pending = GST_STATE_NULL;
1325 if (!(player->pipeline && player->pipeline->mainbin)) {
1326 LOGE("player pipeline handle is null");
1330 mainbin = player->pipeline->mainbin;
1332 /* we only handle messages from pipeline */
1333 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1336 /* get state info from msg */
1337 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1338 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1339 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1341 if (!voldstate || !vnewstate) {
1342 LOGE("received msg has wrong format.");
1346 oldstate = (GstState)voldstate->data[0].v_int;
1347 newstate = (GstState)vnewstate->data[0].v_int;
1349 pending = (GstState)vpending->data[0].v_int;
1351 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1352 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1353 gst_element_state_get_name((GstState)oldstate),
1354 gst_element_state_get_name((GstState)newstate),
1355 gst_element_state_get_name((GstState)pending));
1357 if (newstate == GST_STATE_PLAYING) {
1358 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1360 int retVal = MM_ERROR_NONE;
1361 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1363 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1365 if (MM_ERROR_NONE != retVal)
1366 LOGE("failed to seek pending postion. just keep staying current position.\n");
1368 player->pending_seek.is_pending = FALSE;
1372 if (oldstate == newstate) {
1373 LOGD("pipeline reports state transition to old state");
1378 case GST_STATE_VOID_PENDING:
1381 case GST_STATE_NULL:
1384 case GST_STATE_READY:
1387 case GST_STATE_PAUSED:
1389 gboolean prepare_async = FALSE;
1390 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1392 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1393 __mmplayer_configure_audio_callback(player);
1395 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1396 // managed prepare async case
1397 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1398 LOGD("checking prepare mode for async transition - %d", prepare_async);
1401 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1402 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1404 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1405 __mm_player_streaming_set_content_bitrate(player->streamer,
1406 player->total_maximum_bitrate, player->total_bitrate);
1408 if (player->pending_seek.is_pending) {
1409 LOGW("trying to do pending seek");
1410 MMPLAYER_CMD_LOCK(player);
1411 __gst_pending_seek(player);
1412 MMPLAYER_CMD_UNLOCK(player);
1418 case GST_STATE_PLAYING:
1420 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1422 if (MMPLAYER_IS_STREAMING(player)) {
1423 // managed prepare async case when buffering is completed
1424 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1425 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1426 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1427 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1429 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1431 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1432 if (player->streamer->buffering_percent < 100) {
1434 MMMessageParamType msg_param = {0, };
1435 LOGW("Posting Buffering Completed Message to Application !!!");
1437 msg_param.connection.buffering = 100;
1438 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1443 if (player->gapless.stream_changed) {
1444 _mmplayer_update_content_attrs(player, ATTR_ALL);
1445 player->gapless.stream_changed = FALSE;
1448 if (player->doing_seek && async_done) {
1449 player->doing_seek = FALSE;
1451 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1462 case GST_MESSAGE_CLOCK_LOST:
1464 GstClock *clock = NULL;
1465 gboolean need_new_clock = FALSE;
1467 gst_message_parse_clock_lost(msg, &clock);
1468 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1470 if (!player->videodec_linked)
1471 need_new_clock = TRUE;
1472 else if (!player->ini.use_system_clock)
1473 need_new_clock = TRUE;
1475 if (need_new_clock) {
1476 LOGD("Provide clock is TRUE, do pause->resume\n");
1477 __gst_pause(player, FALSE);
1478 __gst_resume(player, FALSE);
1483 case GST_MESSAGE_NEW_CLOCK:
1485 GstClock *clock = NULL;
1486 gst_message_parse_new_clock(msg, &clock);
1487 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1491 case GST_MESSAGE_ELEMENT:
1493 const gchar *structure_name;
1494 gint count = 0, idx = 0;
1495 MMHandleType attrs = 0;
1497 attrs = MMPLAYER_GET_ATTRS(player);
1499 LOGE("cannot get content attribute");
1503 if (gst_message_get_structure(msg) == NULL)
1506 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1507 if (!structure_name)
1510 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1512 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1513 const GValue *var_info = NULL;
1515 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1516 if (var_info != NULL) {
1517 if (player->adaptive_info.var_list)
1518 g_list_free_full(player->adaptive_info.var_list, g_free);
1520 /* share addr or copy the list */
1521 player->adaptive_info.var_list =
1522 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1524 count = g_list_length(player->adaptive_info.var_list);
1526 VariantData *temp = NULL;
1528 /* print out for debug */
1529 LOGD("num of variant_info %d", count);
1530 for (idx = 0; idx < count; idx++) {
1531 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1533 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1539 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1540 gint num_buffers = 0;
1541 gint extra_num_buffers = 0;
1543 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1544 player->video_num_buffers = num_buffers;
1545 LOGD("video_num_buffers : %d", player->video_num_buffers);
1548 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1549 player->video_extra_num_buffers = extra_num_buffers;
1550 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1555 if (!strcmp(structure_name, "Language_list")) {
1556 const GValue *lang_list = NULL;
1557 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1558 if (lang_list != NULL) {
1559 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1561 LOGD("Total audio tracks(from parser) = %d \n", count);
1565 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1566 const GValue *lang_list = NULL;
1567 MMPlayerLangStruct *temp = NULL;
1569 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1570 if (lang_list != NULL) {
1571 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1573 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1574 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1575 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1576 if (mmf_attrs_commit(attrs))
1577 LOGE("failed to commit.\n");
1578 LOGD("Total subtitle tracks = %d \n", count);
1581 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1583 LOGD("value of lang_key is %s and lang_code is %s",
1584 temp->language_key, temp->language_code);
1587 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1588 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1593 /* custom message */
1594 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1595 MMMessageParamType msg_param = {0,};
1596 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1597 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1600 /* custom message for RTSP attribute :
1601 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1602 sdp which has contents info is received when rtsp connection is opened.
1603 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1604 if (!strcmp(structure_name, "rtspsrc_properties")) {
1606 gchar *audio_codec = NULL;
1607 gchar *video_codec = NULL;
1608 gchar *video_frame_size = NULL;
1610 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1611 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1612 player->streaming_type = __mmplayer_get_stream_service_type(player);
1613 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1615 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1616 LOGD("rtsp_audio_codec : %s", audio_codec);
1618 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1620 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1621 LOGD("rtsp_video_codec : %s", video_codec);
1623 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1625 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1626 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1627 if (video_frame_size) {
1629 char *seperator = strchr(video_frame_size, '-');
1632 char video_width[10] = {0,};
1633 int frame_size_len = strlen(video_frame_size);
1634 int separtor_len = strlen(seperator);
1636 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1637 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1640 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1644 if (mmf_attrs_commit(attrs))
1645 LOGE("failed to commit.\n");
1650 case GST_MESSAGE_DURATION_CHANGED:
1652 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1653 if (!__mmplayer_gst_handle_duration(player, msg))
1654 LOGW("failed to update duration");
1659 case GST_MESSAGE_ASYNC_START:
1660 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1663 case GST_MESSAGE_ASYNC_DONE:
1665 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1667 /* we only handle messages from pipeline */
1668 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1671 if (player->doing_seek) {
1672 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1673 player->doing_seek = FALSE;
1674 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1675 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1676 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1677 (player->streamer) &&
1678 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1679 (player->streamer->is_buffering == FALSE)) {
1680 GstQuery *query = NULL;
1681 gboolean busy = FALSE;
1684 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1685 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1686 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1687 gst_query_parse_buffering_percent(query, &busy, &percent);
1688 gst_query_unref(query);
1690 LOGD("buffered percent(%s): %d\n",
1691 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1694 if (percent >= 100) {
1695 player->streamer->is_buffering = FALSE;
1696 __mmplayer_handle_buffering_message(player);
1706 #if 0 /* delete unnecessary logs */
1707 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1708 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1709 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1710 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1711 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1712 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1713 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1714 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1715 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1716 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1717 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1718 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1719 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1720 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1721 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1728 /* should not call 'gst_message_unref(msg)' */
1733 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1739 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1740 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1742 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1743 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1744 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1746 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1747 LOGD("data total size of http content: %lld", bytes);
1748 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1751 /* handling audio clip which has vbr. means duration is keep changing */
1752 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1759 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1760 mm_player_spherical_metadata_t *metadata) {
1761 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1762 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1763 gst_tag_list_get_string(tags, "stitching_software",
1764 &metadata->stitching_software);
1765 gst_tag_list_get_string(tags, "projection_type",
1766 &metadata->projection_type_string);
1767 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1768 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1769 gst_tag_list_get_int(tags, "init_view_heading",
1770 &metadata->init_view_heading);
1771 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1772 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1773 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1774 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1775 &metadata->full_pano_width_pixels);
1776 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1777 &metadata->full_pano_height_pixels);
1778 gst_tag_list_get_int(tags, "cropped_area_image_width",
1779 &metadata->cropped_area_image_width);
1780 gst_tag_list_get_int(tags, "cropped_area_image_height",
1781 &metadata->cropped_area_image_height);
1782 gst_tag_list_get_int(tags, "cropped_area_left",
1783 &metadata->cropped_area_left);
1784 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1785 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1786 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1787 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1791 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1794 /* macro for better code readability */
1795 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1796 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1797 if (string != NULL) { \
1798 SECURE_LOGD("update tag string : %s\n", string); \
1799 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1800 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1801 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1802 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1803 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1804 g_free(new_string); \
1805 new_string = NULL; \
1807 mm_attrs_set_string_by_name(attribute, playertag, string); \
1814 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1816 GstSample *sample = NULL;\
1817 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1818 GstMapInfo info = GST_MAP_INFO_INIT;\
1819 buffer = gst_sample_get_buffer(sample);\
1820 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1821 LOGD("failed to get image data from tag");\
1822 gst_sample_unref(sample);\
1825 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1826 MMPLAYER_FREEIF(player->album_art);\
1827 player->album_art = (gchar *)g_malloc(info.size);\
1828 if (player->album_art) {\
1829 memcpy(player->album_art, info.data, info.size);\
1830 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1831 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1832 msg_param.data = (void *)player->album_art;\
1833 msg_param.size = info.size;\
1834 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1835 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1838 gst_buffer_unmap(buffer, &info);\
1839 gst_sample_unref(sample);\
1843 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1845 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1848 gchar *tag_list_str = NULL; \
1849 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1850 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1851 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1852 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1853 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1855 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1856 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1857 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1858 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1859 player->bitrate[track_type] = v_uint; \
1860 player->total_bitrate = 0; \
1861 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1862 player->total_bitrate += player->bitrate[i]; \
1863 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1864 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1865 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1866 player->maximum_bitrate[track_type] = v_uint; \
1867 player->total_maximum_bitrate = 0; \
1868 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1869 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1870 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1871 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1873 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1876 g_free(tag_list_str); \
1881 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1882 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1883 if (date != NULL) {\
1884 string = g_strdup_printf("%d", g_date_get_year(date));\
1885 mm_attrs_set_string_by_name(attribute, playertag, string);\
1886 SECURE_LOGD("metainfo year : %s\n", string);\
1887 MMPLAYER_FREEIF(string);\
1892 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1893 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1894 if (datetime != NULL) {\
1895 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1896 mm_attrs_set_string_by_name(attribute, playertag, string);\
1897 SECURE_LOGD("metainfo year : %s\n", string);\
1898 MMPLAYER_FREEIF(string);\
1899 gst_date_time_unref(datetime);\
1903 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1904 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1906 /* FIXIT : don't know how to store date */\
1912 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1913 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1915 /* FIXIT : don't know how to store date */\
1921 /* function start */
1922 GstTagList* tag_list = NULL;
1924 MMHandleType attrs = 0;
1926 char *string = NULL;
1929 GstDateTime *datetime = NULL;
1931 GstBuffer *buffer = NULL;
1933 MMMessageParamType msg_param = {0, };
1935 /* currently not used. but those are needed for above macro */
1936 //guint64 v_uint64 = 0;
1937 //gdouble v_double = 0;
1939 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1941 attrs = MMPLAYER_GET_ATTRS(player);
1943 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1945 /* get tag list from gst message */
1946 gst_message_parse_tag(msg, &tag_list);
1948 /* store tags to player attributes */
1949 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1950 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1951 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1952 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1953 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1954 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1955 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1956 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1957 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1958 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1959 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1961 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1962 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1963 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1964 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1966 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1967 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1970 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1972 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1973 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1974 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1975 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1976 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1977 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1978 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1979 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1980 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1981 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1982 MMPLAYER_UPDATE_TAG_LOCK(player);
1983 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1984 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1985 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1992 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1993 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1994 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1995 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1996 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1997 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1999 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2000 if (player->video360_metadata.is_spherical == -1) {
2001 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2002 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2003 player->video360_metadata.is_spherical);
2004 if (player->video360_metadata.is_spherical == 1) {
2005 LOGD("This is spherical content for 360 playback.");
2006 player->is_content_spherical = TRUE;
2008 LOGD("This is not spherical content");
2009 player->is_content_spherical = FALSE;
2012 if (player->video360_metadata.projection_type_string) {
2013 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2014 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2016 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2017 player->is_content_spherical = player->is_video360_enabled = FALSE;
2021 if (player->video360_metadata.stereo_mode_string) {
2022 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2023 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2024 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2025 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2026 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2027 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2029 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2030 player->is_content_spherical = player->is_video360_enabled = FALSE;
2036 if (mmf_attrs_commit(attrs))
2037 LOGE("failed to commit.\n");
2039 gst_tag_list_free(tag_list);
2045 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2047 mm_player_t* player = (mm_player_t*) data;
2051 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2052 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2053 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2054 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2056 * [1] audio and video will be dumped with filesink.
2057 * [2] autoplugging is done by just using pad caps.
2058 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2059 * and the video will be dumped via filesink.
2061 if (player->num_dynamic_pad == 0) {
2062 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2064 if (!__mmplayer_gst_remove_fakesink(player,
2065 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2066 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2067 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2068 * source element are not same. To overcome this situation, this function will called
2069 * several places and several times. Therefore, this is not an error case.
2074 /* create dot before error-return. for debugging */
2075 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2077 player->no_more_pad = TRUE;
2083 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2085 GstElement* parent = NULL;
2087 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2089 /* if we have no fakesink. this meas we are using decodebin which doesn'
2090 t need to add extra fakesink */
2091 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2094 MMPLAYER_FSINK_LOCK(player);
2099 /* get parent of fakesink */
2100 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2102 LOGD("fakesink already removed\n");
2106 gst_element_set_locked_state(fakesink->gst, TRUE);
2108 /* setting the state to NULL never returns async
2109 * so no need to wait for completion of state transiton
2111 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2112 LOGE("fakesink state change failure!\n");
2113 /* FIXIT : should I return here? or try to proceed to next? */
2116 /* remove fakesink from it's parent */
2117 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2118 LOGE("failed to remove fakesink\n");
2120 gst_object_unref(parent);
2125 gst_object_unref(parent);
2127 LOGD("state-holder removed\n");
2129 gst_element_set_locked_state(fakesink->gst, FALSE);
2131 MMPLAYER_FSINK_UNLOCK(player);
2136 gst_element_set_locked_state(fakesink->gst, FALSE);
2138 MMPLAYER_FSINK_UNLOCK(player);
2144 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2146 GstPad *sinkpad = NULL;
2147 GstCaps* caps = NULL;
2148 GstElement* new_element = NULL;
2149 GstStructure* str = NULL;
2150 const gchar* name = NULL;
2152 mm_player_t* player = (mm_player_t*) data;
2156 MMPLAYER_RETURN_IF_FAIL(element && pad);
2157 MMPLAYER_RETURN_IF_FAIL(player &&
2159 player->pipeline->mainbin);
2162 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2163 * num_dynamic_pad will decreased after creating a sinkbin.
2165 player->num_dynamic_pad++;
2166 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2168 caps = gst_pad_query_caps(pad, NULL);
2170 MMPLAYER_CHECK_NULL(caps);
2172 /* clear previous result*/
2173 player->have_dynamic_pad = FALSE;
2175 str = gst_caps_get_structure(caps, 0);
2178 LOGE("cannot get structure from caps.\n");
2182 name = gst_structure_get_name(str);
2184 LOGE("cannot get mimetype from structure.\n");
2188 if (strstr(name, "video")) {
2190 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2192 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2193 if (player->v_stream_caps) {
2194 gst_caps_unref(player->v_stream_caps);
2195 player->v_stream_caps = NULL;
2198 new_element = gst_element_factory_make("fakesink", NULL);
2199 player->num_dynamic_pad--;
2204 /* clear previous result*/
2205 player->have_dynamic_pad = FALSE;
2207 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2208 LOGE("failed to autoplug for caps");
2212 /* check if there's dynamic pad*/
2213 if (player->have_dynamic_pad) {
2214 LOGE("using pad caps assums there's no dynamic pad !\n");
2218 gst_caps_unref(caps);
2223 /* excute new_element if created*/
2225 LOGD("adding new element to pipeline\n");
2227 /* set state to READY before add to bin */
2228 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2230 /* add new element to the pipeline */
2231 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2232 LOGE("failed to add autoplug element to bin\n");
2236 /* get pad from element */
2237 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2239 LOGE("failed to get sinkpad from autoplug element\n");
2244 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2245 LOGE("failed to link autoplug element\n");
2249 gst_object_unref(sinkpad);
2252 /* run. setting PLAYING here since streamming source is live source */
2253 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2257 gst_caps_unref(caps);
2263 STATE_CHANGE_FAILED:
2265 /* FIXIT : take care if new_element has already added to pipeline */
2267 gst_object_unref(GST_OBJECT(new_element));
2270 gst_object_unref(GST_OBJECT(sinkpad));
2273 gst_caps_unref(caps);
2275 /* FIXIT : how to inform this error to MSL ????? */
2276 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2277 * then post an error to application
2281 static GstPadProbeReturn
2282 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2284 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2285 return GST_PAD_PROBE_OK;
2288 static GstPadProbeReturn
2289 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2291 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2292 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2293 mm_player_t* player = (mm_player_t*)data;
2294 GstCaps* caps = NULL;
2295 GstStructure* str = NULL;
2296 const gchar* name = NULL;
2297 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2300 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2301 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2302 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2303 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2304 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2306 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2307 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2311 caps = gst_pad_query_caps(pad, NULL);
2313 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2317 str = gst_caps_get_structure(caps, 0);
2319 LOGE("failed to get structure from caps");
2323 name = gst_structure_get_name(str);
2325 LOGE("failed to get name from str");
2329 if (strstr(name, "audio")) {
2330 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2331 } else if (strstr(name, "video")) {
2332 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2334 /* text track is not supportable */
2335 LOGE("invalid name %s", name);
2339 switch (GST_EVENT_TYPE(event)) {
2342 /* in case of gapless, drop eos event not to send it to sink */
2343 if (player->gapless.reconfigure && !player->msg_posted) {
2344 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2345 ret = GST_PAD_PROBE_DROP;
2349 case GST_EVENT_STREAM_START:
2351 gint64 stop_running_time = 0;
2352 gint64 position_running_time = 0;
2353 gint64 position = 0;
2356 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2357 if ((player->gapless.update_segment[idx] == TRUE) ||
2358 !(player->selector[idx].event_probe_id)) {
2359 /* LOGW("[%d] skip", idx); */
2363 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2365 gst_segment_to_running_time(&player->gapless.segment[idx],
2366 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2367 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2369 gst_segment_to_running_time(&player->gapless.segment[idx],
2370 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2372 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2374 gst_segment_to_running_time(&player->gapless.segment[idx],
2375 GST_FORMAT_TIME, player->duration);
2378 position_running_time =
2379 gst_segment_to_running_time(&player->gapless.segment[idx],
2380 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2382 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2383 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2385 GST_TIME_ARGS(stop_running_time),
2386 GST_TIME_ARGS(position_running_time),
2387 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2388 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2390 position_running_time = MAX(position_running_time, stop_running_time);
2391 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2392 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2393 position_running_time = MAX(0, position_running_time);
2394 position = MAX(position, position_running_time);
2397 if (position != 0) {
2398 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2399 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2400 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2402 player->gapless.start_time[stream_type] += position;
2406 case GST_EVENT_FLUSH_STOP:
2408 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2409 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2410 player->gapless.start_time[stream_type] = 0;
2413 case GST_EVENT_SEGMENT:
2418 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2419 gst_event_copy_segment(event, &segment);
2421 if (segment.format == GST_FORMAT_TIME) {
2422 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2423 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2424 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2425 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2426 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2427 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2429 /* keep the all the segment ev to cover the seeking */
2430 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2431 player->gapless.update_segment[stream_type] = TRUE;
2433 if (!player->gapless.running)
2436 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2438 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2440 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2441 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2442 gst_event_unref(event);
2443 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2449 gdouble proportion = 0.0;
2450 GstClockTimeDiff diff = 0;
2451 GstClockTime timestamp = 0;
2452 gint64 running_time_diff = -1;
2453 GstQOSType type = 0;
2454 GstEvent *tmpev = NULL;
2456 running_time_diff = player->gapless.segment[stream_type].base;
2458 if (running_time_diff <= 0) /* don't need to adjust */
2461 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2462 gst_event_unref(event);
2464 if (timestamp < running_time_diff) {
2465 LOGW("QOS event from previous group");
2466 ret = GST_PAD_PROBE_DROP;
2470 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2471 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2472 stream_type, GST_TIME_ARGS(timestamp),
2473 GST_TIME_ARGS(running_time_diff),
2474 GST_TIME_ARGS(timestamp - running_time_diff));
2476 timestamp -= running_time_diff;
2478 /* That case is invalid for QoS events */
2479 if (diff < 0 && -diff > timestamp) {
2480 LOGW("QOS event from previous group");
2481 ret = GST_PAD_PROBE_DROP;
2485 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2486 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2496 gst_caps_unref(caps);
2501 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2503 mm_player_t* player = NULL;
2504 GstElement* pipeline = NULL;
2505 GstElement* selector = NULL;
2506 GstElement* fakesink = NULL;
2507 GstCaps* caps = NULL;
2508 GstStructure* str = NULL;
2509 const gchar* name = NULL;
2510 GstPad* sinkpad = NULL;
2511 GstPad* srcpad = NULL;
2512 gboolean first_track = FALSE;
2514 enum MainElementID elemId = MMPLAYER_M_NUM;
2515 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2518 player = (mm_player_t*)data;
2520 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2521 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2523 //LOGD("pad-added signal handling\n");
2525 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2527 /* get mimetype from caps */
2528 caps = gst_pad_query_caps(pad, NULL);
2530 LOGE("cannot get caps from pad.\n");
2534 str = gst_caps_get_structure(caps, 0);
2536 LOGE("cannot get structure from caps.\n");
2540 name = gst_structure_get_name(str);
2542 LOGE("cannot get mimetype from structure.\n");
2546 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2547 //LOGD("detected mimetype : %s\n", name);
2549 if (strstr(name, "video")) {
2552 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2553 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2555 /* don't make video because of not required, and not support multiple track */
2556 if (stype == MM_DISPLAY_SURFACE_NULL) {
2557 LOGD("no video sink by null surface");
2559 gchar *caps_str = gst_caps_to_string(caps);
2560 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2561 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2562 player->set_mode.video_zc = TRUE;
2564 MMPLAYER_FREEIF(caps_str);
2566 if (player->v_stream_caps) {
2567 gst_caps_unref(player->v_stream_caps);
2568 player->v_stream_caps = NULL;
2571 LOGD("create fakesink instead of videobin");
2574 fakesink = gst_element_factory_make("fakesink", NULL);
2575 if (fakesink == NULL) {
2576 LOGE("ERROR : fakesink create error\n");
2580 if (player->ini.set_dump_element_flag)
2581 __mmplayer_add_dump_buffer_probe(player, fakesink);
2583 player->video_fakesink = fakesink;
2585 /* store it as it's sink element */
2586 __mmplayer_add_sink(player, player->video_fakesink);
2588 gst_bin_add(GST_BIN(pipeline), fakesink);
2591 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2593 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2594 LOGW("failed to link fakesink\n");
2595 gst_object_unref(GST_OBJECT(fakesink));
2599 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2600 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2601 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2604 if (player->set_mode.media_packet_video_stream) {
2605 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2607 MMPLAYER_SIGNAL_CONNECT(player,
2609 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2611 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2614 MMPLAYER_SIGNAL_CONNECT(player,
2616 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2618 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2622 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2623 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2627 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2628 __mmplayer_gst_decode_callback(elem, pad, player);
2632 LOGD("video selector \n");
2633 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2634 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2636 if (strstr(name, "audio")) {
2637 gint samplerate = 0;
2640 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2641 __mmplayer_gst_decode_callback(elem, pad, player);
2645 LOGD("audio selector \n");
2646 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2647 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2649 gst_structure_get_int(str, "rate", &samplerate);
2650 gst_structure_get_int(str, "channels", &channels);
2652 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2654 fakesink = gst_element_factory_make("fakesink", NULL);
2655 if (fakesink == NULL) {
2656 LOGE("ERROR : fakesink create error\n");
2660 gst_bin_add(GST_BIN(pipeline), fakesink);
2663 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2665 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2666 LOGW("failed to link fakesink\n");
2667 gst_object_unref(GST_OBJECT(fakesink));
2671 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2672 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2673 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2677 } else if (strstr(name, "text")) {
2678 LOGD("text selector \n");
2679 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2680 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2682 LOGE("wrong elem id \n");
2687 selector = player->pipeline->mainbin[elemId].gst;
2688 if (selector == NULL) {
2689 selector = gst_element_factory_make("input-selector", NULL);
2690 LOGD("Creating input-selector\n");
2691 if (selector == NULL) {
2692 LOGE("ERROR : input-selector create error\n");
2695 g_object_set(selector, "sync-streams", TRUE, NULL);
2697 player->pipeline->mainbin[elemId].id = elemId;
2698 player->pipeline->mainbin[elemId].gst = selector;
2701 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2703 srcpad = gst_element_get_static_pad(selector, "src");
2705 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2706 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2707 __mmplayer_gst_selector_blocked, NULL, NULL);
2708 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2709 __mmplayer_gst_selector_event_probe, player, NULL);
2711 gst_element_set_state(selector, GST_STATE_PAUSED);
2712 gst_bin_add(GST_BIN(pipeline), selector);
2714 LOGD("input-selector is already created.\n");
2717 LOGD("Calling request pad with selector %p \n", selector);
2718 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2720 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2722 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2723 LOGW("failed to link selector\n");
2724 gst_object_unref(GST_OBJECT(selector));
2729 LOGD("this is first track --> active track \n");
2730 g_object_set(selector, "active-pad", sinkpad, NULL);
2733 _mmplayer_track_update_info(player, stream_type, sinkpad);
2740 gst_caps_unref(caps);
2743 gst_object_unref(GST_OBJECT(sinkpad));
2748 gst_object_unref(GST_OBJECT(srcpad));
2755 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2757 GstPad* srcpad = NULL;
2758 MMHandleType attrs = 0;
2759 gint active_index = 0;
2761 // [link] input-selector :: textbin
2762 srcpad = gst_element_get_static_pad(text_selector, "src");
2764 LOGE("failed to get srcpad from selector\n");
2768 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2770 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2771 if ((active_index != DEFAULT_TRACK) &&
2772 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2773 LOGW("failed to change text track\n");
2774 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2777 player->no_more_pad = TRUE;
2778 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2780 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2781 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2782 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2783 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2786 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2788 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2789 player->has_closed_caption = TRUE;
2791 attrs = MMPLAYER_GET_ATTRS(player);
2793 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2794 if (mmf_attrs_commit(attrs))
2795 LOGE("failed to commit.\n");
2797 LOGE("cannot get content attribute");
2800 gst_object_unref(GST_OBJECT(srcpad));
2806 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2808 mm_player_t* player = (mm_player_t*)data;
2809 GstElement* selector = NULL;
2810 GstElement* queue = NULL;
2812 GstPad* srcpad = NULL;
2813 GstPad* sinkpad = NULL;
2814 GstCaps* caps = NULL;
2815 gchar* caps_str = NULL;
2818 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2820 caps = gst_pad_get_current_caps(pad);
2821 caps_str = gst_caps_to_string(caps);
2822 LOGD("deinterleave new caps : %s\n", caps_str);
2823 MMPLAYER_FREEIF(caps_str);
2824 gst_caps_unref(caps);
2826 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2827 LOGE("ERROR : queue create error\n");
2831 g_object_set(G_OBJECT(queue),
2832 "max-size-buffers", 10,
2833 "max-size-bytes", 0,
2834 "max-size-time", (guint64)0,
2837 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2840 LOGE("there is no audio channel selector.\n");
2844 srcpad = gst_element_get_static_pad(queue, "src");
2845 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2847 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2849 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2850 LOGW("failed to link deinterleave - selector\n");
2854 gst_element_set_state(queue, GST_STATE_PAUSED);
2855 player->audio_mode.total_track_num++;
2860 gst_object_unref(GST_OBJECT(srcpad));
2865 gst_object_unref(GST_OBJECT(sinkpad));
2874 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2876 mm_player_t* player = NULL;
2877 GstElement* selector = NULL;
2878 GstPad* sinkpad = NULL;
2879 gint active_index = 0;
2880 gchar* change_pad_name = NULL;
2881 GstCaps* caps = NULL; // no need to unref
2882 gint default_audio_ch = 0;
2885 player = (mm_player_t*) data;
2887 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2890 LOGE("there is no audio channel selector.\n");
2894 active_index = player->audio_mode.active_pad_index;
2896 if (active_index != default_audio_ch) {
2897 gint audio_ch = default_audio_ch;
2899 /*To get the new pad from the selector*/
2900 change_pad_name = g_strdup_printf("sink%d", active_index);
2901 if (change_pad_name != NULL) {
2902 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2903 if (sinkpad != NULL) {
2904 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2905 g_object_set(selector, "active-pad", sinkpad, NULL);
2907 audio_ch = active_index;
2909 caps = gst_pad_get_current_caps(sinkpad);
2910 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2912 __mmplayer_set_audio_attrs(player, caps);
2913 gst_caps_unref(caps);
2915 MMPLAYER_FREEIF(change_pad_name);
2918 player->audio_mode.active_pad_index = audio_ch;
2919 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2925 gst_object_unref(sinkpad);
2932 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2934 mm_player_t* player = NULL;
2935 MMPlayerGstElement *mainbin = NULL;
2937 GstElement* tee = NULL;
2938 GstElement* stereo_queue = NULL;
2939 GstElement* mono_queue = NULL;
2940 GstElement* conv = NULL;
2941 GstElement* filter = NULL;
2942 GstElement* deinterleave = NULL;
2943 GstElement* selector = NULL;
2945 GstPad* srcpad = NULL;
2946 GstPad* selector_srcpad = NULL;
2947 GstPad* sinkpad = NULL;
2948 GstCaps* caps = NULL;
2949 gulong block_id = 0;
2954 player = (mm_player_t*) data;
2956 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2957 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2959 mainbin = player->pipeline->mainbin;
2962 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2963 LOGE("ERROR : tee create error\n");
2967 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2968 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2970 gst_element_set_state(tee, GST_STATE_PAUSED);
2973 srcpad = gst_element_get_request_pad(tee, "src_%u");
2974 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2975 LOGE("ERROR : stereo queue create error\n");
2979 g_object_set(G_OBJECT(stereo_queue),
2980 "max-size-buffers", 10,
2981 "max-size-bytes", 0,
2982 "max-size-time", (guint64)0,
2985 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2986 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2989 gst_object_unref(GST_OBJECT(srcpad));
2993 srcpad = gst_element_get_request_pad(tee, "src_%u");
2995 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2996 LOGE("ERROR : mono queue create error\n");
3000 g_object_set(G_OBJECT(mono_queue),
3001 "max-size-buffers", 10,
3002 "max-size-bytes", 0,
3003 "max-size-time", (guint64)0,
3006 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3007 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3009 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3010 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3013 srcpad = gst_element_get_static_pad(mono_queue, "src");
3014 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3015 LOGE("ERROR : audioconvert create error\n");
3019 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3020 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3024 gst_object_unref(GST_OBJECT(srcpad));
3027 srcpad = gst_element_get_static_pad(conv, "src");
3029 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3030 LOGE("ERROR : capsfilter create error\n");
3034 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3035 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3037 caps = gst_caps_from_string("audio/x-raw-int, "
3038 "width = (int) 16, "
3039 "depth = (int) 16, "
3040 "channels = (int) 2");
3042 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3043 gst_caps_unref(caps);
3045 gst_element_set_state(conv, GST_STATE_PAUSED);
3046 gst_element_set_state(filter, GST_STATE_PAUSED);
3050 gst_object_unref(GST_OBJECT(srcpad));
3053 srcpad = gst_element_get_static_pad(filter, "src");
3055 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3056 LOGE("ERROR : deinterleave create error\n");
3060 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3062 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3063 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3065 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3066 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3068 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3069 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3072 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3073 if (selector == NULL) {
3074 LOGE("ERROR : audio-selector create error\n");
3078 g_object_set(selector, "sync-streams", TRUE, NULL);
3079 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3081 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3082 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3084 selector_srcpad = gst_element_get_static_pad(selector, "src");
3086 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3088 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3089 __mmplayer_gst_selector_blocked, NULL, NULL);
3092 gst_object_unref(GST_OBJECT(srcpad));
3096 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3097 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3099 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3100 LOGW("failed to link queue_stereo - selector\n");
3104 player->audio_mode.total_track_num++;
3106 g_object_set(selector, "active-pad", sinkpad, NULL);
3107 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3108 gst_element_set_state(selector, GST_STATE_PAUSED);
3110 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3114 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3115 if (block_id != 0) {
3116 gst_pad_remove_probe(selector_srcpad, block_id);
3121 gst_object_unref(GST_OBJECT(sinkpad));
3126 gst_object_unref(GST_OBJECT(srcpad));
3130 if (selector_srcpad) {
3131 gst_object_unref(GST_OBJECT(selector_srcpad));
3132 selector_srcpad = NULL;
3140 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3142 mm_player_t* player = NULL;
3143 GstPad* srcpad = NULL;
3144 GstElement* video_selector = NULL;
3145 GstElement* audio_selector = NULL;
3146 GstElement* text_selector = NULL;
3147 MMHandleType attrs = 0;
3148 gint active_index = 0;
3149 gint64 dur_bytes = 0L;
3151 player = (mm_player_t*) data;
3153 LOGD("no-more-pad signal handling\n");
3155 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3156 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3157 LOGW("no need to go more");
3159 if (player->gapless.reconfigure) {
3160 player->gapless.reconfigure = FALSE;
3161 MMPLAYER_PLAYBACK_UNLOCK(player);
3167 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3168 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3169 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3170 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3171 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3173 if (NULL == player->streamer) {
3174 LOGW("invalid state for buffering");
3178 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3179 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3181 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3182 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3184 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3186 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3187 LOGE("fail to get duration.\n");
3189 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3190 // use file information was already set on Q2 when it was created.
3191 __mm_player_streaming_set_queue2(player->streamer,
3192 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3193 TRUE, // use_buffering
3195 init_buffering_time,
3197 player->ini.http_buffering_limit, // high percent
3198 MUXED_BUFFER_TYPE_MEM_QUEUE,
3200 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3203 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3204 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3205 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3206 if (video_selector) {
3207 // [link] input-selector :: videobin
3208 srcpad = gst_element_get_static_pad(video_selector, "src");
3210 LOGE("failed to get srcpad from video selector\n");
3214 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3215 if (!text_selector && !audio_selector)
3216 player->no_more_pad = TRUE;
3218 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3220 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3221 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3222 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3223 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3227 if (audio_selector) {
3228 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3229 if ((active_index != DEFAULT_TRACK) &&
3230 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3231 LOGW("failed to change audio track\n");
3232 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3235 // [link] input-selector :: audiobin
3236 srcpad = gst_element_get_static_pad(audio_selector, "src");
3238 LOGE("failed to get srcpad from selector\n");
3242 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3244 player->no_more_pad = TRUE;
3246 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3247 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3248 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3249 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3250 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3253 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3255 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3257 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3258 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3259 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3260 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3264 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3266 attrs = MMPLAYER_GET_ATTRS(player);
3268 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3269 if (mmf_attrs_commit(attrs))
3270 LOGE("failed to commit.\n");
3272 LOGE("cannot get content attribute");
3274 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3275 LOGD("There is no audio track : remove audiobin");
3277 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3278 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3280 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3281 MMPLAYER_FREEIF(player->pipeline->audiobin);
3284 if (player->num_dynamic_pad == 0)
3285 __mmplayer_pipeline_complete(NULL, player);
3288 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3290 __mmplayer_handle_text_decode_path(player, text_selector);
3297 gst_object_unref(GST_OBJECT(srcpad));
3301 if (player->gapless.reconfigure) {
3302 player->gapless.reconfigure = FALSE;
3303 MMPLAYER_PLAYBACK_UNLOCK(player);
3308 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3310 mm_player_t* player = NULL;
3311 MMHandleType attrs = 0;
3312 GstElement* pipeline = NULL;
3313 GstCaps* caps = NULL;
3314 gchar* caps_str = NULL;
3315 GstStructure* str = NULL;
3316 const gchar* name = NULL;
3317 GstPad* sinkpad = NULL;
3318 GstElement* sinkbin = NULL;
3319 gboolean reusing = FALSE;
3320 GstElement *text_selector = NULL;
3323 player = (mm_player_t*) data;
3325 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3326 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3328 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3330 attrs = MMPLAYER_GET_ATTRS(player);
3332 LOGE("cannot get content attribute\n");
3336 /* get mimetype from caps */
3337 caps = gst_pad_query_caps(pad, NULL);
3339 LOGE("cannot get caps from pad.\n");
3342 caps_str = gst_caps_to_string(caps);
3344 str = gst_caps_get_structure(caps, 0);
3346 LOGE("cannot get structure from caps.\n");
3350 name = gst_structure_get_name(str);
3352 LOGE("cannot get mimetype from structure.\n");
3356 //LOGD("detected mimetype : %s\n", name);
3358 if (strstr(name, "audio")) {
3359 if (player->pipeline->audiobin == NULL) {
3360 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3361 LOGE("failed to create audiobin. continuing without audio\n");
3365 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3366 LOGD("creating audiosink bin success\n");
3369 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3370 LOGD("reusing audiobin\n");
3371 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3374 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3375 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3377 player->audiosink_linked = 1;
3379 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3381 LOGE("failed to get pad from sinkbin\n");
3384 } else if (strstr(name, "video")) {
3385 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3386 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3387 player->set_mode.video_zc = TRUE;
3389 if (player->pipeline->videobin == NULL) {
3390 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3391 /* get video surface type */
3392 int surface_type = 0;
3393 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3394 LOGD("display_surface_type(%d)\n", surface_type);
3396 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3397 LOGD("not make videobin because it dose not want\n");
3401 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3402 /* mark video overlay for acquire */
3403 if (player->video_overlay_resource == NULL) {
3404 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3405 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3406 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3407 &player->video_overlay_resource)
3408 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3409 LOGE("could not mark video_overlay resource for acquire\n");
3415 player->interrupted_by_resource = FALSE;
3416 /* acquire resources for video overlay */
3417 if (mm_resource_manager_commit(player->resource_manager) !=
3418 MM_RESOURCE_MANAGER_ERROR_NONE) {
3419 LOGE("could not acquire resources for video playing\n");
3423 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3424 LOGE("failed to create videobin. continuing without video\n");
3428 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3429 LOGD("creating videosink bin success\n");
3432 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3433 LOGD("re-using videobin\n");
3434 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3437 player->videosink_linked = 1;
3439 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3441 LOGE("failed to get pad from sinkbin\n");
3444 } else if (strstr(name, "text")) {
3445 if (player->pipeline->textbin == NULL) {
3446 MMPlayerGstElement* mainbin = NULL;
3448 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3449 LOGE("failed to create text sink bin. continuing without text\n");
3453 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3454 LOGD("creating textsink bin success\n");
3456 /* FIXIT : track number shouldn't be hardcoded */
3457 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3459 player->textsink_linked = 1;
3460 LOGI("player->textsink_linked set to 1\n");
3462 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3464 LOGE("failed to get pad from sinkbin\n");
3468 mainbin = player->pipeline->mainbin;
3470 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3471 /* input selector */
3472 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3473 if (!text_selector) {
3474 LOGE("failed to create subtitle input selector element\n");
3477 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3479 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3480 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3483 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3484 LOGE("failed to set state(READY) to sinkbin\n");
3488 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3489 LOGW("failed to add subtitle input selector\n");
3493 LOGD("created element input-selector");
3496 LOGD("already having subtitle input selector");
3497 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3500 if (!player->textsink_linked) {
3501 LOGD("re-using textbin\n");
3504 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3506 player->textsink_linked = 1;
3507 LOGI("player->textsink_linked set to 1\n");
3509 LOGD("ignoring internal subtutle since external subtitle is available");
3512 LOGW("unknown type of elementary stream!ignoring it...\n");
3519 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3520 LOGE("failed to set state(READY) to sinkbin\n");
3524 /* Added for multi audio support to avoid adding audio bin again*/
3526 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3527 LOGE("failed to add sinkbin to pipeline\n");
3533 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3534 LOGE("failed to get pad from sinkbin\n");
3540 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3541 LOGE("failed to set state(PAUSED) to sinkbin\n");
3545 if (text_selector) {
3546 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3547 LOGE("failed to set state(PAUSED) to sinkbin\n");
3553 gst_object_unref(sinkpad);
3557 LOGD("[handle: %p] linking sink bin success", player);
3559 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3560 * streaming task. if the task blocked, then buffer will not flow to the next element
3561 *(autoplugging element). so this is special hack for streaming. please try to remove it
3563 /* dec stream count. we can remove fakesink if it's zero */
3564 if (player->num_dynamic_pad)
3565 player->num_dynamic_pad--;
3567 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3569 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3570 __mmplayer_pipeline_complete(NULL, player);
3574 MMPLAYER_FREEIF(caps_str);
3577 gst_caps_unref(caps);
3580 gst_object_unref(GST_OBJECT(sinkpad));
3582 /* flusing out new attributes */
3583 if (mmf_attrs_commit(attrs))
3584 LOGE("failed to comit attributes\n");
3590 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3592 int pro_value = 0; // in the case of expection, default will be returned.
3593 int dest_angle = rotation_angle;
3594 int rotation_type = -1;
3596 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3597 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3598 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3600 if (rotation_angle >= 360)
3601 dest_angle = rotation_angle - 360;
3603 /* chech if supported or not */
3604 if (dest_angle % 90) {
3605 LOGD("not supported rotation angle = %d", rotation_angle);
3611 * custom_convert - none (B)
3612 * videoflip - none (C)
3614 if (player->set_mode.video_zc) {
3615 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3616 rotation_type = ROTATION_USING_CUSTOM;
3618 rotation_type = ROTATION_USING_SINK;
3620 int surface_type = 0;
3621 rotation_type = ROTATION_USING_FLIP;
3623 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3624 LOGD("check display surface type attribute: %d", surface_type);
3626 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3627 rotation_type = ROTATION_USING_SINK;
3629 rotation_type = ROTATION_USING_FLIP; //C
3631 LOGD("using %d type for rotation", rotation_type);
3634 /* get property value for setting */
3635 switch (rotation_type) {
3636 case ROTATION_USING_SINK: // tizenwlsink
3638 switch (dest_angle) {
3642 pro_value = 3; // clockwise 90
3648 pro_value = 1; // counter-clockwise 90
3653 case ROTATION_USING_CUSTOM:
3655 gchar *ename = NULL;
3656 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3658 if (g_strrstr(ename, "fimcconvert")) {
3659 switch (dest_angle) {
3663 pro_value = 90; // clockwise 90
3669 pro_value = 270; // counter-clockwise 90
3675 case ROTATION_USING_FLIP: // videoflip
3677 switch (dest_angle) {
3681 pro_value = 1; // clockwise 90
3687 pro_value = 3; // counter-clockwise 90
3694 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3702 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3704 /* check video sinkbin is created */
3705 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3707 player->pipeline->videobin &&
3708 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3709 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3710 MM_ERROR_PLAYER_NOT_INITIALIZED);
3712 return MM_ERROR_NONE;
3716 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3718 int rotation_value = 0;
3719 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3723 /* check video sinkbin is created */
3724 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3727 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3729 /* get rotation value to set */
3730 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3731 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3732 LOGD("set video param : rotate %d", rotation_value);
3736 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3738 MMHandleType attrs = 0;
3742 /* check video sinkbin is created */
3743 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3746 attrs = MMPLAYER_GET_ATTRS(player);
3747 MMPLAYER_RETURN_IF_FAIL(attrs);
3749 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3750 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3751 LOGD("set video param : visible %d", visible);
3755 __mmplayer_video_param_set_display_method(mm_player_t* player)
3757 MMHandleType attrs = 0;
3758 int display_method = 0;
3761 /* check video sinkbin is created */
3762 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3765 attrs = MMPLAYER_GET_ATTRS(player);
3766 MMPLAYER_RETURN_IF_FAIL(attrs);
3768 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3769 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3770 LOGD("set video param : method %d", display_method);
3774 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3776 MMHandleType attrs = 0;
3777 void *handle = NULL;
3779 int wl_window_x = 0;
3780 int wl_window_y = 0;
3781 int wl_window_width = 0;
3782 int wl_window_height = 0;
3785 /* check video sinkbin is created */
3786 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3789 attrs = MMPLAYER_GET_ATTRS(player);
3790 MMPLAYER_RETURN_IF_FAIL(attrs);
3792 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3795 /*It should be set after setting window*/
3796 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3797 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3798 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3799 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3801 /* After setting window handle, set render rectangle */
3802 gst_video_overlay_set_render_rectangle(
3803 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3804 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3805 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3806 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3811 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3813 MMHandleType attrs = 0;
3814 void *handle = NULL;
3816 /* check video sinkbin is created */
3817 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3820 attrs = MMPLAYER_GET_ATTRS(player);
3821 MMPLAYER_RETURN_IF_FAIL(attrs);
3823 /* common case if using overlay surface */
3824 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3827 /* default is using wl_surface_id */
3828 unsigned int wl_surface_id = 0;
3829 wl_surface_id = *(int*)handle;
3830 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3831 gst_video_overlay_set_wl_window_wl_surface_id(
3832 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3835 /* FIXIT : is it error case? */
3836 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3841 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3843 bool update_all_param = FALSE;
3846 /* check video sinkbin is created */
3847 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3848 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3850 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3851 LOGE("can not find tizenwlsink");
3852 return MM_ERROR_PLAYER_INTERNAL;
3855 LOGD("param_name : %s", param_name);
3856 if (!g_strcmp0(param_name, "update_all_param"))
3857 update_all_param = TRUE;
3859 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3860 __mmplayer_video_param_set_display_overlay(player);
3861 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3862 __mmplayer_video_param_set_display_method(player);
3863 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3864 __mmplayer_video_param_set_render_rectangle(player);
3865 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3866 __mmplayer_video_param_set_display_visible(player);
3867 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3868 __mmplayer_video_param_set_display_rotation(player);
3870 return MM_ERROR_NONE;
3874 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3876 MMHandleType attrs = 0;
3877 int surface_type = 0;
3878 int ret = MM_ERROR_NONE;
3882 /* check video sinkbin is created */
3883 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3884 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3886 attrs = MMPLAYER_GET_ATTRS(player);
3888 LOGE("cannot get content attribute");
3889 return MM_ERROR_PLAYER_INTERNAL;
3891 LOGD("param_name : %s", param_name);
3893 /* update display surface */
3894 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3895 LOGD("check display surface type attribute: %d", surface_type);
3897 /* configuring display */
3898 switch (surface_type) {
3899 case MM_DISPLAY_SURFACE_OVERLAY:
3901 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3902 if (ret != MM_ERROR_NONE)
3910 return MM_ERROR_NONE;
3914 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3916 gboolean disable_overlay = FALSE;
3917 mm_player_t* player = (mm_player_t*) hplayer;
3918 int ret = MM_ERROR_NONE;
3921 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3922 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3923 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3924 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3926 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3927 LOGW("Display control is not supported");
3928 return MM_ERROR_PLAYER_INTERNAL;
3931 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3933 if (audio_only == (bool)disable_overlay) {
3934 LOGE("It's the same with current setting: (%d)", audio_only);
3935 return MM_ERROR_NONE;
3939 LOGE("disable overlay");
3940 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3942 /* release overlay resource */
3943 if (player->video_overlay_resource != NULL) {
3944 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3945 player->video_overlay_resource);
3946 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3947 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3950 player->video_overlay_resource = NULL;
3953 ret = mm_resource_manager_commit(player->resource_manager);
3954 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3955 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3959 /* mark video overlay for acquire */
3960 if (player->video_overlay_resource == NULL) {
3961 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3962 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3963 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3964 &player->video_overlay_resource);
3965 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3966 LOGE("could not prepare for video_overlay resource\n");
3971 player->interrupted_by_resource = FALSE;
3972 /* acquire resources for video overlay */
3973 ret = mm_resource_manager_commit(player->resource_manager);
3974 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3975 LOGE("could not acquire resources for video playing\n");
3979 LOGD("enable overlay");
3980 __mmplayer_video_param_set_display_overlay(player);
3981 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3986 return MM_ERROR_NONE;
3990 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3992 mm_player_t* player = (mm_player_t*) hplayer;
3993 gboolean disable_overlay = FALSE;
3997 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3998 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4004 LOGW("Display control is not supported");
4005 return MM_ERROR_PLAYER_INTERNAL;
4008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4010 *paudio_only = (bool)(disable_overlay);
4012 LOGD("audio_only : %d", *paudio_only);
4016 return MM_ERROR_NONE;
4020 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4022 GList* bucket = element_bucket;
4023 MMPlayerGstElement* element = NULL;
4024 MMPlayerGstElement* prv_element = NULL;
4025 gint successful_link_count = 0;
4029 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4031 prv_element = (MMPlayerGstElement*)bucket->data;
4032 bucket = bucket->next;
4034 for (; bucket; bucket = bucket->next) {
4035 element = (MMPlayerGstElement*)bucket->data;
4037 if (element && element->gst) {
4038 /* If next element is audio appsrc then make a separate audio pipeline */
4039 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4040 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4041 prv_element = element;
4045 if (prv_element && prv_element->gst) {
4046 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4047 LOGD("linking [%s] to [%s] success\n",
4048 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4049 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4050 successful_link_count++;
4052 LOGD("linking [%s] to [%s] failed\n",
4053 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4054 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4060 prv_element = element;
4065 return successful_link_count;
4069 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4071 GList* bucket = element_bucket;
4072 MMPlayerGstElement* element = NULL;
4073 int successful_add_count = 0;
4077 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4078 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4080 for (; bucket; bucket = bucket->next) {
4081 element = (MMPlayerGstElement*)bucket->data;
4083 if (element && element->gst) {
4084 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4085 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4086 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4087 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4090 successful_add_count++;
4096 return successful_add_count;
4099 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4101 mm_player_t* player = (mm_player_t*) data;
4102 GstCaps *caps = NULL;
4103 GstStructure *str = NULL;
4108 MMPLAYER_RETURN_IF_FAIL(pad)
4109 MMPLAYER_RETURN_IF_FAIL(unused)
4110 MMPLAYER_RETURN_IF_FAIL(data)
4112 caps = gst_pad_get_current_caps(pad);
4116 str = gst_caps_get_structure(caps, 0);
4120 name = gst_structure_get_name(str);
4124 LOGD("name = %s\n", name);
4126 if (strstr(name, "audio")) {
4127 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4129 if (player->audio_stream_changed_cb) {
4130 LOGE("call the audio stream changed cb\n");
4131 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4133 } else if (strstr(name, "video")) {
4134 if ((name = gst_structure_get_string(str, "format")))
4135 player->set_mode.video_zc = name[0] == 'S';
4137 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4139 if (player->video_stream_changed_cb) {
4140 LOGE("call the video stream changed cb\n");
4141 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4148 gst_caps_unref(caps);
4158 * This function is to create audio pipeline for playing.
4160 * @param player [in] handle of player
4162 * @return This function returns zero on success.
4164 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4166 /* macro for code readability. just for sinkbin-creation functions */
4167 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4169 x_bin[x_id].id = x_id;\
4170 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4171 if (!x_bin[x_id].gst) {\
4172 LOGE("failed to create %s \n", x_factory);\
4175 if (x_player->ini.set_dump_element_flag)\
4176 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4179 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4183 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4188 MMPLAYER_RETURN_IF_FAIL(player);
4190 if (player->audio_stream_buff_list) {
4191 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4192 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4195 LOGD("[%lld] send remained data.", tmp->channel_mask);
4196 __mmplayer_audio_stream_send_data(player, tmp);
4199 g_free(tmp->pcm_data);
4203 g_list_free(player->audio_stream_buff_list);
4204 player->audio_stream_buff_list = NULL;
4211 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4213 MMPlayerAudioStreamDataType audio_stream = { 0, };
4216 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4218 audio_stream.bitrate = a_buffer->bitrate;
4219 audio_stream.channel = a_buffer->channel;
4220 audio_stream.depth = a_buffer->depth;
4221 audio_stream.is_little_endian = a_buffer->is_little_endian;
4222 audio_stream.channel_mask = a_buffer->channel_mask;
4223 audio_stream.data_size = a_buffer->data_size;
4224 audio_stream.data = a_buffer->pcm_data;
4226 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4227 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4233 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4235 mm_player_t* player = (mm_player_t*) data;
4240 gint endianness = 0;
4241 guint64 channel_mask = 0;
4242 void *a_data = NULL;
4244 mm_player_audio_stream_buff_t *a_buffer = NULL;
4245 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4249 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4251 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4252 a_data = mapinfo.data;
4253 a_size = mapinfo.size;
4255 GstCaps *caps = gst_pad_get_current_caps(pad);
4256 GstStructure *structure = gst_caps_get_structure(caps, 0);
4258 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4259 gst_structure_get_int(structure, "rate", &rate);
4260 gst_structure_get_int(structure, "channels", &channel);
4261 gst_structure_get_int(structure, "depth", &depth);
4262 gst_structure_get_int(structure, "endianness", &endianness);
4263 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4264 gst_caps_unref(GST_CAPS(caps));
4266 /* In case of the sync is false, use buffer list. *
4267 * The num of buffer list depends on the num of audio channels */
4268 if (player->audio_stream_buff_list) {
4269 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4270 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4272 if (channel_mask == tmp->channel_mask) {
4273 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4274 if (tmp->data_size + a_size < tmp->buff_size) {
4275 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4276 tmp->data_size += a_size;
4278 /* send data to client */
4279 __mmplayer_audio_stream_send_data(player, tmp);
4281 if (a_size > tmp->buff_size) {
4282 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4283 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4284 if (tmp->pcm_data == NULL) {
4285 LOGE("failed to realloc data.");
4288 tmp->buff_size = a_size;
4290 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4291 memcpy(tmp->pcm_data, a_data, a_size);
4292 tmp->data_size = a_size;
4297 LOGE("data is empty in list.");
4303 /* create new audio stream data */
4304 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4305 if (a_buffer == NULL) {
4306 LOGE("failed to alloc data.");
4309 a_buffer->bitrate = rate;
4310 a_buffer->channel = channel;
4311 a_buffer->depth = depth;
4312 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4313 a_buffer->channel_mask = channel_mask;
4314 a_buffer->data_size = a_size;
4316 if (!player->audio_stream_sink_sync) {
4317 /* If sync is FALSE, use buffer list to reduce the IPC. */
4318 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4319 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4320 if (a_buffer->pcm_data == NULL) {
4321 LOGE("failed to alloc data.");
4325 memcpy(a_buffer->pcm_data, a_data, a_size);
4326 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4327 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4329 /* If sync is TRUE, send data directly. */
4330 a_buffer->pcm_data = a_data;
4331 __mmplayer_audio_stream_send_data(player, a_buffer);
4336 gst_buffer_unmap(buffer, &mapinfo);
4341 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4343 mm_player_t* player = (mm_player_t*)data;
4344 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4345 GstPad* sinkpad = NULL;
4346 GstElement *queue = NULL, *sink = NULL;
4349 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4351 queue = gst_element_factory_make("queue", NULL);
4352 if (queue == NULL) {
4353 LOGD("fail make queue\n");
4357 sink = gst_element_factory_make("fakesink", NULL);
4359 LOGD("fail make fakesink\n");
4363 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4365 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4366 LOGW("failed to link queue & sink\n");
4370 sinkpad = gst_element_get_static_pad(queue, "sink");
4372 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4373 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4377 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4379 gst_object_unref(sinkpad);
4380 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4381 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4383 gst_element_set_state(sink, GST_STATE_PAUSED);
4384 gst_element_set_state(queue, GST_STATE_PAUSED);
4386 MMPLAYER_SIGNAL_CONNECT(player,
4388 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4390 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4397 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4399 gst_object_unref(GST_OBJECT(queue));
4403 gst_object_unref(GST_OBJECT(sink));
4407 gst_object_unref(GST_OBJECT(sinkpad));
4414 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4416 #define MAX_PROPS_LEN 128
4417 gint latency_mode = 0;
4418 gchar *stream_type = NULL;
4419 gchar *latency = NULL;
4421 gchar stream_props[MAX_PROPS_LEN] = {0,};
4422 GstStructure *props = NULL;
4425 * It should be set after player creation through attribute.
4426 * But, it can not be changed during playing.
4429 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4430 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4433 LOGE("stream_type is null.\n");
4435 if (player->sound.focus_id)
4436 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4437 stream_type, stream_id, player->sound.focus_id);
4439 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4440 stream_type, stream_id);
4441 props = gst_structure_from_string(stream_props, NULL);
4442 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4443 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4444 stream_type, stream_id, player->sound.focus_id, stream_props);
4445 gst_structure_free(props);
4448 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4450 switch (latency_mode) {
4451 case AUDIO_LATENCY_MODE_LOW:
4452 latency = g_strndup("low", 3);
4454 case AUDIO_LATENCY_MODE_MID:
4455 latency = g_strndup("mid", 3);
4457 case AUDIO_LATENCY_MODE_HIGH:
4458 latency = g_strndup("high", 4);
4462 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4466 LOGD("audiosink property - latency=%s \n", latency);
4474 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4476 MMPlayerGstElement* first_element = NULL;
4477 MMPlayerGstElement* audiobin = NULL;
4478 MMHandleType attrs = 0;
4480 GstPad *ghostpad = NULL;
4481 GList* element_bucket = NULL;
4482 gboolean link_audio_sink_now = TRUE;
4488 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4491 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4493 LOGE("failed to allocate memory for audiobin\n");
4494 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4497 attrs = MMPLAYER_GET_ATTRS(player);
4500 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4501 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4502 if (!audiobin[MMPLAYER_A_BIN].gst) {
4503 LOGE("failed to create audiobin\n");
4508 player->pipeline->audiobin = audiobin;
4510 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4512 /* Adding audiotp plugin for reverse trickplay feature */
4513 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4516 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4518 /* replaygain volume */
4519 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4520 if (player->sound.rg_enable)
4521 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4523 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4526 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4528 if (player->set_mode.pcm_extraction) {
4529 // pcm extraction only and no sound output
4530 if (player->audio_stream_render_cb_ex) {
4531 char *caps_str = NULL;
4532 GstCaps* caps = NULL;
4533 gchar *format = NULL;
4536 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4538 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4540 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4542 caps = gst_caps_new_simple("audio/x-raw",
4543 "format", G_TYPE_STRING, format,
4544 "rate", G_TYPE_INT, player->pcm_samplerate,
4545 "channels", G_TYPE_INT, player->pcm_channel,
4547 caps_str = gst_caps_to_string(caps);
4548 LOGD("new caps : %s\n", caps_str);
4550 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4553 gst_caps_unref(caps);
4554 MMPLAYER_FREEIF(caps_str);
4556 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4558 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4559 /* raw pad handling signal */
4560 MMPLAYER_SIGNAL_CONNECT(player,
4561 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4562 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4563 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4565 int dst_samplerate = 0;
4566 int dst_channels = 0;
4568 char *caps_str = NULL;
4569 GstCaps* caps = NULL;
4571 /* get conf. values */
4572 mm_attrs_multiple_get(player->attrs,
4574 "pcm_extraction_samplerate", &dst_samplerate,
4575 "pcm_extraction_channels", &dst_channels,
4576 "pcm_extraction_depth", &dst_depth,
4580 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4581 caps = gst_caps_new_simple("audio/x-raw",
4582 "rate", G_TYPE_INT, dst_samplerate,
4583 "channels", G_TYPE_INT, dst_channels,
4584 "depth", G_TYPE_INT, dst_depth,
4586 caps_str = gst_caps_to_string(caps);
4587 LOGD("new caps : %s\n", caps_str);
4589 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4592 gst_caps_unref(caps);
4593 MMPLAYER_FREEIF(caps_str);
4596 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4599 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4603 //GstCaps* caps = NULL;
4606 /* for logical volume control */
4607 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4608 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4610 if (player->sound.mute) {
4611 LOGD("mute enabled\n");
4612 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4617 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4618 caps = gst_caps_from_string("audio/x-raw-int, "
4619 "endianness = (int) LITTLE_ENDIAN, "
4620 "signed = (boolean) true, "
4621 "width = (int) 16, "
4622 "depth = (int) 16");
4623 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4624 gst_caps_unref(caps);
4627 /* check if multi-channels */
4628 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4629 GstPad *srcpad = NULL;
4630 GstCaps *caps = NULL;
4632 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4633 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4634 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4635 GstStructure *str = gst_caps_get_structure(caps, 0);
4637 gst_structure_get_int(str, "channels", &channels);
4638 gst_caps_unref(caps);
4640 gst_object_unref(srcpad);
4644 /* audio effect element. if audio effect is enabled */
4645 if ((strcmp(player->ini.audioeffect_element, ""))
4647 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4648 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4650 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4652 if ((!player->bypass_audio_effect)
4653 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4654 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4655 if (!_mmplayer_audio_effect_custom_apply(player))
4656 LOGI("apply audio effect(custom) setting success\n");
4660 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4661 && (player->set_mode.rich_audio))
4662 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4665 /* create audio sink */
4666 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4667 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4668 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4670 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4671 if (player->is_360_feature_enabled &&
4672 player->is_content_spherical &&
4674 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4675 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4676 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4678 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4683 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4685 gst_caps_unref(acaps);
4687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4689 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4690 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4692 player->is_openal_plugin_used = TRUE;
4694 if (player->video360_yaw_radians <= M_PI &&
4695 player->video360_yaw_radians >= -M_PI &&
4696 player->video360_pitch_radians <= M_PI_2 &&
4697 player->video360_pitch_radians >= -M_PI_2) {
4698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4699 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4700 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4701 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4703 "source-orientation-y", player->video360_metadata.init_view_heading,
4704 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4707 if (player->is_360_feature_enabled && player->is_content_spherical)
4708 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4717 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4718 (player->videodec_linked && player->ini.use_system_clock)) {
4719 LOGD("system clock will be used.\n");
4720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4723 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4724 __mmplayer_gst_set_audiosink_property(player, attrs);
4727 if (audiobin[MMPLAYER_A_SINK].gst) {
4728 GstPad *sink_pad = NULL;
4729 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4730 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4731 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4732 gst_object_unref(GST_OBJECT(sink_pad));
4735 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4737 /* adding created elements to bin */
4738 LOGD("adding created elements to bin\n");
4739 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4740 LOGE("failed to add elements\n");
4744 /* linking elements in the bucket by added order. */
4745 LOGD("Linking elements in the bucket by added order.\n");
4746 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4747 LOGE("failed to link elements\n");
4751 /* get first element's sinkpad for creating ghostpad */
4752 first_element = (MMPlayerGstElement *)element_bucket->data;
4753 if (!first_element) {
4754 LOGE("failed to get first elem\n");
4758 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4760 LOGE("failed to get pad from first element of audiobin\n");
4764 ghostpad = gst_ghost_pad_new("sink", pad);
4766 LOGE("failed to create ghostpad\n");
4770 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4771 LOGE("failed to add ghostpad to audiobin\n");
4775 gst_object_unref(pad);
4777 g_list_free(element_bucket);
4780 return MM_ERROR_NONE;
4784 LOGD("ERROR : releasing audiobin\n");
4787 gst_object_unref(GST_OBJECT(pad));
4790 gst_object_unref(GST_OBJECT(ghostpad));
4793 g_list_free(element_bucket);
4795 /* release element which are not added to bin */
4796 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4797 /* NOTE : skip bin */
4798 if (audiobin[i].gst) {
4799 GstObject* parent = NULL;
4800 parent = gst_element_get_parent(audiobin[i].gst);
4803 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4804 audiobin[i].gst = NULL;
4806 gst_object_unref(GST_OBJECT(parent));
4810 /* release audiobin with it's childs */
4811 if (audiobin[MMPLAYER_A_BIN].gst)
4812 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4814 MMPLAYER_FREEIF(audiobin);
4816 player->pipeline->audiobin = NULL;
4818 return MM_ERROR_PLAYER_INTERNAL;
4821 static GstPadProbeReturn
4822 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4824 mm_player_t* player = (mm_player_t*) u_data;
4825 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4826 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4828 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4830 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4831 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4833 return GST_PAD_PROBE_OK;
4836 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4838 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4841 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4843 int ret = MM_ERROR_NONE;
4845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4846 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4848 MMPLAYER_VIDEO_BO_LOCK(player);
4850 if (player->video_bo_list) {
4851 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4852 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4853 if (tmp && tmp->bo == bo) {
4855 LOGD("release bo %p", bo);
4856 tbm_bo_unref(tmp->bo);
4857 MMPLAYER_VIDEO_BO_UNLOCK(player);
4858 MMPLAYER_VIDEO_BO_SIGNAL(player);
4863 /* hw codec is running or the list was reset for DRC. */
4864 LOGW("there is no bo list.");
4866 MMPLAYER_VIDEO_BO_UNLOCK(player);
4868 LOGW("failed to find bo %p", bo);
4873 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4878 MMPLAYER_RETURN_IF_FAIL(player);
4880 MMPLAYER_VIDEO_BO_LOCK(player);
4881 if (player->video_bo_list) {
4882 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4883 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4884 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887 tbm_bo_unref(tmp->bo);
4891 g_list_free(player->video_bo_list);
4892 player->video_bo_list = NULL;
4894 player->video_bo_size = 0;
4895 MMPLAYER_VIDEO_BO_UNLOCK(player);
4902 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4905 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4906 gboolean ret = TRUE;
4908 /* check DRC, if it is, destroy the prev bo list to create again */
4909 if (player->video_bo_size != size) {
4910 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4911 __mmplayer_video_stream_destroy_bo_list(player);
4912 player->video_bo_size = size;
4915 MMPLAYER_VIDEO_BO_LOCK(player);
4917 if ((!player->video_bo_list) ||
4918 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4920 /* create bo list */
4922 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4924 if (player->video_bo_list) {
4925 /* if bo list did not created all, try it again. */
4926 idx = g_list_length(player->video_bo_list);
4927 LOGD("bo list exist(len: %d)", idx);
4930 for (; idx < player->ini.num_of_video_bo; idx++) {
4931 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4933 LOGE("Fail to alloc bo_info.");
4936 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4938 LOGE("Fail to tbm_bo_alloc.");
4942 bo_info->using = FALSE;
4943 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4946 /* update video num buffers */
4947 player->video_num_buffers = idx;
4948 if (idx == player->ini.num_of_video_bo)
4949 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4952 MMPLAYER_VIDEO_BO_UNLOCK(player);
4956 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4960 /* get bo from list*/
4961 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4962 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4963 if (tmp && (tmp->using == FALSE)) {
4964 LOGD("found bo %p to use", tmp->bo);
4966 MMPLAYER_VIDEO_BO_UNLOCK(player);
4967 return tbm_bo_ref(tmp->bo);
4971 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4972 MMPLAYER_VIDEO_BO_UNLOCK(player);
4976 if (player->ini.video_bo_timeout <= 0) {
4977 MMPLAYER_VIDEO_BO_WAIT(player);
4979 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4980 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4987 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4989 mm_player_t* player = (mm_player_t*)data;
4991 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4993 /* send prerolled pkt */
4994 player->video_stream_prerolled = FALSE;
4996 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4998 /* not to send prerolled pkt again */
4999 player->video_stream_prerolled = TRUE;
5003 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5005 mm_player_t* player = (mm_player_t*)data;
5006 GstCaps *caps = NULL;
5007 MMPlayerVideoStreamDataType *stream = NULL;
5008 MMVideoBuffer *video_buffer = NULL;
5009 GstMemory *dataBlock = NULL;
5010 GstMemory *metaBlock = NULL;
5011 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5012 GstStructure *structure = NULL;
5013 const gchar *string_format = NULL;
5014 unsigned int fourcc = 0;
5017 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5019 if (player->video_stream_prerolled) {
5020 player->video_stream_prerolled = FALSE;
5021 LOGD("skip the prerolled pkt not to send it again");
5025 caps = gst_pad_get_current_caps(pad);
5027 LOGE("Caps is NULL.");
5031 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5033 /* clear stream data structure */
5034 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5036 LOGE("failed to alloc mem for video data");
5040 structure = gst_caps_get_structure(caps, 0);
5041 gst_structure_get_int(structure, "width", &(stream->width));
5042 gst_structure_get_int(structure, "height", &(stream->height));
5043 string_format = gst_structure_get_string(structure, "format");
5045 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5046 stream->format = util_get_pixtype(fourcc);
5047 gst_caps_unref(caps);
5050 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5053 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5054 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5057 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5058 LOGE("Wrong condition!!");
5062 /* set size and timestamp */
5063 dataBlock = gst_buffer_peek_memory(buffer, 0);
5064 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5065 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5067 /* check zero-copy */
5068 if (player->set_mode.video_zc &&
5069 player->set_mode.media_packet_video_stream &&
5070 gst_buffer_n_memory(buffer) > 1) {
5071 metaBlock = gst_buffer_peek_memory(buffer, 1);
5072 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5073 video_buffer = (MMVideoBuffer *)mapinfo.data;
5076 if (video_buffer) { /* hw codec */
5078 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5081 /* copy pointer of tbm bo, stride, elevation */
5082 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5083 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5087 LOGE("Not support video buffer format");
5090 memcpy(stream->stride, video_buffer->stride_width,
5091 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5092 memcpy(stream->elevation, video_buffer->stride_height,
5093 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5095 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5096 stream->internal_buffer = gst_buffer_ref(buffer);
5097 } else { /* sw codec */
5101 int ret = TBM_SURFACE_ERROR_NONE;
5102 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5103 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5105 unsigned char *src = NULL;
5106 unsigned char *dest = NULL;
5107 tbm_bo_handle thandle;
5108 tbm_surface_h surface;
5109 tbm_surface_info_s info;
5112 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5114 LOGE("fail to gst_memory_map");
5119 if (stream->format == MM_PIXEL_FORMAT_I420) {
5120 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5122 ret = tbm_surface_get_info(surface, &info);
5124 if (ret != TBM_SURFACE_ERROR_NONE) {
5125 tbm_surface_destroy(surface);
5128 tbm_surface_destroy(surface);
5130 src_stride[0] = GST_ROUND_UP_4(stream->width);
5131 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5132 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5133 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5134 stream->stride[0] = info.planes[0].stride;
5135 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5136 stream->stride[1] = info.planes[1].stride;
5137 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5138 stream->stride[2] = info.planes[2].stride;
5139 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5140 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5141 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5142 stream->stride[0] = stream->width * 4;
5143 stream->elevation[0] = stream->height;
5144 size = stream->stride[0] * stream->height;
5146 LOGE("Not support format %d", stream->format);
5150 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5151 if (!stream->bo[0]) {
5152 LOGE("Fail to tbm_bo_alloc!!");
5156 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5157 if (thandle.ptr && mapinfo.data) {
5158 if (stream->format == MM_PIXEL_FORMAT_I420) {
5159 for (i = 0; i < 3; i++) {
5160 src = mapinfo.data + src_offset[i];
5161 dest = thandle.ptr + info.planes[i].offset;
5164 for (j = 0; j < stream->height>>k; j++) {
5165 memcpy(dest, src, stream->width>>k);
5166 src += src_stride[i];
5167 dest += stream->stride[i];
5170 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5171 memcpy(thandle.ptr, mapinfo.data, size);
5173 LOGE("Not support format %d", stream->format);
5177 LOGE("data pointer is wrong. dest : %p, src : %p",
5178 thandle.ptr, mapinfo.data);
5181 tbm_bo_unmap(stream->bo[0]);
5184 if (player->video_stream_cb) { /* This has been already checked at the entry */
5185 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5186 LOGE("failed to send video stream data.");
5192 gst_memory_unmap(metaBlock, &mapinfo);
5194 gst_memory_unmap(dataBlock, &mapinfo);
5199 LOGE("release video stream resource.");
5202 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5204 tbm_bo_unref(stream->bo[i]);
5206 gst_memory_unmap(metaBlock, &mapinfo);
5208 /* unref gst buffer */
5209 if (stream->internal_buffer)
5210 gst_buffer_unref(stream->internal_buffer);
5211 } else if (dataBlock) {
5213 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5214 gst_memory_unmap(dataBlock, &mapinfo);
5222 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5224 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5225 GList* element_bucket = NULL;
5227 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5232 LOGD("do not need to add video filters.");
5233 return MM_ERROR_NONE;
5236 /* in case of sw codec except 360 playback,
5237 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5238 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5239 LOGD("using video converter: %s", video_csc);
5241 /* set video rotator */
5242 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5244 *bucket = element_bucket;
5246 return MM_ERROR_NONE;
5248 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5249 g_list_free(element_bucket);
5253 return MM_ERROR_PLAYER_INTERNAL;
5257 * This function is to create video pipeline.
5259 * @param player [in] handle of player
5260 * caps [in] src caps of decoder
5261 * surface_type [in] surface type for video rendering
5263 * @return This function returns zero on success.
5265 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5269 * - video overlay surface(arm/x86) : tizenwlsink
5272 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5276 GList*element_bucket = NULL;
5277 MMPlayerGstElement* first_element = NULL;
5278 MMPlayerGstElement* videobin = NULL;
5279 gchar *videosink_element = NULL;
5283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5286 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5288 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5290 player->pipeline->videobin = videobin;
5292 attrs = MMPLAYER_GET_ATTRS(player);
5294 LOGE("cannot get content attribute");
5295 return MM_ERROR_PLAYER_INTERNAL;
5299 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5300 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5301 if (!videobin[MMPLAYER_V_BIN].gst) {
5302 LOGE("failed to create videobin");
5306 int enable_video_decoded_cb = 0;
5307 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5309 if (player->is_360_feature_enabled && player->is_content_spherical) {
5310 LOGD("video360 elem will be added.");
5312 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5313 "video-360", TRUE, player);
5315 /* Set spatial media metadata and/or user settings to the element.
5317 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5318 "projection-type", player->video360_metadata.projection_type, NULL);
5320 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5321 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5323 if (player->video360_metadata.full_pano_width_pixels &&
5324 player->video360_metadata.full_pano_height_pixels &&
5325 player->video360_metadata.cropped_area_image_width &&
5326 player->video360_metadata.cropped_area_image_height) {
5327 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5328 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5329 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5330 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5331 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5332 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5333 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5337 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5338 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5339 "horizontal-fov", player->video360_horizontal_fov,
5340 "vertical-fov", player->video360_vertical_fov, NULL);
5343 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5344 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5345 "zoom", 1.0f / player->video360_zoom, NULL);
5348 if (player->video360_yaw_radians <= M_PI &&
5349 player->video360_yaw_radians >= -M_PI &&
5350 player->video360_pitch_radians <= M_PI_2 &&
5351 player->video360_pitch_radians >= -M_PI_2) {
5352 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5353 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5354 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5355 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5357 "pose-yaw", player->video360_metadata.init_view_heading,
5358 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5362 "passthrough", !player->is_video360_enabled, NULL);
5365 /* set video sink */
5366 switch (surface_type) {
5367 case MM_DISPLAY_SURFACE_OVERLAY:
5368 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5370 if (strlen(player->ini.videosink_element_overlay) > 0)
5371 videosink_element = player->ini.videosink_element_overlay;
5375 case MM_DISPLAY_SURFACE_NULL:
5376 if (strlen(player->ini.videosink_element_fake) > 0)
5377 videosink_element = player->ini.videosink_element_fake;
5381 case MM_DISPLAY_SURFACE_REMOTE:
5382 if (strlen(player->ini.videosink_element_fake) > 0)
5383 videosink_element = player->ini.videosink_element_fake;
5388 LOGE("unidentified surface type");
5391 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5393 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5395 /* additional setting for sink plug-in */
5396 switch (surface_type) {
5397 case MM_DISPLAY_SURFACE_OVERLAY:
5399 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5401 LOGD("selected videosink name: %s", videosink_element);
5403 /* support shard memory with S/W codec on HawkP */
5404 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5405 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5406 "use-tbm", use_tbm, NULL);
5412 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5415 LOGD("disable last-sample");
5416 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5420 if (player->set_mode.media_packet_video_stream) {
5422 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5424 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5426 MMPLAYER_SIGNAL_CONNECT(player,
5427 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5428 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5430 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5433 MMPLAYER_SIGNAL_CONNECT(player,
5434 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5435 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5437 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5442 case MM_DISPLAY_SURFACE_REMOTE:
5444 if (player->set_mode.media_packet_video_stream) {
5445 LOGE("add data probe at videosink");
5446 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5447 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5449 MMPLAYER_SIGNAL_CONNECT(player,
5450 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5451 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5453 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5456 MMPLAYER_SIGNAL_CONNECT(player,
5457 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5458 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5460 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5465 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5468 LOGD("disable last-sample");
5469 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5479 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5482 if (videobin[MMPLAYER_V_SINK].gst) {
5483 GstPad *sink_pad = NULL;
5484 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5486 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5487 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5488 gst_object_unref(GST_OBJECT(sink_pad));
5490 LOGW("failed to get sink pad from videosink\n");
5493 /* store it as it's sink element */
5494 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5496 /* adding created elements to bin */
5497 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5498 LOGE("failed to add elements\n");
5502 /* Linking elements in the bucket by added order */
5503 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5504 LOGE("failed to link elements\n");
5508 /* get first element's sinkpad for creating ghostpad */
5510 first_element = (MMPlayerGstElement *)element_bucket->data;
5511 if (!first_element) {
5512 LOGE("failed to get first element from bucket\n");
5516 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5518 LOGE("failed to get pad from first element\n");
5522 /* create ghostpad */
5523 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5524 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5525 LOGE("failed to add ghostpad to videobin\n");
5528 gst_object_unref(pad);
5530 /* done. free allocated variables */
5532 g_list_free(element_bucket);
5536 return MM_ERROR_NONE;
5539 LOGE("ERROR : releasing videobin\n");
5541 g_list_free(element_bucket);
5544 gst_object_unref(GST_OBJECT(pad));
5546 /* release videobin with it's childs */
5547 if (videobin[MMPLAYER_V_BIN].gst)
5548 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5551 MMPLAYER_FREEIF(videobin);
5553 player->pipeline->videobin = NULL;
5555 return MM_ERROR_PLAYER_INTERNAL;
5558 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5560 GList *element_bucket = NULL;
5561 MMPlayerGstElement *textbin = player->pipeline->textbin;
5563 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5564 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5565 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5566 "signal-handoffs", FALSE,
5569 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5570 MMPLAYER_SIGNAL_CONNECT(player,
5571 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5572 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5574 G_CALLBACK(__mmplayer_update_subtitle),
5577 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5578 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5579 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5581 if (!player->play_subtitle) {
5582 LOGD("add textbin sink as sink element of whole pipeline.\n");
5583 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5586 /* adding created elements to bin */
5587 LOGD("adding created elements to bin\n");
5588 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5589 LOGE("failed to add elements\n");
5593 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5594 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5595 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5597 /* linking elements in the bucket by added order. */
5598 LOGD("Linking elements in the bucket by added order.\n");
5599 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5600 LOGE("failed to link elements\n");
5604 /* done. free allocated variables */
5605 g_list_free(element_bucket);
5607 if (textbin[MMPLAYER_T_QUEUE].gst) {
5609 GstPad *ghostpad = NULL;
5611 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5613 LOGE("failed to get sink pad of text queue");
5617 ghostpad = gst_ghost_pad_new("text_sink", pad);
5618 gst_object_unref(pad);
5621 LOGE("failed to create ghostpad of textbin\n");
5625 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5626 LOGE("failed to add ghostpad to textbin\n");
5627 gst_object_unref(ghostpad);
5632 return MM_ERROR_NONE;
5635 g_list_free(element_bucket);
5637 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5638 LOGE("remove textbin sink from sink list");
5639 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5642 /* release element at __mmplayer_gst_create_text_sink_bin */
5643 return MM_ERROR_PLAYER_INTERNAL;
5646 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5648 MMPlayerGstElement *textbin = NULL;
5649 GList *element_bucket = NULL;
5650 int surface_type = 0;
5655 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5658 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5660 LOGE("failed to allocate memory for textbin\n");
5661 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5665 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5666 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5667 if (!textbin[MMPLAYER_T_BIN].gst) {
5668 LOGE("failed to create textbin\n");
5673 player->pipeline->textbin = textbin;
5676 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5677 LOGD("surface type for subtitle : %d", surface_type);
5678 switch (surface_type) {
5679 case MM_DISPLAY_SURFACE_OVERLAY:
5680 case MM_DISPLAY_SURFACE_NULL:
5681 case MM_DISPLAY_SURFACE_REMOTE:
5682 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5683 LOGE("failed to make plain text elements\n");
5694 return MM_ERROR_NONE;
5698 LOGD("ERROR : releasing textbin\n");
5700 g_list_free(element_bucket);
5702 /* release signal */
5703 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5705 /* release element which are not added to bin */
5706 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5707 /* NOTE : skip bin */
5708 if (textbin[i].gst) {
5709 GstObject* parent = NULL;
5710 parent = gst_element_get_parent(textbin[i].gst);
5713 gst_object_unref(GST_OBJECT(textbin[i].gst));
5714 textbin[i].gst = NULL;
5716 gst_object_unref(GST_OBJECT(parent));
5721 /* release textbin with it's childs */
5722 if (textbin[MMPLAYER_T_BIN].gst)
5723 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5725 MMPLAYER_FREEIF(player->pipeline->textbin);
5726 player->pipeline->textbin = NULL;
5729 return MM_ERROR_PLAYER_INTERNAL;
5734 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5736 MMPlayerGstElement* mainbin = NULL;
5737 MMPlayerGstElement* textbin = NULL;
5738 MMHandleType attrs = 0;
5739 GstElement *subsrc = NULL;
5740 GstElement *subparse = NULL;
5741 gchar *subtitle_uri = NULL;
5742 const gchar *charset = NULL;
5748 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5750 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5752 mainbin = player->pipeline->mainbin;
5754 attrs = MMPLAYER_GET_ATTRS(player);
5756 LOGE("cannot get content attribute\n");
5757 return MM_ERROR_PLAYER_INTERNAL;
5760 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5761 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5762 LOGE("subtitle uri is not proper filepath.\n");
5763 return MM_ERROR_PLAYER_INVALID_URI;
5766 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5767 LOGE("failed to get storage info of subtitle path");
5768 return MM_ERROR_PLAYER_INVALID_URI;
5771 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5773 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5774 player->subtitle_language_list = NULL;
5775 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5777 /* create the subtitle source */
5778 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5780 LOGE("failed to create filesrc element\n");
5783 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5785 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5786 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5788 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5789 LOGW("failed to add queue\n");
5790 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5791 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5792 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5797 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5799 LOGE("failed to create subparse element\n");
5803 charset = util_get_charset(subtitle_uri);
5805 LOGD("detected charset is %s\n", charset);
5806 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5809 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5810 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5812 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5813 LOGW("failed to add subparse\n");
5814 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5815 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5816 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5820 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5821 LOGW("failed to link subsrc and subparse\n");
5825 player->play_subtitle = TRUE;
5826 player->adjust_subtitle_pos = 0;
5828 LOGD("play subtitle using subtitle file\n");
5830 if (player->pipeline->textbin == NULL) {
5831 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5832 LOGE("failed to create text sink bin. continuing without text\n");
5836 textbin = player->pipeline->textbin;
5838 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5839 LOGW("failed to add textbin\n");
5841 /* release signal */
5842 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5844 /* release textbin with it's childs */
5845 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5846 MMPLAYER_FREEIF(player->pipeline->textbin);
5847 player->pipeline->textbin = textbin = NULL;
5851 LOGD("link text input selector and textbin ghost pad");
5853 player->textsink_linked = 1;
5854 player->external_text_idx = 0;
5855 LOGI("player->textsink_linked set to 1\n");
5857 textbin = player->pipeline->textbin;
5858 LOGD("text bin has been created. reuse it.");
5859 player->external_text_idx = 1;
5862 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5863 LOGW("failed to link subparse and textbin\n");
5867 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5869 LOGE("failed to get sink pad from textsink to probe data");
5873 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5874 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5876 gst_object_unref(pad);
5879 /* create dot. for debugging */
5880 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5883 return MM_ERROR_NONE;
5886 /* release text pipeline resource */
5887 player->textsink_linked = 0;
5889 /* release signal */
5890 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5892 if (player->pipeline->textbin) {
5893 LOGE("remove textbin");
5895 /* release textbin with it's childs */
5896 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5897 MMPLAYER_FREEIF(player->pipeline->textbin);
5898 player->pipeline->textbin = NULL;
5902 /* release subtitle elem */
5903 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5904 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5906 return MM_ERROR_PLAYER_INTERNAL;
5910 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5912 mm_player_t* player = (mm_player_t*) data;
5913 MMMessageParamType msg = {0, };
5914 GstClockTime duration = 0;
5915 gpointer text = NULL;
5916 guint text_size = 0;
5917 gboolean ret = TRUE;
5918 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5922 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5923 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5925 if (player->is_subtitle_force_drop) {
5926 LOGW("subtitle is dropped forcedly.");
5930 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5931 text = mapinfo.data;
5932 text_size = mapinfo.size;
5933 duration = GST_BUFFER_DURATION(buffer);
5935 if (player->set_mode.subtitle_off) {
5936 LOGD("subtitle is OFF.\n");
5940 if (!text || (text_size == 0)) {
5941 LOGD("There is no subtitle to be displayed.\n");
5945 msg.data = (void *) text;
5946 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5948 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5950 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5951 gst_buffer_unmap(buffer, &mapinfo);
5958 static GstPadProbeReturn
5959 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5961 mm_player_t *player = (mm_player_t *) u_data;
5962 GstClockTime cur_timestamp = 0;
5963 gint64 adjusted_timestamp = 0;
5964 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5966 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5968 if (player->set_mode.subtitle_off) {
5969 LOGD("subtitle is OFF.\n");
5973 if (player->adjust_subtitle_pos == 0) {
5974 LOGD("nothing to do");
5978 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5979 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5981 if (adjusted_timestamp < 0) {
5982 LOGD("adjusted_timestamp under zero");
5987 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5988 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5989 GST_TIME_ARGS(cur_timestamp),
5990 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5992 return GST_PAD_PROBE_OK;
5994 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5998 /* check player and subtitlebin are created */
5999 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6000 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6002 if (position == 0) {
6003 LOGD("nothing to do\n");
6005 return MM_ERROR_NONE;
6009 case MM_PLAYER_POS_FORMAT_TIME:
6011 /* check current postion */
6012 player->adjust_subtitle_pos = position;
6014 LOGD("save adjust_subtitle_pos in player") ;
6020 LOGW("invalid format.\n");
6022 return MM_ERROR_INVALID_ARGUMENT;
6028 return MM_ERROR_NONE;
6030 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6033 LOGD("adjusting video_pos in player") ;
6034 int current_pos = 0;
6035 /* check player and videobin are created */
6036 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6037 if (!player->pipeline->videobin ||
6038 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6039 LOGD("no video pipeline or sink is there");
6040 return MM_ERROR_PLAYER_INVALID_STATE ;
6043 LOGD("nothing to do\n");
6045 return MM_ERROR_NONE;
6047 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6048 LOGD("failed to get current position");
6049 return MM_ERROR_PLAYER_INTERNAL;
6051 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6052 LOGD("enter video delay is valid");
6054 LOGD("enter video delay is crossing content boundary");
6055 return MM_ERROR_INVALID_ARGUMENT ;
6057 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6058 LOGD("video delay has been done");
6061 return MM_ERROR_NONE;
6065 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6067 GstElement *appsrc = element;
6068 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6069 GstBuffer *buffer = NULL;
6070 GstFlowReturn ret = GST_FLOW_OK;
6073 MMPLAYER_RETURN_IF_FAIL(element);
6074 MMPLAYER_RETURN_IF_FAIL(buf);
6076 buffer = gst_buffer_new();
6078 if (buf->offset >= buf->len) {
6079 LOGD("call eos appsrc\n");
6080 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6084 if (buf->len - buf->offset < size)
6085 len = buf->len - buf->offset;
6087 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6088 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6089 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6091 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6092 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6098 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6100 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6102 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6104 buf->offset = (int)size;
6109 static GstBusSyncReply
6110 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6112 mm_player_t *player = (mm_player_t *)data;
6113 GstBusSyncReply reply = GST_BUS_DROP;
6115 if (!(player->pipeline && player->pipeline->mainbin)) {
6116 LOGE("player pipeline handle is null");
6117 return GST_BUS_PASS;
6120 if (!__mmplayer_check_useful_message(player, message)) {
6121 gst_message_unref(message);
6122 return GST_BUS_DROP;
6125 switch (GST_MESSAGE_TYPE(message)) {
6126 case GST_MESSAGE_STATE_CHANGED:
6127 /* post directly for fast launch */
6128 if (player->sync_handler) {
6129 __mmplayer_gst_callback(message, player);
6130 reply = GST_BUS_DROP;
6132 reply = GST_BUS_PASS;
6134 case GST_MESSAGE_TAG:
6135 __mmplayer_gst_extract_tag_from_msg(player, message);
6139 GstTagList *tags = NULL;
6141 gst_message_parse_tag(message, &tags);
6143 LOGE("TAGS received from element \"%s\".\n",
6144 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6146 gst_tag_list_foreach(tags, print_tag, NULL);
6147 gst_tag_list_free(tags);
6155 case GST_MESSAGE_DURATION_CHANGED:
6156 __mmplayer_gst_handle_duration(player, message);
6158 case GST_MESSAGE_ASYNC_DONE:
6159 /* NOTE:Don't call gst_callback directly
6160 * because previous frame can be showed even though this message is received for seek.
6163 reply = GST_BUS_PASS;
6167 if (reply == GST_BUS_DROP)
6168 gst_message_unref(message);
6174 __mmplayer_gst_create_decoder(mm_player_t *player,
6175 MMPlayerTrackType track,
6177 enum MainElementID elemId,
6180 gboolean ret = TRUE;
6181 GstPad *sinkpad = NULL;
6185 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6187 player->pipeline->mainbin, FALSE);
6188 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6189 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6190 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6192 GstElement *decodebin = NULL;
6193 GstCaps *dec_caps = NULL;
6195 /* create decodebin */
6196 decodebin = gst_element_factory_make("decodebin", name);
6199 LOGE("error : fail to create decodebin for %d decoder\n", track);
6204 /* raw pad handling signal */
6205 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6206 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6208 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6209 before looking for any elements that can handle that stream.*/
6210 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6211 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6213 /* This signal is emitted when a element is added to the bin.*/
6214 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6215 G_CALLBACK(__mmplayer_gst_element_added), player);
6217 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6218 LOGE("failed to add new decodebin\n");
6223 dec_caps = gst_pad_query_caps(srcpad, NULL);
6225 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6226 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6227 gst_caps_unref(dec_caps);
6230 player->pipeline->mainbin[elemId].id = elemId;
6231 player->pipeline->mainbin[elemId].gst = decodebin;
6233 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6235 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6236 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6237 gst_object_unref(GST_OBJECT(decodebin));
6240 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6241 LOGE("failed to sync second level decodebin state with parent\n");
6243 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6247 gst_object_unref(GST_OBJECT(sinkpad));
6256 * This function is to create audio or video pipeline for playing.
6258 * @param player [in] handle of player
6260 * @return This function returns zero on success.
6265 __mmplayer_gst_create_pipeline(mm_player_t* player)
6268 MMPlayerGstElement *mainbin = NULL;
6269 MMHandleType attrs = 0;
6270 GstElement* element = NULL;
6271 GstElement* elem_src_audio = NULL;
6272 GstElement* elem_src_subtitle = NULL;
6273 GstElement* es_video_queue = NULL;
6274 GstElement* es_audio_queue = NULL;
6275 GstElement* es_subtitle_queue = NULL;
6276 GList* element_bucket = NULL;
6277 gboolean need_state_holder = TRUE;
6279 #ifdef SW_CODEC_ONLY
6280 int surface_type = 0;
6284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6286 /* get profile attribute */
6287 attrs = MMPLAYER_GET_ATTRS(player);
6289 LOGE("cannot get content attribute\n");
6293 /* create pipeline handles */
6294 if (player->pipeline) {
6295 LOGW("pipeline should be released before create new one\n");
6299 player->video360_metadata.is_spherical = -1;
6300 player->is_openal_plugin_used = FALSE;
6302 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6303 if (player->pipeline == NULL)
6306 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6308 /* create mainbin */
6309 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6310 if (mainbin == NULL)
6313 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6315 /* create pipeline */
6316 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6317 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6318 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6319 LOGE("failed to create pipeline\n");
6322 player->demux_pad_index = 0;
6323 player->subtitle_language_list = NULL;
6325 player->is_subtitle_force_drop = FALSE;
6326 player->last_multiwin_status = FALSE;
6328 _mmplayer_track_initialize(player);
6329 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6331 /* create source element */
6332 switch (player->profile.uri_type) {
6333 /* rtsp streamming */
6334 case MM_PLAYER_URI_TYPE_URL_RTSP:
6338 element = gst_element_factory_make("rtspsrc", "rtsp source");
6341 LOGE("failed to create streaming source element\n");
6349 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6351 SECURE_LOGD("user_agent : %s\n", user_agent);
6353 /* setting property to streaming source */
6354 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6356 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6358 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6359 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6360 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6361 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6366 case MM_PLAYER_URI_TYPE_URL_HTTP:
6368 gchar *user_agent, *cookies, **cookie_list;
6369 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6370 user_agent = cookies = NULL;
6372 gint mode = MM_PLAYER_PD_MODE_NONE;
6374 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6376 player->pd_mode = mode;
6378 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6380 if (!MMPLAYER_IS_HTTP_PD(player)) {
6381 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6383 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6386 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6389 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6390 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6392 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6393 LOGD("get timeout from ini\n");
6394 http_timeout = player->ini.http_timeout;
6398 SECURE_LOGD("location : %s\n", player->profile.uri);
6399 SECURE_LOGD("cookies : %s\n", cookies);
6400 SECURE_LOGD("user_agent : %s\n", user_agent);
6401 LOGD("timeout : %d\n", http_timeout);
6403 /* setting property to streaming source */
6404 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6405 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6406 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6408 /* parsing cookies */
6409 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6410 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6411 g_strfreev(cookie_list);
6414 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6416 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6417 LOGW("it's dash. and it's still experimental feature.");
6419 // progressive download
6420 gchar* location = NULL;
6422 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6425 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6427 MMPLAYER_FREEIF(player->pd_file_save_path);
6429 LOGD("PD Location : %s\n", path);
6432 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6433 LOGE("failed to get storage info");
6436 player->pd_file_save_path = g_strdup(path);
6438 LOGE("can't find pd location so, it should be set \n");
6443 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6445 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6449 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6450 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6452 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6453 g_object_get(element, "location", &location, NULL);
6454 LOGD("PD_LOCATION [%s].\n", location);
6462 case MM_PLAYER_URI_TYPE_FILE:
6464 LOGD("using filesrc for 'file://' handler.\n");
6465 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6466 LOGE("failed to get storage info");
6470 element = gst_element_factory_make("filesrc", "source");
6472 LOGE("failed to create filesrc\n");
6476 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6480 case MM_PLAYER_URI_TYPE_SS:
6482 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6483 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6485 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6489 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6490 LOGD("get timeout from ini\n");
6491 http_timeout = player->ini.http_timeout;
6494 /* setting property to streaming source */
6495 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6496 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6499 case MM_PLAYER_URI_TYPE_MS_BUFF:
6501 LOGD("MS buff src is selected\n");
6503 if (player->v_stream_caps) {
6504 element = gst_element_factory_make("appsrc", "video_appsrc");
6506 LOGF("failed to create video app source element[appsrc].\n");
6510 if (player->a_stream_caps) {
6511 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6512 if (!elem_src_audio) {
6513 LOGF("failed to create audio app source element[appsrc].\n");
6517 } else if (player->a_stream_caps) {
6518 /* no video, only audio pipeline*/
6519 element = gst_element_factory_make("appsrc", "audio_appsrc");
6521 LOGF("failed to create audio app source element[appsrc].\n");
6526 if (player->s_stream_caps) {
6527 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6528 if (!elem_src_subtitle) {
6529 LOGF("failed to create subtitle app source element[appsrc].\n");
6534 LOGD("setting app sources properties.\n");
6535 LOGD("location : %s\n", player->profile.uri);
6537 if (player->v_stream_caps && element) {
6538 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6539 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6540 "caps", player->v_stream_caps, NULL);
6542 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6544 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6545 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6547 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6548 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6549 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6550 G_CALLBACK(__gst_seek_video_data), player);
6552 if (player->a_stream_caps && elem_src_audio) {
6553 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6554 "caps", player->a_stream_caps, NULL);
6556 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6559 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6561 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6562 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6563 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6564 G_CALLBACK(__gst_seek_audio_data), player);
6566 } else if (player->a_stream_caps && element) {
6567 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6568 "caps", player->a_stream_caps, NULL);
6570 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6572 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6573 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6575 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6576 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6577 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6578 G_CALLBACK(__gst_seek_audio_data), player);
6581 if (player->s_stream_caps && elem_src_subtitle) {
6582 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6583 "caps", player->s_stream_caps, NULL);
6585 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6587 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6588 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6590 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6592 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6593 G_CALLBACK(__gst_seek_subtitle_data), player);
6596 if (player->v_stream_caps && element) {
6597 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6599 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6600 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6602 if (player->a_stream_caps && elem_src_audio) {
6603 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6605 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6606 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6608 } else if (player->a_stream_caps && element) {
6609 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6611 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6612 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6615 if (player->s_stream_caps && elem_src_subtitle)
6616 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6617 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6619 need_state_holder = FALSE;
6621 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6622 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6623 LOGE("failed to commit\n");
6627 case MM_PLAYER_URI_TYPE_MEM:
6629 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6631 LOGD("mem src is selected\n");
6633 element = gst_element_factory_make("appsrc", "mem-source");
6635 LOGE("failed to create appsrc element\n");
6639 g_object_set(element, "stream-type", stream_type, NULL);
6640 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6641 g_object_set(element, "blocksize", (guint64)20480, NULL);
6643 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6644 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6645 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6646 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6649 case MM_PLAYER_URI_TYPE_URL:
6652 case MM_PLAYER_URI_TYPE_TEMP:
6655 case MM_PLAYER_URI_TYPE_NONE:
6660 /* check source element is OK */
6662 LOGE("no source element was created.\n");
6666 /* take source element */
6667 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6668 mainbin[MMPLAYER_M_SRC].gst = element;
6669 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6671 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6672 player->streamer = __mm_player_streaming_create();
6673 __mm_player_streaming_initialize(player->streamer);
6676 if (MMPLAYER_IS_HTTP_PD(player)) {
6677 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6679 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6680 element = gst_element_factory_make("queue2", "queue2");
6682 LOGE("failed to create http streaming buffer element\n");
6687 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6688 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6689 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6691 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6693 player->streamer->is_pd_mode = TRUE;
6695 __mm_player_streaming_set_queue2(player->streamer,
6698 player->ini.http_max_size_bytes + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6701 player->ini.http_buffering_limit,
6702 MUXED_BUFFER_TYPE_MEM_QUEUE,
6706 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6707 if (player->v_stream_caps) {
6708 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6709 if (!es_video_queue) {
6710 LOGE("create es_video_queue for es player failed\n");
6713 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6714 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6716 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6718 /* Adding audio appsrc to bucket */
6719 if (player->a_stream_caps && elem_src_audio) {
6720 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6721 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6722 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6724 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6725 if (!es_audio_queue) {
6726 LOGE("create es_audio_queue for es player failed\n");
6729 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6731 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6732 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6733 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6735 } else if (player->a_stream_caps) {
6736 /* Only audio stream, no video */
6737 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6738 if (!es_audio_queue) {
6739 LOGE("create es_audio_queue for es player failed\n");
6742 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6743 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6744 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6747 if (player->s_stream_caps && elem_src_subtitle) {
6748 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6749 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6750 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6752 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6753 if (!es_subtitle_queue) {
6754 LOGE("create es_subtitle_queue for es player failed\n");
6757 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6758 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6759 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6763 /* create autoplugging element if src element is not a rtsp src */
6764 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6765 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6767 enum MainElementID elemId = MMPLAYER_M_NUM;
6769 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6770 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6771 elemId = MMPLAYER_M_AUTOPLUG;
6772 element = __mmplayer_create_decodebin(player);
6774 /* default size of mq in decodebin is 2M
6775 * but it can cause blocking issue during seeking depends on content. */
6776 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6778 need_state_holder = FALSE;
6780 elemId = MMPLAYER_M_TYPEFIND;
6781 element = gst_element_factory_make("typefind", "typefinder");
6782 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6783 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6787 /* check autoplug element is OK */
6789 LOGE("can not create element(%d)\n", elemId);
6793 mainbin[elemId].id = elemId;
6794 mainbin[elemId].gst = element;
6796 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6799 /* add elements to pipeline */
6800 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6801 LOGE("Failed to add elements to pipeline\n");
6806 /* linking elements in the bucket by added order. */
6807 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6808 LOGE("Failed to link some elements\n");
6813 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6814 if (need_state_holder) {
6816 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6817 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6819 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6820 LOGE("fakesink element could not be created\n");
6823 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6825 /* take ownership of fakesink. we are reusing it */
6826 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6829 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6830 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6831 LOGE("failed to add fakesink to bin\n");
6836 /* now we have completed mainbin. take it */
6837 player->pipeline->mainbin = mainbin;
6839 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6840 GstPad *srcpad = NULL;
6842 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6843 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6845 __mmplayer_gst_create_decoder(player,
6846 MM_PLAYER_TRACK_TYPE_VIDEO,
6848 MMPLAYER_M_AUTOPLUG_V_DEC,
6851 gst_object_unref(GST_OBJECT(srcpad));
6856 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6857 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6859 __mmplayer_gst_create_decoder(player,
6860 MM_PLAYER_TRACK_TYPE_AUDIO,
6862 MMPLAYER_M_AUTOPLUG_A_DEC,
6865 gst_object_unref(GST_OBJECT(srcpad));
6870 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6871 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6874 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6875 if (__mmplayer_check_subtitle(player)) {
6876 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6877 LOGE("fail to create text pipeline");
6880 /* connect bus callback */
6881 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6883 LOGE("cannot get bus from pipeline.\n");
6887 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6889 player->context.thread_default = g_main_context_get_thread_default();
6891 if (player->context.thread_default == NULL) {
6892 player->context.thread_default = g_main_context_default();
6893 LOGD("thread-default context is the global default context");
6895 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6897 /* set sync handler to get tag synchronously */
6898 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6901 gst_object_unref(GST_OBJECT(bus));
6902 g_list_free(element_bucket);
6904 /* create gst bus_msb_cb thread */
6905 g_mutex_init(&player->bus_msg_thread_mutex);
6906 g_cond_init(&player->bus_msg_thread_cond);
6907 player->bus_msg_thread_exit = FALSE;
6908 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6909 player->bus_msg_thread =
6910 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6911 if (!player->bus_msg_thread) {
6912 LOGE("failed to create gst BUS msg thread");
6913 g_mutex_clear(&player->bus_msg_thread_mutex);
6914 g_cond_clear(&player->bus_msg_thread_cond);
6920 return MM_ERROR_NONE;
6923 __mmplayer_gst_destroy_pipeline(player);
6924 g_list_free(element_bucket);
6927 /* release element which are not added to bin */
6928 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6929 /* NOTE : skip pipeline */
6930 if (mainbin[i].gst) {
6931 GstObject* parent = NULL;
6932 parent = gst_element_get_parent(mainbin[i].gst);
6935 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6936 mainbin[i].gst = NULL;
6938 gst_object_unref(GST_OBJECT(parent));
6942 /* release pipeline with it's childs */
6943 if (mainbin[MMPLAYER_M_PIPE].gst)
6944 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6946 MMPLAYER_FREEIF(mainbin);
6949 MMPLAYER_FREEIF(player->pipeline);
6950 return MM_ERROR_PLAYER_INTERNAL;
6954 __mmplayer_reset_gapless_state(mm_player_t* player)
6957 MMPLAYER_RETURN_IF_FAIL(player
6959 && player->pipeline->audiobin
6960 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6962 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6969 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6972 int ret = MM_ERROR_NONE;
6976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6978 /* cleanup stuffs */
6979 MMPLAYER_FREEIF(player->type);
6980 player->have_dynamic_pad = FALSE;
6981 player->no_more_pad = FALSE;
6982 player->num_dynamic_pad = 0;
6983 player->demux_pad_index = 0;
6984 player->use_deinterleave = FALSE;
6985 player->max_audio_channels = 0;
6986 player->video_share_api_delta = 0;
6987 player->video_share_clock_delta = 0;
6988 player->video_hub_download_mode = 0;
6990 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6991 player->subtitle_language_list = NULL;
6992 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6994 __mmplayer_reset_gapless_state(player);
6996 if (player->streamer) {
6997 __mm_player_streaming_deinitialize(player->streamer);
6998 __mm_player_streaming_destroy(player->streamer);
6999 player->streamer = NULL;
7002 /* cleanup unlinked mime type */
7003 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7004 MMPLAYER_FREEIF(player->unlinked_video_mime);
7005 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7007 /* cleanup running stuffs */
7008 __mmplayer_cancel_eos_timer(player);
7010 /* cleanup gst stuffs */
7011 if (player->pipeline) {
7012 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7013 GstTagList* tag_list = player->pipeline->tag_list;
7015 /* first we need to disconnect all signal hander */
7016 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7018 if (player->bus_watcher)
7019 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7020 player->bus_watcher = 0;
7023 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7024 MMPlayerGstElement* videobin = player->pipeline->videobin;
7025 MMPlayerGstElement* textbin = player->pipeline->textbin;
7026 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7027 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7028 gst_object_unref(bus);
7030 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7031 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7032 if (ret != MM_ERROR_NONE) {
7033 LOGE("fail to change state to NULL\n");
7034 return MM_ERROR_PLAYER_INTERNAL;
7037 LOGW("succeeded in chaning state to NULL\n");
7039 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7042 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7043 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7045 /* free avsysaudiosink
7046 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7047 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7049 MMPLAYER_FREEIF(audiobin);
7050 MMPLAYER_FREEIF(videobin);
7051 MMPLAYER_FREEIF(textbin);
7052 MMPLAYER_FREEIF(mainbin);
7056 gst_tag_list_free(tag_list);
7058 MMPLAYER_FREEIF(player->pipeline);
7060 MMPLAYER_FREEIF(player->album_art);
7062 if (player->v_stream_caps) {
7063 gst_caps_unref(player->v_stream_caps);
7064 player->v_stream_caps = NULL;
7066 if (player->a_stream_caps) {
7067 gst_caps_unref(player->a_stream_caps);
7068 player->a_stream_caps = NULL;
7071 if (player->s_stream_caps) {
7072 gst_caps_unref(player->s_stream_caps);
7073 player->s_stream_caps = NULL;
7075 _mmplayer_track_destroy(player);
7077 if (player->sink_elements)
7078 g_list_free(player->sink_elements);
7079 player->sink_elements = NULL;
7081 if (player->bufmgr) {
7082 tbm_bufmgr_deinit(player->bufmgr);
7083 player->bufmgr = NULL;
7086 LOGW("finished destroy pipeline\n");
7093 static int __gst_realize(mm_player_t* player)
7096 int ret = MM_ERROR_NONE;
7100 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7102 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7104 ret = __mmplayer_gst_create_pipeline(player);
7106 LOGE("failed to create pipeline\n");
7110 /* set pipeline state to READY */
7111 /* NOTE : state change to READY must be performed sync. */
7112 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7113 ret = __mmplayer_gst_set_state(player,
7114 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7116 if (ret != MM_ERROR_NONE) {
7117 /* return error if failed to set state */
7118 LOGE("failed to set READY state");
7122 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7124 /* create dot before error-return. for debugging */
7125 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7132 static int __gst_unrealize(mm_player_t* player)
7134 int ret = MM_ERROR_NONE;
7138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7140 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7141 MMPLAYER_PRINT_STATE(player);
7143 /* release miscellaneous information */
7144 __mmplayer_release_misc(player);
7146 /* destroy pipeline */
7147 ret = __mmplayer_gst_destroy_pipeline(player);
7148 if (ret != MM_ERROR_NONE) {
7149 LOGE("failed to destory pipeline\n");
7153 /* release miscellaneous information.
7154 these info needs to be released after pipeline is destroyed. */
7155 __mmplayer_release_misc_post(player);
7157 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7164 static int __gst_pending_seek(mm_player_t* player)
7166 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7167 int ret = MM_ERROR_NONE;
7171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7173 if (!player->pending_seek.is_pending) {
7174 LOGD("pending seek is not reserved. nothing to do.\n");
7178 /* check player state if player could pending seek or not. */
7179 current_state = MMPLAYER_CURRENT_STATE(player);
7181 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7182 LOGW("try to pending seek in %s state, try next time. \n",
7183 MMPLAYER_STATE_GET_NAME(current_state));
7187 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7189 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7191 if (MM_ERROR_NONE != ret)
7192 LOGE("failed to seek pending postion. just keep staying current position.\n");
7194 player->pending_seek.is_pending = FALSE;
7201 static int __gst_start(mm_player_t* player)
7203 gboolean sound_extraction = 0;
7204 int ret = MM_ERROR_NONE;
7205 gboolean async = FALSE;
7209 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7211 /* get sound_extraction property */
7212 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7214 /* NOTE : if SetPosition was called before Start. do it now */
7215 /* streaming doesn't support it. so it should be always sync */
7216 /* !!create one more api to check if there is pending seek rather than checking variables */
7217 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7218 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7219 ret = __gst_pause(player, FALSE);
7220 if (ret != MM_ERROR_NONE) {
7221 LOGE("failed to set state to PAUSED for pending seek\n");
7225 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7227 if (sound_extraction) {
7228 LOGD("setting pcm extraction\n");
7230 ret = __mmplayer_set_pcm_extraction(player);
7231 if (MM_ERROR_NONE != ret) {
7232 LOGW("failed to set pcm extraction\n");
7236 if (MM_ERROR_NONE != __gst_pending_seek(player))
7237 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7241 LOGD("current state before doing transition");
7242 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7243 MMPLAYER_PRINT_STATE(player);
7245 /* set pipeline state to PLAYING */
7246 if (player->es_player_push_mode)
7248 /* set pipeline state to PLAYING */
7249 ret = __mmplayer_gst_set_state(player,
7250 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7252 if (ret == MM_ERROR_NONE) {
7253 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7255 LOGE("failed to set state to PLAYING");
7259 /* generating debug info before returning error */
7260 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7267 static int __gst_stop(mm_player_t* player)
7269 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7270 MMHandleType attrs = 0;
7271 gboolean rewind = FALSE;
7273 int ret = MM_ERROR_NONE;
7274 gboolean async = FALSE;
7278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7279 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7281 LOGD("current state before doing transition");
7282 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7283 MMPLAYER_PRINT_STATE(player);
7285 attrs = MMPLAYER_GET_ATTRS(player);
7287 LOGE("cannot get content attribute\n");
7288 return MM_ERROR_PLAYER_INTERNAL;
7291 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7292 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7294 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7295 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7298 if (player->es_player_push_mode)
7301 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7303 /* return if set_state has failed */
7304 if (ret != MM_ERROR_NONE) {
7305 LOGE("failed to set state.\n");
7311 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7312 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7313 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7314 LOGW("failed to rewind\n");
7315 ret = MM_ERROR_PLAYER_SEEK;
7320 player->sent_bos = FALSE;
7322 if (player->es_player_push_mode) //for cloudgame
7325 /* wait for seek to complete */
7326 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7327 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7328 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7330 LOGE("fail to stop player.\n");
7331 ret = MM_ERROR_PLAYER_INTERNAL;
7332 __mmplayer_dump_pipeline_state(player);
7335 /* generate dot file if enabled */
7336 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7343 int __gst_pause(mm_player_t* player, gboolean async)
7345 int ret = MM_ERROR_NONE;
7349 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7350 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7352 LOGD("current state before doing transition");
7353 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7354 MMPLAYER_PRINT_STATE(player);
7356 /* set pipeline status to PAUSED */
7357 ret = __mmplayer_gst_set_state(player,
7358 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7360 if (FALSE == async) {
7361 if (ret != MM_ERROR_NONE) {
7362 GstMessage *msg = NULL;
7363 GTimer *timer = NULL;
7364 gdouble MAX_TIMEOUT_SEC = 3;
7366 LOGE("failed to set state to PAUSED");
7368 if (player->msg_posted) {
7369 LOGE("error msg is already posted.");
7373 timer = g_timer_new();
7374 g_timer_start(timer);
7376 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7379 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7381 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7382 GError *error = NULL;
7384 /* parse error code */
7385 gst_message_parse_error(msg, &error, NULL);
7387 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7388 /* Note : the streaming error from the streaming source is handled
7389 * using __mmplayer_handle_streaming_error.
7391 __mmplayer_handle_streaming_error(player, msg);
7394 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7396 if (error->domain == GST_STREAM_ERROR)
7397 ret = __gst_handle_stream_error(player, error, msg);
7398 else if (error->domain == GST_RESOURCE_ERROR)
7399 ret = __gst_handle_resource_error(player, error->code, NULL);
7400 else if (error->domain == GST_LIBRARY_ERROR)
7401 ret = __gst_handle_library_error(player, error->code);
7402 else if (error->domain == GST_CORE_ERROR)
7403 ret = __gst_handle_core_error(player, error->code);
7405 g_error_free(error);
7407 player->msg_posted = TRUE;
7409 gst_message_unref(msg);
7411 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7413 gst_object_unref(bus);
7414 g_timer_stop(timer);
7415 g_timer_destroy(timer);
7419 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7420 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7422 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7424 } else if (ret == MM_ERROR_NONE) {
7426 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7430 /* generate dot file before returning error */
7431 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7438 int __gst_resume(mm_player_t* player, gboolean async)
7440 int ret = MM_ERROR_NONE;
7445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7446 MM_ERROR_PLAYER_NOT_INITIALIZED);
7448 LOGD("current state before doing transition");
7449 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7450 MMPLAYER_PRINT_STATE(player);
7452 /* generate dot file before returning error */
7453 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7456 LOGD("do async state transition to PLAYING.\n");
7458 /* set pipeline state to PLAYING */
7459 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7461 ret = __mmplayer_gst_set_state(player,
7462 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7463 if (ret != MM_ERROR_NONE) {
7464 LOGE("failed to set state to PLAYING\n");
7467 if (async == FALSE) {
7468 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7469 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7470 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7474 /* generate dot file before returning error */
7475 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7483 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7485 unsigned long dur_msec = 0;
7486 gint64 dur_nsec = 0;
7487 gint64 pos_nsec = 0;
7488 gboolean ret = TRUE;
7489 gboolean accurated = FALSE;
7490 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7494 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7496 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7497 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7500 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7501 /* check duration */
7502 /* NOTE : duration cannot be zero except live streaming.
7503 * Since some element could have some timing problemn with quering duration, try again.
7505 if (!player->duration) {
7506 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7507 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7508 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7509 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7510 player->pending_seek.is_pending = TRUE;
7511 player->pending_seek.format = format;
7512 player->pending_seek.pos = position;
7513 player->doing_seek = FALSE;
7514 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7515 return MM_ERROR_NONE;
7520 player->duration = dur_nsec;
7523 if (player->duration) {
7524 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7526 LOGE("could not get the duration. fail to seek.\n");
7530 LOGD("playback rate: %f\n", player->playback_rate);
7532 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7534 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7536 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7540 case MM_PLAYER_POS_FORMAT_TIME:
7542 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7543 GstQuery *query = NULL;
7544 gboolean seekable = FALSE;
7546 /* check position is valid or not */
7547 if (position > dur_msec)
7550 query = gst_query_new_seeking(GST_FORMAT_TIME);
7551 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7552 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7553 gst_query_unref(query);
7556 LOGW("non-seekable content");
7557 player->doing_seek = FALSE;
7558 return MM_ERROR_PLAYER_NO_OP;
7561 LOGW("failed to get seeking query");
7562 gst_query_unref(query); /* keep seeking operation */
7565 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7567 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7568 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7569 This causes problem is position calculation during normal pause resume scenarios also.
7570 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7571 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7572 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7573 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7574 LOGW("getting current position failed in seek\n");
7576 player->last_position = pos_nsec;
7577 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7580 if (player->doing_seek) {
7581 LOGD("not completed seek");
7582 return MM_ERROR_PLAYER_DOING_SEEK;
7586 if (!internal_called)
7587 player->doing_seek = TRUE;
7589 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7591 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7592 gint64 cur_time = 0;
7594 /* get current position */
7595 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7598 GstEvent *event = gst_event_new_seek(1.0,
7600 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7601 GST_SEEK_TYPE_SET, cur_time,
7602 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7604 __gst_send_event_to_sink(player, event);
7606 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7607 __gst_pause(player, FALSE);
7610 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7611 that's why set position through property. */
7612 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7613 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7614 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7615 (!player->videodec_linked) && (!player->audiodec_linked)) {
7617 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7618 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7619 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7620 player->doing_seek = FALSE;
7621 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7623 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7624 GST_FORMAT_TIME, seek_flags,
7625 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7629 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7635 case MM_PLAYER_POS_FORMAT_PERCENT:
7637 LOGD("seeking to(%lu)%% \n", position);
7639 if (player->doing_seek) {
7640 LOGD("not completed seek");
7641 return MM_ERROR_PLAYER_DOING_SEEK;
7644 if (!internal_called)
7645 player->doing_seek = TRUE;
7647 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7648 pos_nsec = (gint64)((position * player->duration) / 100);
7649 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7650 GST_FORMAT_TIME, seek_flags,
7651 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7653 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7663 /* NOTE : store last seeking point to overcome some bad operation
7664 * (returning zero when getting current position) of some elements
7666 player->last_position = pos_nsec;
7668 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7669 if (player->playback_rate > 1.0)
7670 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7673 return MM_ERROR_NONE;
7676 player->pending_seek.is_pending = TRUE;
7677 player->pending_seek.format = format;
7678 player->pending_seek.pos = position;
7680 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7681 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7683 return MM_ERROR_NONE;
7686 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7687 return MM_ERROR_INVALID_ARGUMENT;
7690 player->doing_seek = FALSE;
7691 return MM_ERROR_PLAYER_SEEK;
7694 #define TRICKPLAY_OFFSET GST_MSECOND
7697 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7699 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7700 gint64 pos_msec = 0;
7701 gboolean ret = TRUE;
7703 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7704 MM_ERROR_PLAYER_NOT_INITIALIZED);
7706 current_state = MMPLAYER_CURRENT_STATE(player);
7708 /* NOTE : query position except paused state to overcome some bad operation
7709 * please refer to below comments in details
7711 if (current_state != MM_PLAYER_STATE_PAUSED)
7712 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7714 /* NOTE : get last point to overcome some bad operation of some elements
7715 *(returning zero when getting current position in paused state
7716 * and when failed to get postion during seeking
7718 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7719 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7721 if (player->playback_rate < 0.0)
7722 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7724 pos_msec = player->last_position;
7727 pos_msec = player->last_position;
7729 player->last_position = pos_msec;
7731 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7734 if (player->duration > 0 && pos_msec > player->duration)
7735 pos_msec = player->duration;
7737 player->last_position = pos_msec;
7741 case MM_PLAYER_POS_FORMAT_TIME:
7742 *position = GST_TIME_AS_MSECONDS(pos_msec);
7745 case MM_PLAYER_POS_FORMAT_PERCENT:
7747 if (player->duration <= 0) {
7748 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7751 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7752 *position = pos_msec * 100 / player->duration;
7757 return MM_ERROR_PLAYER_INTERNAL;
7760 return MM_ERROR_NONE;
7764 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7766 #define STREAMING_IS_FINISHED 0
7767 #define BUFFERING_MAX_PER 100
7768 #define DEFAULT_PER_VALUE -1
7769 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7771 MMPlayerGstElement *mainbin = NULL;
7772 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7773 gint64 buffered_total = 0;
7774 unsigned long position = 0;
7775 gint buffered_sec = -1;
7776 GstBufferingMode mode = GST_BUFFERING_STREAM;
7777 gint64 content_size_time = player->duration;
7778 guint64 content_size_bytes = player->http_content_size;
7780 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7782 player->pipeline->mainbin,
7783 MM_ERROR_PLAYER_NOT_INITIALIZED);
7785 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7790 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7791 /* and rtsp is not ready yet. */
7792 LOGW("it's only used for http streaming case.\n");
7793 return MM_ERROR_PLAYER_NO_OP;
7796 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7797 LOGW("Time format is not supported yet.\n");
7798 return MM_ERROR_INVALID_ARGUMENT;
7801 if (content_size_time <= 0 || content_size_bytes <= 0) {
7802 LOGW("there is no content size.");
7803 return MM_ERROR_NONE;
7806 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7807 LOGW("fail to get current position.");
7808 return MM_ERROR_NONE;
7811 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7812 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7814 mainbin = player->pipeline->mainbin;
7815 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7817 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7818 GstQuery *query = NULL;
7819 gint byte_in_rate = 0, byte_out_rate = 0;
7820 gint64 estimated_total = 0;
7822 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7823 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7824 LOGW("fail to get buffering query from queue2");
7826 gst_query_unref(query);
7827 return MM_ERROR_NONE;
7830 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7831 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7833 if (mode == GST_BUFFERING_STREAM) {
7834 /* using only queue in case of push mode(ts / mp3) */
7835 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7836 GST_FORMAT_BYTES, &buffered_total)) {
7837 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7838 stop_per = 100 * buffered_total / content_size_bytes;
7841 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7843 guint num_of_ranges = 0;
7844 gint64 start_byte = 0, stop_byte = 0;
7846 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7847 if (estimated_total != STREAMING_IS_FINISHED) {
7848 /* buffered size info from queue2 */
7849 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7850 for (idx = 0; idx < num_of_ranges; idx++) {
7851 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7852 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7854 buffered_total += (stop_byte - start_byte);
7857 stop_per = BUFFERING_MAX_PER;
7859 gst_query_unref(query);
7862 if (stop_per == DEFAULT_PER_VALUE) {
7863 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7865 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7867 /* buffered size info from multiqueue */
7868 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7869 guint curr_size_bytes = 0;
7870 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7871 "curr-size-bytes", &curr_size_bytes, NULL);
7872 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7873 buffered_total += curr_size_bytes;
7876 if (avg_byterate > 0)
7877 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7878 else if (player->total_maximum_bitrate > 0)
7879 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7880 else if (player->total_bitrate > 0)
7881 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7883 if (buffered_sec >= 0)
7884 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7888 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7889 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7891 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7892 buffered_total, buffered_sec, *start_pos, *stop_pos);
7894 return MM_ERROR_NONE;
7898 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7903 LOGW("set_message_callback is called with invalid player handle\n");
7904 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7907 player->msg_cb = callback;
7908 player->msg_cb_param = user_param;
7910 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7914 return MM_ERROR_NONE;
7917 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7919 int ret = MM_ERROR_PLAYER_INVALID_URI;
7924 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7925 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7926 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7928 memset(data, 0, sizeof(MMPlayerParseProfile));
7930 if ((path = strstr(uri, "es_buff://"))) {
7932 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7933 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7934 ret = MM_ERROR_NONE;
7936 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7938 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7939 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7940 ret = MM_ERROR_NONE;
7942 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7945 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946 tmp = g_ascii_strdown(uri, strlen(uri));
7948 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7949 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7951 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7953 ret = MM_ERROR_NONE;
7956 } else if ((path = strstr(uri, "rtspu://"))) {
7958 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7959 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7960 ret = MM_ERROR_NONE;
7962 } else if ((path = strstr(uri, "rtspr://"))) {
7963 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7964 char *separater = strstr(path, "*");
7968 char *urgent = separater + strlen("*");
7970 if ((urgent_len = strlen(urgent))) {
7971 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7972 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7973 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7974 ret = MM_ERROR_NONE;
7977 } else if ((path = strstr(uri, "mms://"))) {
7979 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7980 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7981 ret = MM_ERROR_NONE;
7983 } else if ((path = strstr(uri, "mem://"))) {
7986 char *buffer = NULL;
7987 char *seperator = strchr(path, ',');
7988 char ext[100] = {0,}, size[100] = {0,};
7991 if ((buffer = strstr(path, "ext="))) {
7992 buffer += strlen("ext=");
7994 if (strlen(buffer)) {
7995 strncpy(ext, buffer, 99);
7997 if ((seperator = strchr(ext, ','))
7998 || (seperator = strchr(ext, ' '))
7999 || (seperator = strchr(ext, '\0'))) {
8000 seperator[0] = '\0';
8005 if ((buffer = strstr(path, "size="))) {
8006 buffer += strlen("size=");
8008 if (strlen(buffer) > 0) {
8009 strncpy(size, buffer, 99);
8011 if ((seperator = strchr(size, ','))
8012 || (seperator = strchr(size, ' '))
8013 || (seperator = strchr(size, '\0'))) {
8014 seperator[0] = '\0';
8017 mem_size = atoi(size);
8022 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8023 if (mem_size && param) {
8024 if (data->input_mem.buf)
8025 free(data->input_mem.buf);
8026 data->input_mem.buf = malloc(mem_size);
8028 if (data->input_mem.buf) {
8029 memcpy(data->input_mem.buf, param, mem_size);
8030 data->input_mem.len = mem_size;
8031 ret = MM_ERROR_NONE;
8033 LOGE("failed to alloc mem %d", mem_size);
8034 ret = MM_ERROR_PLAYER_INTERNAL;
8037 data->input_mem.offset = 0;
8038 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8042 gchar *location = NULL;
8045 if ((path = strstr(uri, "file://"))) {
8047 location = g_filename_from_uri(uri, NULL, &err);
8049 if (!location || (err != NULL)) {
8050 LOGE("Invalid URI '%s' for filesrc: %s", path,
8051 (err != NULL) ? err->message : "unknown error");
8053 if (err) g_error_free(err);
8054 if (location) g_free(location);
8056 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8060 LOGD("path from uri: %s", location);
8063 path = (location != NULL) ? (location) : ((char*)uri);
8064 int file_stat = MM_ERROR_NONE;
8066 file_stat = util_exist_file_path(path);
8068 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8069 if (file_stat == MM_ERROR_NONE) {
8070 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8072 if (util_is_sdp_file(path)) {
8073 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8074 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8076 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8078 ret = MM_ERROR_NONE;
8079 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8080 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8082 LOGE("invalid uri, could not play..\n");
8083 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8086 if (location) g_free(location);
8090 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8091 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8092 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8093 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8095 /* dump parse result */
8096 SECURE_LOGW("incomming uri : %s\n", uri);
8097 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8098 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8106 __mmplayer_can_do_interrupt(mm_player_t *player)
8108 if (!player || !player->pipeline || !player->attrs) {
8109 LOGW("not initialized");
8113 if (player->set_mode.pcm_extraction) {
8114 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8118 /* check if seeking */
8119 if (player->doing_seek) {
8120 MMMessageParamType msg_param;
8121 memset(&msg_param, 0, sizeof(MMMessageParamType));
8122 msg_param.code = MM_ERROR_PLAYER_SEEK;
8123 player->doing_seek = FALSE;
8124 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8128 /* check other thread */
8129 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8130 LOGW("locked already, cmd state : %d", player->cmd);
8132 /* check application command */
8133 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8134 LOGW("playing.. should wait cmd lock then, will be interrupted");
8136 /* lock will be released at mrp_resource_release_cb() */
8137 MMPLAYER_CMD_LOCK(player);
8140 LOGW("nothing to do");
8143 LOGW("can interrupt immediately");
8147 FAILED: /* with CMD UNLOCKED */
8150 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8155 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8158 mm_player_t *player = NULL;
8162 if (user_data == NULL) {
8163 LOGE("- user_data is null\n");
8166 player = (mm_player_t *)user_data;
8168 /* do something to release resource here.
8169 * player stop and interrupt forwarding */
8170 if (!__mmplayer_can_do_interrupt(player)) {
8171 LOGW("no need to interrupt, so leave");
8173 MMMessageParamType msg = {0, };
8174 unsigned long pos = 0;
8176 player->interrupted_by_resource = TRUE;
8178 /* get last play position */
8179 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8180 LOGW("failed to get play position.");
8182 msg.union_type = MM_MSG_UNION_TIME;
8183 msg.time.elapsed = (unsigned int)pos;
8184 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8186 LOGD("video resource conflict so, resource will be freed by unrealizing");
8187 if (_mmplayer_unrealize((MMHandleType)player))
8188 LOGW("failed to unrealize");
8190 /* lock is called in __mmplayer_can_do_interrupt() */
8191 MMPLAYER_CMD_UNLOCK(player);
8194 if (res == player->video_overlay_resource)
8195 player->video_overlay_resource = FALSE;
8197 player->video_decoder_resource = FALSE;
8205 _mmplayer_create_player(MMHandleType handle)
8207 int ret = MM_ERROR_PLAYER_INTERNAL;
8208 bool enabled = false;
8210 mm_player_t* player = MM_PLAYER_CAST(handle);
8214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8216 /* initialize player state */
8217 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8218 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8219 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8220 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8222 /* check current state */
8223 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8225 /* construct attributes */
8226 player->attrs = _mmplayer_construct_attribute(handle);
8228 if (!player->attrs) {
8229 LOGE("Failed to construct attributes\n");
8233 /* initialize gstreamer with configured parameter */
8234 if (!__mmplayer_init_gstreamer(player)) {
8235 LOGE("Initializing gstreamer failed\n");
8236 _mmplayer_deconstruct_attribute(handle);
8240 /* create lock. note that g_tread_init() has already called in gst_init() */
8241 g_mutex_init(&player->fsink_lock);
8243 /* create update tag lock */
8244 g_mutex_init(&player->update_tag_lock);
8246 /* create next play mutex */
8247 g_mutex_init(&player->next_play_thread_mutex);
8249 /* create next play cond */
8250 g_cond_init(&player->next_play_thread_cond);
8252 /* create next play thread */
8253 player->next_play_thread =
8254 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8255 if (!player->next_play_thread) {
8256 LOGE("failed to create next play thread");
8257 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8258 g_mutex_clear(&player->next_play_thread_mutex);
8259 g_cond_clear(&player->next_play_thread_cond);
8263 player->bus_msg_q = g_queue_new();
8264 if (!player->bus_msg_q) {
8265 LOGE("failed to create queue for bus_msg");
8266 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8270 ret = _mmplayer_initialize_video_capture(player);
8271 if (ret != MM_ERROR_NONE) {
8272 LOGE("failed to initialize video capture\n");
8276 /* initialize resource manager */
8277 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8278 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8279 &player->resource_manager)) {
8280 LOGE("failed to initialize resource manager\n");
8284 if (MMPLAYER_IS_HTTP_PD(player)) {
8285 player->pd_downloader = NULL;
8286 player->pd_file_save_path = NULL;
8289 /* create video bo lock and cond */
8290 g_mutex_init(&player->video_bo_mutex);
8291 g_cond_init(&player->video_bo_cond);
8293 /* create media stream callback mutex */
8294 g_mutex_init(&player->media_stream_cb_lock);
8296 /* create subtitle info lock and cond */
8297 g_mutex_init(&player->subtitle_info_mutex);
8298 g_cond_init(&player->subtitle_info_cond);
8300 player->streaming_type = STREAMING_SERVICE_NONE;
8302 /* give default value of audio effect setting */
8303 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8304 player->sound.rg_enable = false;
8305 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8307 player->play_subtitle = FALSE;
8308 player->use_deinterleave = FALSE;
8309 player->max_audio_channels = 0;
8310 player->video_share_api_delta = 0;
8311 player->video_share_clock_delta = 0;
8312 player->has_closed_caption = FALSE;
8313 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8314 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8315 player->pending_resume = FALSE;
8316 if (player->ini.dump_element_keyword[0][0] == '\0')
8317 player->ini.set_dump_element_flag = FALSE;
8319 player->ini.set_dump_element_flag = TRUE;
8321 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8322 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8323 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8325 /* Set video360 settings to their defaults for just-created player.
8328 player->is_360_feature_enabled = FALSE;
8329 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8330 LOGI("spherical feature info: %d", enabled);
8332 player->is_360_feature_enabled = TRUE;
8334 LOGE("failed to get spherical feature info");
8337 player->is_content_spherical = FALSE;
8338 player->is_video360_enabled = TRUE;
8339 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8340 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8341 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8342 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8343 player->video360_zoom = 1.0f;
8344 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8345 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8347 /* set player state to null */
8348 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8349 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8351 return MM_ERROR_NONE;
8355 g_mutex_clear(&player->fsink_lock);
8357 /* free update tag lock */
8358 g_mutex_clear(&player->update_tag_lock);
8360 g_queue_free(player->bus_msg_q);
8362 /* free next play thread */
8363 if (player->next_play_thread) {
8364 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8365 player->next_play_thread_exit = TRUE;
8366 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8367 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8369 g_thread_join(player->next_play_thread);
8370 player->next_play_thread = NULL;
8372 g_mutex_clear(&player->next_play_thread_mutex);
8373 g_cond_clear(&player->next_play_thread_cond);
8376 /* release attributes */
8377 _mmplayer_deconstruct_attribute(handle);
8385 __mmplayer_init_gstreamer(mm_player_t* player)
8387 static gboolean initialized = FALSE;
8388 static const int max_argc = 50;
8390 gchar** argv = NULL;
8391 gchar** argv2 = NULL;
8397 LOGD("gstreamer already initialized.\n");
8402 argc = malloc(sizeof(int));
8403 argv = malloc(sizeof(gchar*) * max_argc);
8404 argv2 = malloc(sizeof(gchar*) * max_argc);
8406 if (!argc || !argv || !argv2)
8409 memset(argv, 0, sizeof(gchar*) * max_argc);
8410 memset(argv2, 0, sizeof(gchar*) * max_argc);
8414 argv[0] = g_strdup("mmplayer");
8417 for (i = 0; i < 5; i++) {
8418 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8419 if (strlen(player->ini.gst_param[i]) > 0) {
8420 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8425 /* we would not do fork for scanning plugins */
8426 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8429 /* check disable registry scan */
8430 if (player->ini.skip_rescan) {
8431 argv[*argc] = g_strdup("--gst-disable-registry-update");
8435 /* check disable segtrap */
8436 if (player->ini.disable_segtrap) {
8437 argv[*argc] = g_strdup("--gst-disable-segtrap");
8441 LOGD("initializing gstreamer with following parameter\n");
8442 LOGD("argc : %d\n", *argc);
8445 for (i = 0; i < arg_count; i++) {
8447 LOGD("argv[%d] : %s\n", i, argv2[i]);
8450 /* initializing gstreamer */
8451 if (!gst_init_check(argc, &argv, &err)) {
8452 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8459 for (i = 0; i < arg_count; i++) {
8460 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8461 MMPLAYER_FREEIF(argv2[i]);
8464 MMPLAYER_FREEIF(argv);
8465 MMPLAYER_FREEIF(argv2);
8466 MMPLAYER_FREEIF(argc);
8476 for (i = 0; i < arg_count; i++) {
8477 LOGD("free[%d] : %s\n", i, argv2[i]);
8478 MMPLAYER_FREEIF(argv2[i]);
8481 MMPLAYER_FREEIF(argv);
8482 MMPLAYER_FREEIF(argv2);
8483 MMPLAYER_FREEIF(argc);
8489 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8491 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8493 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8494 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8495 MMPLAYER_FREEIF(player->pd_file_save_path);
8498 return MM_ERROR_NONE;
8502 __mmplayer_check_async_state_transition(mm_player_t* player)
8504 GstState element_state = GST_STATE_VOID_PENDING;
8505 GstState element_pending_state = GST_STATE_VOID_PENDING;
8506 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8507 GstElement * element = NULL;
8508 gboolean async = FALSE;
8510 /* check player handle */
8511 MMPLAYER_RETURN_IF_FAIL(player &&
8513 player->pipeline->mainbin &&
8514 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8517 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8519 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8520 LOGD("don't need to check the pipeline state");
8524 MMPLAYER_PRINT_STATE(player);
8526 /* wait for state transition */
8527 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8528 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8530 if (ret == GST_STATE_CHANGE_FAILURE) {
8531 LOGE(" [%s] state : %s pending : %s \n",
8532 GST_ELEMENT_NAME(element),
8533 gst_element_state_get_name(element_state),
8534 gst_element_state_get_name(element_pending_state));
8536 /* dump state of all element */
8537 __mmplayer_dump_pipeline_state(player);
8542 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8547 _mmplayer_destroy(MMHandleType handle)
8549 mm_player_t* player = MM_PLAYER_CAST(handle);
8553 /* check player handle */
8554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556 /* destroy can called at anytime */
8557 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8559 /* check async state transition */
8560 __mmplayer_check_async_state_transition(player);
8562 __mmplayer_destroy_streaming_ext(player);
8564 /* release next play thread */
8565 if (player->next_play_thread) {
8566 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8567 player->next_play_thread_exit = TRUE;
8568 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8569 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8571 LOGD("waitting for next play thread exit\n");
8572 g_thread_join(player->next_play_thread);
8573 g_mutex_clear(&player->next_play_thread_mutex);
8574 g_cond_clear(&player->next_play_thread_cond);
8575 LOGD("next play thread released\n");
8578 _mmplayer_release_video_capture(player);
8580 /* de-initialize resource manager */
8581 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8582 player->resource_manager))
8583 LOGE("failed to deinitialize resource manager\n");
8585 /* release pipeline */
8586 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8587 LOGE("failed to destory pipeline\n");
8588 return MM_ERROR_PLAYER_INTERNAL;
8591 g_queue_free(player->bus_msg_q);
8593 /* release subtitle info lock and cond */
8594 g_mutex_clear(&player->subtitle_info_mutex);
8595 g_cond_clear(&player->subtitle_info_cond);
8597 __mmplayer_release_dump_list(player->dump_list);
8599 /* release miscellaneous information */
8600 __mmplayer_release_misc(player);
8602 /* release miscellaneous information.
8603 these info needs to be released after pipeline is destroyed. */
8604 __mmplayer_release_misc_post(player);
8606 /* release attributes */
8607 _mmplayer_deconstruct_attribute(handle);
8610 g_mutex_clear(&player->fsink_lock);
8613 g_mutex_clear(&player->update_tag_lock);
8615 /* release video bo lock and cond */
8616 g_mutex_clear(&player->video_bo_mutex);
8617 g_cond_clear(&player->video_bo_cond);
8619 /* release media stream callback lock */
8620 g_mutex_clear(&player->media_stream_cb_lock);
8624 return MM_ERROR_NONE;
8628 __mmplayer_realize_streaming_ext(mm_player_t* player)
8630 int ret = MM_ERROR_NONE;
8633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8635 if (MMPLAYER_IS_HTTP_PD(player)) {
8636 gboolean bret = FALSE;
8638 player->pd_downloader = _mmplayer_create_pd_downloader();
8639 if (!player->pd_downloader) {
8640 LOGE("Unable to create PD Downloader...");
8641 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8644 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8646 if (FALSE == bret) {
8647 LOGE("Unable to create PD Downloader...");
8648 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8657 _mmplayer_realize(MMHandleType hplayer)
8659 mm_player_t* player = (mm_player_t*)hplayer;
8662 MMHandleType attrs = 0;
8663 int ret = MM_ERROR_NONE;
8667 /* check player handle */
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8670 /* check current state */
8671 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8673 attrs = MMPLAYER_GET_ATTRS(player);
8675 LOGE("fail to get attributes.\n");
8676 return MM_ERROR_PLAYER_INTERNAL;
8678 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8679 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8681 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8682 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8684 if (ret != MM_ERROR_NONE) {
8685 LOGE("failed to parse profile\n");
8690 if (uri && (strstr(uri, "es_buff://"))) {
8691 if (strstr(uri, "es_buff://push_mode"))
8692 player->es_player_push_mode = TRUE;
8694 player->es_player_push_mode = FALSE;
8697 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8698 LOGW("mms protocol is not supported format.\n");
8699 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8702 if (MMPLAYER_IS_STREAMING(player))
8703 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8705 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8707 player->smooth_streaming = FALSE;
8708 player->videodec_linked = 0;
8709 player->videosink_linked = 0;
8710 player->audiodec_linked = 0;
8711 player->audiosink_linked = 0;
8712 player->textsink_linked = 0;
8713 player->is_external_subtitle_present = FALSE;
8714 player->is_external_subtitle_added_now = FALSE;
8715 /* set the subtitle ON default */
8716 player->is_subtitle_off = FALSE;
8718 /* realize pipeline */
8719 ret = __gst_realize(player);
8720 if (ret != MM_ERROR_NONE)
8721 LOGE("fail to realize the player.\n");
8723 ret = __mmplayer_realize_streaming_ext(player);
8725 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8726 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8734 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8739 /* destroy can called at anytime */
8740 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8741 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8744 return MM_ERROR_NONE;
8748 _mmplayer_unrealize(MMHandleType hplayer)
8750 mm_player_t* player = (mm_player_t*)hplayer;
8751 int ret = MM_ERROR_NONE;
8755 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8757 MMPLAYER_CMD_UNLOCK(player);
8758 /* destroy the gst bus msg thread which is created during realize.
8759 this funct have to be called before getting cmd lock. */
8760 _mmplayer_bus_msg_thread_destroy(player);
8761 MMPLAYER_CMD_LOCK(player);
8763 /* check current state */
8764 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8766 /* check async state transition */
8767 __mmplayer_check_async_state_transition(player);
8769 __mmplayer_unrealize_streaming_ext(player);
8771 /* unrealize pipeline */
8772 ret = __gst_unrealize(player);
8774 /* set asm stop if success */
8775 if (MM_ERROR_NONE == ret) {
8776 if (!player->interrupted_by_resource) {
8777 if (player->video_decoder_resource != NULL) {
8778 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8779 player->video_decoder_resource);
8780 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8781 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8783 player->video_decoder_resource = NULL;
8786 if (player->video_overlay_resource != NULL) {
8787 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8788 player->video_overlay_resource);
8789 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8790 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8792 player->video_overlay_resource = NULL;
8795 ret = mm_resource_manager_commit(player->resource_manager);
8796 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8797 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8800 LOGE("failed and don't change asm state to stop");
8808 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8810 mm_player_t* player = (mm_player_t*)hplayer;
8812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8814 return __gst_set_message_callback(player, callback, user_param);
8818 _mmplayer_get_state(MMHandleType hplayer, int* state)
8820 mm_player_t *player = (mm_player_t*)hplayer;
8822 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8824 *state = MMPLAYER_CURRENT_STATE(player);
8826 return MM_ERROR_NONE;
8831 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8833 mm_player_t* player = (mm_player_t*) hplayer;
8834 GstElement* vol_element = NULL;
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8841 LOGD("volume [L]=%f:[R]=%f\n",
8842 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8844 /* invalid factor range or not */
8845 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8846 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8847 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8848 return MM_ERROR_INVALID_ARGUMENT;
8852 /* not support to set other value into each channel */
8853 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8854 return MM_ERROR_INVALID_ARGUMENT;
8856 /* Save volume to handle. Currently the first array element will be saved. */
8857 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8859 /* check pipeline handle */
8860 if (!player->pipeline || !player->pipeline->audiobin) {
8861 LOGD("audiobin is not created yet\n");
8862 LOGD("but, current stored volume will be set when it's created.\n");
8864 /* NOTE : stored volume will be used in create_audiobin
8865 * returning MM_ERROR_NONE here makes application to able to
8866 * set volume at anytime.
8868 return MM_ERROR_NONE;
8871 /* setting volume to volume element */
8872 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8875 LOGD("volume is set [%f]\n", player->sound.volume);
8876 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8881 return MM_ERROR_NONE;
8886 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8888 mm_player_t* player = (mm_player_t*) hplayer;
8893 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8894 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8896 /* returning stored volume */
8897 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8898 volume->level[i] = player->sound.volume;
8902 return MM_ERROR_NONE;
8906 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8908 mm_player_t* player = (mm_player_t*) hplayer;
8909 GstElement* vol_element = NULL;
8913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8915 /* mute value shoud 0 or 1 */
8916 if (mute != 0 && mute != 1) {
8917 LOGE("bad mute value\n");
8919 /* FIXIT : definitly, we need _BAD_PARAM error code */
8920 return MM_ERROR_INVALID_ARGUMENT;
8923 player->sound.mute = mute;
8925 /* just hold mute value if pipeline is not ready */
8926 if (!player->pipeline || !player->pipeline->audiobin) {
8927 LOGD("pipeline is not ready. holding mute value\n");
8928 return MM_ERROR_NONE;
8931 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8933 /* NOTE : volume will only created when the bt is enabled */
8935 LOGD("mute : %d\n", mute);
8936 g_object_set(vol_element, "mute", mute, NULL);
8938 LOGD("volume elemnet is not created. using volume in audiosink\n");
8942 return MM_ERROR_NONE;
8946 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8948 mm_player_t* player = (mm_player_t*) hplayer;
8952 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8953 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8955 /* just hold mute value if pipeline is not ready */
8956 if (!player->pipeline || !player->pipeline->audiobin) {
8957 LOGD("pipeline is not ready. returning stored value\n");
8958 *pmute = player->sound.mute;
8959 return MM_ERROR_NONE;
8962 *pmute = player->sound.mute;
8966 return MM_ERROR_NONE;
8970 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8972 mm_player_t* player = (mm_player_t*) hplayer;
8976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8978 player->video_stream_changed_cb = callback;
8979 player->video_stream_changed_cb_user_param = user_param;
8980 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8984 return MM_ERROR_NONE;
8988 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8990 mm_player_t* player = (mm_player_t*) hplayer;
8994 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8996 player->audio_stream_changed_cb = callback;
8997 player->audio_stream_changed_cb_user_param = user_param;
8998 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9002 return MM_ERROR_NONE;
9006 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9008 mm_player_t* player = (mm_player_t*) hplayer;
9012 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9014 player->audio_stream_render_cb_ex = callback;
9015 player->audio_stream_cb_user_param = user_param;
9016 player->audio_stream_sink_sync = sync;
9017 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);
9021 return MM_ERROR_NONE;
9025 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9027 mm_player_t* player = (mm_player_t*) hplayer;
9031 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9033 if (callback && !player->bufmgr)
9034 player->bufmgr = tbm_bufmgr_init(-1);
9036 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9037 player->video_stream_cb = callback;
9038 player->video_stream_cb_user_param = user_param;
9040 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9044 return MM_ERROR_NONE;
9048 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9050 mm_player_t* player = (mm_player_t*) hplayer;
9054 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9056 player->audio_stream_cb = callback;
9057 player->audio_stream_cb_user_param = user_param;
9058 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9062 return MM_ERROR_NONE;
9066 __mmplayer_start_streaming_ext(mm_player_t *player)
9068 gint ret = MM_ERROR_NONE;
9071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9073 if (MMPLAYER_IS_HTTP_PD(player)) {
9074 if (!player->pd_downloader) {
9075 ret = __mmplayer_realize_streaming_ext(player);
9077 if (ret != MM_ERROR_NONE) {
9078 LOGE("failed to realize streaming ext\n");
9083 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9084 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9086 LOGE("ERROR while starting PD...\n");
9087 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9089 ret = MM_ERROR_NONE;
9098 _mmplayer_start(MMHandleType hplayer)
9100 mm_player_t* player = (mm_player_t*) hplayer;
9101 gint ret = MM_ERROR_NONE;
9105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9107 /* check current state */
9108 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9110 /* NOTE : we should check and create pipeline again if not created as we destroy
9111 * whole pipeline when stopping in streamming playback
9113 if (!player->pipeline) {
9114 ret = __gst_realize(player);
9115 if (MM_ERROR_NONE != ret) {
9116 LOGE("failed to realize before starting. only in streamming\n");
9122 ret = __mmplayer_start_streaming_ext(player);
9123 if (ret != MM_ERROR_NONE) {
9124 LOGE("failed to start streaming ext 0x%X", ret);
9128 /* start pipeline */
9129 ret = __gst_start(player);
9130 if (ret != MM_ERROR_NONE)
9131 LOGE("failed to start player.\n");
9138 /* NOTE: post "not supported codec message" to application
9139 * when one codec is not found during AUTOPLUGGING in MSL.
9140 * So, it's separated with error of __mmplayer_gst_callback().
9141 * And, if any codec is not found, don't send message here.
9142 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9145 __mmplayer_handle_missed_plugin(mm_player_t* player)
9147 MMMessageParamType msg_param;
9148 memset(&msg_param, 0, sizeof(MMMessageParamType));
9149 gboolean post_msg_direct = FALSE;
9153 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9155 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9156 player->not_supported_codec, player->can_support_codec);
9158 if (player->not_found_demuxer) {
9159 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9160 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9162 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9163 MMPLAYER_FREEIF(msg_param.data);
9165 return MM_ERROR_NONE;
9168 if (player->not_supported_codec) {
9169 if (player->can_support_codec) {
9170 // There is one codec to play
9171 post_msg_direct = TRUE;
9173 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9174 post_msg_direct = TRUE;
9177 if (post_msg_direct) {
9178 MMMessageParamType msg_param;
9179 memset(&msg_param, 0, sizeof(MMMessageParamType));
9181 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9182 LOGW("not found AUDIO codec, posting error code to application.\n");
9184 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9185 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9186 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9187 LOGW("not found VIDEO codec, posting error code to application.\n");
9189 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9190 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9193 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9195 MMPLAYER_FREEIF(msg_param.data);
9197 return MM_ERROR_NONE;
9199 // no any supported codec case
9200 LOGW("not found any codec, posting error code to application.\n");
9202 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9203 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9204 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9206 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9207 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9210 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9212 MMPLAYER_FREEIF(msg_param.data);
9218 return MM_ERROR_NONE;
9221 static void __mmplayer_check_pipeline(mm_player_t* player)
9223 GstState element_state = GST_STATE_VOID_PENDING;
9224 GstState element_pending_state = GST_STATE_VOID_PENDING;
9226 int ret = MM_ERROR_NONE;
9228 if (player->gapless.reconfigure) {
9229 LOGW("pipeline is under construction.\n");
9231 MMPLAYER_PLAYBACK_LOCK(player);
9232 MMPLAYER_PLAYBACK_UNLOCK(player);
9234 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9236 /* wait for state transition */
9237 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9239 if (ret == GST_STATE_CHANGE_FAILURE)
9240 LOGE("failed to change pipeline state within %d sec\n", timeout);
9244 /* NOTE : it should be able to call 'stop' anytime*/
9246 _mmplayer_stop(MMHandleType hplayer)
9248 mm_player_t* player = (mm_player_t*)hplayer;
9249 int ret = MM_ERROR_NONE;
9253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9255 /* check current state */
9256 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9258 /* check pipline building state */
9259 __mmplayer_check_pipeline(player);
9260 __mmplayer_reset_gapless_state(player);
9262 /* NOTE : application should not wait for EOS after calling STOP */
9263 __mmplayer_cancel_eos_timer(player);
9265 __mmplayer_unrealize_streaming_ext(player);
9268 player->doing_seek = FALSE;
9271 ret = __gst_stop(player);
9273 if (ret != MM_ERROR_NONE)
9274 LOGE("failed to stop player.\n");
9282 _mmplayer_pause(MMHandleType hplayer)
9284 mm_player_t* player = (mm_player_t*)hplayer;
9285 gint64 pos_msec = 0;
9286 gboolean async = FALSE;
9287 gint ret = MM_ERROR_NONE;
9291 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9293 /* check current state */
9294 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9296 /* check pipline building state */
9297 __mmplayer_check_pipeline(player);
9299 switch (MMPLAYER_CURRENT_STATE(player)) {
9300 case MM_PLAYER_STATE_READY:
9302 /* check prepare async or not.
9303 * In the case of streaming playback, it's recommned to avoid blocking wait.
9305 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9306 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9308 /* Changing back sync of rtspsrc to async */
9309 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9310 LOGD("async prepare working mode for rtsp");
9316 case MM_PLAYER_STATE_PLAYING:
9318 /* NOTE : store current point to overcome some bad operation
9319 *(returning zero when getting current position in paused state) of some
9322 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9323 LOGW("getting current position failed in paused\n");
9325 player->last_position = pos_msec;
9327 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9328 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9329 This causes problem is position calculation during normal pause resume scenarios also.
9330 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9331 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9332 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9333 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9339 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9340 LOGD("doing async pause in case of ms buff src");
9344 /* pause pipeline */
9345 ret = __gst_pause(player, async);
9347 if (ret != MM_ERROR_NONE)
9348 LOGE("failed to pause player. ret : 0x%x\n", ret);
9350 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9351 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9352 LOGE("failed to update display_rotation");
9361 _mmplayer_resume(MMHandleType hplayer)
9363 mm_player_t* player = (mm_player_t*)hplayer;
9364 int ret = MM_ERROR_NONE;
9365 gboolean async = FALSE;
9369 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9371 /* Changing back sync mode rtspsrc to async */
9372 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9373 LOGD("async resume for rtsp case");
9377 /* check current state */
9378 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9380 ret = __gst_resume(player, async);
9382 if (ret != MM_ERROR_NONE)
9383 LOGE("failed to resume player.\n");
9391 __mmplayer_set_pcm_extraction(mm_player_t* player)
9393 gint64 start_nsec = 0;
9394 gint64 end_nsec = 0;
9395 gint64 dur_nsec = 0;
9396 gint64 dur_msec = 0;
9397 int required_start = 0;
9398 int required_end = 0;
9403 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9405 mm_attrs_multiple_get(player->attrs,
9407 "pcm_extraction_start_msec", &required_start,
9408 "pcm_extraction_end_msec", &required_end,
9411 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9413 if (required_start == 0 && required_end == 0) {
9414 LOGD("extracting entire stream");
9415 return MM_ERROR_NONE;
9416 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9417 LOGD("invalid range for pcm extraction");
9418 return MM_ERROR_INVALID_ARGUMENT;
9422 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9424 LOGE("failed to get duration");
9425 return MM_ERROR_PLAYER_INTERNAL;
9427 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9429 if (dur_msec < required_end) {
9431 LOGD("invalid end pos for pcm extraction");
9432 return MM_ERROR_INVALID_ARGUMENT;
9435 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9436 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9438 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9441 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9442 GST_SEEK_TYPE_SET, start_nsec,
9443 GST_SEEK_TYPE_SET, end_nsec))) {
9444 LOGE("failed to seek for pcm extraction\n");
9446 return MM_ERROR_PLAYER_SEEK;
9449 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9453 return MM_ERROR_NONE;
9457 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9459 mm_player_t* player = (mm_player_t*)hplayer;
9460 gint64 pos_msec = 0;
9461 int ret = MM_ERROR_NONE;
9463 signed long long start = 0, stop = 0;
9464 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9467 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9468 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9470 /* The sound of video is not supported under 0.0 and over 2.0. */
9471 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9472 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9475 _mmplayer_set_mute(hplayer, mute);
9477 if (player->playback_rate == rate)
9478 return MM_ERROR_NONE;
9480 /* If the position is reached at start potion during fast backward, EOS is posted.
9481 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9483 player->playback_rate = rate;
9485 current_state = MMPLAYER_CURRENT_STATE(player);
9487 if (current_state != MM_PLAYER_STATE_PAUSED)
9488 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9490 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9492 if ((current_state == MM_PLAYER_STATE_PAUSED)
9493 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9494 LOGW("returning last point : %lld\n", player->last_position);
9495 pos_msec = player->last_position;
9500 stop = GST_CLOCK_TIME_NONE;
9502 start = GST_CLOCK_TIME_NONE;
9506 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9507 player->playback_rate,
9509 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9510 GST_SEEK_TYPE_SET, start,
9511 GST_SEEK_TYPE_SET, stop)) {
9512 LOGE("failed to set speed playback\n");
9513 return MM_ERROR_PLAYER_SEEK;
9516 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9520 return MM_ERROR_NONE;;
9524 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9526 mm_player_t* player = (mm_player_t*)hplayer;
9527 int ret = MM_ERROR_NONE;
9531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9533 /* check pipline building state */
9534 __mmplayer_check_pipeline(player);
9536 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9544 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9546 mm_player_t* player = (mm_player_t*)hplayer;
9547 int ret = MM_ERROR_NONE;
9549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9551 ret = __gst_get_position(player, format, position);
9557 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9559 mm_player_t* player = (mm_player_t*)hplayer;
9560 int ret = MM_ERROR_NONE;
9562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9564 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9570 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9572 mm_player_t* player = (mm_player_t*)hplayer;
9573 int ret = MM_ERROR_NONE;
9577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9579 ret = __gst_adjust_subtitle_position(player, format, position);
9586 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9588 mm_player_t* player = (mm_player_t*)hplayer;
9589 int ret = MM_ERROR_NONE;
9593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9595 ret = __gst_adjust_video_position(player, offset);
9603 __mmplayer_is_midi_type(gchar* str_caps)
9605 if ((g_strrstr(str_caps, "audio/midi")) ||
9606 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9607 (g_strrstr(str_caps, "application/x-smaf")) ||
9608 (g_strrstr(str_caps, "audio/x-imelody")) ||
9609 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9610 (g_strrstr(str_caps, "audio/xmf")) ||
9611 (g_strrstr(str_caps, "audio/mxmf"))) {
9620 __mmplayer_is_only_mp3_type(gchar *str_caps)
9622 if (g_strrstr(str_caps, "application/x-id3") ||
9623 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9629 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9631 GstStructure* caps_structure = NULL;
9632 gint samplerate = 0;
9636 MMPLAYER_RETURN_IF_FAIL(player && caps);
9638 caps_structure = gst_caps_get_structure(caps, 0);
9640 /* set stream information */
9641 gst_structure_get_int(caps_structure, "rate", &samplerate);
9642 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9644 gst_structure_get_int(caps_structure, "channels", &channels);
9645 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9647 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9651 __mmplayer_update_content_type_info(mm_player_t* player)
9654 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9656 if (__mmplayer_is_midi_type(player->type)) {
9657 player->bypass_audio_effect = TRUE;
9658 } else if (g_strrstr(player->type, "application/x-hls")) {
9659 /* If it can't know exact type when it parses uri because of redirection case,
9660 * it will be fixed by typefinder or when doing autoplugging.
9662 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9663 if (player->streamer) {
9664 player->streamer->is_adaptive_streaming = TRUE;
9665 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9666 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9668 } else if (g_strrstr(player->type, "application/dash+xml")) {
9669 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9676 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9677 GstCaps *caps, gpointer data)
9679 mm_player_t* player = (mm_player_t*)data;
9684 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9686 /* store type string */
9687 MMPLAYER_FREEIF(player->type);
9688 player->type = gst_caps_to_string(caps);
9690 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9691 player, player->type, probability, gst_caps_get_size(caps));
9694 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9695 (g_strrstr(player->type, "audio/x-raw-int"))) {
9696 LOGE("not support media format\n");
9698 if (player->msg_posted == FALSE) {
9699 MMMessageParamType msg_param;
9700 memset(&msg_param, 0, sizeof(MMMessageParamType));
9702 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9703 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9705 /* don't post more if one was sent already */
9706 player->msg_posted = TRUE;
9711 __mmplayer_update_content_type_info(player);
9713 pad = gst_element_get_static_pad(tf, "src");
9715 LOGE("fail to get typefind src pad.\n");
9719 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9720 gboolean async = FALSE;
9721 LOGE("failed to autoplug %s\n", player->type);
9723 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9725 if (async && player->msg_posted == FALSE)
9726 __mmplayer_handle_missed_plugin(player);
9732 gst_object_unref(GST_OBJECT(pad));
9740 __mmplayer_create_decodebin(mm_player_t* player)
9742 GstElement *decodebin = NULL;
9746 /* create decodebin */
9747 decodebin = gst_element_factory_make("decodebin", NULL);
9750 LOGE("fail to create decodebin\n");
9754 /* raw pad handling signal */
9755 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9756 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9758 /* no-more-pad pad handling signal */
9759 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9760 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9762 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9763 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9765 /* This signal is emitted when a pad for which there is no further possible
9766 decoding is added to the decodebin.*/
9767 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9768 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9770 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9771 before looking for any elements that can handle that stream.*/
9772 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9773 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9775 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9776 before looking for any elements that can handle that stream.*/
9777 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9778 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9780 /* This signal is emitted once decodebin has finished decoding all the data.*/
9781 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9782 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9784 /* This signal is emitted when a element is added to the bin.*/
9785 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9786 G_CALLBACK(__mmplayer_gst_element_added), player);
9793 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9795 MMPlayerGstElement* mainbin = NULL;
9796 GstElement* decodebin = NULL;
9797 GstElement* queue2 = NULL;
9798 GstPad* sinkpad = NULL;
9799 GstPad* qsrcpad = NULL;
9800 gint64 dur_bytes = 0L;
9802 guint max_buffer_size_bytes = 0;
9803 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9806 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9808 mainbin = player->pipeline->mainbin;
9810 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9811 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9812 LOGD("creating http streaming buffering queue(queue2)\n");
9814 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9815 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9817 queue2 = gst_element_factory_make("queue2", "queue2");
9819 LOGE("failed to create buffering queue element\n");
9823 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9824 LOGE("failed to add buffering queue\n");
9828 sinkpad = gst_element_get_static_pad(queue2, "sink");
9829 qsrcpad = gst_element_get_static_pad(queue2, "src");
9831 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9832 LOGE("failed to link buffering queue\n");
9836 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9837 LOGE("fail to get duration.\n");
9839 LOGD("dur_bytes = %lld\n", dur_bytes);
9841 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9843 if (dur_bytes > 0) {
9844 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9845 type = MUXED_BUFFER_TYPE_FILE;
9847 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9848 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9854 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9855 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9856 if (!g_strrstr(player->type, "video/mpegts")) {
9857 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9858 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9860 // FIXME : pass ini setting directly. is this ok?
9861 __mm_player_streaming_set_queue2(player->streamer,
9864 max_buffer_size_bytes,
9865 player->ini.http_buffering_time,
9867 player->ini.http_buffering_limit, // no meaning
9869 player->http_file_buffering_path,
9870 (guint64)dur_bytes);
9873 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9874 LOGE("failed to sync queue2 state with parent\n");
9880 gst_object_unref(GST_OBJECT(sinkpad));
9882 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9883 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9887 /* create decodebin */
9888 decodebin = __mmplayer_create_decodebin(player);
9891 LOGE("can not create autoplug element\n");
9895 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9896 LOGE("failed to add decodebin\n");
9900 /* to force caps on the decodebin element and avoid reparsing stuff by
9901 * typefind. It also avoids a deadlock in the way typefind activates pads in
9902 * the state change */
9903 g_object_set(decodebin, "sink-caps", caps, NULL);
9905 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9907 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9908 LOGE("failed to link decodebin\n");
9912 gst_object_unref(GST_OBJECT(sinkpad));
9914 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9915 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9917 /* set decodebin property about buffer in streaming playback. *
9918 * in case of HLS/DASH, it does not need to have big buffer *
9919 * because it is kind of adaptive streaming. */
9920 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9921 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9922 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9923 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9925 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9926 || MMPLAYER_IS_DASH_STREAMING(player)) {
9927 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9928 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9931 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9932 "high-percent", (gint)player->ini.http_buffering_limit,
9933 "low-percent", 1, // 1%
9934 "max-size-bytes", max_size_bytes,
9935 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9936 "max-size-buffers", 0, NULL); // disable or automatic
9939 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9940 LOGE("failed to sync decodebin state with parent\n");
9951 gst_object_unref(GST_OBJECT(sinkpad));
9954 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9955 * You need to explicitly set elements to the NULL state before
9956 * dropping the final reference, to allow them to clean up.
9958 gst_element_set_state(queue2, GST_STATE_NULL);
9960 /* And, it still has a parent "player".
9961 * You need to let the parent manage the object instead of unreffing the object directly.
9963 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9964 gst_object_unref(queue2);
9969 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9970 * You need to explicitly set elements to the NULL state before
9971 * dropping the final reference, to allow them to clean up.
9973 gst_element_set_state(decodebin, GST_STATE_NULL);
9975 /* And, it still has a parent "player".
9976 * You need to let the parent manage the object instead of unreffing the object directly.
9979 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9980 gst_object_unref(decodebin);
9988 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9992 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9993 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9995 LOGD("class : %s, mime : %s \n", factory_class, mime);
9997 /* add missing plugin */
9998 /* NOTE : msl should check missing plugin for image mime type.
9999 * Some motion jpeg clips can have playable audio track.
10000 * So, msl have to play audio after displaying popup written video format not supported.
10002 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10003 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10004 LOGD("not found demuxer\n");
10005 player->not_found_demuxer = TRUE;
10006 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10012 if (!g_strrstr(factory_class, "Demuxer")) {
10013 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10014 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10015 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10017 /* check that clip have multi tracks or not */
10018 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10019 LOGD("video plugin is already linked\n");
10021 LOGW("add VIDEO to missing plugin\n");
10022 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10023 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10025 } else if (g_str_has_prefix(mime, "audio")) {
10026 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10027 LOGD("audio plugin is already linked\n");
10029 LOGW("add AUDIO to missing plugin\n");
10030 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10031 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10039 return MM_ERROR_NONE;
10044 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10046 mm_player_t* player = (mm_player_t*)data;
10050 MMPLAYER_RETURN_IF_FAIL(player);
10052 /* remove fakesink. */
10053 if (!__mmplayer_gst_remove_fakesink(player,
10054 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10055 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10056 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10057 * source element are not same. To overcome this situation, this function will called
10058 * several places and several times. Therefore, this is not an error case.
10063 LOGD("[handle: %p] pipeline has completely constructed", player);
10065 if ((player->ini.async_start) &&
10066 (player->msg_posted == FALSE) &&
10067 (player->cmd >= MMPLAYER_COMMAND_START))
10068 __mmplayer_handle_missed_plugin(player);
10070 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10074 __mmplayer_verify_next_play_path(mm_player_t *player)
10076 MMHandleType attrs = 0;
10077 MMPlayerParseProfile profile;
10078 gint uri_idx = 0, check_cnt = 0;
10080 gint mode = MM_PLAYER_PD_MODE_NONE;
10084 guint num_of_list = 0;
10085 static int profile_tv = -1;
10089 LOGD("checking for gapless play");
10091 if (player->pipeline->textbin) {
10092 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10096 attrs = MMPLAYER_GET_ATTRS(player);
10098 LOGE("fail to get attributes.\n");
10102 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10104 if (__builtin_expect(profile_tv == -1, 0)) {
10106 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10107 switch (*profileName) {
10117 /* gapless playback is not supported in case of video at TV profile. */
10118 if (profile_tv && video) {
10119 LOGW("not support video gapless playback");
10123 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10124 if (mode == TRUE) {
10130 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10131 LOGE("can not get play count\n");
10133 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10134 LOGE("can not get gapless mode\n");
10136 if (video && !gapless) {
10137 LOGW("not enabled video gapless playback");
10141 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10145 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10149 num_of_list = g_list_length(player->uri_info.uri_list);
10151 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10153 if (num_of_list == 0) {
10154 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10155 LOGE("can not get profile_uri\n");
10160 LOGE("uri list is empty.\n");
10164 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10165 LOGD("add original path : %s ", uri);
10171 uri_idx = player->uri_info.uri_idx;
10176 if (check_cnt > num_of_list) {
10177 LOGE("there is no valid uri.");
10181 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10183 if (uri_idx < num_of_list-1) {
10186 if ((count <= 1) && (count != -1)) {
10187 LOGD("no repeat.");
10189 } else if (count > 1) {
10190 /* decrease play count */
10191 /* we succeeded to rewind. update play count and then wait for next EOS */
10194 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10196 /* commit attribute */
10197 if (mmf_attrs_commit(attrs))
10198 LOGE("failed to commit attribute\n");
10201 /* count < 0 : repeat continually */
10205 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10206 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10209 LOGW("next uri does not exist\n");
10213 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10214 LOGE("failed to parse profile\n");
10218 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10219 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10220 LOGW("uri type is not supported(%d).", profile.uri_type);
10227 player->uri_info.uri_idx = uri_idx;
10228 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10230 if (mmf_attrs_commit(player->attrs)) {
10231 LOGE("failed to commit.\n");
10235 LOGD("next uri %s(%d)\n", uri, uri_idx);
10241 LOGE("unable to play next path. EOS will be posted soon.\n");
10246 __mmplayer_initialize_next_play(mm_player_t *player)
10252 player->smooth_streaming = FALSE;
10253 player->videodec_linked = 0;
10254 player->audiodec_linked = 0;
10255 player->videosink_linked = 0;
10256 player->audiosink_linked = 0;
10257 player->textsink_linked = 0;
10258 player->is_external_subtitle_present = FALSE;
10259 player->is_external_subtitle_added_now = FALSE;
10260 player->not_supported_codec = MISSING_PLUGIN_NONE;
10261 player->can_support_codec = FOUND_PLUGIN_NONE;
10262 player->pending_seek.is_pending = FALSE;
10263 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10264 player->pending_seek.pos = 0;
10265 player->msg_posted = FALSE;
10266 player->has_many_types = FALSE;
10267 player->no_more_pad = FALSE;
10268 player->not_found_demuxer = 0;
10269 player->doing_seek = FALSE;
10270 player->max_audio_channels = 0;
10271 player->is_subtitle_force_drop = FALSE;
10272 player->play_subtitle = FALSE;
10273 player->adjust_subtitle_pos = 0;
10275 player->total_bitrate = 0;
10276 player->total_maximum_bitrate = 0;
10278 _mmplayer_track_initialize(player);
10279 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10281 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10282 player->bitrate[i] = 0;
10283 player->maximum_bitrate[i] = 0;
10286 if (player->v_stream_caps) {
10287 gst_caps_unref(player->v_stream_caps);
10288 player->v_stream_caps = NULL;
10291 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10293 /* clean found parsers */
10294 if (player->parsers) {
10295 GList *parsers = player->parsers;
10296 for (; parsers; parsers = g_list_next(parsers)) {
10297 gchar *name = parsers->data;
10298 MMPLAYER_FREEIF(name);
10300 g_list_free(player->parsers);
10301 player->parsers = NULL;
10304 /* clean found audio decoders */
10305 if (player->audio_decoders) {
10306 GList *a_dec = player->audio_decoders;
10307 for (; a_dec; a_dec = g_list_next(a_dec)) {
10308 gchar *name = a_dec->data;
10309 MMPLAYER_FREEIF(name);
10311 g_list_free(player->audio_decoders);
10312 player->audio_decoders = NULL;
10319 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10321 MMPlayerGstElement *mainbin = NULL;
10322 MMMessageParamType msg_param = {0,};
10323 GstElement *element = NULL;
10324 MMHandleType attrs = 0;
10326 enum MainElementID elemId = MMPLAYER_M_NUM;
10330 if ((player == NULL) ||
10331 (player->pipeline == NULL) ||
10332 (player->pipeline->mainbin == NULL)) {
10333 LOGE("player is null.\n");
10337 mainbin = player->pipeline->mainbin;
10338 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10340 attrs = MMPLAYER_GET_ATTRS(player);
10342 LOGE("fail to get attributes.\n");
10346 /* Initialize Player values */
10347 __mmplayer_initialize_next_play(player);
10349 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10351 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10352 LOGE("failed to parse profile\n");
10353 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10357 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10358 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10359 LOGE("it's dash or hls. not support.");
10360 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10365 switch (player->profile.uri_type) {
10367 case MM_PLAYER_URI_TYPE_FILE:
10369 LOGD("using filesrc for 'file://' handler.\n");
10370 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10371 LOGE("failed to get storage info");
10375 element = gst_element_factory_make("filesrc", "source");
10378 LOGE("failed to create filesrc\n");
10382 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10385 case MM_PLAYER_URI_TYPE_URL_HTTP:
10387 gchar *user_agent, *cookies, **cookie_list;
10388 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10389 user_agent = cookies = NULL;
10390 cookie_list = NULL;
10392 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10394 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10397 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10399 /* get attribute */
10400 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10401 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10403 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10404 LOGD("get timeout from ini\n");
10405 http_timeout = player->ini.http_timeout;
10408 /* get attribute */
10409 SECURE_LOGD("location : %s\n", player->profile.uri);
10410 SECURE_LOGD("cookies : %s\n", cookies);
10411 SECURE_LOGD("user_agent : %s\n", user_agent);
10412 LOGD("timeout : %d\n", http_timeout);
10414 /* setting property to streaming source */
10415 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10416 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10417 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10419 /* parsing cookies */
10420 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10421 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10423 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10427 LOGE("not support uri type %d\n", player->profile.uri_type);
10432 LOGE("no source element was created.\n");
10436 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10437 LOGE("failed to add source element to pipeline\n");
10438 gst_object_unref(GST_OBJECT(element));
10443 /* take source element */
10444 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10445 mainbin[MMPLAYER_M_SRC].gst = element;
10449 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10450 if (player->streamer == NULL) {
10451 player->streamer = __mm_player_streaming_create();
10452 __mm_player_streaming_initialize(player->streamer);
10455 elemId = MMPLAYER_M_TYPEFIND;
10456 element = gst_element_factory_make("typefind", "typefinder");
10457 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10458 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10460 elemId = MMPLAYER_M_AUTOPLUG;
10461 element = __mmplayer_create_decodebin(player);
10464 /* check autoplug element is OK */
10466 LOGE("can not create element(%d)\n", elemId);
10470 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10471 LOGE("failed to add sinkbin to pipeline\n");
10472 gst_object_unref(GST_OBJECT(element));
10477 mainbin[elemId].id = elemId;
10478 mainbin[elemId].gst = element;
10480 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10481 LOGE("Failed to link src - autoplug(or typefind)\n");
10485 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10486 LOGE("Failed to change state of src element\n");
10490 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10491 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10492 LOGE("Failed to change state of decodebin\n");
10496 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10497 LOGE("Failed to change state of src element\n");
10502 player->gapless.stream_changed = TRUE;
10503 player->gapless.running = TRUE;
10509 MMPLAYER_PLAYBACK_UNLOCK(player);
10511 if (!player->msg_posted) {
10512 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10513 player->msg_posted = TRUE;
10520 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10522 mm_player_selector_t *selector = &player->selector[type];
10523 MMPlayerGstElement *sinkbin = NULL;
10524 enum MainElementID selectorId = MMPLAYER_M_NUM;
10525 enum MainElementID sinkId = MMPLAYER_M_NUM;
10526 GstPad *srcpad = NULL;
10527 GstPad *sinkpad = NULL;
10528 gboolean send_notice = FALSE;
10531 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10533 LOGD("type %d", type);
10536 case MM_PLAYER_TRACK_TYPE_AUDIO:
10537 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10538 sinkId = MMPLAYER_A_BIN;
10539 sinkbin = player->pipeline->audiobin;
10541 case MM_PLAYER_TRACK_TYPE_VIDEO:
10542 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10543 sinkId = MMPLAYER_V_BIN;
10544 sinkbin = player->pipeline->videobin;
10545 send_notice = TRUE;
10547 case MM_PLAYER_TRACK_TYPE_TEXT:
10548 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10549 sinkId = MMPLAYER_T_BIN;
10550 sinkbin = player->pipeline->textbin;
10553 LOGE("requested type is not supportable");
10558 if (player->pipeline->mainbin[selectorId].gst) {
10561 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10563 if (selector->event_probe_id != 0)
10564 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10565 selector->event_probe_id = 0;
10567 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10568 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10570 if (srcpad && sinkpad) {
10571 /* after getting drained signal there is no data flows, so no need to do pad_block */
10572 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10573 gst_pad_unlink(srcpad, sinkpad);
10575 /* send custom event to sink pad to handle it at video sink */
10577 LOGD("send custom event to sinkpad");
10578 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10579 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10580 gst_pad_send_event(sinkpad, event);
10584 gst_object_unref(sinkpad);
10587 gst_object_unref(srcpad);
10590 LOGD("selector release");
10592 /* release and unref requests pad from the selector */
10593 for (n = 0; n < selector->channels->len; n++) {
10594 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10595 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10597 g_ptr_array_set_size(selector->channels, 0);
10599 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10600 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10602 player->pipeline->mainbin[selectorId].gst = NULL;
10610 __mmplayer_deactivate_old_path(mm_player_t *player)
10613 MMPLAYER_RETURN_IF_FAIL(player);
10615 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10616 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10617 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10618 LOGE("deactivate selector error");
10622 _mmplayer_track_destroy(player);
10623 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10625 if (player->streamer) {
10626 __mm_player_streaming_deinitialize(player->streamer);
10627 __mm_player_streaming_destroy(player->streamer);
10628 player->streamer = NULL;
10631 MMPLAYER_PLAYBACK_LOCK(player);
10632 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10639 if (!player->msg_posted) {
10640 MMMessageParamType msg = {0,};
10643 msg.code = MM_ERROR_PLAYER_INTERNAL;
10644 LOGE("next_uri_play> deactivate error");
10646 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10647 player->msg_posted = TRUE;
10652 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10654 int result = MM_ERROR_NONE;
10655 mm_player_t* player = (mm_player_t*) hplayer;
10658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10661 player->http_file_buffering_path = (gchar*)file_path;
10662 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10668 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10670 int result = MM_ERROR_NONE;
10671 mm_player_t* player = (mm_player_t*) hplayer;
10674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10676 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10677 if (mmf_attrs_commit(player->attrs)) {
10678 LOGE("failed to commit the original uri.\n");
10679 result = MM_ERROR_PLAYER_INTERNAL;
10681 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10682 LOGE("failed to add the original uri in the uri list.\n");
10689 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10691 mm_player_t* player = (mm_player_t*) hplayer;
10692 guint num_of_list = 0;
10696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10697 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10699 if (player->pipeline && player->pipeline->textbin) {
10700 LOGE("subtitle path is enabled.\n");
10701 return MM_ERROR_PLAYER_INVALID_STATE;
10704 num_of_list = g_list_length(player->uri_info.uri_list);
10706 if (is_first_path == TRUE) {
10707 if (num_of_list == 0) {
10708 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10709 LOGD("add original path : %s", uri);
10711 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10712 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10714 LOGD("change original path : %s", uri);
10717 MMHandleType attrs = 0;
10718 attrs = MMPLAYER_GET_ATTRS(player);
10720 if (num_of_list == 0) {
10721 char *original_uri = NULL;
10724 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10726 if (!original_uri) {
10727 LOGE("there is no original uri.");
10728 return MM_ERROR_PLAYER_INVALID_STATE;
10731 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10732 player->uri_info.uri_idx = 0;
10734 LOGD("add original path at first : %s(%d)", original_uri);
10738 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10739 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10743 return MM_ERROR_NONE;
10746 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10748 mm_player_t* player = (mm_player_t*) hplayer;
10749 char *next_uri = NULL;
10750 guint num_of_list = 0;
10753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10755 num_of_list = g_list_length(player->uri_info.uri_list);
10757 if (num_of_list > 0) {
10758 gint uri_idx = player->uri_info.uri_idx;
10760 if (uri_idx < num_of_list-1)
10765 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10766 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10768 *uri = g_strdup(next_uri);
10772 return MM_ERROR_NONE;
10776 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10777 GstCaps *caps, gpointer data)
10779 mm_player_t* player = (mm_player_t*)data;
10780 const gchar* klass = NULL;
10781 const gchar* mime = NULL;
10782 gchar* caps_str = NULL;
10784 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10785 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10786 caps_str = gst_caps_to_string(caps);
10788 LOGW("unknown type of caps : %s from %s",
10789 caps_str, GST_ELEMENT_NAME(elem));
10791 MMPLAYER_FREEIF(caps_str);
10793 /* There is no available codec. */
10794 __mmplayer_check_not_supported_codec(player, klass, mime);
10798 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10799 GstCaps * caps, gpointer data)
10801 mm_player_t* player = (mm_player_t*)data;
10802 const char* mime = NULL;
10803 gboolean ret = TRUE;
10805 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10806 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10808 if (g_str_has_prefix(mime, "audio")) {
10809 GstStructure* caps_structure = NULL;
10810 gint samplerate = 0;
10812 gchar *caps_str = NULL;
10814 caps_structure = gst_caps_get_structure(caps, 0);
10815 gst_structure_get_int(caps_structure, "rate", &samplerate);
10816 gst_structure_get_int(caps_structure, "channels", &channels);
10818 if ((channels > 0 && samplerate == 0)) {
10819 LOGD("exclude audio...");
10823 caps_str = gst_caps_to_string(caps);
10824 /* set it directly because not sent by TAG */
10825 if (g_strrstr(caps_str, "mobile-xmf"))
10826 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10827 MMPLAYER_FREEIF(caps_str);
10828 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10829 MMMessageParamType msg_param;
10830 memset(&msg_param, 0, sizeof(MMMessageParamType));
10831 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10832 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10833 LOGD("video file is not supported on this device");
10835 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10836 LOGD("already video linked");
10839 LOGD("found new stream");
10846 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10848 int ret = MM_ERROR_NONE;
10850 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10852 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10853 GstStructure* str = NULL;
10855 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10857 LOGD("audio codec type: %d", codec_type);
10858 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10859 /* sw codec will be skipped */
10860 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10861 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10862 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10863 ret = MM_ERROR_PLAYER_INTERNAL;
10867 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10868 /* hw codec will be skipped */
10869 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10870 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10871 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10872 ret = MM_ERROR_PLAYER_INTERNAL;
10877 str = gst_caps_get_structure(caps, 0);
10879 gst_structure_get_int(str, "channels", &channels);
10881 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10882 if (player->max_audio_channels < channels)
10883 player->max_audio_channels = channels;
10885 /* set stream information */
10886 if (!player->audiodec_linked)
10887 __mmplayer_set_audio_attrs(player, caps);
10889 /* update codec info */
10890 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10891 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10892 player->audiodec_linked = 1;
10894 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10896 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10898 LOGD("video codec type: %d", codec_type);
10899 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10900 /* sw codec is skipped */
10901 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10902 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10903 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10904 ret = MM_ERROR_PLAYER_INTERNAL;
10908 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10909 /* hw codec is skipped */
10910 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10911 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10912 ret = MM_ERROR_PLAYER_INTERNAL;
10917 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10918 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10920 /* mark video decoder for acquire */
10921 if (player->video_decoder_resource == NULL) {
10922 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10923 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10924 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10925 &player->video_decoder_resource)
10926 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10927 LOGE("could not mark video_decoder resource for acquire");
10928 ret = MM_ERROR_PLAYER_INTERNAL;
10932 LOGW("video decoder resource is already acquired, skip it.");
10933 ret = MM_ERROR_PLAYER_INTERNAL;
10937 player->interrupted_by_resource = FALSE;
10938 /* acquire resources for video playing */
10939 if (mm_resource_manager_commit(player->resource_manager)
10940 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10941 LOGE("could not acquire resources for video decoding\n");
10942 ret = MM_ERROR_PLAYER_INTERNAL;
10947 /* update codec info */
10948 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10949 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10950 player->videodec_linked = 1;
10958 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10959 GstCaps* caps, GstElementFactory* factory, gpointer data)
10961 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10962 We are defining our own and will be removed when it actually exposed */
10964 GST_AUTOPLUG_SELECT_TRY,
10965 GST_AUTOPLUG_SELECT_EXPOSE,
10966 GST_AUTOPLUG_SELECT_SKIP
10967 } GstAutoplugSelectResult;
10969 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10970 mm_player_t* player = (mm_player_t*)data;
10972 gchar* factory_name = NULL;
10973 gchar* caps_str = NULL;
10974 const gchar* klass = NULL;
10977 factory_name = GST_OBJECT_NAME(factory);
10978 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10979 caps_str = gst_caps_to_string(caps);
10981 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10983 /* store type string */
10984 if (player->type == NULL) {
10985 player->type = gst_caps_to_string(caps);
10986 __mmplayer_update_content_type_info(player);
10989 /* filtering exclude keyword */
10990 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10991 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10992 LOGW("skipping [%s] by exculde keyword [%s]\n",
10993 factory_name, player->ini.exclude_element_keyword[idx]);
10995 result = GST_AUTOPLUG_SELECT_SKIP;
11000 /* exclude webm format */
11001 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11002 * because webm format is not supportable.
11003 * If webm is disabled in "autoplug-continue", there is no state change
11004 * failure or error because the decodebin will expose the pad directly.
11005 * It make MSL invoke _prepare_async_callback.
11006 * So, we need to disable webm format in "autoplug-select" */
11007 if (caps_str && strstr(caps_str, "webm")) {
11008 LOGW("webm is not supported");
11009 result = GST_AUTOPLUG_SELECT_SKIP;
11013 /* check factory class for filtering */
11014 /* NOTE : msl don't need to use image plugins.
11015 * So, those plugins should be skipped for error handling.
11017 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11018 LOGD("skipping [%s] by not required\n", factory_name);
11019 result = GST_AUTOPLUG_SELECT_SKIP;
11023 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11024 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11025 // TO CHECK : subtitle if needed, add subparse exception.
11026 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11027 result = GST_AUTOPLUG_SELECT_SKIP;
11031 if (g_strrstr(factory_name, "mpegpsdemux")) {
11032 LOGD("skipping PS container - not support\n");
11033 result = GST_AUTOPLUG_SELECT_SKIP;
11037 if (g_strrstr(factory_name, "mssdemux"))
11038 player->smooth_streaming = TRUE;
11040 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11041 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11044 GstStructure *str = NULL;
11045 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11047 /* don't make video because of not required */
11048 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11049 (player->set_mode.media_packet_video_stream == FALSE)) {
11050 LOGD("no video because it's not required. -> return expose");
11051 result = GST_AUTOPLUG_SELECT_EXPOSE;
11055 /* get w/h for omx state-tune */
11056 /* FIXME: deprecated? */
11057 str = gst_caps_get_structure(caps, 0);
11058 gst_structure_get_int(str, "width", &width);
11061 if (player->v_stream_caps) {
11062 gst_caps_unref(player->v_stream_caps);
11063 player->v_stream_caps = NULL;
11066 player->v_stream_caps = gst_caps_copy(caps);
11067 LOGD("take caps for video state tune");
11068 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11072 if (g_strrstr(klass, "Codec/Decoder")) {
11073 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11074 LOGD("skipping %s codec", factory_name);
11075 result = GST_AUTOPLUG_SELECT_SKIP;
11081 MMPLAYER_FREEIF(caps_str);
11087 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11090 //mm_player_t* player = (mm_player_t*)data;
11091 GstCaps* caps = NULL;
11093 LOGD("[Decodebin2] pad-removed signal\n");
11095 caps = gst_pad_query_caps(new_pad, NULL);
11097 gchar* caps_str = NULL;
11098 caps_str = gst_caps_to_string(caps);
11100 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11102 MMPLAYER_FREEIF(caps_str);
11103 gst_caps_unref(caps);
11108 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11110 mm_player_t* player = (mm_player_t*)data;
11111 GstIterator *iter = NULL;
11112 GValue item = { 0, };
11113 GstPad *pad = NULL;
11114 gboolean done = FALSE;
11115 gboolean is_all_drained = TRUE;
11118 MMPLAYER_RETURN_IF_FAIL(player);
11120 LOGD("__mmplayer_gst_decode_drained");
11122 if (player->use_deinterleave == TRUE) {
11123 LOGD("group playing mode.");
11127 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11128 LOGW("Fail to get cmd lock");
11132 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11133 !__mmplayer_verify_next_play_path(player)) {
11134 LOGD("decoding is finished.");
11135 __mmplayer_reset_gapless_state(player);
11136 MMPLAYER_CMD_UNLOCK(player);
11140 player->gapless.reconfigure = TRUE;
11142 /* check decodebin src pads whether they received EOS or not */
11143 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11146 switch (gst_iterator_next(iter, &item)) {
11147 case GST_ITERATOR_OK:
11148 pad = g_value_get_object(&item);
11149 if (pad && !GST_PAD_IS_EOS(pad)) {
11150 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11151 is_all_drained = FALSE;
11154 g_value_reset(&item);
11156 case GST_ITERATOR_RESYNC:
11157 gst_iterator_resync(iter);
11159 case GST_ITERATOR_ERROR:
11160 case GST_ITERATOR_DONE:
11165 g_value_unset(&item);
11166 gst_iterator_free(iter);
11168 if (!is_all_drained) {
11169 LOGD("Wait util the all pads get EOS.");
11170 MMPLAYER_CMD_UNLOCK(player);
11175 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11176 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11178 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11179 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11180 __mmplayer_deactivate_old_path(player);
11181 MMPLAYER_CMD_UNLOCK(player);
11187 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11189 mm_player_t* player = (mm_player_t*)data;
11190 const gchar* klass = NULL;
11191 gchar* factory_name = NULL;
11193 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11194 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11196 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11198 if (__mmplayer_add_dump_buffer_probe(player, element))
11199 LOGD("add buffer probe");
11202 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11203 gchar* selected = NULL;
11204 selected = g_strdup(GST_ELEMENT_NAME(element));
11205 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11209 if (g_strrstr(klass, "Parser")) {
11210 gchar* selected = NULL;
11212 selected = g_strdup(factory_name);
11213 player->parsers = g_list_append(player->parsers, selected);
11216 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11217 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11218 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11220 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11221 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11223 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11224 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11225 "max-video-width", player->adaptive_info.limit.width,
11226 "max-video-height", player->adaptive_info.limit.height, NULL);
11228 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11229 /* FIXIT : first value will be overwritten if there's more
11230 * than 1 demuxer/parser
11233 //LOGD("plugged element is demuxer. take it\n");
11234 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11235 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11237 /*Added for multi audio support */ // Q. del?
11238 if (g_strrstr(klass, "Demux")) {
11239 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11240 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11244 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11245 int surface_type = 0;
11247 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11250 // to support trust-zone only
11251 if (g_strrstr(factory_name, "asfdemux")) {
11252 LOGD("set file-location %s\n", player->profile.uri);
11253 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11255 if (player->video_hub_download_mode == TRUE)
11256 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11257 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11258 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11259 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11260 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11261 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11262 (__mmplayer_is_only_mp3_type(player->type))) {
11263 LOGD("[mpegaudioparse] set streaming pull mode.");
11264 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11266 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11267 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11270 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11271 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11272 LOGD("plugged element is multiqueue. take it\n");
11274 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11275 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11277 if (!MMPLAYER_IS_HTTP_PD(player) &&
11278 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11279 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11280 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11281 __mm_player_streaming_set_multiqueue(player->streamer,
11284 player->ini.http_buffering_time,
11286 player->ini.http_buffering_limit);
11288 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11295 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11298 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11300 if (MMPLAYER_IS_STREAMING(player))
11303 /* This callback can be set to music player only. */
11304 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11305 LOGW("audio callback is not supported for video");
11309 if (player->audio_stream_cb) {
11310 GstPad *pad = NULL;
11312 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11315 LOGE("failed to get sink pad from audiosink to probe data\n");
11318 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11319 __mmplayer_audio_stream_probe, player, NULL);
11321 gst_object_unref(pad);
11325 LOGE("There is no audio callback to configure.\n");
11335 __mmplayer_release_misc(mm_player_t* player)
11338 bool cur_mode = player->set_mode.rich_audio;
11341 MMPLAYER_RETURN_IF_FAIL(player);
11343 player->video_stream_cb = NULL;
11344 player->video_stream_cb_user_param = NULL;
11345 player->video_stream_prerolled = FALSE;
11347 player->audio_stream_cb = NULL;
11348 player->audio_stream_render_cb_ex = NULL;
11349 player->audio_stream_cb_user_param = NULL;
11350 player->audio_stream_sink_sync = false;
11352 player->video_stream_changed_cb = NULL;
11353 player->video_stream_changed_cb_user_param = NULL;
11355 player->audio_stream_changed_cb = NULL;
11356 player->audio_stream_changed_cb_user_param = NULL;
11358 player->sent_bos = FALSE;
11359 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11361 player->doing_seek = FALSE;
11363 player->total_bitrate = 0;
11364 player->total_maximum_bitrate = 0;
11366 player->not_found_demuxer = 0;
11368 player->last_position = 0;
11369 player->duration = 0;
11370 player->http_content_size = 0;
11371 player->not_supported_codec = MISSING_PLUGIN_NONE;
11372 player->can_support_codec = FOUND_PLUGIN_NONE;
11373 player->pending_seek.is_pending = FALSE;
11374 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11375 player->pending_seek.pos = 0;
11376 player->msg_posted = FALSE;
11377 player->has_many_types = FALSE;
11378 player->max_audio_channels = 0;
11379 player->video_share_api_delta = 0;
11380 player->video_share_clock_delta = 0;
11381 player->is_subtitle_force_drop = FALSE;
11382 player->play_subtitle = FALSE;
11383 player->adjust_subtitle_pos = 0;
11384 player->last_multiwin_status = FALSE;
11385 player->has_closed_caption = FALSE;
11386 player->set_mode.media_packet_video_stream = FALSE;
11387 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11388 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11390 player->set_mode.rich_audio = cur_mode;
11392 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11393 player->bitrate[i] = 0;
11394 player->maximum_bitrate[i] = 0;
11397 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11399 /* remove media stream cb(appsrc cb) */
11400 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11401 player->media_stream_buffer_status_cb[i] = NULL;
11402 player->media_stream_seek_data_cb[i] = NULL;
11403 player->buffer_cb_user_param[i] = NULL;
11404 player->seek_cb_user_param[i] = NULL;
11406 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11408 /* free memory related to audio effect */
11409 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11411 if (player->adaptive_info.var_list) {
11412 g_list_free_full(player->adaptive_info.var_list, g_free);
11413 player->adaptive_info.var_list = NULL;
11416 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11417 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11418 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11420 /* Reset video360 settings to their defaults in case if the pipeline is to be
11423 player->video360_metadata.is_spherical = -1;
11424 player->is_openal_plugin_used = FALSE;
11426 player->is_content_spherical = FALSE;
11427 player->is_video360_enabled = TRUE;
11428 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11429 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11430 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11431 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11432 player->video360_zoom = 1.0f;
11433 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11434 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11436 player->sound.rg_enable = false;
11442 __mmplayer_release_misc_post(mm_player_t* player)
11444 char *original_uri = NULL;
11447 /* player->pipeline is already released before. */
11449 MMPLAYER_RETURN_IF_FAIL(player);
11451 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11453 /* clean found parsers */
11454 if (player->parsers) {
11455 GList *parsers = player->parsers;
11456 for (; parsers; parsers = g_list_next(parsers)) {
11457 gchar *name = parsers->data;
11458 MMPLAYER_FREEIF(name);
11460 g_list_free(player->parsers);
11461 player->parsers = NULL;
11464 /* clean found audio decoders */
11465 if (player->audio_decoders) {
11466 GList *a_dec = player->audio_decoders;
11467 for (; a_dec; a_dec = g_list_next(a_dec)) {
11468 gchar *name = a_dec->data;
11469 MMPLAYER_FREEIF(name);
11471 g_list_free(player->audio_decoders);
11472 player->audio_decoders = NULL;
11475 /* clean the uri list except original uri */
11476 if (player->uri_info.uri_list) {
11477 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11479 if (player->attrs) {
11480 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11481 LOGD("restore original uri = %s\n", original_uri);
11483 if (mmf_attrs_commit(player->attrs))
11484 LOGE("failed to commit the original uri.\n");
11487 GList *uri_list = player->uri_info.uri_list;
11488 for (; uri_list; uri_list = g_list_next(uri_list)) {
11489 gchar *uri = uri_list->data;
11490 MMPLAYER_FREEIF(uri);
11492 g_list_free(player->uri_info.uri_list);
11493 player->uri_info.uri_list = NULL;
11496 /* clear the audio stream buffer list */
11497 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11499 /* clear the video stream bo list */
11500 __mmplayer_video_stream_destroy_bo_list(player);
11501 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11503 if (player->profile.input_mem.buf) {
11504 free(player->profile.input_mem.buf);
11505 player->profile.input_mem.buf = NULL;
11507 player->profile.input_mem.len = 0;
11508 player->profile.input_mem.offset = 0;
11510 player->uri_info.uri_idx = 0;
11514 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11516 GstElement *element = NULL;
11519 LOGD("creating %s to plug\n", name);
11521 element = gst_element_factory_make(name, NULL);
11523 LOGE("failed to create queue\n");
11527 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11528 LOGE("failed to set state READY to %s\n", name);
11529 gst_object_unref(element);
11533 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11534 LOGE("failed to add %s\n", name);
11535 gst_object_unref(element);
11539 sinkpad = gst_element_get_static_pad(element, "sink");
11541 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11542 LOGE("failed to link %s\n", name);
11543 gst_object_unref(sinkpad);
11544 gst_object_unref(element);
11548 LOGD("linked %s to pipeline successfully\n", name);
11550 gst_object_unref(sinkpad);
11556 __mmplayer_check_subtitle(mm_player_t* player)
11558 MMHandleType attrs = 0;
11559 char *subtitle_uri = NULL;
11563 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11565 /* get subtitle attribute */
11566 attrs = MMPLAYER_GET_ATTRS(player);
11570 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11571 if (!subtitle_uri || !strlen(subtitle_uri))
11574 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11575 player->is_external_subtitle_present = TRUE;
11583 __mmplayer_can_extract_pcm(mm_player_t* player)
11585 MMHandleType attrs = 0;
11586 gboolean sound_extraction = FALSE;
11588 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11590 attrs = MMPLAYER_GET_ATTRS(player);
11592 LOGE("fail to get attributes.");
11596 /* get sound_extraction property */
11597 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11599 if (!sound_extraction) {
11600 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11608 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11611 MMMessageParamType msg_param;
11612 gchar *msg_src_element = NULL;
11613 GstStructure *s = NULL;
11614 guint error_id = 0;
11615 gchar *error_string = NULL;
11619 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11620 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11622 s = gst_structure_copy(gst_message_get_structure(message));
11625 if (!gst_structure_get_uint(s, "error_id", &error_id))
11626 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11628 switch (error_id) {
11629 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11630 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11632 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11633 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11635 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11636 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11638 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11639 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11641 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11642 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11644 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11645 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11647 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11648 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11650 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11651 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11653 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11654 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11656 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11657 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11659 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11660 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11662 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11663 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11665 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11666 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11668 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11669 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11671 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11672 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11674 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11675 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11677 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11678 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11680 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11681 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11683 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11684 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11686 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11687 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11689 case MMPLAYER_STREAMING_ERROR_GONE:
11690 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11692 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11693 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11695 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11696 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11698 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11699 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11701 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11702 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11704 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11705 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11707 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11708 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11710 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11711 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11713 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11714 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11716 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11717 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11719 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11720 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11722 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11723 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11725 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11726 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11728 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11729 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11731 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11732 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11734 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11735 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11737 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11738 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11740 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11741 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11743 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11744 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11746 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11747 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11749 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11750 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11752 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11753 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11755 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11756 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11758 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11759 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11761 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11762 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11766 gst_structure_free(s);
11767 return MM_ERROR_PLAYER_STREAMING_FAIL;
11771 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11773 msg_param.data = (void *) error_string;
11775 if (message->src) {
11776 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11778 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11779 msg_src_element, msg_param.code, (char*)msg_param.data);
11782 /* post error to application */
11783 if (!player->msg_posted) {
11784 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11786 /* don't post more if one was sent already */
11787 player->msg_posted = TRUE;
11789 LOGD("skip error post because it's sent already.\n");
11791 gst_structure_free(s);
11793 g_free(error_string);
11800 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11802 MMPLAYER_RETURN_IF_FAIL(player);
11804 /* post now if delay is zero */
11805 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11806 LOGD("eos delay is zero. posting EOS now\n");
11807 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11809 if (player->set_mode.pcm_extraction)
11810 __mmplayer_cancel_eos_timer(player);
11815 /* cancel if existing */
11816 __mmplayer_cancel_eos_timer(player);
11818 /* init new timeout */
11819 /* NOTE : consider give high priority to this timer */
11820 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11822 player->eos_timer = g_timeout_add(delay_in_ms,
11823 __mmplayer_eos_timer_cb, player);
11825 player->context.global_default = g_main_context_default();
11826 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11828 /* check timer is valid. if not, send EOS now */
11829 if (player->eos_timer == 0) {
11830 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11831 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11836 __mmplayer_cancel_eos_timer(mm_player_t* player)
11838 MMPLAYER_RETURN_IF_FAIL(player);
11840 if (player->eos_timer) {
11841 LOGD("cancel eos timer");
11842 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11843 player->eos_timer = 0;
11850 __mmplayer_eos_timer_cb(gpointer u_data)
11852 mm_player_t* player = NULL;
11853 MMHandleType attrs = 0;
11856 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11858 player = (mm_player_t*) u_data;
11859 attrs = MMPLAYER_GET_ATTRS(player);
11861 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11864 gint ret_value = 0;
11865 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11866 if (ret_value != MM_ERROR_NONE)
11867 LOGE("seeking to 0 failed in repeat play");
11870 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11873 /* we are returning FALSE as we need only one posting */
11877 /* sending event to one of sinkelements */
11879 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11881 GstEvent * event2 = NULL;
11882 GList *sinks = NULL;
11883 gboolean res = FALSE;
11886 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11887 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11889 /* While adding subtitles in live feeds seek is getting called.
11890 Adding defensive check in framework layer.*/
11891 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11892 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11893 LOGE("Should not send seek event during live playback");
11898 if (player->play_subtitle)
11899 event2 = gst_event_copy((const GstEvent *)event);
11901 sinks = player->sink_elements;
11903 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11905 if (GST_IS_ELEMENT(sink)) {
11906 /* keep ref to the event */
11907 gst_event_ref(event);
11909 if ((res = gst_element_send_event(sink, event))) {
11910 LOGD("sending event[%s] to sink element [%s] success!\n",
11911 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11913 /* rtsp case, asyn_done is not called after seek during pause state */
11914 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11915 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11916 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11917 LOGD("RTSP seek completed, after pause state..\n");
11918 player->doing_seek = FALSE;
11919 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11925 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11926 sinks = g_list_next(sinks);
11933 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11934 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11937 sinks = g_list_next(sinks);
11940 /* Note : Textbin is not linked to the video or audio bin.
11941 * It needs to send the event to the text sink seperatelly.
11943 if (player->play_subtitle && player->pipeline) {
11944 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11946 if (GST_IS_ELEMENT(text_sink)) {
11947 /* keep ref to the event */
11948 gst_event_ref(event2);
11950 if ((res = gst_element_send_event(text_sink, event2)))
11951 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11952 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11954 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11955 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11957 gst_event_unref(event2);
11961 gst_event_unref(event);
11969 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11973 MMPLAYER_RETURN_IF_FAIL(player);
11974 MMPLAYER_RETURN_IF_FAIL(sink);
11976 player->sink_elements =
11977 g_list_append(player->sink_elements, sink);
11983 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11987 MMPLAYER_RETURN_IF_FAIL(player);
11988 MMPLAYER_RETURN_IF_FAIL(sink);
11990 player->sink_elements =
11991 g_list_remove(player->sink_elements, sink);
11997 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11998 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11999 gint64 cur, GstSeekType stop_type, gint64 stop)
12001 GstEvent* event = NULL;
12002 gboolean result = FALSE;
12006 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12008 if (player->pipeline && player->pipeline->textbin)
12009 __mmplayer_drop_subtitle(player, FALSE);
12011 event = gst_event_new_seek(rate, format, flags, cur_type,
12012 cur, stop_type, stop);
12014 result = __gst_send_event_to_sink(player, event);
12021 /* NOTE : be careful with calling this api. please refer to below glib comment
12022 * glib comment : Note that there is a bug in GObject that makes this function much
12023 * less useful than it might seem otherwise. Once gobject is disposed, the callback
12024 * will no longer be called, but, the signal handler is not currently disconnected.
12025 * If the instance is itself being freed at the same time than this doesn't matter,
12026 * since the signal will automatically be removed, but if instance persists,
12027 * then the signal handler will leak. You should not remove the signal yourself
12028 * because in a future versions of GObject, the handler will automatically be
12031 * It's possible to work around this problem in a way that will continue to work
12032 * with future versions of GObject by checking that the signal handler is still
12033 * connected before disconnected it:
12035 * if (g_signal_handler_is_connected(instance, id))
12036 * g_signal_handler_disconnect(instance, id);
12039 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12041 GList* sig_list = NULL;
12042 MMPlayerSignalItem* item = NULL;
12046 MMPLAYER_RETURN_IF_FAIL(player);
12048 LOGD("release signals type : %d", type);
12050 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12051 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12052 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12053 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12054 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12055 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12059 sig_list = player->signals[type];
12061 for (; sig_list; sig_list = sig_list->next) {
12062 item = sig_list->data;
12064 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12065 if (g_signal_handler_is_connected(item->obj, item->sig))
12066 g_signal_handler_disconnect(item->obj, item->sig);
12069 MMPLAYER_FREEIF(item);
12072 g_list_free(player->signals[type]);
12073 player->signals[type] = NULL;
12080 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12082 mm_player_t* player = 0;
12083 int prev_display_surface_type = 0;
12084 void *prev_display_overlay = NULL;
12085 const gchar *klass = NULL;
12086 gchar *cur_videosink_name = NULL;
12089 int num_of_dec = 2; /* DEC1, DEC2 */
12093 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12094 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12096 player = MM_PLAYER_CAST(handle);
12098 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12099 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12101 return MM_ERROR_INVALID_ARGUMENT;
12104 /* load previous attributes */
12105 if (player->attrs) {
12106 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12107 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12108 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12109 if (prev_display_surface_type == surface_type) {
12110 LOGD("incoming display surface type is same as previous one, do nothing..");
12112 return MM_ERROR_NONE;
12115 LOGE("failed to load attributes");
12117 return MM_ERROR_PLAYER_INTERNAL;
12120 /* check videosink element is created */
12121 if (!player->pipeline || !player->pipeline->videobin ||
12122 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12123 LOGD("videosink element is not yet ready");
12125 /* videobin is not created yet, so we just set attributes related to display surface */
12126 LOGD("store display attribute for given surface type(%d)", surface_type);
12127 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12128 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12129 if (mmf_attrs_commit(player->attrs)) {
12130 LOGE("failed to commit attribute");
12132 return MM_ERROR_PLAYER_INTERNAL;
12135 return MM_ERROR_NONE;
12137 /* get player command status */
12138 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12139 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12141 return MM_ERROR_PLAYER_INVALID_STATE;
12144 /* surface change */
12145 for (i = 0 ; i < num_of_dec ; i++) {
12146 if (player->pipeline->mainbin &&
12147 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12148 GstElementFactory *decfactory;
12149 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12151 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12152 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12153 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12154 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12158 LOGW("success to changing display surface(%d)", surface_type);
12160 return MM_ERROR_NONE;
12162 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12163 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12167 LOGW("success to changing display surface(%d)", surface_type);
12169 return MM_ERROR_NONE;
12172 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12173 ret = MM_ERROR_PLAYER_INTERNAL;
12182 /* rollback to previous attributes */
12183 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12184 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12185 if (mmf_attrs_commit(player->attrs)) {
12186 LOGE("failed to commit attributes to rollback");
12188 return MM_ERROR_PLAYER_INTERNAL;
12194 /* NOTE : It does not support some use cases, eg using colorspace converter */
12196 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12198 GstPad *src_pad_dec = NULL;
12199 GstPad *sink_pad_videosink = NULL;
12200 GstPad *sink_pad_videobin = NULL;
12201 GstClock *clock = NULL;
12202 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12203 int ret = MM_ERROR_NONE;
12204 gboolean is_audiobin_created = TRUE;
12208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12209 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12210 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12212 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12213 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12215 /* get information whether if audiobin is created */
12216 if (!player->pipeline->audiobin ||
12217 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12218 LOGW("audiobin is null, this video content may not have audio data");
12219 is_audiobin_created = FALSE;
12222 /* get current state of player */
12223 previous_state = MMPLAYER_CURRENT_STATE(player);
12224 LOGD("previous state(%d)", previous_state);
12227 /* get src pad of decoder and block it */
12228 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12229 if (!src_pad_dec) {
12230 LOGE("failed to get src pad from decode in mainbin");
12231 return MM_ERROR_PLAYER_INTERNAL;
12234 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12235 LOGW("trying to block pad(video)");
12236 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12237 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12240 LOGE("failed to set block pad(video)");
12241 return MM_ERROR_PLAYER_INTERNAL;
12243 LOGW("pad is blocked(video)");
12245 /* no data flows, so no need to do pad_block */
12246 if (player->doing_seek)
12247 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12249 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12253 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12254 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12255 LOGE("failed to remove previous ghost_pad for videobin");
12256 return MM_ERROR_PLAYER_INTERNAL;
12259 /* change state of videobin to NULL */
12260 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12261 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12262 if (ret != GST_STATE_CHANGE_SUCCESS) {
12263 LOGE("failed to change state of videobin to NULL");
12264 return MM_ERROR_PLAYER_INTERNAL;
12267 /* unlink between decoder and videobin and remove previous videosink from videobin */
12268 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12269 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12270 LOGE("failed to remove former videosink from videobin");
12271 return MM_ERROR_PLAYER_INTERNAL;
12274 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12276 /* create a new videosink and add it to videobin */
12277 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12278 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12279 LOGE("failed to create videosink element\n");
12281 return MM_ERROR_PLAYER_INTERNAL;
12283 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12284 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12285 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12287 /* save attributes */
12288 if (player->attrs) {
12289 /* set a new display surface type */
12290 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12291 /* set a new diplay overlay */
12292 switch (surface_type) {
12293 case MM_DISPLAY_SURFACE_OVERLAY:
12294 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12295 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12298 LOGE("invalid type(%d) for changing display surface", surface_type);
12300 return MM_ERROR_INVALID_ARGUMENT;
12302 if (mmf_attrs_commit(player->attrs)) {
12303 LOGE("failed to commit");
12305 return MM_ERROR_PLAYER_INTERNAL;
12308 LOGE("player->attrs is null, failed to save attributes");
12310 return MM_ERROR_PLAYER_INTERNAL;
12313 /* update video param */
12314 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12315 LOGE("failed to update video param");
12316 return MM_ERROR_PLAYER_INTERNAL;
12319 /* change state of videobin to READY */
12320 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12321 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12322 if (ret != GST_STATE_CHANGE_SUCCESS) {
12323 LOGE("failed to change state of videobin to READY");
12324 return MM_ERROR_PLAYER_INTERNAL;
12327 /* change ghostpad */
12328 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12329 if (!sink_pad_videosink) {
12330 LOGE("failed to get sink pad from videosink element");
12331 return MM_ERROR_PLAYER_INTERNAL;
12333 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12334 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12335 LOGE("failed to set active to ghost_pad");
12336 return MM_ERROR_PLAYER_INTERNAL;
12338 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12339 LOGE("failed to change ghostpad for videobin");
12340 return MM_ERROR_PLAYER_INTERNAL;
12342 gst_object_unref(sink_pad_videosink);
12344 /* link decoder with videobin */
12345 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12346 if (!sink_pad_videobin) {
12347 LOGE("failed to get sink pad from videobin");
12348 return MM_ERROR_PLAYER_INTERNAL;
12350 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12351 LOGE("failed to link");
12352 return MM_ERROR_PLAYER_INTERNAL;
12354 gst_object_unref(sink_pad_videobin);
12356 /* clock setting for a new videosink plugin */
12357 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12358 so we set it from audiosink plugin or pipeline(system clock) */
12359 if (!is_audiobin_created) {
12360 LOGW("audiobin is not created, get clock from pipeline..");
12361 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12363 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12367 GstClockTime base_time;
12368 LOGD("set the clock to videosink");
12369 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12370 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12372 LOGD("got clock of videosink");
12373 now = gst_clock_get_time(clock);
12374 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12375 LOGD("at time %" GST_TIME_FORMAT ", base %"
12376 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12378 LOGE("failed to get clock of videosink after setting clock");
12379 return MM_ERROR_PLAYER_INTERNAL;
12382 LOGW("failed to get clock, maybe it is the time before first playing");
12384 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12385 /* change state of videobin to PAUSED */
12386 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12387 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12388 if (ret != GST_STATE_CHANGE_FAILURE) {
12389 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12391 LOGE("failed to change state of videobin to PLAYING");
12392 return MM_ERROR_PLAYER_INTERNAL;
12395 /* release blocked and unref src pad of video decoder */
12397 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12398 LOGE("failed to set pad blocked FALSE(video)");
12399 return MM_ERROR_PLAYER_INTERNAL;
12402 LOGW("pad is unblocked(video)");
12404 if (player->doing_seek)
12405 LOGW("not completed seek(%d)", player->doing_seek);
12406 /* change state of videobin to PAUSED */
12407 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12408 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12409 if (ret != GST_STATE_CHANGE_FAILURE) {
12410 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12412 LOGE("failed to change state of videobin to PLAYING");
12413 return MM_ERROR_PLAYER_INTERNAL;
12416 /* already skipped pad block */
12417 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12420 /* do get/set position for new videosink plugin */
12422 unsigned long position = 0;
12423 gint64 pos_msec = 0;
12425 LOGD("do get/set position for new videosink plugin");
12426 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12427 LOGE("failed to get position");
12428 return MM_ERROR_PLAYER_INTERNAL;
12430 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12431 /* accurate seek */
12432 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12433 LOGE("failed to set position");
12434 return MM_ERROR_PLAYER_INTERNAL;
12437 /* key unit seek */
12438 pos_msec = position * G_GINT64_CONSTANT(1000000);
12439 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12440 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12441 GST_SEEK_TYPE_SET, pos_msec,
12442 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12444 LOGE("failed to set position");
12445 return MM_ERROR_PLAYER_INTERNAL;
12451 gst_object_unref(src_pad_dec);
12452 LOGD("success to change sink");
12456 return MM_ERROR_NONE;
12460 /* Note : if silent is true, then subtitle would not be displayed. :*/
12461 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12463 mm_player_t* player = (mm_player_t*) hplayer;
12467 /* check player handle */
12468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12470 player->set_mode.subtitle_off = silent;
12472 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12476 return MM_ERROR_NONE;
12479 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12481 MMPlayerGstElement* mainbin = NULL;
12482 MMPlayerGstElement* textbin = NULL;
12483 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12484 GstState current_state = GST_STATE_VOID_PENDING;
12485 GstState element_state = GST_STATE_VOID_PENDING;
12486 GstState element_pending_state = GST_STATE_VOID_PENDING;
12488 GstEvent *event = NULL;
12489 int result = MM_ERROR_NONE;
12491 GstClock *curr_clock = NULL;
12492 GstClockTime base_time, start_time, curr_time;
12497 /* check player handle */
12498 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12499 player->pipeline &&
12500 player->pipeline->mainbin &&
12501 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12503 mainbin = player->pipeline->mainbin;
12504 textbin = player->pipeline->textbin;
12506 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12508 // sync clock with current pipeline
12509 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12510 curr_time = gst_clock_get_time(curr_clock);
12512 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12513 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12515 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12516 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12518 if (current_state > GST_STATE_READY) {
12519 // sync state with current pipeline
12520 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12521 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12522 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12524 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12525 if (GST_STATE_CHANGE_FAILURE == ret) {
12526 LOGE("fail to state change.\n");
12527 result = MM_ERROR_PLAYER_INTERNAL;
12532 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12533 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12536 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12537 gst_object_unref(curr_clock);
12540 // seek to current position
12541 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12542 result = MM_ERROR_PLAYER_INVALID_STATE;
12543 LOGE("gst_element_query_position failed, invalid state\n");
12547 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12548 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);
12550 __gst_send_event_to_sink(player, event);
12552 result = MM_ERROR_PLAYER_INTERNAL;
12553 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12557 /* sync state with current pipeline */
12558 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12559 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12560 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12562 return MM_ERROR_NONE;
12565 /* release text pipeline resource */
12566 player->textsink_linked = 0;
12568 /* release signal */
12569 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12571 /* release textbin with it's childs */
12572 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12573 MMPLAYER_FREEIF(player->pipeline->textbin);
12574 player->pipeline->textbin = NULL;
12576 /* release subtitle elem */
12577 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12578 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12584 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12586 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12587 GstState current_state = GST_STATE_VOID_PENDING;
12589 MMHandleType attrs = 0;
12590 MMPlayerGstElement* mainbin = NULL;
12591 MMPlayerGstElement* textbin = NULL;
12593 gchar* subtitle_uri = NULL;
12594 int result = MM_ERROR_NONE;
12595 const gchar *charset = NULL;
12599 /* check player handle */
12600 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12601 player->pipeline &&
12602 player->pipeline->mainbin &&
12603 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12604 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12606 mainbin = player->pipeline->mainbin;
12607 textbin = player->pipeline->textbin;
12609 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12610 if (current_state < GST_STATE_READY) {
12611 result = MM_ERROR_PLAYER_INVALID_STATE;
12612 LOGE("Pipeline is not in proper state\n");
12616 attrs = MMPLAYER_GET_ATTRS(player);
12618 LOGE("cannot get content attribute\n");
12619 result = MM_ERROR_PLAYER_INTERNAL;
12623 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12624 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12625 LOGE("subtitle uri is not proper filepath\n");
12626 result = MM_ERROR_PLAYER_INVALID_URI;
12630 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12631 LOGE("failed to get storage info of subtitle path");
12632 result = MM_ERROR_PLAYER_INVALID_URI;
12636 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12637 LOGD("new subtitle file path is [%s]\n", filepath);
12639 if (!strcmp(filepath, subtitle_uri)) {
12640 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12643 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12644 if (mmf_attrs_commit(player->attrs)) {
12645 LOGE("failed to commit.\n");
12650 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12651 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12652 player->subtitle_language_list = NULL;
12653 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12655 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12656 if (ret != GST_STATE_CHANGE_SUCCESS) {
12657 LOGE("failed to change state of textbin to READY");
12658 result = MM_ERROR_PLAYER_INTERNAL;
12662 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12663 if (ret != GST_STATE_CHANGE_SUCCESS) {
12664 LOGE("failed to change state of subparse to READY");
12665 result = MM_ERROR_PLAYER_INTERNAL;
12669 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12670 if (ret != GST_STATE_CHANGE_SUCCESS) {
12671 LOGE("failed to change state of filesrc to READY");
12672 result = MM_ERROR_PLAYER_INTERNAL;
12676 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12678 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12680 charset = util_get_charset(filepath);
12682 LOGD("detected charset is %s\n", charset);
12683 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12686 result = _mmplayer_sync_subtitle_pipeline(player);
12693 /* API to switch between external subtitles */
12694 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12696 int result = MM_ERROR_NONE;
12697 mm_player_t* player = (mm_player_t*)hplayer;
12702 /* check player handle */
12703 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12705 /* filepath can be null in idle state */
12707 /* check file path */
12708 if ((path = strstr(filepath, "file://")))
12709 result = util_exist_file_path(path + 7);
12711 result = util_exist_file_path(filepath);
12713 if (result != MM_ERROR_NONE) {
12714 LOGE("invalid subtitle path 0x%X", result);
12715 return result; /* file not found or permission denied */
12719 if (!player->pipeline) {
12721 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12722 if (mmf_attrs_commit(player->attrs)) {
12723 LOGE("failed to commit"); /* subtitle path will not be created */
12724 return MM_ERROR_PLAYER_INTERNAL;
12727 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12728 /* check filepath */
12729 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12731 if (!__mmplayer_check_subtitle(player)) {
12732 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12733 if (mmf_attrs_commit(player->attrs)) {
12734 LOGE("failed to commit");
12735 return MM_ERROR_PLAYER_INTERNAL;
12738 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12739 LOGE("fail to create text pipeline");
12740 return MM_ERROR_PLAYER_INTERNAL;
12743 result = _mmplayer_sync_subtitle_pipeline(player);
12745 result = __mmplayer_change_external_subtitle_language(player, filepath);
12748 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12749 player->is_external_subtitle_added_now = TRUE;
12751 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12752 if (!player->subtitle_language_list) {
12753 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12754 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12755 LOGW("subtitle language list is not updated yet");
12757 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12765 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12767 int result = MM_ERROR_NONE;
12768 gchar* change_pad_name = NULL;
12769 GstPad* sinkpad = NULL;
12770 MMPlayerGstElement* mainbin = NULL;
12771 enum MainElementID elemId = MMPLAYER_M_NUM;
12772 GstCaps* caps = NULL;
12773 gint total_track_num = 0;
12777 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12778 MM_ERROR_PLAYER_NOT_INITIALIZED);
12780 LOGD("Change Track(%d) to %d\n", type, index);
12782 mainbin = player->pipeline->mainbin;
12784 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12785 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12786 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12787 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12789 /* Changing Video Track is not supported. */
12790 LOGE("Track Type Error\n");
12794 if (mainbin[elemId].gst == NULL) {
12795 result = MM_ERROR_PLAYER_NO_OP;
12796 LOGD("Req track doesn't exist\n");
12800 total_track_num = player->selector[type].total_track_num;
12801 if (total_track_num <= 0) {
12802 result = MM_ERROR_PLAYER_NO_OP;
12803 LOGD("Language list is not available \n");
12807 if ((index < 0) || (index >= total_track_num)) {
12808 result = MM_ERROR_INVALID_ARGUMENT;
12809 LOGD("Not a proper index : %d \n", index);
12813 /*To get the new pad from the selector*/
12814 change_pad_name = g_strdup_printf("sink_%u", index);
12815 if (change_pad_name == NULL) {
12816 result = MM_ERROR_PLAYER_INTERNAL;
12817 LOGD("Pad does not exists\n");
12821 LOGD("new active pad name: %s\n", change_pad_name);
12823 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12824 if (sinkpad == NULL) {
12825 LOGD("sinkpad is NULL");
12826 result = MM_ERROR_PLAYER_INTERNAL;
12830 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12831 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12833 caps = gst_pad_get_current_caps(sinkpad);
12834 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12837 gst_object_unref(sinkpad);
12839 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12840 __mmplayer_set_audio_attrs(player, caps);
12844 MMPLAYER_FREEIF(change_pad_name);
12848 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12850 int result = MM_ERROR_NONE;
12851 mm_player_t* player = NULL;
12852 MMPlayerGstElement* mainbin = NULL;
12854 gint current_active_index = 0;
12856 GstState current_state = GST_STATE_VOID_PENDING;
12857 GstEvent* event = NULL;
12862 player = (mm_player_t*)hplayer;
12863 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12865 if (!player->pipeline) {
12866 LOGE("Track %d pre setting -> %d\n", type, index);
12868 player->selector[type].active_pad_index = index;
12872 mainbin = player->pipeline->mainbin;
12874 current_active_index = player->selector[type].active_pad_index;
12876 /*If index is same as running index no need to change the pad*/
12877 if (current_active_index == index)
12880 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12881 result = MM_ERROR_PLAYER_INVALID_STATE;
12885 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12886 if (current_state < GST_STATE_PAUSED) {
12887 result = MM_ERROR_PLAYER_INVALID_STATE;
12888 LOGW("Pipeline not in porper state\n");
12892 result = __mmplayer_change_selector_pad(player, type, index);
12893 if (result != MM_ERROR_NONE) {
12894 LOGE("change selector pad error\n");
12898 player->selector[type].active_pad_index = index;
12900 if (current_state == GST_STATE_PLAYING) {
12901 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);
12903 __gst_send_event_to_sink(player, event);
12905 result = MM_ERROR_PLAYER_INTERNAL;
12914 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12916 mm_player_t* player = (mm_player_t*) hplayer;
12920 /* check player handle */
12921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12923 *silent = player->set_mode.subtitle_off;
12925 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12929 return MM_ERROR_NONE;
12933 __is_ms_buff_src(mm_player_t* player)
12935 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12937 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12941 __has_suffix(mm_player_t* player, const gchar* suffix)
12943 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12944 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12946 gboolean ret = FALSE;
12947 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12948 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12950 if (g_str_has_suffix(player->profile.uri, suffix))
12953 MMPLAYER_FREEIF(t_url);
12954 MMPLAYER_FREEIF(t_suffix);
12960 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12962 mm_player_t* player = (mm_player_t*) hplayer;
12964 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12966 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12967 MMPLAYER_PRINT_STATE(player);
12968 LOGE("wrong-state : can't set the download mode to parse");
12969 return MM_ERROR_PLAYER_INVALID_STATE;
12972 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12973 player->video_hub_download_mode = mode;
12975 return MM_ERROR_NONE;
12979 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12981 mm_player_t* player = (mm_player_t*) hplayer;
12983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12985 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12986 player->sync_handler = enable;
12988 return MM_ERROR_NONE;
12992 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12994 long long clock_delta,
12995 long long video_time,
12996 long long media_clock,
12997 long long audio_time)
12999 mm_player_t* player = (mm_player_t*) hplayer;
13000 MMPlayerGstElement* mainbin = NULL;
13001 GstClockTime start_time_audio = 0, start_time_video = 0;
13002 GstClockTimeDiff base_time = 0, new_base_time = 0;
13003 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13004 gint64 api_delta = 0;
13005 gint64 position = 0, position_delta = 0;
13006 gint64 adj_base_time = 0;
13007 GstClock *curr_clock = NULL;
13008 GstClockTime curr_time = 0;
13009 gboolean query_ret = TRUE;
13010 int result = MM_ERROR_NONE;
13014 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13015 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13016 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13018 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13020 if ((video_time < 0) || (player->doing_seek)) {
13021 LOGD("skip setting master clock. %lld", video_time);
13025 mainbin = player->pipeline->mainbin;
13027 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13028 curr_time = gst_clock_get_time(curr_clock);
13030 current_state = MMPLAYER_CURRENT_STATE(player);
13032 if (current_state == MM_PLAYER_STATE_PLAYING)
13033 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13035 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13037 position = player->last_position;
13038 LOGD("query fail. %lld", position);
13041 clock *= GST_USECOND;
13042 clock_delta *= GST_USECOND;
13044 api_delta = clock - curr_time;
13045 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13046 player->video_share_api_delta = api_delta;
13048 clock_delta += (api_delta - player->video_share_api_delta);
13050 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13051 player->video_share_clock_delta = (gint64)clock_delta;
13053 position_delta = (position/GST_USECOND) - video_time;
13054 position_delta *= GST_USECOND;
13056 adj_base_time = position_delta;
13057 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13060 gint64 new_play_time = 0;
13061 gint64 network_delay = 0;
13063 video_time *= GST_USECOND;
13065 network_delay = clock_delta - player->video_share_clock_delta;
13066 new_play_time = video_time + network_delay;
13068 adj_base_time = position - new_play_time;
13070 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13071 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13074 /* Adjust Current Stream Time with base_time of sink
13075 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13076 * 2. Set new base time
13077 * if adj_base_time is positive value, the stream time will be decreased.
13078 * 3. If seek event is occurred, the start time will be reset. */
13079 if ((player->pipeline->audiobin) &&
13080 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13081 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13083 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13084 LOGD("audio sink : gst_element_set_start_time -> NONE");
13085 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13088 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13091 if ((player->pipeline->videobin) &&
13092 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13093 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13095 if (start_time_video != GST_CLOCK_TIME_NONE) {
13096 LOGD("video sink : gst_element_set_start_time -> NONE");
13097 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13100 // if videobin exist, get base_time from videobin.
13101 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13104 new_base_time = base_time + adj_base_time;
13106 if ((player->pipeline->audiobin) &&
13107 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13108 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13110 if ((player->pipeline->videobin) &&
13111 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13112 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13121 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13122 long long *video_time,
13123 long long *media_clock,
13124 long long *audio_time)
13126 mm_player_t* player = (mm_player_t*) hplayer;
13127 MMPlayerGstElement* mainbin = NULL;
13128 GstClock *curr_clock = NULL;
13129 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13130 gint64 position = 0;
13131 gboolean query_ret = TRUE;
13135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13136 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13137 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13139 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13140 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13141 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13143 mainbin = player->pipeline->mainbin;
13145 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13147 current_state = MMPLAYER_CURRENT_STATE(player);
13149 if (current_state != MM_PLAYER_STATE_PAUSED)
13150 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13152 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13154 position = player->last_position;
13156 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13158 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13161 gst_object_unref(curr_clock);
13165 return MM_ERROR_NONE;
13169 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13171 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13172 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13174 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13175 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13179 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13180 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13181 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13182 mm_player_dump_t *dump_s;
13183 dump_s = g_malloc(sizeof(mm_player_dump_t));
13185 if (dump_s == NULL) {
13186 LOGE("malloc fail");
13190 dump_s->dump_element_file = NULL;
13191 dump_s->dump_pad = NULL;
13192 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13194 if (dump_s->dump_pad) {
13195 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13196 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]);
13197 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13198 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);
13199 /* add list for removed buffer probe and close FILE */
13200 player->dump_list = g_list_append(player->dump_list, dump_s);
13201 LOGD("%s sink pad added buffer probe for dump", factory_name);
13206 LOGE("failed to get %s sink pad added", factory_name);
13215 static GstPadProbeReturn
13216 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13218 FILE *dump_data = (FILE *) u_data;
13219 // int written = 0;
13220 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13221 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13223 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13225 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13227 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13229 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13231 return GST_PAD_PROBE_OK;
13235 __mmplayer_release_dump_list(GList *dump_list)
13238 GList *d_list = dump_list;
13239 for (; d_list; d_list = g_list_next(d_list)) {
13240 mm_player_dump_t *dump_s = d_list->data;
13241 if (dump_s->dump_pad) {
13242 if (dump_s->probe_handle_id)
13243 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13245 if (dump_s->dump_element_file) {
13246 fclose(dump_s->dump_element_file);
13247 dump_s->dump_element_file = NULL;
13249 MMPLAYER_FREEIF(dump_s);
13251 g_list_free(dump_list);
13257 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13259 mm_player_t* player = (mm_player_t*) hplayer;
13263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13264 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13266 *exist = player->has_closed_caption;
13270 return MM_ERROR_NONE;
13273 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13277 // LOGD("unref internal gst buffer %p", buffer);
13278 gst_buffer_unref((GstBuffer *)buffer);
13285 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13287 mm_player_t *player = (mm_player_t*)user_data;
13288 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13289 guint64 current_level_bytes = 0;
13291 MMPLAYER_RETURN_IF_FAIL(player);
13293 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13295 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13296 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13298 if (player->media_stream_buffer_status_cb[type])
13299 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13300 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13305 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13307 mm_player_t *player = (mm_player_t*)user_data;
13308 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13309 guint64 current_level_bytes = 0;
13311 MMPLAYER_RETURN_IF_FAIL(player);
13313 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13315 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13317 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13318 if (player->media_stream_buffer_status_cb[type])
13319 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13320 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13324 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13326 mm_player_t *player = (mm_player_t*)user_data;
13327 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13328 guint64 current_level_bytes = 0;
13330 MMPLAYER_RETURN_IF_FAIL(player);
13332 LOGI("app-src: feed subtitle\n");
13334 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13336 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13337 if (player->media_stream_buffer_status_cb[type])
13338 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13340 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13344 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13346 mm_player_t *player = (mm_player_t*)user_data;
13347 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13348 guint64 current_level_bytes = 0;
13350 MMPLAYER_RETURN_IF_FAIL(player);
13352 LOGI("app-src: audio buffer is full.\n");
13354 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13356 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13358 if (player->media_stream_buffer_status_cb[type])
13359 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13361 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13365 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13367 mm_player_t *player = (mm_player_t*)user_data;
13368 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13369 guint64 current_level_bytes = 0;
13371 MMPLAYER_RETURN_IF_FAIL(player);
13373 LOGI("app-src: video buffer is full.\n");
13375 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13377 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13378 if (player->media_stream_buffer_status_cb[type])
13379 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13381 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13385 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13387 mm_player_t *player = (mm_player_t*)user_data;
13388 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13390 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13392 LOGD("app-src: seek audio data %llu\n", position);
13393 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13395 if (player->media_stream_seek_data_cb[type])
13396 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13397 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13403 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13405 mm_player_t *player = (mm_player_t*)user_data;
13406 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13408 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13410 LOGD("app-src: seek video data %llu\n", position);
13411 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13412 if (player->media_stream_seek_data_cb[type])
13413 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13414 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13420 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13422 mm_player_t *player = (mm_player_t*)user_data;
13423 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13425 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13427 LOGD("app-src: seek subtitle data\n");
13428 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13430 if (player->media_stream_seek_data_cb[type])
13431 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13432 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13438 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13440 mm_player_t* player = (mm_player_t*) hplayer;
13444 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13446 player->pcm_samplerate = samplerate;
13447 player->pcm_channel = channel;
13450 return MM_ERROR_NONE;
13453 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13455 mm_player_t* player = (mm_player_t*) hplayer;
13459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13460 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13462 if (MMPLAYER_IS_STREAMING(player))
13463 *timeout = player->ini.live_state_change_timeout;
13465 *timeout = player->ini.localplayback_state_change_timeout;
13467 LOGD("timeout = %d\n", *timeout);
13470 return MM_ERROR_NONE;
13473 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13475 mm_player_t* player = (mm_player_t*) hplayer;
13479 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13480 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13482 *num = player->video_num_buffers;
13483 *extra_num = player->video_extra_num_buffers;
13485 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13488 return MM_ERROR_NONE;
13492 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13496 MMPLAYER_RETURN_IF_FAIL(player);
13498 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13500 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13501 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13502 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13503 player->storage_info[i].id = -1;
13504 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13506 if (path_type != MMPLAYER_PATH_MAX)
13514 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13516 int ret = MM_ERROR_NONE;
13517 mm_player_t* player = (mm_player_t*)hplayer;
13518 MMMessageParamType msg_param = {0, };
13521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13523 LOGW("state changed storage %d:%d", id, state);
13525 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13526 return MM_ERROR_NONE;
13528 /* FIXME: text path should be handled seperately. */
13529 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13530 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13531 LOGW("external storage is removed");
13533 if (player->msg_posted == FALSE) {
13534 memset(&msg_param, 0, sizeof(MMMessageParamType));
13535 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13536 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13537 player->msg_posted = TRUE;
13540 /* unrealize the player */
13541 ret = _mmplayer_unrealize(hplayer);
13542 if (ret != MM_ERROR_NONE)
13543 LOGE("failed to unrealize");
13550 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13552 int ret = MM_ERROR_NONE;
13553 mm_player_t* player = (mm_player_t*) hplayer;
13554 int idx = 0, total = 0;
13555 gchar *result = NULL, *tmp = NULL;
13558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13559 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13561 total = *num = g_list_length(player->adaptive_info.var_list);
13563 LOGW("There is no stream variant info.");
13567 result = g_strdup("");
13568 for (idx = 0 ; idx < total ; idx++) {
13569 VariantData *v_data = NULL;
13570 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13573 gchar data[64] = {0};
13574 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13576 tmp = g_strconcat(result, data, NULL);
13580 LOGW("There is no variant data in %d", idx);
13585 *var_info = (char *)result;
13587 LOGD("variant info %d:%s", *num, *var_info);
13592 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13594 int ret = MM_ERROR_NONE;
13595 mm_player_t* player = (mm_player_t*) hplayer;
13598 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13600 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13602 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13603 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13604 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13606 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13607 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13608 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13609 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13611 /* FIXME: seek to current position for applying new variant limitation */
13619 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13621 int ret = MM_ERROR_NONE;
13622 mm_player_t* player = (mm_player_t*) hplayer;
13625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13626 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13628 *bandwidth = player->adaptive_info.limit.bandwidth;
13629 *width = player->adaptive_info.limit.width;
13630 *height = player->adaptive_info.limit.height;
13632 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13638 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13640 int ret = MM_ERROR_NONE;
13641 mm_player_t* player = (mm_player_t*) hplayer;
13644 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13646 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13647 LOGW("buffer_ms will not be applied.");
13650 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13652 if (player->streamer == NULL) {
13653 player->streamer = __mm_player_streaming_create();
13654 __mm_player_streaming_initialize(player->streamer);
13657 if (buffer_ms >= 0)
13658 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13660 if (rebuffer_ms >= 0)
13661 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13668 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13670 int ret = MM_ERROR_NONE;
13671 mm_player_t* player = (mm_player_t*) hplayer;
13674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13675 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13677 if (player->streamer == NULL) {
13678 player->streamer = __mm_player_streaming_create();
13679 __mm_player_streaming_initialize(player->streamer);
13682 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13683 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13685 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13691 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13693 #define IDX_FIRST_SW_CODEC 0
13694 mm_player_t* player = (mm_player_t*) hplayer;
13695 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13696 MMHandleType attrs = 0;
13699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13701 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13702 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13703 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13705 switch (stream_type) {
13706 case MM_PLAYER_STREAM_TYPE_AUDIO:
13707 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13708 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13709 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13710 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13711 LOGE("There is no a codec for codec_type %d", codec_type);
13712 return MM_ERROR_PLAYER_NO_OP;
13715 case MM_PLAYER_STREAM_TYPE_VIDEO:
13716 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13717 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13718 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13719 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13720 LOGE("There is no v codec for codec_type %d", codec_type);
13721 return MM_ERROR_PLAYER_NO_OP;
13726 LOGE("Invalid stream type %d", stream_type);
13727 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13731 LOGD("update %s codec_type to %d", attr_name, codec_type);
13733 attrs = MMPLAYER_GET_ATTRS(player);
13734 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13736 if (mmf_attrs_commit(player->attrs)) {
13737 LOGE("failed to commit codec_type attributes");
13738 return MM_ERROR_PLAYER_INTERNAL;
13742 return MM_ERROR_NONE;
13746 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13748 mm_player_t* player = (mm_player_t*) hplayer;
13749 GstElement* rg_vol_element = NULL;
13753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13755 player->sound.rg_enable = enabled;
13757 /* just hold rgvolume enable value if pipeline is not ready */
13758 if (!player->pipeline || !player->pipeline->audiobin) {
13759 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13760 return MM_ERROR_NONE;
13763 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13765 if (!rg_vol_element) {
13766 LOGD("rgvolume element is not created");
13767 return MM_ERROR_PLAYER_INTERNAL;
13771 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13773 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13777 return MM_ERROR_NONE;
13781 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13783 mm_player_t* player = (mm_player_t*) hplayer;
13784 GstElement* rg_vol_element = NULL;
13785 gboolean enable = FALSE;
13789 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13790 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13792 /* just hold enable_rg value if pipeline is not ready */
13793 if (!player->pipeline || !player->pipeline->audiobin) {
13794 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13795 *enabled = player->sound.rg_enable;
13796 return MM_ERROR_NONE;
13799 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13801 if (!rg_vol_element) {
13802 LOGD("rgvolume element is not created");
13803 return MM_ERROR_PLAYER_INTERNAL;
13806 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13811 return MM_ERROR_NONE;