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_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
109 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
158 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
159 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_release_misc(mm_player_t* player);
163 static void __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
194 static int __gst_realize(mm_player_t* player);
195 static int __gst_unrealize(mm_player_t* player);
196 static int __gst_start(mm_player_t* player);
197 static int __gst_stop(mm_player_t* player);
198 static int __gst_pause(mm_player_t* player, gboolean async);
199 static int __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202 gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
205 static int __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
213 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
216 static gboolean __is_ms_buff_src(mm_player_t* player);
217 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
219 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
220 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
221 static int __mmplayer_start_streaming_ext(mm_player_t *player);
222 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
223 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
225 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
226 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
227 static void __mmplayer_check_pipeline(mm_player_t* player);
228 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
229 static void __mmplayer_deactivate_old_path(mm_player_t *player);
231 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
232 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
234 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
235 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
236 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
237 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
238 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
239 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
240 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
241 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
242 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
245 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
246 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
247 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
248 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
249 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
250 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type);
252 /*===========================================================================================
254 | FUNCTION DEFINITIONS |
256 ========================================================================================== */
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
264 count = gst_tag_list_get_tag_size(list, tag);
266 LOGD("count = %d", count);
268 for (i = 0; i < count; i++) {
271 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272 if (!gst_tag_list_get_string_index(list, tag, i, &str))
273 g_assert_not_reached();
275 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
278 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
280 g_print(" : %s\n", str);
287 /* This function should be called after the pipeline goes PAUSED or higher
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
292 static gboolean has_duration = FALSE;
293 static gboolean has_video_attrs = FALSE;
294 static gboolean has_audio_attrs = FALSE;
295 static gboolean has_bitrate = FALSE;
296 gboolean missing_only = FALSE;
297 gboolean all = FALSE;
299 GstStructure* p = NULL;
300 MMHandleType attrs = 0;
306 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
308 /* check player state here */
309 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311 /* give warning now only */
312 LOGW("be careful. content attributes may not available in this state ");
315 /* get content attribute first */
316 attrs = MMPLAYER_GET_ATTRS(player);
318 LOGE("cannot get content attribute");
322 /* get update flag */
324 if (flag & ATTR_MISSING_ONLY) {
326 LOGD("updating missed attr only");
329 if (flag & ATTR_ALL) {
331 has_duration = FALSE;
332 has_video_attrs = FALSE;
333 has_audio_attrs = FALSE;
336 LOGD("updating all attrs");
339 if (missing_only && all) {
340 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341 missing_only = FALSE;
344 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345 LOGD("try to update duration");
346 has_duration = FALSE;
348 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349 player->duration = dur_nsec;
350 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
354 if (player->duration < 0) {
355 LOGW("duration is Non-Initialized !!!");
356 player->duration = 0;
359 /* update streaming service type */
360 player->streaming_type = __mmplayer_get_stream_service_type(player);
362 /* check duration is OK */
363 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364 /* FIXIT : find another way to get duration here. */
365 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
369 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370 /* update audio params
371 NOTE : We need original audio params and it can be only obtained from src pad of audio
372 decoder. Below code only valid when we are not using 'resampler' just before
375 LOGD("try to update audio attrs");
376 has_audio_attrs = FALSE;
378 if (player->pipeline->audiobin &&
379 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380 GstCaps *caps_a = NULL;
382 gint samplerate = 0, channels = 0;
384 pad = gst_element_get_static_pad(
385 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
388 caps_a = gst_pad_get_current_caps(pad);
391 p = gst_caps_get_structure(caps_a, 0);
393 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
395 gst_structure_get_int(p, "rate", &samplerate);
396 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
398 gst_structure_get_int(p, "channels", &channels);
399 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
401 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
403 gst_caps_unref(caps_a);
406 has_audio_attrs = TRUE;
408 LOGW("not ready to get audio caps");
410 gst_object_unref(pad);
412 LOGW("failed to get pad from audiosink");
416 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417 LOGD("try to update video attrs");
418 has_video_attrs = FALSE;
420 if (player->pipeline->videobin &&
421 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422 GstCaps *caps_v = NULL;
427 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
429 caps_v = gst_pad_get_current_caps(pad);
431 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432 if (!caps_v && player->v_stream_caps) {
433 caps_v = player->v_stream_caps;
434 gst_caps_ref(caps_v);
438 p = gst_caps_get_structure(caps_v, 0);
439 gst_structure_get_int(p, "width", &width);
440 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
442 gst_structure_get_int(p, "height", &height);
443 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
445 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
447 SECURE_LOGD("width : %d height : %d", width, height);
449 gst_caps_unref(caps_v);
453 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
457 has_video_attrs = TRUE;
459 LOGD("no negitiated caps from videosink");
460 gst_object_unref(pad);
463 LOGD("no videosink sink pad");
469 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
472 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473 if (player->duration) {
474 guint64 data_size = 0;
476 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
479 if (stat(path, &sb) == 0)
480 data_size = (guint64)sb.st_size;
481 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482 data_size = player->http_content_size;
484 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
488 guint64 msec_dur = 0;
490 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
492 bitrate = data_size * 8 * 1000 / msec_dur;
493 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
498 LOGD("player duration is less than 0");
502 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503 if (player->total_bitrate) {
504 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
512 if (mmf_attrs_commit(attrs)) {
513 LOGE("failed to update attributes\n");
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
524 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
528 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
530 player->pipeline->mainbin &&
531 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532 STREAMING_SERVICE_NONE);
534 /* streaming service type if streaming */
535 if (!MMPLAYER_IS_STREAMING(player))
536 return STREAMING_SERVICE_NONE;
538 if (MMPLAYER_IS_HTTP_STREAMING(player))
539 streaming_type = (player->duration == 0) ?
540 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
542 switch (streaming_type) {
543 case STREAMING_SERVICE_LIVE:
544 LOGD("it's live streaming");
546 case STREAMING_SERVICE_VOD:
547 LOGD("it's vod streaming");
550 LOGE("should not get here");
556 return streaming_type;
560 /* this function sets the player state and also report
561 * it to applicaton by calling callback function
564 __mmplayer_set_state(mm_player_t* player, int state)
566 MMMessageParamType msg = {0, };
567 gboolean post_bos = FALSE;
569 MMPLAYER_RETURN_IF_FAIL(player);
571 if (MMPLAYER_CURRENT_STATE(player) == state) {
572 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
577 /* update player states */
578 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579 MMPLAYER_CURRENT_STATE(player) = state;
581 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
585 MMPLAYER_PRINT_STATE(player);
587 switch (MMPLAYER_CURRENT_STATE(player)) {
588 case MM_PLAYER_STATE_NULL:
589 case MM_PLAYER_STATE_READY:
592 case MM_PLAYER_STATE_PAUSED:
594 if (!player->sent_bos) {
595 /* rtsp case, get content attrs by GstMessage */
596 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597 /* it's first time to update all content attrs. */
598 _mmplayer_update_content_attrs(player, ATTR_ALL);
602 /* add audio callback probe if condition is satisfied */
603 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604 __mmplayer_configure_audio_callback(player);
606 /* FIXIT : handle return value */
610 case MM_PLAYER_STATE_PLAYING:
612 /* try to get content metadata */
613 if (!player->sent_bos) {
614 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615 * c-api since c-api doesn't use _start() anymore. It may not work propery with
616 * legacy mmfw-player api */
617 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
620 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621 if (!player->sent_bos)
622 __mmplayer_handle_missed_plugin(player);
625 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626 /* initialize because auto resume is done well. */
627 player->resumed_by_rewind = FALSE;
628 player->playback_rate = 1.0;
631 if (!player->sent_bos) {
632 /* check audio codec field is set or not
633 * we can get it from typefinder or codec's caps.
635 gchar *audio_codec = NULL;
636 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
638 /* The codec format can't be sent for audio only case like amr, mid etc.
639 * Because, parser don't make related TAG.
640 * So, if it's not set yet, fill it with found data.
643 if (g_strrstr(player->type, "audio/midi"))
644 audio_codec = g_strdup("MIDI");
645 else if (g_strrstr(player->type, "audio/x-amr"))
646 audio_codec = g_strdup("AMR");
647 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648 audio_codec = g_strdup("AAC");
650 audio_codec = g_strdup("unknown");
651 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
653 MMPLAYER_FREEIF(audio_codec);
654 if (mmf_attrs_commit(player->attrs))
655 LOGE("failed to update attributes\n");
657 LOGD("set audio codec type with caps\n");
665 case MM_PLAYER_STATE_NONE:
667 LOGW("invalid target state, there is nothing to do.\n");
672 /* post message to application */
673 if (MMPLAYER_TARGET_STATE(player) == state) {
674 /* fill the message with state of player */
675 msg.union_type = MM_MSG_UNION_STATE;
676 msg.state.previous = MMPLAYER_PREV_STATE(player);
677 msg.state.current = MMPLAYER_CURRENT_STATE(player);
679 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
681 /* state changed by resource callback */
682 if (player->interrupted_by_resource) {
683 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
684 } else { /* state changed by usecase */
685 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
688 LOGD("intermediate state, do nothing.\n");
689 MMPLAYER_PRINT_STATE(player);
694 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
695 player->sent_bos = TRUE;
701 static gpointer __mmplayer_next_play_thread(gpointer data)
703 mm_player_t* player = (mm_player_t*) data;
704 MMPlayerGstElement *mainbin = NULL;
706 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
709 while (!player->next_play_thread_exit) {
710 LOGD("next play thread started. waiting for signal.\n");
711 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
713 LOGD("reconfigure pipeline for gapless play.\n");
715 if (player->next_play_thread_exit) {
716 if (player->gapless.reconfigure) {
717 player->gapless.reconfigure = false;
718 MMPLAYER_PLAYBACK_UNLOCK(player);
720 LOGD("exiting gapless play thread\n");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
734 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
740 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
742 MMHandleType attrs = 0;
743 guint64 data_size = 0;
748 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
750 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec); /* to update player->last_position */
752 attrs = MMPLAYER_GET_ATTRS(player);
754 LOGE("fail to get attributes.\n");
758 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
759 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
761 if (stat(path, &sb) == 0)
762 data_size = (guint64)sb.st_size;
763 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
764 data_size = player->http_content_size;
766 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
767 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
773 __mmplayer_handle_buffering_message(mm_player_t* player)
775 int ret = MM_ERROR_NONE;
776 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
777 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
778 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
779 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
781 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
782 LOGW("do nothing for buffering msg\n");
783 ret = MM_ERROR_PLAYER_INVALID_STATE;
787 prev_state = MMPLAYER_PREV_STATE(player);
788 current_state = MMPLAYER_CURRENT_STATE(player);
789 target_state = MMPLAYER_TARGET_STATE(player);
790 pending_state = MMPLAYER_PENDING_STATE(player);
792 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
793 MMPLAYER_STATE_GET_NAME(prev_state),
794 MMPLAYER_STATE_GET_NAME(current_state),
795 MMPLAYER_STATE_GET_NAME(pending_state),
796 MMPLAYER_STATE_GET_NAME(target_state),
797 player->streamer->buffering_state);
799 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
800 /* NOTE : if buffering has done, player has to go to target state. */
801 switch (target_state) {
802 case MM_PLAYER_STATE_PAUSED:
804 switch (pending_state) {
805 case MM_PLAYER_STATE_PLAYING:
806 __gst_pause(player, TRUE);
809 case MM_PLAYER_STATE_PAUSED:
810 LOGD("player is already going to paused state, there is nothing to do.\n");
813 case MM_PLAYER_STATE_NONE:
814 case MM_PLAYER_STATE_NULL:
815 case MM_PLAYER_STATE_READY:
817 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
823 case MM_PLAYER_STATE_PLAYING:
825 switch (pending_state) {
826 case MM_PLAYER_STATE_NONE:
828 if (current_state != MM_PLAYER_STATE_PLAYING)
829 __gst_resume(player, TRUE);
833 case MM_PLAYER_STATE_PAUSED:
834 /* NOTE: It should be worked as asynchronously.
835 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
837 if (current_state == MM_PLAYER_STATE_PLAYING) {
838 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
839 * The current state should be changed to paused purposely to prevent state conflict.
841 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
843 __gst_resume(player, TRUE);
846 case MM_PLAYER_STATE_PLAYING:
847 LOGD("player is already going to playing state, there is nothing to do.\n");
850 case MM_PLAYER_STATE_NULL:
851 case MM_PLAYER_STATE_READY:
853 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
859 case MM_PLAYER_STATE_NULL:
860 case MM_PLAYER_STATE_READY:
861 case MM_PLAYER_STATE_NONE:
863 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
867 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
868 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
870 switch (pending_state) {
871 case MM_PLAYER_STATE_NONE:
873 if (current_state != MM_PLAYER_STATE_PAUSED) {
874 /* rtsp streaming pause makes rtsp server stop sending data. */
875 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
876 LOGD("set pause state during buffering\n");
877 __gst_pause(player, TRUE);
883 case MM_PLAYER_STATE_PLAYING:
884 /* rtsp streaming pause makes rtsp server stop sending data. */
885 if (!MMPLAYER_IS_RTSP_STREAMING(player))
886 __gst_pause(player, TRUE);
889 case MM_PLAYER_STATE_PAUSED:
892 case MM_PLAYER_STATE_NULL:
893 case MM_PLAYER_STATE_READY:
895 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
905 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
907 MMPlayerGstElement *textbin;
910 MMPLAYER_RETURN_IF_FAIL(player &&
912 player->pipeline->textbin);
914 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
916 textbin = player->pipeline->textbin;
919 LOGD("Drop subtitle text after getting EOS\n");
921 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
922 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
924 player->is_subtitle_force_drop = TRUE;
926 if (player->is_subtitle_force_drop == TRUE) {
927 LOGD("Enable subtitle data path without drop\n");
929 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
930 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
932 LOGD("non-connected with external display");
934 player->is_subtitle_force_drop = FALSE;
940 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
942 VariantData *var_info = NULL;
943 g_return_val_if_fail(self != NULL, NULL);
945 var_info = g_new0(VariantData, 1);
946 if (!var_info) return NULL;
947 var_info->bandwidth = self->bandwidth;
948 var_info->width = self->width;
949 var_info->height = self->height;
953 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
955 mm_player_t* player = (mm_player_t*)hplayer;
956 GstMessage *msg = NULL;
957 GQueue *queue = NULL;
960 MMPLAYER_RETURN_IF_FAIL(player);
962 /* disconnecting bus watch */
963 if (player->bus_watcher)
964 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
965 player->bus_watcher = 0;
967 /* destroy the gst bus msg thread */
968 if (player->bus_msg_thread) {
969 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
970 player->bus_msg_thread_exit = TRUE;
971 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
972 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
974 LOGD("gst bus msg thread exit.");
975 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
976 player->bus_msg_thread = NULL;
978 g_mutex_clear(&player->bus_msg_thread_mutex);
979 g_cond_clear(&player->bus_msg_thread_cond);
982 g_mutex_lock(&player->bus_msg_q_lock);
983 queue = player->bus_msg_q;
984 while (!g_queue_is_empty(queue)) {
985 msg = (GstMessage *)g_queue_pop_head(queue);
986 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
987 gst_message_unref(msg);
989 g_mutex_unlock(&player->bus_msg_q_lock);
994 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
996 mm_player_t *player = (mm_player_t *) data;
998 g_return_val_if_fail(player, FALSE);
999 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1001 gst_message_ref(msg);
1003 g_mutex_lock(&player->bus_msg_q_lock);
1004 g_queue_push_tail(player->bus_msg_q, msg);
1005 g_mutex_unlock(&player->bus_msg_q_lock);
1007 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1008 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1009 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1013 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1015 mm_player_t *player = (mm_player_t*)(data);
1016 GstMessage *msg = NULL;
1020 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1022 player->pipeline->mainbin &&
1023 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1026 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1028 LOGE("cannot get BUS from the pipeline");
1032 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1034 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1035 while (!player->bus_msg_thread_exit) {
1036 g_mutex_lock(&player->bus_msg_q_lock);
1037 msg = g_queue_pop_head(player->bus_msg_q);
1038 g_mutex_unlock(&player->bus_msg_q_lock);
1040 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1043 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1044 /* handle the gst msg */
1045 __mmplayer_gst_callback(msg, player);
1046 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1047 gst_message_unref(msg);
1050 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1051 gst_object_unref(GST_OBJECT(bus));
1058 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1060 mm_player_t* player = (mm_player_t*)(data);
1062 MMPLAYER_RETURN_IF_FAIL(player);
1063 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1065 switch (GST_MESSAGE_TYPE(msg)) {
1066 case GST_MESSAGE_UNKNOWN:
1067 LOGD("unknown message received\n");
1070 case GST_MESSAGE_EOS:
1072 MMHandleType attrs = 0;
1075 LOGD("GST_MESSAGE_EOS received\n");
1077 /* NOTE : EOS event is comming multiple time. watch out it */
1078 /* check state. we only process EOS when pipeline state goes to PLAYING */
1079 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1080 LOGD("EOS received on non-playing state. ignoring it\n");
1084 if (player->pipeline) {
1085 if (player->pipeline->textbin)
1086 __mmplayer_drop_subtitle(player, TRUE);
1088 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1091 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1093 LOGD("release audio callback\n");
1095 /* release audio callback */
1096 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1097 player->audio_cb_probe_id = 0;
1098 /* audio callback should be free because it can be called even though probe remove.*/
1099 player->audio_stream_cb = NULL;
1100 player->audio_stream_cb_user_param = NULL;
1104 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1105 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1107 /* rewind if repeat count is greater then zero */
1108 /* get play count */
1109 attrs = MMPLAYER_GET_ATTRS(player);
1112 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1114 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1116 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1117 if (player->playback_rate < 0.0) {
1118 player->resumed_by_rewind = TRUE;
1119 _mmplayer_set_mute((MMHandleType)player, 0);
1120 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1123 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1126 player->sent_bos = FALSE;
1128 /* not posting eos when repeating */
1133 if (player->pipeline)
1134 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1136 /* post eos message to application */
1137 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1139 /* reset last position */
1140 player->last_position = 0;
1144 case GST_MESSAGE_ERROR:
1146 GError *error = NULL;
1147 gchar* debug = NULL;
1149 /* generating debug info before returning error */
1150 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1152 /* get error code */
1153 gst_message_parse_error(msg, &error, &debug);
1155 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1156 /* Note : the streaming error from the streaming source is handled
1157 * using __mmplayer_handle_streaming_error.
1159 __mmplayer_handle_streaming_error(player, msg);
1161 /* dump state of all element */
1162 __mmplayer_dump_pipeline_state(player);
1164 /* traslate gst error code to msl error code. then post it
1165 * to application if needed
1167 __mmplayer_handle_gst_error(player, msg, error);
1170 LOGE("error debug : %s", debug);
1173 if (MMPLAYER_IS_HTTP_PD(player))
1174 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1176 MMPLAYER_FREEIF(debug);
1177 g_error_free(error);
1181 case GST_MESSAGE_WARNING:
1184 GError* error = NULL;
1186 gst_message_parse_warning(msg, &error, &debug);
1188 LOGD("warning : %s\n", error->message);
1189 LOGD("debug : %s\n", debug);
1191 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1193 MMPLAYER_FREEIF(debug);
1194 g_error_free(error);
1198 case GST_MESSAGE_TAG:
1200 LOGD("GST_MESSAGE_TAG\n");
1201 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1202 LOGW("failed to extract tags from gstmessage\n");
1206 case GST_MESSAGE_BUFFERING:
1208 MMMessageParamType msg_param = {0, };
1209 int bRet = MM_ERROR_NONE;
1211 if (!(player->pipeline && player->pipeline->mainbin)) {
1212 LOGE("Pipeline is not initialized");
1216 if (!MMPLAYER_IS_STREAMING(player))
1219 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1220 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1221 /* skip the playback control by buffering msg while user request is handled. */
1224 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1226 gst_message_parse_buffering(msg, &per);
1227 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1229 msg_param.connection.buffering = per;
1230 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1234 MMPLAYER_CMD_LOCK(player);
1237 if (!player->streamer) {
1238 LOGW("Pipeline is shutting down");
1239 MMPLAYER_CMD_UNLOCK(player);
1243 /* ignore the remained buffering message till getting 100% msg */
1244 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1245 gint buffer_percent = 0;
1247 gst_message_parse_buffering(msg, &buffer_percent);
1249 if (buffer_percent == MAX_BUFFER_PERCENT) {
1250 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1251 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1253 MMPLAYER_CMD_UNLOCK(player);
1257 /* ignore the remained buffering message */
1258 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1259 gint buffer_percent = 0;
1261 gst_message_parse_buffering(msg, &buffer_percent);
1263 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1264 player->streamer->buffering_percent, buffer_percent);
1266 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1267 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1268 player->streamer->buffering_req.is_pre_buffering = FALSE;
1270 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1272 LOGD("interrupted buffering - ignored the remained buffering msg!");
1273 MMPLAYER_CMD_UNLOCK(player);
1278 __mmplayer_update_buffer_setting(player, msg);
1280 bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1282 if (bRet == MM_ERROR_NONE) {
1283 msg_param.connection.buffering = player->streamer->buffering_percent;
1284 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1286 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1287 player->pending_resume &&
1288 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1290 player->is_external_subtitle_added_now = FALSE;
1291 player->pending_resume = FALSE;
1292 _mmplayer_resume((MMHandleType)player);
1295 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1296 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1298 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1299 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1300 player->seek_state = MMPLAYER_SEEK_NONE;
1301 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1302 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1303 /* Considering the async state trasition in case of RTSP.
1304 After getting state change gst msg, seek cmpleted msg will be posted. */
1305 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1309 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310 if (!player->streamer) {
1311 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312 MMPLAYER_CMD_UNLOCK(player);
1316 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1318 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1321 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322 msg_param.connection.buffering = player->streamer->buffering_percent;
1323 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1325 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1328 msg_param.connection.buffering = player->streamer->buffering_percent;
1329 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1332 MMPLAYER_CMD_UNLOCK(player);
1336 case GST_MESSAGE_STATE_CHANGED:
1338 MMPlayerGstElement *mainbin;
1339 const GValue *voldstate, *vnewstate, *vpending;
1340 GstState oldstate = GST_STATE_NULL;
1341 GstState newstate = GST_STATE_NULL;
1342 GstState pending = GST_STATE_NULL;
1344 if (!(player->pipeline && player->pipeline->mainbin)) {
1345 LOGE("player pipeline handle is null");
1349 mainbin = player->pipeline->mainbin;
1351 /* we only handle messages from pipeline */
1352 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1355 /* get state info from msg */
1356 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1360 if (!voldstate || !vnewstate) {
1361 LOGE("received msg has wrong format.");
1365 oldstate = (GstState)voldstate->data[0].v_int;
1366 newstate = (GstState)vnewstate->data[0].v_int;
1368 pending = (GstState)vpending->data[0].v_int;
1370 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1371 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372 gst_element_state_get_name((GstState)oldstate),
1373 gst_element_state_get_name((GstState)newstate),
1374 gst_element_state_get_name((GstState)pending));
1376 if (newstate == GST_STATE_PLAYING) {
1377 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1379 int retVal = MM_ERROR_NONE;
1380 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1382 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1384 if (MM_ERROR_NONE != retVal)
1385 LOGE("failed to seek pending postion. just keep staying current position.\n");
1387 player->pending_seek.is_pending = FALSE;
1391 if (oldstate == newstate) {
1392 LOGD("pipeline reports state transition to old state");
1397 case GST_STATE_VOID_PENDING:
1400 case GST_STATE_NULL:
1403 case GST_STATE_READY:
1406 case GST_STATE_PAUSED:
1408 gboolean prepare_async = FALSE;
1410 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411 __mmplayer_configure_audio_callback(player);
1413 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414 // managed prepare async case
1415 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416 LOGD("checking prepare mode for async transition - %d", prepare_async);
1419 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1422 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423 __mm_player_streaming_set_content_bitrate(player->streamer,
1424 player->total_maximum_bitrate, player->total_bitrate);
1426 if (player->pending_seek.is_pending) {
1427 LOGW("trying to do pending seek");
1428 MMPLAYER_CMD_LOCK(player);
1429 __gst_pending_seek(player);
1430 MMPLAYER_CMD_UNLOCK(player);
1436 case GST_STATE_PLAYING:
1438 if (MMPLAYER_IS_STREAMING(player)) {
1439 // managed prepare async case when buffering is completed
1440 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1445 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1447 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448 if (player->streamer->buffering_percent < 100) {
1450 MMMessageParamType msg_param = {0, };
1451 LOGW("Posting Buffering Completed Message to Application !!!");
1453 msg_param.connection.buffering = 100;
1454 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1459 if (player->gapless.stream_changed) {
1460 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461 player->gapless.stream_changed = FALSE;
1464 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1465 player->seek_state = MMPLAYER_SEEK_NONE;
1466 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1477 case GST_MESSAGE_CLOCK_LOST:
1479 GstClock *clock = NULL;
1480 gboolean need_new_clock = FALSE;
1482 gst_message_parse_clock_lost(msg, &clock);
1483 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1485 if (!player->videodec_linked)
1486 need_new_clock = TRUE;
1487 else if (!player->ini.use_system_clock)
1488 need_new_clock = TRUE;
1490 if (need_new_clock) {
1491 LOGD("Provide clock is TRUE, do pause->resume\n");
1492 __gst_pause(player, FALSE);
1493 __gst_resume(player, FALSE);
1498 case GST_MESSAGE_NEW_CLOCK:
1500 GstClock *clock = NULL;
1501 gst_message_parse_new_clock(msg, &clock);
1502 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1506 case GST_MESSAGE_ELEMENT:
1508 const gchar *structure_name;
1509 gint count = 0, idx = 0;
1510 MMHandleType attrs = 0;
1512 attrs = MMPLAYER_GET_ATTRS(player);
1514 LOGE("cannot get content attribute");
1518 if (gst_message_get_structure(msg) == NULL)
1521 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1522 if (!structure_name)
1525 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1527 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1528 const GValue *var_info = NULL;
1530 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1531 if (var_info != NULL) {
1532 if (player->adaptive_info.var_list)
1533 g_list_free_full(player->adaptive_info.var_list, g_free);
1535 /* share addr or copy the list */
1536 player->adaptive_info.var_list =
1537 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1539 count = g_list_length(player->adaptive_info.var_list);
1541 VariantData *temp = NULL;
1543 /* print out for debug */
1544 LOGD("num of variant_info %d", count);
1545 for (idx = 0; idx < count; idx++) {
1546 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1548 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1554 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1555 gint num_buffers = 0;
1556 gint extra_num_buffers = 0;
1558 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1559 player->video_num_buffers = num_buffers;
1560 LOGD("video_num_buffers : %d", player->video_num_buffers);
1563 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1564 player->video_extra_num_buffers = extra_num_buffers;
1565 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1570 if (!strcmp(structure_name, "Language_list")) {
1571 const GValue *lang_list = NULL;
1572 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1573 if (lang_list != NULL) {
1574 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1576 LOGD("Total audio tracks(from parser) = %d \n", count);
1580 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1581 const GValue *lang_list = NULL;
1582 MMPlayerLangStruct *temp = NULL;
1584 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1585 if (lang_list != NULL) {
1586 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1588 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1589 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1590 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1591 if (mmf_attrs_commit(attrs))
1592 LOGE("failed to commit.\n");
1593 LOGD("Total subtitle tracks = %d \n", count);
1596 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1598 LOGD("value of lang_key is %s and lang_code is %s",
1599 temp->language_key, temp->language_code);
1602 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1603 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1608 /* custom message */
1609 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1610 MMMessageParamType msg_param = {0,};
1611 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1612 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1615 /* custom message for RTSP attribute :
1616 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1617 sdp which has contents info is received when rtsp connection is opened.
1618 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1619 if (!strcmp(structure_name, "rtspsrc_properties")) {
1621 gchar *audio_codec = NULL;
1622 gchar *video_codec = NULL;
1623 gchar *video_frame_size = NULL;
1625 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1626 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1627 player->streaming_type = __mmplayer_get_stream_service_type(player);
1629 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1630 LOGD("rtsp_audio_codec : %s", audio_codec);
1632 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1634 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1635 LOGD("rtsp_video_codec : %s", video_codec);
1637 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1639 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1640 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1641 if (video_frame_size) {
1643 char *seperator = strchr(video_frame_size, '-');
1646 char video_width[10] = {0,};
1647 int frame_size_len = strlen(video_frame_size);
1648 int separtor_len = strlen(seperator);
1650 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1651 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1654 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1658 if (mmf_attrs_commit(attrs))
1659 LOGE("failed to commit.\n");
1664 case GST_MESSAGE_DURATION_CHANGED:
1666 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1667 if (!__mmplayer_gst_handle_duration(player, msg))
1668 LOGW("failed to update duration");
1673 case GST_MESSAGE_ASYNC_START:
1674 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1677 case GST_MESSAGE_ASYNC_DONE:
1679 MMPlayerGstElement *mainbin;
1681 if (!(player->pipeline && player->pipeline->mainbin)) {
1682 LOGE("player pipeline handle is null");
1686 mainbin = player->pipeline->mainbin;
1688 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1690 /* we only handle messages from pipeline */
1691 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1694 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1695 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1696 player->seek_state = MMPLAYER_SEEK_NONE;
1697 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1698 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1699 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1700 LOGD("sync %s state(%s) with parent state(%s)",
1701 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1702 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1703 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1705 /* In case of streaming, pause is required before finishing seeking by buffering.
1706 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1707 Because the buffering state is controlled according to the state transition for force resume,
1708 the decodebin state should be paused as player state. */
1709 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1712 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1713 (player->streamer) &&
1714 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1715 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1716 GstQuery *query = NULL;
1717 gboolean busy = FALSE;
1720 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1721 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1722 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1723 gst_query_parse_buffering_percent(query, &busy, &percent);
1724 gst_query_unref(query);
1726 LOGD("buffered percent(%s): %d\n",
1727 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1731 __mmplayer_handle_buffering_message(player);
1734 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1740 #if 0 /* delete unnecessary logs */
1741 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1742 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1743 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1744 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1745 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1746 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1747 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1748 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1749 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1750 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1751 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1752 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1753 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1754 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1755 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1762 /* should not call 'gst_message_unref(msg)' */
1767 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1773 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1774 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1776 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1777 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1778 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1780 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1781 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1782 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1785 /* handling audio clip which has vbr. means duration is keep changing */
1786 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1794 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1795 mm_player_spherical_metadata_t *metadata) {
1796 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1797 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1798 gst_tag_list_get_string(tags, "stitching_software",
1799 &metadata->stitching_software);
1800 gst_tag_list_get_string(tags, "projection_type",
1801 &metadata->projection_type_string);
1802 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1803 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1804 gst_tag_list_get_int(tags, "init_view_heading",
1805 &metadata->init_view_heading);
1806 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1807 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1808 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1809 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1810 &metadata->full_pano_width_pixels);
1811 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1812 &metadata->full_pano_height_pixels);
1813 gst_tag_list_get_int(tags, "cropped_area_image_width",
1814 &metadata->cropped_area_image_width);
1815 gst_tag_list_get_int(tags, "cropped_area_image_height",
1816 &metadata->cropped_area_image_height);
1817 gst_tag_list_get_int(tags, "cropped_area_left",
1818 &metadata->cropped_area_left);
1819 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1820 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1821 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1822 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1826 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1829 /* macro for better code readability */
1830 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1832 if (string != NULL) { \
1833 SECURE_LOGD("update tag string : %s\n", string); \
1834 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1835 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1836 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1837 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1838 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1839 g_free(new_string); \
1840 new_string = NULL; \
1842 mm_attrs_set_string_by_name(attribute, playertag, string); \
1849 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1851 GstSample *sample = NULL;\
1852 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1853 GstMapInfo info = GST_MAP_INFO_INIT;\
1854 buffer = gst_sample_get_buffer(sample);\
1855 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1856 LOGD("failed to get image data from tag");\
1857 gst_sample_unref(sample);\
1860 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1861 MMPLAYER_FREEIF(player->album_art);\
1862 player->album_art = (gchar *)g_malloc(info.size);\
1863 if (player->album_art) {\
1864 memcpy(player->album_art, info.data, info.size);\
1865 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1866 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1867 msg_param.data = (void *)player->album_art;\
1868 msg_param.size = info.size;\
1869 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1870 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1873 gst_buffer_unmap(buffer, &info);\
1874 gst_sample_unref(sample);\
1878 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1880 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1883 gchar *tag_list_str = NULL; \
1884 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1885 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1886 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1887 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1888 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1890 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1891 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1892 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1893 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1894 player->bitrate[track_type] = v_uint; \
1895 player->total_bitrate = 0; \
1896 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1897 player->total_bitrate += player->bitrate[i]; \
1898 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1899 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1900 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1901 player->maximum_bitrate[track_type] = v_uint; \
1902 player->total_maximum_bitrate = 0; \
1903 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1904 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1905 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1906 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1908 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1911 g_free(tag_list_str); \
1916 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1917 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1918 if (date != NULL) {\
1919 string = g_strdup_printf("%d", g_date_get_year(date));\
1920 mm_attrs_set_string_by_name(attribute, playertag, string);\
1921 SECURE_LOGD("metainfo year : %s\n", string);\
1922 MMPLAYER_FREEIF(string);\
1927 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1928 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1929 if (datetime != NULL) {\
1930 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1931 mm_attrs_set_string_by_name(attribute, playertag, string);\
1932 SECURE_LOGD("metainfo year : %s\n", string);\
1933 MMPLAYER_FREEIF(string);\
1934 gst_date_time_unref(datetime);\
1938 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1939 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1941 /* FIXIT : don't know how to store date */\
1947 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1948 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1950 /* FIXIT : don't know how to store date */\
1956 /* function start */
1957 GstTagList* tag_list = NULL;
1959 MMHandleType attrs = 0;
1961 char *string = NULL;
1964 GstDateTime *datetime = NULL;
1966 GstBuffer *buffer = NULL;
1968 MMMessageParamType msg_param = {0, };
1970 /* currently not used. but those are needed for above macro */
1971 //guint64 v_uint64 = 0;
1972 //gdouble v_double = 0;
1974 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1976 attrs = MMPLAYER_GET_ATTRS(player);
1978 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1980 /* get tag list from gst message */
1981 gst_message_parse_tag(msg, &tag_list);
1983 /* store tags to player attributes */
1984 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1985 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1986 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1987 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1988 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1989 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1990 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1991 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1992 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1993 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1994 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1995 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1996 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1997 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1998 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1999 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2000 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2001 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2002 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2003 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2004 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2005 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2006 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2007 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2008 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2009 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2010 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2011 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2012 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2013 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2014 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2015 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2016 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2017 MMPLAYER_UPDATE_TAG_LOCK(player);
2018 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2019 MMPLAYER_UPDATE_TAG_UNLOCK(player);
2020 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2021 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2022 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2023 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2024 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2025 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2026 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2027 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2028 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2029 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2030 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2031 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2032 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2034 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2035 if (player->video360_metadata.is_spherical == -1) {
2036 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2037 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2038 player->video360_metadata.is_spherical);
2039 if (player->video360_metadata.is_spherical == 1) {
2040 LOGD("This is spherical content for 360 playback.");
2041 player->is_content_spherical = TRUE;
2043 LOGD("This is not spherical content");
2044 player->is_content_spherical = FALSE;
2047 if (player->video360_metadata.projection_type_string) {
2048 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2049 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2051 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2052 player->is_content_spherical = player->is_video360_enabled = FALSE;
2056 if (player->video360_metadata.stereo_mode_string) {
2057 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2058 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2059 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2060 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2061 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2062 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2064 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2065 player->is_content_spherical = player->is_video360_enabled = FALSE;
2071 if (mmf_attrs_commit(attrs))
2072 LOGE("failed to commit.\n");
2074 gst_tag_list_free(tag_list);
2080 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2082 mm_player_t* player = (mm_player_t*) data;
2086 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2087 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2088 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2089 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2091 * [1] audio and video will be dumped with filesink.
2092 * [2] autoplugging is done by just using pad caps.
2093 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2094 * and the video will be dumped via filesink.
2096 if (player->num_dynamic_pad == 0) {
2097 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2099 if (!__mmplayer_gst_remove_fakesink(player,
2100 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2101 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2102 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2103 * source element are not same. To overcome this situation, this function will called
2104 * several places and several times. Therefore, this is not an error case.
2109 /* create dot before error-return. for debugging */
2110 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2112 player->no_more_pad = TRUE;
2118 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2120 GstElement* parent = NULL;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2124 /* if we have no fakesink. this meas we are using decodebin which doesn'
2125 t need to add extra fakesink */
2126 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2129 MMPLAYER_FSINK_LOCK(player);
2134 /* get parent of fakesink */
2135 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2137 LOGD("fakesink already removed\n");
2141 gst_element_set_locked_state(fakesink->gst, TRUE);
2143 /* setting the state to NULL never returns async
2144 * so no need to wait for completion of state transiton
2146 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2147 LOGE("fakesink state change failure!\n");
2148 /* FIXIT : should I return here? or try to proceed to next? */
2151 /* remove fakesink from it's parent */
2152 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2153 LOGE("failed to remove fakesink\n");
2155 gst_object_unref(parent);
2160 gst_object_unref(parent);
2162 LOGD("state-holder removed\n");
2164 gst_element_set_locked_state(fakesink->gst, FALSE);
2166 MMPLAYER_FSINK_UNLOCK(player);
2171 gst_element_set_locked_state(fakesink->gst, FALSE);
2173 MMPLAYER_FSINK_UNLOCK(player);
2179 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2181 GstPad *sinkpad = NULL;
2182 GstCaps* caps = NULL;
2183 GstElement* new_element = NULL;
2184 GstStructure* str = NULL;
2185 const gchar* name = NULL;
2187 mm_player_t* player = (mm_player_t*) data;
2191 MMPLAYER_RETURN_IF_FAIL(element && pad);
2192 MMPLAYER_RETURN_IF_FAIL(player &&
2194 player->pipeline->mainbin);
2197 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2198 * num_dynamic_pad will decreased after creating a sinkbin.
2200 player->num_dynamic_pad++;
2201 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2203 caps = gst_pad_query_caps(pad, NULL);
2205 MMPLAYER_CHECK_NULL(caps);
2207 /* clear previous result*/
2208 player->have_dynamic_pad = FALSE;
2210 str = gst_caps_get_structure(caps, 0);
2213 LOGE("cannot get structure from caps.\n");
2217 name = gst_structure_get_name(str);
2219 LOGE("cannot get mimetype from structure.\n");
2223 if (strstr(name, "video")) {
2225 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2227 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2228 if (player->v_stream_caps) {
2229 gst_caps_unref(player->v_stream_caps);
2230 player->v_stream_caps = NULL;
2233 new_element = gst_element_factory_make("fakesink", NULL);
2234 player->num_dynamic_pad--;
2239 /* clear previous result*/
2240 player->have_dynamic_pad = FALSE;
2242 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2243 LOGE("failed to autoplug for caps");
2247 /* check if there's dynamic pad*/
2248 if (player->have_dynamic_pad) {
2249 LOGE("using pad caps assums there's no dynamic pad !\n");
2253 gst_caps_unref(caps);
2258 /* excute new_element if created*/
2260 LOGD("adding new element to pipeline\n");
2262 /* set state to READY before add to bin */
2263 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2265 /* add new element to the pipeline */
2266 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2267 LOGE("failed to add autoplug element to bin\n");
2271 /* get pad from element */
2272 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2274 LOGE("failed to get sinkpad from autoplug element\n");
2279 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2280 LOGE("failed to link autoplug element\n");
2284 gst_object_unref(sinkpad);
2287 /* run. setting PLAYING here since streamming source is live source */
2288 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2292 gst_caps_unref(caps);
2298 STATE_CHANGE_FAILED:
2300 /* FIXIT : take care if new_element has already added to pipeline */
2302 gst_object_unref(GST_OBJECT(new_element));
2305 gst_object_unref(GST_OBJECT(sinkpad));
2308 gst_caps_unref(caps);
2310 /* FIXIT : how to inform this error to MSL ????? */
2311 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2312 * then post an error to application
2316 static GstPadProbeReturn
2317 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2319 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2320 return GST_PAD_PROBE_OK;
2323 static GstPadProbeReturn
2324 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2326 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2327 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2328 mm_player_t* player = (mm_player_t*)data;
2329 GstCaps* caps = NULL;
2330 GstStructure* str = NULL;
2331 const gchar* name = NULL;
2332 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2335 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2336 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2337 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2338 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2339 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2341 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2342 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2346 caps = gst_pad_query_caps(pad, NULL);
2348 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2352 str = gst_caps_get_structure(caps, 0);
2354 LOGE("failed to get structure from caps");
2358 name = gst_structure_get_name(str);
2360 LOGE("failed to get name from str");
2364 if (strstr(name, "audio")) {
2365 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2366 } else if (strstr(name, "video")) {
2367 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2369 /* text track is not supportable */
2370 LOGE("invalid name %s", name);
2374 switch (GST_EVENT_TYPE(event)) {
2377 /* in case of gapless, drop eos event not to send it to sink */
2378 if (player->gapless.reconfigure && !player->msg_posted) {
2379 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2380 ret = GST_PAD_PROBE_DROP;
2384 case GST_EVENT_STREAM_START:
2386 gint64 stop_running_time = 0;
2387 gint64 position_running_time = 0;
2388 gint64 position = 0;
2391 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2392 if ((player->gapless.update_segment[idx] == TRUE) ||
2393 !(player->selector[idx].event_probe_id)) {
2394 /* LOGW("[%d] skip", idx); */
2398 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2400 gst_segment_to_running_time(&player->gapless.segment[idx],
2401 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2402 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2404 gst_segment_to_running_time(&player->gapless.segment[idx],
2405 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2407 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2409 gst_segment_to_running_time(&player->gapless.segment[idx],
2410 GST_FORMAT_TIME, player->duration);
2413 position_running_time =
2414 gst_segment_to_running_time(&player->gapless.segment[idx],
2415 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2417 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2418 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2420 GST_TIME_ARGS(stop_running_time),
2421 GST_TIME_ARGS(position_running_time),
2422 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2423 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2425 position_running_time = MAX(position_running_time, stop_running_time);
2426 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2427 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2428 position_running_time = MAX(0, position_running_time);
2429 position = MAX(position, position_running_time);
2432 if (position != 0) {
2433 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2434 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2435 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2437 player->gapless.start_time[stream_type] += position;
2441 case GST_EVENT_FLUSH_STOP:
2443 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2444 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2445 player->gapless.start_time[stream_type] = 0;
2448 case GST_EVENT_SEGMENT:
2453 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2454 gst_event_copy_segment(event, &segment);
2456 if (segment.format == GST_FORMAT_TIME) {
2457 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2458 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2459 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2460 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2461 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2462 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2464 /* keep the all the segment ev to cover the seeking */
2465 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2466 player->gapless.update_segment[stream_type] = TRUE;
2468 if (!player->gapless.running)
2471 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2473 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2475 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2476 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2477 gst_event_unref(event);
2478 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2484 gdouble proportion = 0.0;
2485 GstClockTimeDiff diff = 0;
2486 GstClockTime timestamp = 0;
2487 gint64 running_time_diff = -1;
2488 GstQOSType type = 0;
2489 GstEvent *tmpev = NULL;
2491 running_time_diff = player->gapless.segment[stream_type].base;
2493 if (running_time_diff <= 0) /* don't need to adjust */
2496 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2497 gst_event_unref(event);
2499 if (timestamp < running_time_diff) {
2500 LOGW("QOS event from previous group");
2501 ret = GST_PAD_PROBE_DROP;
2505 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2506 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2507 stream_type, GST_TIME_ARGS(timestamp),
2508 GST_TIME_ARGS(running_time_diff),
2509 GST_TIME_ARGS(timestamp - running_time_diff));
2511 timestamp -= running_time_diff;
2513 /* That case is invalid for QoS events */
2514 if (diff < 0 && -diff > timestamp) {
2515 LOGW("QOS event from previous group");
2516 ret = GST_PAD_PROBE_DROP;
2520 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2521 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2531 gst_caps_unref(caps);
2536 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2538 mm_player_t* player = NULL;
2539 GstElement* pipeline = NULL;
2540 GstElement* selector = NULL;
2541 GstElement* fakesink = NULL;
2542 GstCaps* caps = NULL;
2543 GstStructure* str = NULL;
2544 const gchar* name = NULL;
2545 GstPad* sinkpad = NULL;
2546 GstPad* srcpad = NULL;
2547 gboolean first_track = FALSE;
2549 enum MainElementID elemId = MMPLAYER_M_NUM;
2550 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2553 player = (mm_player_t*)data;
2555 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2556 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2558 //LOGD("pad-added signal handling\n");
2560 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2562 /* get mimetype from caps */
2563 caps = gst_pad_query_caps(pad, NULL);
2565 LOGE("cannot get caps from pad.\n");
2569 str = gst_caps_get_structure(caps, 0);
2571 LOGE("cannot get structure from caps.\n");
2575 name = gst_structure_get_name(str);
2577 LOGE("cannot get mimetype from structure.\n");
2581 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2582 //LOGD("detected mimetype : %s\n", name);
2584 if (strstr(name, "video")) {
2587 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2588 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2590 /* don't make video because of not required, and not support multiple track */
2591 if (stype == MM_DISPLAY_SURFACE_NULL) {
2592 LOGD("no video sink by null surface");
2594 gchar *caps_str = gst_caps_to_string(caps);
2595 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2596 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2597 player->set_mode.video_zc = TRUE;
2599 MMPLAYER_FREEIF(caps_str);
2601 if (player->v_stream_caps) {
2602 gst_caps_unref(player->v_stream_caps);
2603 player->v_stream_caps = NULL;
2606 LOGD("create fakesink instead of videobin");
2609 fakesink = gst_element_factory_make("fakesink", NULL);
2610 if (fakesink == NULL) {
2611 LOGE("ERROR : fakesink create error\n");
2615 if (player->ini.set_dump_element_flag)
2616 __mmplayer_add_dump_buffer_probe(player, fakesink);
2618 player->video_fakesink = fakesink;
2620 /* store it as it's sink element */
2621 __mmplayer_add_sink(player, player->video_fakesink);
2623 gst_bin_add(GST_BIN(pipeline), fakesink);
2626 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2628 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2629 LOGW("failed to link fakesink\n");
2630 gst_object_unref(GST_OBJECT(fakesink));
2634 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2635 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2636 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2639 if (player->set_mode.media_packet_video_stream) {
2640 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2642 MMPLAYER_SIGNAL_CONNECT(player,
2644 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2646 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2649 MMPLAYER_SIGNAL_CONNECT(player,
2651 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2653 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2657 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2658 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2662 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2663 __mmplayer_gst_decode_callback(elem, pad, player);
2667 LOGD("video selector \n");
2668 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2669 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2671 if (strstr(name, "audio")) {
2672 gint samplerate = 0;
2675 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2676 __mmplayer_gst_decode_callback(elem, pad, player);
2680 LOGD("audio selector \n");
2681 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2682 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2684 gst_structure_get_int(str, "rate", &samplerate);
2685 gst_structure_get_int(str, "channels", &channels);
2687 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2689 fakesink = gst_element_factory_make("fakesink", NULL);
2690 if (fakesink == NULL) {
2691 LOGE("ERROR : fakesink create error\n");
2695 gst_bin_add(GST_BIN(pipeline), fakesink);
2698 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2700 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2701 LOGW("failed to link fakesink\n");
2702 gst_object_unref(GST_OBJECT(fakesink));
2706 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2707 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2711 } else if (strstr(name, "text")) {
2712 LOGD("text selector \n");
2713 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2714 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2716 LOGE("wrong elem id \n");
2721 selector = player->pipeline->mainbin[elemId].gst;
2722 if (selector == NULL) {
2723 selector = gst_element_factory_make("input-selector", NULL);
2724 LOGD("Creating input-selector\n");
2725 if (selector == NULL) {
2726 LOGE("ERROR : input-selector create error\n");
2729 g_object_set(selector, "sync-streams", TRUE, NULL);
2731 player->pipeline->mainbin[elemId].id = elemId;
2732 player->pipeline->mainbin[elemId].gst = selector;
2735 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2737 srcpad = gst_element_get_static_pad(selector, "src");
2739 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2740 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2741 __mmplayer_gst_selector_blocked, NULL, NULL);
2742 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2743 __mmplayer_gst_selector_event_probe, player, NULL);
2745 gst_element_set_state(selector, GST_STATE_PAUSED);
2746 gst_bin_add(GST_BIN(pipeline), selector);
2748 LOGD("input-selector is already created.\n");
2751 LOGD("Calling request pad with selector %p \n", selector);
2752 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2754 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2756 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2757 LOGW("failed to link selector\n");
2758 gst_object_unref(GST_OBJECT(selector));
2763 LOGD("this is first track --> active track \n");
2764 g_object_set(selector, "active-pad", sinkpad, NULL);
2767 _mmplayer_track_update_info(player, stream_type, sinkpad);
2774 gst_caps_unref(caps);
2777 gst_object_unref(GST_OBJECT(sinkpad));
2782 gst_object_unref(GST_OBJECT(srcpad));
2789 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2791 GstPad* srcpad = NULL;
2792 MMHandleType attrs = 0;
2793 gint active_index = 0;
2795 // [link] input-selector :: textbin
2796 srcpad = gst_element_get_static_pad(text_selector, "src");
2798 LOGE("failed to get srcpad from selector\n");
2802 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2804 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2805 if ((active_index != DEFAULT_TRACK) &&
2806 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2807 LOGW("failed to change text track\n");
2808 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2811 player->no_more_pad = TRUE;
2812 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2814 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2815 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2816 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2817 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2820 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2822 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2823 player->has_closed_caption = TRUE;
2825 attrs = MMPLAYER_GET_ATTRS(player);
2827 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2828 if (mmf_attrs_commit(attrs))
2829 LOGE("failed to commit.\n");
2831 LOGE("cannot get content attribute");
2834 gst_object_unref(GST_OBJECT(srcpad));
2840 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2842 mm_player_t* player = (mm_player_t*)data;
2843 GstElement* selector = NULL;
2844 GstElement* queue = NULL;
2846 GstPad* srcpad = NULL;
2847 GstPad* sinkpad = NULL;
2848 GstCaps* caps = NULL;
2849 gchar* caps_str = NULL;
2852 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2854 caps = gst_pad_get_current_caps(pad);
2855 caps_str = gst_caps_to_string(caps);
2856 LOGD("deinterleave new caps : %s\n", caps_str);
2857 MMPLAYER_FREEIF(caps_str);
2858 gst_caps_unref(caps);
2860 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2861 LOGE("ERROR : queue create error\n");
2865 g_object_set(G_OBJECT(queue),
2866 "max-size-buffers", 10,
2867 "max-size-bytes", 0,
2868 "max-size-time", (guint64)0,
2871 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2874 LOGE("there is no audio channel selector.\n");
2878 srcpad = gst_element_get_static_pad(queue, "src");
2879 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2881 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2883 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2884 LOGW("failed to link deinterleave - selector\n");
2888 gst_element_set_state(queue, GST_STATE_PAUSED);
2889 player->audio_mode.total_track_num++;
2894 gst_object_unref(GST_OBJECT(srcpad));
2899 gst_object_unref(GST_OBJECT(sinkpad));
2908 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2910 mm_player_t* player = NULL;
2911 GstElement* selector = NULL;
2912 GstPad* sinkpad = NULL;
2913 gint active_index = 0;
2914 gchar* change_pad_name = NULL;
2915 GstCaps* caps = NULL; // no need to unref
2916 gint default_audio_ch = 0;
2919 player = (mm_player_t*) data;
2921 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2924 LOGE("there is no audio channel selector.\n");
2928 active_index = player->audio_mode.active_pad_index;
2930 if (active_index != default_audio_ch) {
2931 gint audio_ch = default_audio_ch;
2933 /*To get the new pad from the selector*/
2934 change_pad_name = g_strdup_printf("sink%d", active_index);
2935 if (change_pad_name != NULL) {
2936 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2937 if (sinkpad != NULL) {
2938 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2939 g_object_set(selector, "active-pad", sinkpad, NULL);
2941 audio_ch = active_index;
2943 caps = gst_pad_get_current_caps(sinkpad);
2944 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2946 __mmplayer_set_audio_attrs(player, caps);
2947 gst_caps_unref(caps);
2949 MMPLAYER_FREEIF(change_pad_name);
2952 player->audio_mode.active_pad_index = audio_ch;
2953 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2959 gst_object_unref(sinkpad);
2966 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2968 mm_player_t* player = NULL;
2969 MMPlayerGstElement *mainbin = NULL;
2971 GstElement* tee = NULL;
2972 GstElement* stereo_queue = NULL;
2973 GstElement* mono_queue = NULL;
2974 GstElement* conv = NULL;
2975 GstElement* filter = NULL;
2976 GstElement* deinterleave = NULL;
2977 GstElement* selector = NULL;
2979 GstPad* srcpad = NULL;
2980 GstPad* selector_srcpad = NULL;
2981 GstPad* sinkpad = NULL;
2982 GstCaps* caps = NULL;
2983 gulong block_id = 0;
2988 player = (mm_player_t*) data;
2990 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2991 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2993 mainbin = player->pipeline->mainbin;
2996 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2997 LOGE("ERROR : tee create error\n");
3001 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3002 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3004 gst_element_set_state(tee, GST_STATE_PAUSED);
3007 srcpad = gst_element_get_request_pad(tee, "src_%u");
3008 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3009 LOGE("ERROR : stereo queue create error\n");
3013 g_object_set(G_OBJECT(stereo_queue),
3014 "max-size-buffers", 10,
3015 "max-size-bytes", 0,
3016 "max-size-time", (guint64)0,
3019 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3020 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3023 gst_object_unref(GST_OBJECT(srcpad));
3027 srcpad = gst_element_get_request_pad(tee, "src_%u");
3029 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3030 LOGE("ERROR : mono queue create error\n");
3034 g_object_set(G_OBJECT(mono_queue),
3035 "max-size-buffers", 10,
3036 "max-size-bytes", 0,
3037 "max-size-time", (guint64)0,
3040 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3041 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3043 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3044 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3047 srcpad = gst_element_get_static_pad(mono_queue, "src");
3048 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3049 LOGE("ERROR : audioconvert create error\n");
3053 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3054 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3058 gst_object_unref(GST_OBJECT(srcpad));
3061 srcpad = gst_element_get_static_pad(conv, "src");
3063 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3064 LOGE("ERROR : capsfilter create error\n");
3068 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3069 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3071 caps = gst_caps_from_string("audio/x-raw-int, "
3072 "width = (int) 16, "
3073 "depth = (int) 16, "
3074 "channels = (int) 2");
3076 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3077 gst_caps_unref(caps);
3079 gst_element_set_state(conv, GST_STATE_PAUSED);
3080 gst_element_set_state(filter, GST_STATE_PAUSED);
3084 gst_object_unref(GST_OBJECT(srcpad));
3087 srcpad = gst_element_get_static_pad(filter, "src");
3089 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3090 LOGE("ERROR : deinterleave create error\n");
3094 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3096 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3097 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3099 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3100 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3102 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3103 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3106 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3107 if (selector == NULL) {
3108 LOGE("ERROR : audio-selector create error\n");
3112 g_object_set(selector, "sync-streams", TRUE, NULL);
3113 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3115 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3116 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3118 selector_srcpad = gst_element_get_static_pad(selector, "src");
3120 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3122 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3123 __mmplayer_gst_selector_blocked, NULL, NULL);
3126 gst_object_unref(GST_OBJECT(srcpad));
3130 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3131 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3133 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3134 LOGW("failed to link queue_stereo - selector\n");
3138 player->audio_mode.total_track_num++;
3140 g_object_set(selector, "active-pad", sinkpad, NULL);
3141 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3142 gst_element_set_state(selector, GST_STATE_PAUSED);
3144 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3148 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3149 if (block_id != 0) {
3150 gst_pad_remove_probe(selector_srcpad, block_id);
3155 gst_object_unref(GST_OBJECT(sinkpad));
3160 gst_object_unref(GST_OBJECT(srcpad));
3164 if (selector_srcpad) {
3165 gst_object_unref(GST_OBJECT(selector_srcpad));
3166 selector_srcpad = NULL;
3174 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3176 mm_player_t* player = NULL;
3177 GstPad* srcpad = NULL;
3178 GstElement* video_selector = NULL;
3179 GstElement* audio_selector = NULL;
3180 GstElement* text_selector = NULL;
3181 MMHandleType attrs = 0;
3182 gint active_index = 0;
3183 gint64 dur_bytes = 0L;
3185 player = (mm_player_t*) data;
3187 LOGD("no-more-pad signal handling\n");
3189 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3190 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3191 LOGW("no need to go more");
3193 if (player->gapless.reconfigure) {
3194 player->gapless.reconfigure = FALSE;
3195 MMPLAYER_PLAYBACK_UNLOCK(player);
3201 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3202 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3203 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3204 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3205 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3207 if (NULL == player->streamer) {
3208 LOGW("invalid state for buffering");
3212 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3213 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3215 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3216 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3218 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3220 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3221 LOGE("fail to get duration.\n");
3223 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3224 * use file information was already set on Q2 when it was created. */
3225 __mm_player_streaming_set_queue2(player->streamer,
3226 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3227 TRUE, /* use_buffering */
3229 init_buffering_time,
3230 1.0, /* low percent */
3231 player->ini.http_buffering_limit, /* high percent */
3232 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
3234 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3237 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3238 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3239 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3240 if (video_selector) {
3241 // [link] input-selector :: videobin
3242 srcpad = gst_element_get_static_pad(video_selector, "src");
3244 LOGE("failed to get srcpad from video selector\n");
3248 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3249 if (!text_selector && !audio_selector)
3250 player->no_more_pad = TRUE;
3252 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3254 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3256 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3257 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3261 if (audio_selector) {
3262 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3263 if ((active_index != DEFAULT_TRACK) &&
3264 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3265 LOGW("failed to change audio track\n");
3266 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3269 // [link] input-selector :: audiobin
3270 srcpad = gst_element_get_static_pad(audio_selector, "src");
3272 LOGE("failed to get srcpad from selector\n");
3276 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3278 player->no_more_pad = TRUE;
3280 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3281 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3282 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3283 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3284 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3287 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3289 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3291 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3292 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3293 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3294 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3298 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3300 attrs = MMPLAYER_GET_ATTRS(player);
3302 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3303 if (mmf_attrs_commit(attrs))
3304 LOGE("failed to commit.\n");
3306 LOGE("cannot get content attribute");
3308 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3309 LOGD("There is no audio track : remove audiobin");
3311 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3312 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3314 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3315 MMPLAYER_FREEIF(player->pipeline->audiobin);
3318 if (player->num_dynamic_pad == 0)
3319 __mmplayer_pipeline_complete(NULL, player);
3322 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3324 __mmplayer_handle_text_decode_path(player, text_selector);
3331 gst_object_unref(GST_OBJECT(srcpad));
3335 if (player->gapless.reconfigure) {
3336 player->gapless.reconfigure = FALSE;
3337 MMPLAYER_PLAYBACK_UNLOCK(player);
3342 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3344 mm_player_t* player = NULL;
3345 MMHandleType attrs = 0;
3346 GstElement* pipeline = NULL;
3347 GstCaps* caps = NULL;
3348 gchar* caps_str = NULL;
3349 GstStructure* str = NULL;
3350 const gchar* name = NULL;
3351 GstPad* sinkpad = NULL;
3352 GstElement* sinkbin = NULL;
3353 gboolean reusing = FALSE;
3354 GstElement *text_selector = NULL;
3357 player = (mm_player_t*) data;
3359 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3360 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3362 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3364 attrs = MMPLAYER_GET_ATTRS(player);
3366 LOGE("cannot get content attribute\n");
3370 /* get mimetype from caps */
3371 caps = gst_pad_query_caps(pad, NULL);
3373 LOGE("cannot get caps from pad.\n");
3376 caps_str = gst_caps_to_string(caps);
3378 str = gst_caps_get_structure(caps, 0);
3380 LOGE("cannot get structure from caps.\n");
3384 name = gst_structure_get_name(str);
3386 LOGE("cannot get mimetype from structure.\n");
3390 //LOGD("detected mimetype : %s\n", name);
3392 if (strstr(name, "audio")) {
3393 if (player->pipeline->audiobin == NULL) {
3394 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3395 LOGE("failed to create audiobin. continuing without audio\n");
3399 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3400 LOGD("creating audiosink bin success\n");
3403 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3404 LOGD("reusing audiobin\n");
3405 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3408 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3409 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3411 player->audiosink_linked = 1;
3413 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3415 LOGE("failed to get pad from sinkbin\n");
3418 } else if (strstr(name, "video")) {
3419 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3420 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3421 player->set_mode.video_zc = TRUE;
3423 if (player->pipeline->videobin == NULL) {
3424 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3425 /* get video surface type */
3426 int surface_type = 0;
3427 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3428 LOGD("display_surface_type(%d)\n", surface_type);
3430 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3431 LOGD("not make videobin because it dose not want\n");
3435 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3436 /* mark video overlay for acquire */
3437 if (player->video_overlay_resource == NULL) {
3438 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3439 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3440 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3441 &player->video_overlay_resource)
3442 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3443 LOGE("could not mark video_overlay resource for acquire\n");
3449 player->interrupted_by_resource = FALSE;
3450 /* acquire resources for video overlay */
3451 if (mm_resource_manager_commit(player->resource_manager) !=
3452 MM_RESOURCE_MANAGER_ERROR_NONE) {
3453 LOGE("could not acquire resources for video playing\n");
3457 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3458 LOGE("failed to create videobin. continuing without video\n");
3462 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3463 LOGD("creating videosink bin success\n");
3466 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3467 LOGD("re-using videobin\n");
3468 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3471 player->videosink_linked = 1;
3473 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3475 LOGE("failed to get pad from sinkbin\n");
3478 } else if (strstr(name, "text")) {
3479 if (player->pipeline->textbin == NULL) {
3480 MMPlayerGstElement* mainbin = NULL;
3482 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3483 LOGE("failed to create text sink bin. continuing without text\n");
3487 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3488 LOGD("creating textsink bin success\n");
3490 /* FIXIT : track number shouldn't be hardcoded */
3491 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3493 player->textsink_linked = 1;
3494 LOGI("player->textsink_linked set to 1\n");
3496 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3498 LOGE("failed to get pad from sinkbin\n");
3502 mainbin = player->pipeline->mainbin;
3504 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3505 /* input selector */
3506 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3507 if (!text_selector) {
3508 LOGE("failed to create subtitle input selector element\n");
3511 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3513 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3514 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3517 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3518 LOGE("failed to set state(READY) to sinkbin\n");
3522 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3523 LOGW("failed to add subtitle input selector\n");
3527 LOGD("created element input-selector");
3530 LOGD("already having subtitle input selector");
3531 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3534 if (!player->textsink_linked) {
3535 LOGD("re-using textbin\n");
3538 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3540 player->textsink_linked = 1;
3541 LOGI("player->textsink_linked set to 1\n");
3543 LOGD("ignoring internal subtutle since external subtitle is available");
3546 LOGW("unknown type of elementary stream!ignoring it...\n");
3553 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3554 LOGE("failed to set state(READY) to sinkbin\n");
3558 /* Added for multi audio support to avoid adding audio bin again*/
3560 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3561 LOGE("failed to add sinkbin to pipeline\n");
3567 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3568 LOGE("failed to get pad from sinkbin\n");
3574 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3575 LOGE("failed to set state(PAUSED) to sinkbin\n");
3579 if (text_selector) {
3580 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3581 LOGE("failed to set state(PAUSED) to sinkbin\n");
3587 gst_object_unref(sinkpad);
3591 LOGD("[handle: %p] linking sink bin success", player);
3593 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3594 * streaming task. if the task blocked, then buffer will not flow to the next element
3595 *(autoplugging element). so this is special hack for streaming. please try to remove it
3597 /* dec stream count. we can remove fakesink if it's zero */
3598 if (player->num_dynamic_pad)
3599 player->num_dynamic_pad--;
3601 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3603 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3604 __mmplayer_pipeline_complete(NULL, player);
3608 MMPLAYER_FREEIF(caps_str);
3611 gst_caps_unref(caps);
3614 gst_object_unref(GST_OBJECT(sinkpad));
3616 /* flusing out new attributes */
3617 if (mmf_attrs_commit(attrs))
3618 LOGE("failed to comit attributes\n");
3624 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3626 int pro_value = 0; // in the case of expection, default will be returned.
3627 int dest_angle = rotation_angle;
3628 int rotation_type = -1;
3630 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3631 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3632 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3634 if (rotation_angle >= 360)
3635 dest_angle = rotation_angle - 360;
3637 /* chech if supported or not */
3638 if (dest_angle % 90) {
3639 LOGD("not supported rotation angle = %d", rotation_angle);
3645 * custom_convert - none (B)
3646 * videoflip - none (C)
3648 if (player->set_mode.video_zc) {
3649 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3650 rotation_type = ROTATION_USING_CUSTOM;
3652 rotation_type = ROTATION_USING_SINK;
3654 int surface_type = 0;
3655 rotation_type = ROTATION_USING_FLIP;
3657 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3658 LOGD("check display surface type attribute: %d", surface_type);
3660 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3661 rotation_type = ROTATION_USING_SINK;
3663 rotation_type = ROTATION_USING_FLIP; //C
3665 LOGD("using %d type for rotation", rotation_type);
3668 /* get property value for setting */
3669 switch (rotation_type) {
3670 case ROTATION_USING_SINK: // tizenwlsink
3672 switch (dest_angle) {
3676 pro_value = 3; // clockwise 90
3682 pro_value = 1; // counter-clockwise 90
3687 case ROTATION_USING_CUSTOM:
3689 gchar *ename = NULL;
3690 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3692 if (g_strrstr(ename, "fimcconvert")) {
3693 switch (dest_angle) {
3697 pro_value = 90; // clockwise 90
3703 pro_value = 270; // counter-clockwise 90
3709 case ROTATION_USING_FLIP: // videoflip
3711 switch (dest_angle) {
3715 pro_value = 1; // clockwise 90
3721 pro_value = 3; // counter-clockwise 90
3728 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3736 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3738 /* check video sinkbin is created */
3739 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3741 player->pipeline->videobin &&
3742 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3743 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3744 MM_ERROR_PLAYER_NOT_INITIALIZED);
3746 return MM_ERROR_NONE;
3750 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3752 int rotation_value = 0;
3753 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3757 /* check video sinkbin is created */
3758 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3761 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3763 /* get rotation value to set */
3764 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3765 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3766 LOGD("set video param : rotate %d", rotation_value);
3770 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3772 MMHandleType attrs = 0;
3776 /* check video sinkbin is created */
3777 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3780 attrs = MMPLAYER_GET_ATTRS(player);
3781 MMPLAYER_RETURN_IF_FAIL(attrs);
3783 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3784 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3785 LOGD("set video param : visible %d", visible);
3789 __mmplayer_video_param_set_display_method(mm_player_t* player)
3791 MMHandleType attrs = 0;
3792 int display_method = 0;
3795 /* check video sinkbin is created */
3796 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3799 attrs = MMPLAYER_GET_ATTRS(player);
3800 MMPLAYER_RETURN_IF_FAIL(attrs);
3802 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3803 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3804 LOGD("set video param : method %d", display_method);
3808 __mmplayer_video_param_set_roi_area(mm_player_t* player)
3810 MMHandleType attrs = 0;
3811 void *handle = NULL;
3815 int win_roi_width = 0;
3816 int win_roi_height = 0;
3819 /* check video sinkbin is created */
3820 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3823 attrs = MMPLAYER_GET_ATTRS(player);
3824 MMPLAYER_RETURN_IF_FAIL(attrs);
3826 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3829 /* It should be set after setting window */
3830 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
3831 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
3832 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
3833 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
3835 /* After setting window handle, set display roi area */
3836 gst_video_overlay_set_display_roi_area(
3837 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3838 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3839 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
3840 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3845 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3847 MMHandleType attrs = 0;
3848 void *handle = NULL;
3850 /* check video sinkbin is created */
3851 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3854 attrs = MMPLAYER_GET_ATTRS(player);
3855 MMPLAYER_RETURN_IF_FAIL(attrs);
3857 /* common case if using overlay surface */
3858 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3861 /* default is using wl_surface_id */
3862 unsigned int wl_surface_id = 0;
3863 wl_surface_id = *(int*)handle;
3864 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3865 gst_video_overlay_set_wl_window_wl_surface_id(
3866 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3869 /* FIXIT : is it error case? */
3870 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3875 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3877 bool update_all_param = FALSE;
3880 /* check video sinkbin is created */
3881 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3882 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3884 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3885 LOGE("can not find tizenwlsink");
3886 return MM_ERROR_PLAYER_INTERNAL;
3889 LOGD("param_name : %s", param_name);
3890 if (!g_strcmp0(param_name, "update_all_param"))
3891 update_all_param = TRUE;
3893 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3894 __mmplayer_video_param_set_display_overlay(player);
3895 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3896 __mmplayer_video_param_set_display_method(player);
3897 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3898 __mmplayer_video_param_set_display_visible(player);
3899 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3900 __mmplayer_video_param_set_display_rotation(player);
3901 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
3902 __mmplayer_video_param_set_roi_area(player);
3904 return MM_ERROR_NONE;
3908 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3910 MMHandleType attrs = 0;
3911 int surface_type = 0;
3912 int ret = MM_ERROR_NONE;
3916 /* check video sinkbin is created */
3917 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3918 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3920 attrs = MMPLAYER_GET_ATTRS(player);
3922 LOGE("cannot get content attribute");
3923 return MM_ERROR_PLAYER_INTERNAL;
3925 LOGD("param_name : %s", param_name);
3927 /* update display surface */
3928 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3929 LOGD("check display surface type attribute: %d", surface_type);
3931 /* configuring display */
3932 switch (surface_type) {
3933 case MM_DISPLAY_SURFACE_OVERLAY:
3935 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3936 if (ret != MM_ERROR_NONE)
3944 return MM_ERROR_NONE;
3948 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3950 gboolean disable_overlay = FALSE;
3951 mm_player_t* player = (mm_player_t*) hplayer;
3952 int ret = MM_ERROR_NONE;
3955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3956 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3957 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3958 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3960 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3961 LOGW("Display control is not supported");
3962 return MM_ERROR_PLAYER_INTERNAL;
3965 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3967 if (audio_only == (bool)disable_overlay) {
3968 LOGE("It's the same with current setting: (%d)", audio_only);
3969 return MM_ERROR_NONE;
3973 LOGE("disable overlay");
3974 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3976 /* release overlay resource */
3977 if (player->video_overlay_resource != NULL) {
3978 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3979 player->video_overlay_resource);
3980 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3981 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3984 player->video_overlay_resource = NULL;
3987 ret = mm_resource_manager_commit(player->resource_manager);
3988 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3993 /* mark video overlay for acquire */
3994 if (player->video_overlay_resource == NULL) {
3995 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3996 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3997 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3998 &player->video_overlay_resource);
3999 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4000 LOGE("could not prepare for video_overlay resource\n");
4005 player->interrupted_by_resource = FALSE;
4006 /* acquire resources for video overlay */
4007 ret = mm_resource_manager_commit(player->resource_manager);
4008 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4009 LOGE("could not acquire resources for video playing\n");
4013 LOGD("enable overlay");
4014 __mmplayer_video_param_set_display_overlay(player);
4015 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4020 return MM_ERROR_NONE;
4024 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4026 mm_player_t* player = (mm_player_t*) hplayer;
4027 gboolean disable_overlay = FALSE;
4031 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4032 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4033 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4034 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4035 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4037 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4038 LOGW("Display control is not supported");
4039 return MM_ERROR_PLAYER_INTERNAL;
4042 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4044 *paudio_only = (bool)(disable_overlay);
4046 LOGD("audio_only : %d", *paudio_only);
4050 return MM_ERROR_NONE;
4054 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4056 GList* bucket = element_bucket;
4057 MMPlayerGstElement* element = NULL;
4058 MMPlayerGstElement* prv_element = NULL;
4059 gint successful_link_count = 0;
4063 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4065 prv_element = (MMPlayerGstElement*)bucket->data;
4066 bucket = bucket->next;
4068 for (; bucket; bucket = bucket->next) {
4069 element = (MMPlayerGstElement*)bucket->data;
4071 if (element && element->gst) {
4072 /* If next element is audio appsrc then make a separate audio pipeline */
4073 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4074 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4075 prv_element = element;
4079 if (prv_element && prv_element->gst) {
4080 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4081 LOGD("linking [%s] to [%s] success\n",
4082 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4083 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4084 successful_link_count++;
4086 LOGD("linking [%s] to [%s] failed\n",
4087 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4088 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4094 prv_element = element;
4099 return successful_link_count;
4103 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4105 GList* bucket = element_bucket;
4106 MMPlayerGstElement* element = NULL;
4107 int successful_add_count = 0;
4111 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4112 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4114 for (; bucket; bucket = bucket->next) {
4115 element = (MMPlayerGstElement*)bucket->data;
4117 if (element && element->gst) {
4118 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4119 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4120 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4121 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4124 successful_add_count++;
4130 return successful_add_count;
4133 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4135 mm_player_t* player = (mm_player_t*) data;
4136 GstCaps *caps = NULL;
4137 GstStructure *str = NULL;
4142 MMPLAYER_RETURN_IF_FAIL(pad)
4143 MMPLAYER_RETURN_IF_FAIL(unused)
4144 MMPLAYER_RETURN_IF_FAIL(data)
4146 caps = gst_pad_get_current_caps(pad);
4150 str = gst_caps_get_structure(caps, 0);
4154 name = gst_structure_get_name(str);
4158 LOGD("name = %s\n", name);
4160 if (strstr(name, "audio")) {
4161 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4163 if (player->audio_stream_changed_cb) {
4164 LOGE("call the audio stream changed cb\n");
4165 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4167 } else if (strstr(name, "video")) {
4168 if ((name = gst_structure_get_string(str, "format")))
4169 player->set_mode.video_zc = name[0] == 'S';
4171 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4173 if (player->video_stream_changed_cb) {
4174 LOGE("call the video stream changed cb\n");
4175 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4182 gst_caps_unref(caps);
4192 * This function is to create audio pipeline for playing.
4194 * @param player [in] handle of player
4196 * @return This function returns zero on success.
4198 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4200 /* macro for code readability. just for sinkbin-creation functions */
4201 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4203 x_bin[x_id].id = x_id;\
4204 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4205 if (!x_bin[x_id].gst) {\
4206 LOGE("failed to create %s \n", x_factory);\
4209 if (x_player->ini.set_dump_element_flag)\
4210 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4213 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4217 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4222 MMPLAYER_RETURN_IF_FAIL(player);
4224 if (player->audio_stream_buff_list) {
4225 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4226 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4229 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4230 __mmplayer_audio_stream_send_data(player, tmp);
4233 g_free(tmp->pcm_data);
4237 g_list_free(player->audio_stream_buff_list);
4238 player->audio_stream_buff_list = NULL;
4245 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4247 MMPlayerAudioStreamDataType audio_stream = { 0, };
4250 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4252 audio_stream.bitrate = a_buffer->bitrate;
4253 audio_stream.channel = a_buffer->channel;
4254 audio_stream.depth = a_buffer->depth;
4255 audio_stream.is_little_endian = a_buffer->is_little_endian;
4256 audio_stream.channel_mask = a_buffer->channel_mask;
4257 audio_stream.data_size = a_buffer->data_size;
4258 audio_stream.data = a_buffer->pcm_data;
4260 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4261 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4267 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4269 mm_player_t* player = (mm_player_t*) data;
4274 gint endianness = 0;
4275 guint64 channel_mask = 0;
4276 void *a_data = NULL;
4278 mm_player_audio_stream_buff_t *a_buffer = NULL;
4279 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4283 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4285 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4286 a_data = mapinfo.data;
4287 a_size = mapinfo.size;
4289 GstCaps *caps = gst_pad_get_current_caps(pad);
4290 GstStructure *structure = gst_caps_get_structure(caps, 0);
4292 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4293 gst_structure_get_int(structure, "rate", &rate);
4294 gst_structure_get_int(structure, "channels", &channel);
4295 gst_structure_get_int(structure, "depth", &depth);
4296 gst_structure_get_int(structure, "endianness", &endianness);
4297 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4298 gst_caps_unref(GST_CAPS(caps));
4300 /* In case of the sync is false, use buffer list. *
4301 * The num of buffer list depends on the num of audio channels */
4302 if (player->audio_stream_buff_list) {
4303 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4304 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4306 if (channel_mask == tmp->channel_mask) {
4307 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4308 if (tmp->data_size + a_size < tmp->buff_size) {
4309 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4310 tmp->data_size += a_size;
4312 /* send data to client */
4313 __mmplayer_audio_stream_send_data(player, tmp);
4315 if (a_size > tmp->buff_size) {
4316 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4317 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4318 if (tmp->pcm_data == NULL) {
4319 LOGE("failed to realloc data.");
4322 tmp->buff_size = a_size;
4324 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4325 memcpy(tmp->pcm_data, a_data, a_size);
4326 tmp->data_size = a_size;
4331 LOGE("data is empty in list.");
4337 /* create new audio stream data */
4338 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4339 if (a_buffer == NULL) {
4340 LOGE("failed to alloc data.");
4343 a_buffer->bitrate = rate;
4344 a_buffer->channel = channel;
4345 a_buffer->depth = depth;
4346 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4347 a_buffer->channel_mask = channel_mask;
4348 a_buffer->data_size = a_size;
4350 if (!player->audio_stream_sink_sync) {
4351 /* If sync is FALSE, use buffer list to reduce the IPC. */
4352 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4353 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4354 if (a_buffer->pcm_data == NULL) {
4355 LOGE("failed to alloc data.");
4359 memcpy(a_buffer->pcm_data, a_data, a_size);
4360 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4361 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4363 /* If sync is TRUE, send data directly. */
4364 a_buffer->pcm_data = a_data;
4365 __mmplayer_audio_stream_send_data(player, a_buffer);
4370 gst_buffer_unmap(buffer, &mapinfo);
4375 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4377 mm_player_t* player = (mm_player_t*)data;
4378 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4379 GstPad* sinkpad = NULL;
4380 GstElement *queue = NULL, *sink = NULL;
4383 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4385 queue = gst_element_factory_make("queue", NULL);
4386 if (queue == NULL) {
4387 LOGD("fail make queue\n");
4391 sink = gst_element_factory_make("fakesink", NULL);
4393 LOGD("fail make fakesink\n");
4397 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4399 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4400 LOGW("failed to link queue & sink\n");
4404 sinkpad = gst_element_get_static_pad(queue, "sink");
4406 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4407 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4411 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4413 gst_object_unref(sinkpad);
4414 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4415 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4417 gst_element_set_state(sink, GST_STATE_PAUSED);
4418 gst_element_set_state(queue, GST_STATE_PAUSED);
4420 MMPLAYER_SIGNAL_CONNECT(player,
4422 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4424 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4431 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4433 gst_object_unref(GST_OBJECT(queue));
4437 gst_object_unref(GST_OBJECT(sink));
4441 gst_object_unref(GST_OBJECT(sinkpad));
4448 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4450 #define MAX_PROPS_LEN 128
4451 gint latency_mode = 0;
4452 gchar *stream_type = NULL;
4453 gchar *latency = NULL;
4455 gchar stream_props[MAX_PROPS_LEN] = {0,};
4456 GstStructure *props = NULL;
4459 * It should be set after player creation through attribute.
4460 * But, it can not be changed during playing.
4463 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4464 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4467 LOGE("stream_type is null.\n");
4469 if (player->sound.focus_id)
4470 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4471 stream_type, stream_id, player->sound.focus_id);
4473 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4474 stream_type, stream_id);
4475 props = gst_structure_from_string(stream_props, NULL);
4476 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4477 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4478 stream_type, stream_id, player->sound.focus_id, stream_props);
4479 gst_structure_free(props);
4482 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4484 switch (latency_mode) {
4485 case AUDIO_LATENCY_MODE_LOW:
4486 latency = g_strndup("low", 3);
4488 case AUDIO_LATENCY_MODE_MID:
4489 latency = g_strndup("mid", 3);
4491 case AUDIO_LATENCY_MODE_HIGH:
4492 latency = g_strndup("high", 4);
4496 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4500 LOGD("audiosink property - latency=%s \n", latency);
4508 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4510 MMPlayerGstElement* first_element = NULL;
4511 MMPlayerGstElement* audiobin = NULL;
4512 MMHandleType attrs = 0;
4514 GstPad *ghostpad = NULL;
4515 GList* element_bucket = NULL;
4516 gboolean link_audio_sink_now = TRUE;
4522 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4525 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4527 LOGE("failed to allocate memory for audiobin\n");
4528 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4531 attrs = MMPLAYER_GET_ATTRS(player);
4534 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4535 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4536 if (!audiobin[MMPLAYER_A_BIN].gst) {
4537 LOGE("failed to create audiobin\n");
4542 player->pipeline->audiobin = audiobin;
4544 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4546 /* Adding audiotp plugin for reverse trickplay feature */
4547 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4550 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4552 /* replaygain volume */
4553 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4554 if (player->sound.rg_enable)
4555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4560 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4562 if (player->set_mode.pcm_extraction) {
4563 // pcm extraction only and no sound output
4564 if (player->audio_stream_render_cb_ex) {
4565 char *caps_str = NULL;
4566 GstCaps* caps = NULL;
4567 gchar *format = NULL;
4570 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4572 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4574 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4576 caps = gst_caps_new_simple("audio/x-raw",
4577 "format", G_TYPE_STRING, format,
4578 "rate", G_TYPE_INT, player->pcm_samplerate,
4579 "channels", G_TYPE_INT, player->pcm_channel,
4581 caps_str = gst_caps_to_string(caps);
4582 LOGD("new caps : %s\n", caps_str);
4584 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4587 gst_caps_unref(caps);
4588 MMPLAYER_FREEIF(caps_str);
4590 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4593 /* raw pad handling signal */
4594 MMPLAYER_SIGNAL_CONNECT(player,
4595 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4596 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4597 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4599 int dst_samplerate = 0;
4600 int dst_channels = 0;
4602 char *caps_str = NULL;
4603 GstCaps* caps = NULL;
4605 /* get conf. values */
4606 mm_attrs_multiple_get(player->attrs,
4608 "pcm_extraction_samplerate", &dst_samplerate,
4609 "pcm_extraction_channels", &dst_channels,
4610 "pcm_extraction_depth", &dst_depth,
4614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4615 caps = gst_caps_new_simple("audio/x-raw",
4616 "rate", G_TYPE_INT, dst_samplerate,
4617 "channels", G_TYPE_INT, dst_channels,
4618 "depth", G_TYPE_INT, dst_depth,
4620 caps_str = gst_caps_to_string(caps);
4621 LOGD("new caps : %s\n", caps_str);
4623 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4626 gst_caps_unref(caps);
4627 MMPLAYER_FREEIF(caps_str);
4630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4637 //GstCaps* caps = NULL;
4640 /* for logical volume control */
4641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4644 if (player->sound.mute) {
4645 LOGD("mute enabled\n");
4646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4652 caps = gst_caps_from_string("audio/x-raw-int, "
4653 "endianness = (int) LITTLE_ENDIAN, "
4654 "signed = (boolean) true, "
4655 "width = (int) 16, "
4656 "depth = (int) 16");
4657 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4658 gst_caps_unref(caps);
4661 /* check if multi-channels */
4662 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4663 GstPad *srcpad = NULL;
4664 GstCaps *caps = NULL;
4666 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4667 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4668 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4669 GstStructure *str = gst_caps_get_structure(caps, 0);
4671 gst_structure_get_int(str, "channels", &channels);
4672 gst_caps_unref(caps);
4674 gst_object_unref(srcpad);
4678 /* audio effect element. if audio effect is enabled */
4679 if ((strcmp(player->ini.audioeffect_element, ""))
4681 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4684 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4686 if ((!player->bypass_audio_effect)
4687 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4688 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4689 if (!_mmplayer_audio_effect_custom_apply(player))
4690 LOGI("apply audio effect(custom) setting success\n");
4694 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4695 && (player->set_mode.rich_audio))
4696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4699 /* create audio sink */
4700 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4701 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4702 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4704 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4705 if (player->is_360_feature_enabled &&
4706 player->is_content_spherical &&
4708 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4709 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4710 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4712 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4717 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4719 gst_caps_unref(acaps);
4721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4723 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4726 player->is_openal_plugin_used = TRUE;
4728 if (player->video360_yaw_radians <= M_PI &&
4729 player->video360_yaw_radians >= -M_PI &&
4730 player->video360_pitch_radians <= M_PI_2 &&
4731 player->video360_pitch_radians >= -M_PI_2) {
4732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4733 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4734 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4735 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4736 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4737 "source-orientation-y", player->video360_metadata.init_view_heading,
4738 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4741 if (player->is_360_feature_enabled && player->is_content_spherical)
4742 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4751 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4752 (player->videodec_linked && player->ini.use_system_clock)) {
4753 LOGD("system clock will be used.\n");
4754 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4757 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4758 __mmplayer_gst_set_audiosink_property(player, attrs);
4761 if (audiobin[MMPLAYER_A_SINK].gst) {
4762 GstPad *sink_pad = NULL;
4763 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4764 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4765 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4766 gst_object_unref(GST_OBJECT(sink_pad));
4769 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4771 /* adding created elements to bin */
4772 LOGD("adding created elements to bin\n");
4773 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4774 LOGE("failed to add elements\n");
4778 /* linking elements in the bucket by added order. */
4779 LOGD("Linking elements in the bucket by added order.\n");
4780 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4781 LOGE("failed to link elements\n");
4785 /* get first element's sinkpad for creating ghostpad */
4786 first_element = (MMPlayerGstElement *)element_bucket->data;
4787 if (!first_element) {
4788 LOGE("failed to get first elem\n");
4792 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4794 LOGE("failed to get pad from first element of audiobin\n");
4798 ghostpad = gst_ghost_pad_new("sink", pad);
4800 LOGE("failed to create ghostpad\n");
4804 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4805 LOGE("failed to add ghostpad to audiobin\n");
4809 gst_object_unref(pad);
4811 g_list_free(element_bucket);
4814 return MM_ERROR_NONE;
4818 LOGD("ERROR : releasing audiobin\n");
4821 gst_object_unref(GST_OBJECT(pad));
4824 gst_object_unref(GST_OBJECT(ghostpad));
4827 g_list_free(element_bucket);
4829 /* release element which are not added to bin */
4830 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4831 /* NOTE : skip bin */
4832 if (audiobin[i].gst) {
4833 GstObject* parent = NULL;
4834 parent = gst_element_get_parent(audiobin[i].gst);
4837 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4838 audiobin[i].gst = NULL;
4840 gst_object_unref(GST_OBJECT(parent));
4844 /* release audiobin with it's childs */
4845 if (audiobin[MMPLAYER_A_BIN].gst)
4846 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4848 MMPLAYER_FREEIF(audiobin);
4850 player->pipeline->audiobin = NULL;
4852 return MM_ERROR_PLAYER_INTERNAL;
4855 static GstPadProbeReturn
4856 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4858 mm_player_t* player = (mm_player_t*) u_data;
4859 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4860 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4862 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4864 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4865 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4867 return GST_PAD_PROBE_OK;
4870 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4872 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4875 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4877 int ret = MM_ERROR_NONE;
4879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4882 MMPLAYER_VIDEO_BO_LOCK(player);
4884 if (player->video_bo_list) {
4885 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4886 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887 if (tmp && tmp->bo == bo) {
4889 LOGD("release bo %p", bo);
4890 tbm_bo_unref(tmp->bo);
4891 MMPLAYER_VIDEO_BO_UNLOCK(player);
4892 MMPLAYER_VIDEO_BO_SIGNAL(player);
4897 /* hw codec is running or the list was reset for DRC. */
4898 LOGW("there is no bo list.");
4900 MMPLAYER_VIDEO_BO_UNLOCK(player);
4902 LOGW("failed to find bo %p", bo);
4907 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4912 MMPLAYER_RETURN_IF_FAIL(player);
4914 MMPLAYER_VIDEO_BO_LOCK(player);
4915 if (player->video_bo_list) {
4916 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4917 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4918 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4921 tbm_bo_unref(tmp->bo);
4925 g_list_free(player->video_bo_list);
4926 player->video_bo_list = NULL;
4928 player->video_bo_size = 0;
4929 MMPLAYER_VIDEO_BO_UNLOCK(player);
4936 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4939 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4940 gboolean ret = TRUE;
4942 /* check DRC, if it is, destroy the prev bo list to create again */
4943 if (player->video_bo_size != size) {
4944 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4945 __mmplayer_video_stream_destroy_bo_list(player);
4946 player->video_bo_size = size;
4949 MMPLAYER_VIDEO_BO_LOCK(player);
4951 if ((!player->video_bo_list) ||
4952 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4954 /* create bo list */
4956 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4958 if (player->video_bo_list) {
4959 /* if bo list did not created all, try it again. */
4960 idx = g_list_length(player->video_bo_list);
4961 LOGD("bo list exist(len: %d)", idx);
4964 for (; idx < player->ini.num_of_video_bo; idx++) {
4965 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4967 LOGE("Fail to alloc bo_info.");
4970 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4972 LOGE("Fail to tbm_bo_alloc.");
4976 bo_info->using = FALSE;
4977 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4980 /* update video num buffers */
4981 player->video_num_buffers = idx;
4982 if (idx == player->ini.num_of_video_bo)
4983 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4986 MMPLAYER_VIDEO_BO_UNLOCK(player);
4990 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4994 /* get bo from list*/
4995 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4996 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4997 if (tmp && (tmp->using == FALSE)) {
4998 LOGD("found bo %p to use", tmp->bo);
5000 MMPLAYER_VIDEO_BO_UNLOCK(player);
5001 return tbm_bo_ref(tmp->bo);
5005 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5006 MMPLAYER_VIDEO_BO_UNLOCK(player);
5010 if (player->ini.video_bo_timeout <= 0) {
5011 MMPLAYER_VIDEO_BO_WAIT(player);
5013 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5014 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5021 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5023 mm_player_t* player = (mm_player_t*)data;
5025 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5027 /* send prerolled pkt */
5028 player->video_stream_prerolled = FALSE;
5030 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5032 /* not to send prerolled pkt again */
5033 player->video_stream_prerolled = TRUE;
5037 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5039 mm_player_t* player = (mm_player_t*)data;
5040 GstCaps *caps = NULL;
5041 MMPlayerVideoStreamDataType *stream = NULL;
5042 MMVideoBuffer *video_buffer = NULL;
5043 GstMemory *dataBlock = NULL;
5044 GstMemory *metaBlock = NULL;
5045 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5046 GstStructure *structure = NULL;
5047 const gchar *string_format = NULL;
5048 unsigned int fourcc = 0;
5051 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5053 if (player->video_stream_prerolled) {
5054 player->video_stream_prerolled = FALSE;
5055 LOGD("skip the prerolled pkt not to send it again");
5059 caps = gst_pad_get_current_caps(pad);
5061 LOGE("Caps is NULL.");
5065 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5067 /* clear stream data structure */
5068 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5070 LOGE("failed to alloc mem for video data");
5074 structure = gst_caps_get_structure(caps, 0);
5075 gst_structure_get_int(structure, "width", &(stream->width));
5076 gst_structure_get_int(structure, "height", &(stream->height));
5077 string_format = gst_structure_get_string(structure, "format");
5079 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5080 stream->format = util_get_pixtype(fourcc);
5081 gst_caps_unref(caps);
5084 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5087 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5088 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5091 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5092 LOGE("Wrong condition!!");
5096 /* set size and timestamp */
5097 dataBlock = gst_buffer_peek_memory(buffer, 0);
5098 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5099 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5101 /* check zero-copy */
5102 if (player->set_mode.video_zc &&
5103 player->set_mode.media_packet_video_stream &&
5104 gst_buffer_n_memory(buffer) > 1) {
5105 metaBlock = gst_buffer_peek_memory(buffer, 1);
5106 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5107 video_buffer = (MMVideoBuffer *)mapinfo.data;
5110 if (video_buffer) { /* hw codec */
5112 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5115 /* copy pointer of tbm bo, stride, elevation */
5116 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5117 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5121 LOGE("Not support video buffer format");
5124 memcpy(stream->stride, video_buffer->stride_width,
5125 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5126 memcpy(stream->elevation, video_buffer->stride_height,
5127 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5129 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5130 stream->internal_buffer = gst_buffer_ref(buffer);
5131 } else { /* sw codec */
5135 int ret = TBM_SURFACE_ERROR_NONE;
5136 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5137 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5139 unsigned char *src = NULL;
5140 unsigned char *dest = NULL;
5141 tbm_bo_handle thandle;
5142 tbm_surface_h surface;
5143 tbm_surface_info_s info;
5146 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5148 LOGE("fail to gst_memory_map");
5153 if (stream->format == MM_PIXEL_FORMAT_I420) {
5154 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5156 ret = tbm_surface_get_info(surface, &info);
5158 if (ret != TBM_SURFACE_ERROR_NONE) {
5159 tbm_surface_destroy(surface);
5162 tbm_surface_destroy(surface);
5164 src_stride[0] = GST_ROUND_UP_4(stream->width);
5165 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5166 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5167 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5168 stream->stride[0] = info.planes[0].stride;
5169 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5170 stream->stride[1] = info.planes[1].stride;
5171 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5172 stream->stride[2] = info.planes[2].stride;
5173 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5174 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5175 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5176 stream->stride[0] = stream->width * 4;
5177 stream->elevation[0] = stream->height;
5178 size = stream->stride[0] * stream->height;
5180 LOGE("Not support format %d", stream->format);
5184 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5185 if (!stream->bo[0]) {
5186 LOGE("Fail to tbm_bo_alloc!!");
5190 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5191 if (thandle.ptr && mapinfo.data) {
5192 if (stream->format == MM_PIXEL_FORMAT_I420) {
5193 for (i = 0; i < 3; i++) {
5194 src = mapinfo.data + src_offset[i];
5195 dest = thandle.ptr + info.planes[i].offset;
5198 for (j = 0; j < stream->height>>k; j++) {
5199 memcpy(dest, src, stream->width>>k);
5200 src += src_stride[i];
5201 dest += stream->stride[i];
5204 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5205 memcpy(thandle.ptr, mapinfo.data, size);
5207 LOGE("Not support format %d", stream->format);
5211 LOGE("data pointer is wrong. dest : %p, src : %p",
5212 thandle.ptr, mapinfo.data);
5215 tbm_bo_unmap(stream->bo[0]);
5218 if (player->video_stream_cb) { /* This has been already checked at the entry */
5219 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5220 LOGE("failed to send video stream data.");
5226 gst_memory_unmap(metaBlock, &mapinfo);
5228 gst_memory_unmap(dataBlock, &mapinfo);
5233 LOGE("release video stream resource.");
5236 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5238 tbm_bo_unref(stream->bo[i]);
5240 gst_memory_unmap(metaBlock, &mapinfo);
5242 /* unref gst buffer */
5243 if (stream->internal_buffer)
5244 gst_buffer_unref(stream->internal_buffer);
5245 } else if (dataBlock) {
5247 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5248 gst_memory_unmap(dataBlock, &mapinfo);
5256 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5258 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5259 GList* element_bucket = NULL;
5261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5265 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5266 LOGD("do not need to add video filters.");
5267 return MM_ERROR_NONE;
5270 /* in case of sw codec except 360 playback,
5271 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5272 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5273 LOGD("using video converter: %s", video_csc);
5275 /* set video rotator */
5276 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5278 *bucket = element_bucket;
5280 return MM_ERROR_NONE;
5282 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5283 g_list_free(element_bucket);
5287 return MM_ERROR_PLAYER_INTERNAL;
5291 * This function is to create video pipeline.
5293 * @param player [in] handle of player
5294 * caps [in] src caps of decoder
5295 * surface_type [in] surface type for video rendering
5297 * @return This function returns zero on success.
5299 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5303 * - video overlay surface(arm/x86) : tizenwlsink
5306 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5310 GList*element_bucket = NULL;
5311 MMPlayerGstElement* first_element = NULL;
5312 MMPlayerGstElement* videobin = NULL;
5313 gchar *videosink_element = NULL;
5317 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5320 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5322 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5324 player->pipeline->videobin = videobin;
5326 attrs = MMPLAYER_GET_ATTRS(player);
5328 LOGE("cannot get content attribute");
5329 return MM_ERROR_PLAYER_INTERNAL;
5333 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5334 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5335 if (!videobin[MMPLAYER_V_BIN].gst) {
5336 LOGE("failed to create videobin");
5340 int enable_video_decoded_cb = 0;
5341 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5343 if (player->is_360_feature_enabled && player->is_content_spherical) {
5344 LOGD("video360 elem will be added.");
5346 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5347 "video-360", TRUE, player);
5349 /* Set spatial media metadata and/or user settings to the element.
5351 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352 "projection-type", player->video360_metadata.projection_type, NULL);
5354 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5357 if (player->video360_metadata.full_pano_width_pixels &&
5358 player->video360_metadata.full_pano_height_pixels &&
5359 player->video360_metadata.cropped_area_image_width &&
5360 player->video360_metadata.cropped_area_image_height) {
5361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5362 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5363 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5364 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5365 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5366 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5367 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5371 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5372 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5373 "horizontal-fov", player->video360_horizontal_fov,
5374 "vertical-fov", player->video360_vertical_fov, NULL);
5377 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5378 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5379 "zoom", 1.0f / player->video360_zoom, NULL);
5382 if (player->video360_yaw_radians <= M_PI &&
5383 player->video360_yaw_radians >= -M_PI &&
5384 player->video360_pitch_radians <= M_PI_2 &&
5385 player->video360_pitch_radians >= -M_PI_2) {
5386 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5387 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5388 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5389 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5391 "pose-yaw", player->video360_metadata.init_view_heading,
5392 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5395 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5396 "passthrough", !player->is_video360_enabled, NULL);
5399 /* set video sink */
5400 switch (surface_type) {
5401 case MM_DISPLAY_SURFACE_OVERLAY:
5402 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5404 if (strlen(player->ini.videosink_element_overlay) > 0)
5405 videosink_element = player->ini.videosink_element_overlay;
5409 case MM_DISPLAY_SURFACE_NULL:
5410 if (strlen(player->ini.videosink_element_fake) > 0)
5411 videosink_element = player->ini.videosink_element_fake;
5415 case MM_DISPLAY_SURFACE_REMOTE:
5416 if (strlen(player->ini.videosink_element_fake) > 0)
5417 videosink_element = player->ini.videosink_element_fake;
5422 LOGE("unidentified surface type");
5425 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5427 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5429 /* additional setting for sink plug-in */
5430 switch (surface_type) {
5431 case MM_DISPLAY_SURFACE_OVERLAY:
5433 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5435 LOGD("selected videosink name: %s", videosink_element);
5437 /* support shard memory with S/W codec on HawkP */
5438 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5439 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5440 "use-tbm", use_tbm, NULL);
5446 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5449 LOGD("disable last-sample");
5450 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5454 if (player->set_mode.media_packet_video_stream) {
5456 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5458 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5460 MMPLAYER_SIGNAL_CONNECT(player,
5461 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5462 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5464 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5467 MMPLAYER_SIGNAL_CONNECT(player,
5468 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5469 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5471 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5476 case MM_DISPLAY_SURFACE_REMOTE:
5478 if (player->set_mode.media_packet_video_stream) {
5479 LOGE("add data probe at videosink");
5480 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5481 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5483 MMPLAYER_SIGNAL_CONNECT(player,
5484 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5485 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5487 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5490 MMPLAYER_SIGNAL_CONNECT(player,
5491 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5492 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5494 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5499 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5502 LOGD("disable last-sample");
5503 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5513 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5516 if (videobin[MMPLAYER_V_SINK].gst) {
5517 GstPad *sink_pad = NULL;
5518 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5520 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5521 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5522 gst_object_unref(GST_OBJECT(sink_pad));
5524 LOGW("failed to get sink pad from videosink\n");
5527 /* store it as it's sink element */
5528 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5530 /* adding created elements to bin */
5531 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5532 LOGE("failed to add elements\n");
5536 /* Linking elements in the bucket by added order */
5537 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5538 LOGE("failed to link elements\n");
5542 /* get first element's sinkpad for creating ghostpad */
5544 first_element = (MMPlayerGstElement *)element_bucket->data;
5545 if (!first_element) {
5546 LOGE("failed to get first element from bucket\n");
5550 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5552 LOGE("failed to get pad from first element\n");
5556 /* create ghostpad */
5557 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5558 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5559 LOGE("failed to add ghostpad to videobin\n");
5562 gst_object_unref(pad);
5564 /* done. free allocated variables */
5566 g_list_free(element_bucket);
5570 return MM_ERROR_NONE;
5573 LOGE("ERROR : releasing videobin\n");
5575 g_list_free(element_bucket);
5578 gst_object_unref(GST_OBJECT(pad));
5580 /* release videobin with it's childs */
5581 if (videobin[MMPLAYER_V_BIN].gst)
5582 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5585 MMPLAYER_FREEIF(videobin);
5587 player->pipeline->videobin = NULL;
5589 return MM_ERROR_PLAYER_INTERNAL;
5592 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5594 GList *element_bucket = NULL;
5595 MMPlayerGstElement *textbin = player->pipeline->textbin;
5597 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5598 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5599 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5600 "signal-handoffs", FALSE,
5603 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5604 MMPLAYER_SIGNAL_CONNECT(player,
5605 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5606 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5608 G_CALLBACK(__mmplayer_update_subtitle),
5611 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5612 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5614 if (!player->play_subtitle) {
5615 LOGD("add textbin sink as sink element of whole pipeline.\n");
5616 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5619 /* adding created elements to bin */
5620 LOGD("adding created elements to bin\n");
5621 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5622 LOGE("failed to add elements\n");
5626 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5627 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5628 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5630 /* linking elements in the bucket by added order. */
5631 LOGD("Linking elements in the bucket by added order.\n");
5632 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5633 LOGE("failed to link elements\n");
5637 /* done. free allocated variables */
5638 g_list_free(element_bucket);
5640 if (textbin[MMPLAYER_T_QUEUE].gst) {
5642 GstPad *ghostpad = NULL;
5644 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5646 LOGE("failed to get sink pad of text queue");
5650 ghostpad = gst_ghost_pad_new("text_sink", pad);
5651 gst_object_unref(pad);
5654 LOGE("failed to create ghostpad of textbin\n");
5658 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5659 LOGE("failed to add ghostpad to textbin\n");
5660 gst_object_unref(ghostpad);
5665 return MM_ERROR_NONE;
5668 g_list_free(element_bucket);
5670 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5671 LOGE("remove textbin sink from sink list");
5672 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5675 /* release element at __mmplayer_gst_create_text_sink_bin */
5676 return MM_ERROR_PLAYER_INTERNAL;
5679 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5681 MMPlayerGstElement *textbin = NULL;
5682 GList *element_bucket = NULL;
5683 int surface_type = 0;
5688 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5691 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5693 LOGE("failed to allocate memory for textbin\n");
5694 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5698 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5699 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5700 if (!textbin[MMPLAYER_T_BIN].gst) {
5701 LOGE("failed to create textbin\n");
5706 player->pipeline->textbin = textbin;
5709 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5710 LOGD("surface type for subtitle : %d", surface_type);
5711 switch (surface_type) {
5712 case MM_DISPLAY_SURFACE_OVERLAY:
5713 case MM_DISPLAY_SURFACE_NULL:
5714 case MM_DISPLAY_SURFACE_REMOTE:
5715 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5716 LOGE("failed to make plain text elements\n");
5727 return MM_ERROR_NONE;
5731 LOGD("ERROR : releasing textbin\n");
5733 g_list_free(element_bucket);
5735 /* release signal */
5736 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5738 /* release element which are not added to bin */
5739 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5740 /* NOTE : skip bin */
5741 if (textbin[i].gst) {
5742 GstObject* parent = NULL;
5743 parent = gst_element_get_parent(textbin[i].gst);
5746 gst_object_unref(GST_OBJECT(textbin[i].gst));
5747 textbin[i].gst = NULL;
5749 gst_object_unref(GST_OBJECT(parent));
5754 /* release textbin with it's childs */
5755 if (textbin[MMPLAYER_T_BIN].gst)
5756 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5758 MMPLAYER_FREEIF(player->pipeline->textbin);
5759 player->pipeline->textbin = NULL;
5762 return MM_ERROR_PLAYER_INTERNAL;
5767 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5769 MMPlayerGstElement* mainbin = NULL;
5770 MMPlayerGstElement* textbin = NULL;
5771 MMHandleType attrs = 0;
5772 GstElement *subsrc = NULL;
5773 GstElement *subparse = NULL;
5774 gchar *subtitle_uri = NULL;
5775 const gchar *charset = NULL;
5781 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5783 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5785 mainbin = player->pipeline->mainbin;
5787 attrs = MMPLAYER_GET_ATTRS(player);
5789 LOGE("cannot get content attribute\n");
5790 return MM_ERROR_PLAYER_INTERNAL;
5793 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5794 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5795 LOGE("subtitle uri is not proper filepath.\n");
5796 return MM_ERROR_PLAYER_INVALID_URI;
5799 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5800 LOGE("failed to get storage info of subtitle path");
5801 return MM_ERROR_PLAYER_INVALID_URI;
5804 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5806 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5807 player->subtitle_language_list = NULL;
5808 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5810 /* create the subtitle source */
5811 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5813 LOGE("failed to create filesrc element\n");
5816 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5818 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5819 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5821 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5822 LOGW("failed to add queue\n");
5823 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5824 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5825 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5830 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5832 LOGE("failed to create subparse element\n");
5836 charset = util_get_charset(subtitle_uri);
5838 LOGD("detected charset is %s\n", charset);
5839 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5842 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5843 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5845 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5846 LOGW("failed to add subparse\n");
5847 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5848 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5849 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5853 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5854 LOGW("failed to link subsrc and subparse\n");
5858 player->play_subtitle = TRUE;
5859 player->adjust_subtitle_pos = 0;
5861 LOGD("play subtitle using subtitle file\n");
5863 if (player->pipeline->textbin == NULL) {
5864 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5865 LOGE("failed to create text sink bin. continuing without text\n");
5869 textbin = player->pipeline->textbin;
5871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5872 LOGW("failed to add textbin\n");
5874 /* release signal */
5875 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5877 /* release textbin with it's childs */
5878 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5879 MMPLAYER_FREEIF(player->pipeline->textbin);
5880 player->pipeline->textbin = textbin = NULL;
5884 LOGD("link text input selector and textbin ghost pad");
5886 player->textsink_linked = 1;
5887 player->external_text_idx = 0;
5888 LOGI("player->textsink_linked set to 1\n");
5890 textbin = player->pipeline->textbin;
5891 LOGD("text bin has been created. reuse it.");
5892 player->external_text_idx = 1;
5895 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5896 LOGW("failed to link subparse and textbin\n");
5900 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5902 LOGE("failed to get sink pad from textsink to probe data");
5906 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5907 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5909 gst_object_unref(pad);
5912 /* create dot. for debugging */
5913 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5916 return MM_ERROR_NONE;
5919 /* release text pipeline resource */
5920 player->textsink_linked = 0;
5922 /* release signal */
5923 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5925 if (player->pipeline->textbin) {
5926 LOGE("remove textbin");
5928 /* release textbin with it's childs */
5929 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5930 MMPLAYER_FREEIF(player->pipeline->textbin);
5931 player->pipeline->textbin = NULL;
5935 /* release subtitle elem */
5936 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5937 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5939 return MM_ERROR_PLAYER_INTERNAL;
5943 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5945 mm_player_t* player = (mm_player_t*) data;
5946 MMMessageParamType msg = {0, };
5947 GstClockTime duration = 0;
5948 gpointer text = NULL;
5949 guint text_size = 0;
5950 gboolean ret = TRUE;
5951 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5955 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5956 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5958 if (player->is_subtitle_force_drop) {
5959 LOGW("subtitle is dropped forcedly.");
5963 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5964 text = mapinfo.data;
5965 text_size = mapinfo.size;
5966 duration = GST_BUFFER_DURATION(buffer);
5968 if (player->set_mode.subtitle_off) {
5969 LOGD("subtitle is OFF.\n");
5973 if (!text || (text_size == 0)) {
5974 LOGD("There is no subtitle to be displayed.\n");
5978 msg.data = (void *) text;
5979 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5981 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5983 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5984 gst_buffer_unmap(buffer, &mapinfo);
5991 static GstPadProbeReturn
5992 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5994 mm_player_t *player = (mm_player_t *) u_data;
5995 GstClockTime cur_timestamp = 0;
5996 gint64 adjusted_timestamp = 0;
5997 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5999 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6001 if (player->set_mode.subtitle_off) {
6002 LOGD("subtitle is OFF.\n");
6006 if (player->adjust_subtitle_pos == 0) {
6007 LOGD("nothing to do");
6011 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6012 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6014 if (adjusted_timestamp < 0) {
6015 LOGD("adjusted_timestamp under zero");
6020 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6021 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6022 GST_TIME_ARGS(cur_timestamp),
6023 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6025 return GST_PAD_PROBE_OK;
6027 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6031 /* check player and subtitlebin are created */
6032 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6033 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6035 if (position == 0) {
6036 LOGD("nothing to do\n");
6038 return MM_ERROR_NONE;
6042 case MM_PLAYER_POS_FORMAT_TIME:
6044 /* check current postion */
6045 player->adjust_subtitle_pos = position;
6047 LOGD("save adjust_subtitle_pos in player") ;
6053 LOGW("invalid format.\n");
6055 return MM_ERROR_INVALID_ARGUMENT;
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);
6786 /* check autoplug element is OK */
6788 LOGE("can not create element(%d)\n", elemId);
6792 mainbin[elemId].id = elemId;
6793 mainbin[elemId].gst = element;
6795 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6798 /* add elements to pipeline */
6799 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6800 LOGE("Failed to add elements to pipeline\n");
6805 /* linking elements in the bucket by added order. */
6806 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6807 LOGE("Failed to link some elements\n");
6812 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6813 if (need_state_holder) {
6815 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6816 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6818 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6819 LOGE("fakesink element could not be created\n");
6822 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6824 /* take ownership of fakesink. we are reusing it */
6825 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6828 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6829 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6830 LOGE("failed to add fakesink to bin\n");
6835 /* now we have completed mainbin. take it */
6836 player->pipeline->mainbin = mainbin;
6838 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6839 GstPad *srcpad = NULL;
6841 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6842 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6844 __mmplayer_gst_create_decoder(player,
6845 MM_PLAYER_TRACK_TYPE_VIDEO,
6847 MMPLAYER_M_AUTOPLUG_V_DEC,
6850 gst_object_unref(GST_OBJECT(srcpad));
6855 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6856 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6858 __mmplayer_gst_create_decoder(player,
6859 MM_PLAYER_TRACK_TYPE_AUDIO,
6861 MMPLAYER_M_AUTOPLUG_A_DEC,
6864 gst_object_unref(GST_OBJECT(srcpad));
6869 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6870 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6873 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6874 if (__mmplayer_check_subtitle(player)) {
6875 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6876 LOGE("fail to create text pipeline");
6879 /* connect bus callback */
6880 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6882 LOGE("cannot get bus from pipeline.\n");
6886 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6888 player->context.thread_default = g_main_context_get_thread_default();
6890 if (player->context.thread_default == NULL) {
6891 player->context.thread_default = g_main_context_default();
6892 LOGD("thread-default context is the global default context");
6894 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6896 /* set sync handler to get tag synchronously */
6897 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6900 gst_object_unref(GST_OBJECT(bus));
6901 g_list_free(element_bucket);
6903 /* create gst bus_msb_cb thread */
6904 g_mutex_init(&player->bus_msg_thread_mutex);
6905 g_cond_init(&player->bus_msg_thread_cond);
6906 player->bus_msg_thread_exit = FALSE;
6907 player->bus_msg_thread =
6908 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6909 if (!player->bus_msg_thread) {
6910 LOGE("failed to create gst BUS msg thread");
6911 g_mutex_clear(&player->bus_msg_thread_mutex);
6912 g_cond_clear(&player->bus_msg_thread_cond);
6918 return MM_ERROR_NONE;
6921 __mmplayer_gst_destroy_pipeline(player);
6922 g_list_free(element_bucket);
6925 /* release element which are not added to bin */
6926 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6927 /* NOTE : skip pipeline */
6928 if (mainbin[i].gst) {
6929 GstObject* parent = NULL;
6930 parent = gst_element_get_parent(mainbin[i].gst);
6933 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6934 mainbin[i].gst = NULL;
6936 gst_object_unref(GST_OBJECT(parent));
6940 /* release pipeline with it's childs */
6941 if (mainbin[MMPLAYER_M_PIPE].gst)
6942 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6944 MMPLAYER_FREEIF(mainbin);
6947 MMPLAYER_FREEIF(player->pipeline);
6948 return MM_ERROR_PLAYER_INTERNAL;
6952 __mmplayer_reset_gapless_state(mm_player_t* player)
6955 MMPLAYER_RETURN_IF_FAIL(player
6957 && player->pipeline->audiobin
6958 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6960 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6967 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6970 int ret = MM_ERROR_NONE;
6974 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6976 /* cleanup stuffs */
6977 MMPLAYER_FREEIF(player->type);
6978 player->have_dynamic_pad = FALSE;
6979 player->no_more_pad = FALSE;
6980 player->num_dynamic_pad = 0;
6981 player->demux_pad_index = 0;
6982 player->use_deinterleave = FALSE;
6983 player->max_audio_channels = 0;
6984 player->video_share_api_delta = 0;
6985 player->video_share_clock_delta = 0;
6986 player->video_hub_download_mode = 0;
6988 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6989 player->subtitle_language_list = NULL;
6990 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6992 __mmplayer_reset_gapless_state(player);
6994 if (player->streamer) {
6995 __mm_player_streaming_deinitialize(player->streamer);
6996 __mm_player_streaming_destroy(player->streamer);
6997 player->streamer = NULL;
7000 /* cleanup unlinked mime type */
7001 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7002 MMPLAYER_FREEIF(player->unlinked_video_mime);
7003 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7005 /* cleanup running stuffs */
7006 __mmplayer_cancel_eos_timer(player);
7008 /* cleanup gst stuffs */
7009 if (player->pipeline) {
7010 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7011 GstTagList* tag_list = player->pipeline->tag_list;
7013 /* first we need to disconnect all signal hander */
7014 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7017 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7018 MMPlayerGstElement* videobin = player->pipeline->videobin;
7019 MMPlayerGstElement* textbin = player->pipeline->textbin;
7020 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7021 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7022 gst_object_unref(bus);
7024 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7025 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7026 if (ret != MM_ERROR_NONE) {
7027 LOGE("fail to change state to NULL\n");
7028 return MM_ERROR_PLAYER_INTERNAL;
7031 LOGW("succeeded in changing state to NULL\n");
7033 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7036 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7037 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7039 /* free avsysaudiosink
7040 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7041 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7043 MMPLAYER_FREEIF(audiobin);
7044 MMPLAYER_FREEIF(videobin);
7045 MMPLAYER_FREEIF(textbin);
7046 MMPLAYER_FREEIF(mainbin);
7050 gst_tag_list_free(tag_list);
7052 MMPLAYER_FREEIF(player->pipeline);
7054 MMPLAYER_FREEIF(player->album_art);
7056 if (player->v_stream_caps) {
7057 gst_caps_unref(player->v_stream_caps);
7058 player->v_stream_caps = NULL;
7060 if (player->a_stream_caps) {
7061 gst_caps_unref(player->a_stream_caps);
7062 player->a_stream_caps = NULL;
7065 if (player->s_stream_caps) {
7066 gst_caps_unref(player->s_stream_caps);
7067 player->s_stream_caps = NULL;
7069 _mmplayer_track_destroy(player);
7071 if (player->sink_elements)
7072 g_list_free(player->sink_elements);
7073 player->sink_elements = NULL;
7075 if (player->bufmgr) {
7076 tbm_bufmgr_deinit(player->bufmgr);
7077 player->bufmgr = NULL;
7080 LOGW("finished destroy pipeline\n");
7087 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
7089 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
7091 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
7093 audiobin = player->pipeline->audiobin; /* can be null */
7094 videobin = player->pipeline->videobin; /* can be null */
7095 textbin = player->pipeline->textbin; /* can be null */
7097 LOGD("Async will be set to %d about 0x%X type sink", async, type);
7099 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
7100 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
7102 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
7103 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
7105 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
7106 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
7111 static int __gst_realize(mm_player_t* player)
7114 int ret = MM_ERROR_NONE;
7118 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7120 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7122 ret = __mmplayer_gst_create_pipeline(player);
7124 LOGE("failed to create pipeline\n");
7128 /* set pipeline state to READY */
7129 /* NOTE : state change to READY must be performed sync. */
7130 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7131 ret = __mmplayer_gst_set_state(player,
7132 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7134 if (ret != MM_ERROR_NONE) {
7135 /* return error if failed to set state */
7136 LOGE("failed to set READY state");
7140 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7142 /* create dot before error-return. for debugging */
7143 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7150 static int __gst_unrealize(mm_player_t* player)
7152 int ret = MM_ERROR_NONE;
7156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7158 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7159 MMPLAYER_PRINT_STATE(player);
7161 /* release miscellaneous information */
7162 __mmplayer_release_misc(player);
7164 /* destroy pipeline */
7165 ret = __mmplayer_gst_destroy_pipeline(player);
7166 if (ret != MM_ERROR_NONE) {
7167 LOGE("failed to destory pipeline\n");
7171 /* release miscellaneous information.
7172 these info needs to be released after pipeline is destroyed. */
7173 __mmplayer_release_misc_post(player);
7175 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7182 static int __gst_pending_seek(mm_player_t* player)
7184 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7185 int ret = MM_ERROR_NONE;
7189 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7191 if (!player->pending_seek.is_pending) {
7192 LOGD("pending seek is not reserved. nothing to do.\n");
7196 /* check player state if player could pending seek or not. */
7197 current_state = MMPLAYER_CURRENT_STATE(player);
7199 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7200 LOGW("try to pending seek in %s state, try next time. \n",
7201 MMPLAYER_STATE_GET_NAME(current_state));
7205 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7207 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7209 if (MM_ERROR_NONE != ret)
7210 LOGE("failed to seek pending postion. just keep staying current position.\n");
7212 player->pending_seek.is_pending = FALSE;
7219 static int __gst_start(mm_player_t* player)
7221 int ret = MM_ERROR_NONE;
7222 gboolean async = FALSE;
7226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228 /* NOTE : if SetPosition was called before Start. do it now */
7229 /* streaming doesn't support it. so it should be always sync */
7230 /* !!create one more api to check if there is pending seek rather than checking variables */
7231 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
7232 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7233 ret = __gst_pause(player, FALSE);
7234 if (ret != MM_ERROR_NONE) {
7235 LOGE("failed to set state to PAUSED for pending seek");
7239 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7240 if (__gst_pending_seek(player) != MM_ERROR_NONE)
7241 LOGW("failed to seek pending postion. starting from the begin of content");
7244 LOGD("current state before doing transition");
7245 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7246 MMPLAYER_PRINT_STATE(player);
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;
7277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7280 LOGD("current state before doing transition");
7281 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7282 MMPLAYER_PRINT_STATE(player);
7284 attrs = MMPLAYER_GET_ATTRS(player);
7286 LOGE("cannot get content attribute\n");
7287 return MM_ERROR_PLAYER_INTERNAL;
7290 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7291 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7293 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7294 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7297 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7298 /* disable the async state transition because there could be no data in the pipeline */
7299 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
7303 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
7305 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7306 /* enable the async state transition as default operation */
7307 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
7310 /* return if set_state has failed */
7311 if (ret != MM_ERROR_NONE) {
7312 LOGE("failed to set state.\n");
7318 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7319 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7320 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7321 LOGW("failed to rewind\n");
7322 ret = MM_ERROR_PLAYER_SEEK;
7327 player->sent_bos = FALSE;
7329 if (player->es_player_push_mode) //for cloudgame
7332 /* wait for seek to complete */
7333 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7334 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7335 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7337 LOGE("fail to stop player.\n");
7338 ret = MM_ERROR_PLAYER_INTERNAL;
7339 __mmplayer_dump_pipeline_state(player);
7342 /* generate dot file if enabled */
7343 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7350 int __gst_pause(mm_player_t* player, gboolean async)
7352 int ret = MM_ERROR_NONE;
7356 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7357 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7359 LOGD("current state before doing transition");
7360 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7361 MMPLAYER_PRINT_STATE(player);
7363 /* set pipeline status to PAUSED */
7364 ret = __mmplayer_gst_set_state(player,
7365 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7367 if (FALSE == async) {
7368 if (ret != MM_ERROR_NONE) {
7369 GstMessage *msg = NULL;
7370 GTimer *timer = NULL;
7371 gdouble MAX_TIMEOUT_SEC = 3;
7373 LOGE("failed to set state to PAUSED");
7375 if (!player->bus_watcher) {
7376 LOGE("there is no bus msg thread. pipeline is shutting down.");
7380 if (player->msg_posted) {
7381 LOGE("error msg is already posted.");
7385 timer = g_timer_new();
7386 g_timer_start(timer);
7388 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7391 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7393 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7394 GError *error = NULL;
7396 /* parse error code */
7397 gst_message_parse_error(msg, &error, NULL);
7399 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7400 /* Note : the streaming error from the streaming source is handled
7401 * using __mmplayer_handle_streaming_error.
7403 __mmplayer_handle_streaming_error(player, msg);
7406 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7408 if (error->domain == GST_STREAM_ERROR)
7409 ret = __gst_handle_stream_error(player, error, msg);
7410 else if (error->domain == GST_RESOURCE_ERROR)
7411 ret = __gst_handle_resource_error(player, error->code, NULL);
7412 else if (error->domain == GST_LIBRARY_ERROR)
7413 ret = __gst_handle_library_error(player, error->code);
7414 else if (error->domain == GST_CORE_ERROR)
7415 ret = __gst_handle_core_error(player, error->code);
7417 g_error_free(error);
7419 player->msg_posted = TRUE;
7421 gst_message_unref(msg);
7423 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7425 gst_object_unref(bus);
7426 g_timer_stop(timer);
7427 g_timer_destroy(timer);
7431 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7432 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7434 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7437 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7441 /* generate dot file before returning error */
7442 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7449 int __gst_resume(mm_player_t* player, gboolean async)
7451 int ret = MM_ERROR_NONE;
7456 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7457 MM_ERROR_PLAYER_NOT_INITIALIZED);
7459 LOGD("current state before doing transition");
7460 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7461 MMPLAYER_PRINT_STATE(player);
7464 LOGD("do async state transition to PLAYING");
7466 /* set pipeline state to PLAYING */
7467 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7469 ret = __mmplayer_gst_set_state(player,
7470 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7471 if (ret != MM_ERROR_NONE) {
7472 LOGE("failed to set state to PLAYING");
7476 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7480 /* generate dot file */
7481 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7489 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7491 gint64 dur_nsec = 0;
7492 gint64 pos_nsec = 0;
7493 gboolean ret = TRUE;
7494 gboolean accurated = FALSE;
7495 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7498 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7499 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7501 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7502 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7505 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7506 /* check duration */
7507 /* NOTE : duration cannot be zero except live streaming.
7508 * Since some element could have some timing problemn with quering duration, try again.
7510 if (player->duration == 0) {
7511 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7512 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7513 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7514 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7515 player->pending_seek.is_pending = TRUE;
7516 player->pending_seek.format = format;
7517 player->pending_seek.pos = position;
7518 player->seek_state = MMPLAYER_SEEK_NONE;
7519 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7520 return MM_ERROR_NONE;
7525 player->duration = dur_nsec;
7528 LOGD("playback rate: %f\n", player->playback_rate);
7530 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7532 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7534 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7538 case MM_PLAYER_POS_FORMAT_TIME:
7540 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7541 GstQuery *query = NULL;
7542 gboolean seekable = FALSE;
7544 /* check position is valid or not */
7545 if (position > player->duration)
7548 query = gst_query_new_seeking(GST_FORMAT_TIME);
7549 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7550 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7551 gst_query_unref(query);
7554 LOGW("non-seekable content");
7555 player->seek_state = MMPLAYER_SEEK_NONE;
7556 return MM_ERROR_PLAYER_NO_OP;
7559 LOGW("failed to get seeking query");
7560 gst_query_unref(query); /* keep seeking operation */
7563 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7565 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7566 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7567 This causes problem is position calculation during normal pause resume scenarios also.
7568 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7569 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7570 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7571 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7572 LOGW("getting current position failed in seek\n");
7574 player->last_position = pos_nsec;
7575 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7578 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7579 LOGD("not completed seek");
7580 return MM_ERROR_PLAYER_DOING_SEEK;
7584 if (!internal_called)
7585 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7587 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7588 gint64 cur_time = 0;
7590 /* get current position */
7591 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7594 GstEvent *event = gst_event_new_seek(1.0,
7596 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7597 GST_SEEK_TYPE_SET, cur_time,
7598 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7600 __gst_send_event_to_sink(player, event);
7602 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7603 __gst_pause(player, FALSE);
7606 pos_nsec = position;
7608 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7609 that's why set position through property. */
7610 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7611 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7612 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7613 (!player->videodec_linked) && (!player->audiodec_linked)) {
7615 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7616 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7617 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7618 player->seek_state = MMPLAYER_SEEK_NONE;
7619 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7621 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7622 GST_FORMAT_TIME, seek_flags,
7623 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7627 LOGE("failed to set position.");
7633 case MM_PLAYER_POS_FORMAT_PERCENT:
7635 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7637 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7638 LOGD("not completed seek");
7639 return MM_ERROR_PLAYER_DOING_SEEK;
7642 if (!internal_called)
7643 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7645 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7646 pos_nsec = (gint64)((position * player->duration) / 100);
7647 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7648 GST_FORMAT_TIME, seek_flags,
7649 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7651 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7661 /* NOTE : store last seeking point to overcome some bad operation
7662 * (returning zero when getting current position) of some elements
7664 player->last_position = pos_nsec;
7666 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7667 if (player->playback_rate > 1.0)
7668 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7670 if ((!internal_called) &&
7671 (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7672 LOGD("buffering should be reset after seeking");
7673 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7674 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
7678 return MM_ERROR_NONE;
7681 player->pending_seek.is_pending = TRUE;
7682 player->pending_seek.format = format;
7683 player->pending_seek.pos = position;
7685 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7686 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7687 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7688 player->pending_seek.pos);
7690 return MM_ERROR_NONE;
7693 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7694 return MM_ERROR_INVALID_ARGUMENT;
7697 player->seek_state = MMPLAYER_SEEK_NONE;
7698 return MM_ERROR_PLAYER_SEEK;
7701 #define TRICKPLAY_OFFSET GST_MSECOND
7704 __gst_get_position(mm_player_t* player, int format, gint64* position)
7706 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7707 gint64 pos_nsec = 0;
7708 gboolean ret = TRUE;
7710 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7711 MM_ERROR_PLAYER_NOT_INITIALIZED);
7713 current_state = MMPLAYER_CURRENT_STATE(player);
7715 /* NOTE : query position except paused state to overcome some bad operation
7716 * please refer to below comments in details
7718 if (current_state != MM_PLAYER_STATE_PAUSED)
7719 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7721 /* NOTE : get last point to overcome some bad operation of some elements
7722 *(returning zero when getting current position in paused state
7723 * and when failed to get postion during seeking
7725 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7726 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7728 if (player->playback_rate < 0.0)
7729 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7731 pos_nsec = player->last_position;
7734 pos_nsec = player->last_position;
7736 player->last_position = pos_nsec;
7738 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7741 if (player->duration > 0 && pos_nsec > player->duration)
7742 pos_nsec = player->duration;
7744 player->last_position = pos_nsec;
7748 case MM_PLAYER_POS_FORMAT_TIME:
7749 *position = pos_nsec;
7752 case MM_PLAYER_POS_FORMAT_PERCENT:
7754 if (player->duration <= 0) {
7755 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7758 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7759 *position = (gint64)(pos_nsec * 100 / player->duration);
7764 return MM_ERROR_PLAYER_INTERNAL;
7767 return MM_ERROR_NONE;
7771 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7773 #define STREAMING_IS_FINISHED 0
7774 #define BUFFERING_MAX_PER 100
7775 #define DEFAULT_PER_VALUE -1
7776 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7778 MMPlayerGstElement *mainbin = NULL;
7779 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7780 gint64 buffered_total = 0;
7781 gint64 position = 0;
7782 gint buffered_sec = -1;
7783 GstBufferingMode mode = GST_BUFFERING_STREAM;
7784 gint64 content_size_time = player->duration;
7785 guint64 content_size_bytes = player->http_content_size;
7787 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7789 player->pipeline->mainbin,
7790 MM_ERROR_PLAYER_NOT_INITIALIZED);
7792 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7797 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7798 /* and rtsp is not ready yet. */
7799 LOGW("it's only used for http streaming case.\n");
7800 return MM_ERROR_PLAYER_NO_OP;
7803 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7804 LOGW("Time format is not supported yet.\n");
7805 return MM_ERROR_INVALID_ARGUMENT;
7808 if (content_size_time <= 0 || content_size_bytes <= 0) {
7809 LOGW("there is no content size.");
7810 return MM_ERROR_NONE;
7813 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7814 LOGW("fail to get current position.");
7815 return MM_ERROR_NONE;
7818 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7819 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7821 mainbin = player->pipeline->mainbin;
7822 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7824 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7825 GstQuery *query = NULL;
7826 gint byte_in_rate = 0, byte_out_rate = 0;
7827 gint64 estimated_total = 0;
7829 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7830 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7831 LOGW("fail to get buffering query from queue2");
7833 gst_query_unref(query);
7834 return MM_ERROR_NONE;
7837 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7838 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7840 if (mode == GST_BUFFERING_STREAM) {
7841 /* using only queue in case of push mode(ts / mp3) */
7842 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7843 GST_FORMAT_BYTES, &buffered_total)) {
7844 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7845 stop_per = 100 * buffered_total / content_size_bytes;
7848 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7850 guint num_of_ranges = 0;
7851 gint64 start_byte = 0, stop_byte = 0;
7853 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7854 if (estimated_total != STREAMING_IS_FINISHED) {
7855 /* buffered size info from queue2 */
7856 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7857 for (idx = 0; idx < num_of_ranges; idx++) {
7858 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7859 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7861 buffered_total += (stop_byte - start_byte);
7864 stop_per = BUFFERING_MAX_PER;
7866 gst_query_unref(query);
7869 if (stop_per == DEFAULT_PER_VALUE) {
7870 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7872 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7874 /* buffered size info from multiqueue */
7875 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7876 guint curr_size_bytes = 0;
7877 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7878 "curr-size-bytes", &curr_size_bytes, NULL);
7879 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7880 buffered_total += curr_size_bytes;
7883 if (avg_byterate > 0)
7884 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7885 else if (player->total_maximum_bitrate > 0)
7886 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7887 else if (player->total_bitrate > 0)
7888 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7890 if (buffered_sec >= 0)
7891 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7895 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7896 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7898 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7899 buffered_total, buffered_sec, *start_pos, *stop_pos);
7901 return MM_ERROR_NONE;
7905 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7910 LOGW("set_message_callback is called with invalid player handle\n");
7911 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7914 player->msg_cb = callback;
7915 player->msg_cb_param = user_param;
7917 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7921 return MM_ERROR_NONE;
7924 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7926 int ret = MM_ERROR_PLAYER_INVALID_URI;
7931 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7932 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7933 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7935 memset(data, 0, sizeof(MMPlayerParseProfile));
7937 if ((path = strstr(uri, "es_buff://"))) {
7939 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7940 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7941 ret = MM_ERROR_NONE;
7943 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7945 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7947 ret = MM_ERROR_NONE;
7949 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7952 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7953 tmp = g_ascii_strdown(uri, strlen(uri));
7955 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7956 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7958 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7960 ret = MM_ERROR_NONE;
7963 } else if ((path = strstr(uri, "rtspu://"))) {
7965 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7966 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7967 ret = MM_ERROR_NONE;
7969 } else if ((path = strstr(uri, "rtspr://"))) {
7970 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7971 char *separater = strstr(path, "*");
7975 char *urgent = separater + strlen("*");
7977 if ((urgent_len = strlen(urgent))) {
7978 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7979 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7980 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7981 ret = MM_ERROR_NONE;
7984 } else if ((path = strstr(uri, "mms://"))) {
7986 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7987 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7988 ret = MM_ERROR_NONE;
7990 } else if ((path = strstr(uri, "mem://"))) {
7993 char *buffer = NULL;
7994 char *seperator = strchr(path, ',');
7995 char ext[100] = {0,}, size[100] = {0,};
7998 if ((buffer = strstr(path, "ext="))) {
7999 buffer += strlen("ext=");
8001 if (strlen(buffer)) {
8002 strncpy(ext, buffer, 99);
8004 if ((seperator = strchr(ext, ','))
8005 || (seperator = strchr(ext, ' '))
8006 || (seperator = strchr(ext, '\0'))) {
8007 seperator[0] = '\0';
8012 if ((buffer = strstr(path, "size="))) {
8013 buffer += strlen("size=");
8015 if (strlen(buffer) > 0) {
8016 strncpy(size, buffer, 99);
8018 if ((seperator = strchr(size, ','))
8019 || (seperator = strchr(size, ' '))
8020 || (seperator = strchr(size, '\0'))) {
8021 seperator[0] = '\0';
8024 mem_size = atoi(size);
8029 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8030 if (mem_size && param) {
8031 if (data->input_mem.buf)
8032 free(data->input_mem.buf);
8033 data->input_mem.buf = malloc(mem_size);
8035 if (data->input_mem.buf) {
8036 memcpy(data->input_mem.buf, param, mem_size);
8037 data->input_mem.len = mem_size;
8038 ret = MM_ERROR_NONE;
8040 LOGE("failed to alloc mem %d", mem_size);
8041 ret = MM_ERROR_PLAYER_INTERNAL;
8044 data->input_mem.offset = 0;
8045 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8049 gchar *location = NULL;
8052 if ((path = strstr(uri, "file://"))) {
8054 location = g_filename_from_uri(uri, NULL, &err);
8056 if (!location || (err != NULL)) {
8057 LOGE("Invalid URI '%s' for filesrc: %s", path,
8058 (err != NULL) ? err->message : "unknown error");
8060 if (err) g_error_free(err);
8061 if (location) g_free(location);
8063 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8067 LOGD("path from uri: %s", location);
8070 path = (location != NULL) ? (location) : ((char*)uri);
8071 int file_stat = MM_ERROR_NONE;
8073 file_stat = util_exist_file_path(path);
8075 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8076 if (file_stat == MM_ERROR_NONE) {
8077 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8079 if (util_is_sdp_file(path)) {
8080 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8081 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8083 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8085 ret = MM_ERROR_NONE;
8086 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8087 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8089 LOGE("invalid uri, could not play..\n");
8090 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8093 if (location) g_free(location);
8097 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8098 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8099 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8100 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8102 /* dump parse result */
8103 SECURE_LOGW("incomming uri : %s\n", uri);
8104 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8105 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8113 __mmplayer_can_do_interrupt(mm_player_t *player)
8115 if (!player || !player->pipeline || !player->attrs) {
8116 LOGW("not initialized");
8120 if (player->set_mode.pcm_extraction) {
8121 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8125 /* check if seeking */
8126 if (player->seek_state != MMPLAYER_SEEK_NONE) {
8127 MMMessageParamType msg_param;
8128 memset(&msg_param, 0, sizeof(MMMessageParamType));
8129 msg_param.code = MM_ERROR_PLAYER_SEEK;
8130 player->seek_state = MMPLAYER_SEEK_NONE;
8131 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8135 /* check other thread */
8136 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8137 LOGW("locked already, cmd state : %d", player->cmd);
8139 /* check application command */
8140 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8141 LOGW("playing.. should wait cmd lock then, will be interrupted");
8143 /* lock will be released at mrp_resource_release_cb() */
8144 MMPLAYER_CMD_LOCK(player);
8147 LOGW("nothing to do");
8150 LOGW("can interrupt immediately");
8154 FAILED: /* with CMD UNLOCKED */
8157 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8162 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8165 mm_player_t *player = NULL;
8169 if (user_data == NULL) {
8170 LOGE("- user_data is null\n");
8173 player = (mm_player_t *)user_data;
8175 /* do something to release resource here.
8176 * player stop and interrupt forwarding */
8177 if (!__mmplayer_can_do_interrupt(player)) {
8178 LOGW("no need to interrupt, so leave");
8180 MMMessageParamType msg = {0, };
8183 player->interrupted_by_resource = TRUE;
8185 /* get last play position */
8186 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8187 LOGW("failed to get play position.");
8189 msg.union_type = MM_MSG_UNION_TIME;
8190 msg.time.elapsed = pos;
8191 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8193 LOGD("video resource conflict so, resource will be freed by unrealizing");
8194 if (_mmplayer_unrealize((MMHandleType)player))
8195 LOGW("failed to unrealize");
8197 /* lock is called in __mmplayer_can_do_interrupt() */
8198 MMPLAYER_CMD_UNLOCK(player);
8201 if (res == player->video_overlay_resource)
8202 player->video_overlay_resource = FALSE;
8204 player->video_decoder_resource = FALSE;
8212 _mmplayer_create_player(MMHandleType handle)
8214 int ret = MM_ERROR_PLAYER_INTERNAL;
8215 bool enabled = false;
8217 mm_player_t* player = MM_PLAYER_CAST(handle);
8221 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8223 /* initialize player state */
8224 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8225 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8226 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8227 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8229 /* check current state */
8230 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8232 /* construct attributes */
8233 player->attrs = _mmplayer_construct_attribute(handle);
8235 if (!player->attrs) {
8236 LOGE("Failed to construct attributes\n");
8240 /* initialize gstreamer with configured parameter */
8241 if (!__mmplayer_init_gstreamer(player)) {
8242 LOGE("Initializing gstreamer failed\n");
8243 _mmplayer_deconstruct_attribute(handle);
8247 /* create lock. note that g_tread_init() has already called in gst_init() */
8248 g_mutex_init(&player->fsink_lock);
8250 /* create update tag lock */
8251 g_mutex_init(&player->update_tag_lock);
8253 /* create next play mutex */
8254 g_mutex_init(&player->next_play_thread_mutex);
8256 /* create next play cond */
8257 g_cond_init(&player->next_play_thread_cond);
8259 /* create next play thread */
8260 player->next_play_thread =
8261 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8262 if (!player->next_play_thread) {
8263 LOGE("failed to create next play thread");
8264 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8265 g_mutex_clear(&player->next_play_thread_mutex);
8266 g_cond_clear(&player->next_play_thread_cond);
8270 player->bus_msg_q = g_queue_new();
8271 if (!player->bus_msg_q) {
8272 LOGE("failed to create queue for bus_msg");
8273 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8277 ret = _mmplayer_initialize_video_capture(player);
8278 if (ret != MM_ERROR_NONE) {
8279 LOGE("failed to initialize video capture\n");
8283 /* initialize resource manager */
8284 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8285 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8286 &player->resource_manager)) {
8287 LOGE("failed to initialize resource manager\n");
8291 if (MMPLAYER_IS_HTTP_PD(player)) {
8292 player->pd_downloader = NULL;
8293 player->pd_file_save_path = NULL;
8296 /* create video bo lock and cond */
8297 g_mutex_init(&player->video_bo_mutex);
8298 g_cond_init(&player->video_bo_cond);
8300 /* create media stream callback mutex */
8301 g_mutex_init(&player->media_stream_cb_lock);
8303 /* create subtitle info lock and cond */
8304 g_mutex_init(&player->subtitle_info_mutex);
8305 g_cond_init(&player->subtitle_info_cond);
8307 player->streaming_type = STREAMING_SERVICE_NONE;
8309 /* give default value of audio effect setting */
8310 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8311 player->sound.rg_enable = false;
8312 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8314 player->play_subtitle = FALSE;
8315 player->use_deinterleave = FALSE;
8316 player->max_audio_channels = 0;
8317 player->video_share_api_delta = 0;
8318 player->video_share_clock_delta = 0;
8319 player->has_closed_caption = FALSE;
8320 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8321 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8322 player->pending_resume = FALSE;
8323 if (player->ini.dump_element_keyword[0][0] == '\0')
8324 player->ini.set_dump_element_flag = FALSE;
8326 player->ini.set_dump_element_flag = TRUE;
8328 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8329 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8330 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8332 /* Set video360 settings to their defaults for just-created player.
8335 player->is_360_feature_enabled = FALSE;
8336 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8337 LOGI("spherical feature info: %d", enabled);
8339 player->is_360_feature_enabled = TRUE;
8341 LOGE("failed to get spherical feature info");
8344 player->is_content_spherical = FALSE;
8345 player->is_video360_enabled = TRUE;
8346 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8347 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8348 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8349 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8350 player->video360_zoom = 1.0f;
8351 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8352 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8354 /* set player state to null */
8355 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8356 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8358 return MM_ERROR_NONE;
8362 g_mutex_clear(&player->fsink_lock);
8364 /* free update tag lock */
8365 g_mutex_clear(&player->update_tag_lock);
8367 g_queue_free(player->bus_msg_q);
8369 /* free next play thread */
8370 if (player->next_play_thread) {
8371 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8372 player->next_play_thread_exit = TRUE;
8373 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8374 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8376 g_thread_join(player->next_play_thread);
8377 player->next_play_thread = NULL;
8379 g_mutex_clear(&player->next_play_thread_mutex);
8380 g_cond_clear(&player->next_play_thread_cond);
8383 /* release attributes */
8384 _mmplayer_deconstruct_attribute(handle);
8392 __mmplayer_init_gstreamer(mm_player_t* player)
8394 static gboolean initialized = FALSE;
8395 static const int max_argc = 50;
8397 gchar** argv = NULL;
8398 gchar** argv2 = NULL;
8404 LOGD("gstreamer already initialized.\n");
8409 argc = malloc(sizeof(int));
8410 argv = malloc(sizeof(gchar*) * max_argc);
8411 argv2 = malloc(sizeof(gchar*) * max_argc);
8413 if (!argc || !argv || !argv2)
8416 memset(argv, 0, sizeof(gchar*) * max_argc);
8417 memset(argv2, 0, sizeof(gchar*) * max_argc);
8421 argv[0] = g_strdup("mmplayer");
8424 for (i = 0; i < 5; i++) {
8425 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8426 if (strlen(player->ini.gst_param[i]) > 0) {
8427 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8432 /* we would not do fork for scanning plugins */
8433 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8436 /* check disable registry scan */
8437 if (player->ini.skip_rescan) {
8438 argv[*argc] = g_strdup("--gst-disable-registry-update");
8442 /* check disable segtrap */
8443 if (player->ini.disable_segtrap) {
8444 argv[*argc] = g_strdup("--gst-disable-segtrap");
8448 LOGD("initializing gstreamer with following parameter\n");
8449 LOGD("argc : %d\n", *argc);
8452 for (i = 0; i < arg_count; i++) {
8454 LOGD("argv[%d] : %s\n", i, argv2[i]);
8457 /* initializing gstreamer */
8458 if (!gst_init_check(argc, &argv, &err)) {
8459 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8466 for (i = 0; i < arg_count; i++) {
8467 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8468 MMPLAYER_FREEIF(argv2[i]);
8471 MMPLAYER_FREEIF(argv);
8472 MMPLAYER_FREEIF(argv2);
8473 MMPLAYER_FREEIF(argc);
8483 for (i = 0; i < arg_count; i++) {
8484 LOGD("free[%d] : %s\n", i, argv2[i]);
8485 MMPLAYER_FREEIF(argv2[i]);
8488 MMPLAYER_FREEIF(argv);
8489 MMPLAYER_FREEIF(argv2);
8490 MMPLAYER_FREEIF(argc);
8496 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8498 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8500 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8501 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8502 MMPLAYER_FREEIF(player->pd_file_save_path);
8505 return MM_ERROR_NONE;
8509 __mmplayer_check_async_state_transition(mm_player_t* player)
8511 GstState element_state = GST_STATE_VOID_PENDING;
8512 GstState element_pending_state = GST_STATE_VOID_PENDING;
8513 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8514 GstElement * element = NULL;
8515 gboolean async = FALSE;
8517 /* check player handle */
8518 MMPLAYER_RETURN_IF_FAIL(player &&
8520 player->pipeline->mainbin &&
8521 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8524 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8526 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8527 LOGD("don't need to check the pipeline state");
8531 MMPLAYER_PRINT_STATE(player);
8533 /* wait for state transition */
8534 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8535 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8537 if (ret == GST_STATE_CHANGE_FAILURE) {
8538 LOGE(" [%s] state : %s pending : %s \n",
8539 GST_ELEMENT_NAME(element),
8540 gst_element_state_get_name(element_state),
8541 gst_element_state_get_name(element_pending_state));
8543 /* dump state of all element */
8544 __mmplayer_dump_pipeline_state(player);
8549 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8554 _mmplayer_destroy(MMHandleType handle)
8556 mm_player_t* player = MM_PLAYER_CAST(handle);
8560 /* check player handle */
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 /* destroy can called at anytime */
8564 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8566 /* check async state transition */
8567 __mmplayer_check_async_state_transition(player);
8569 __mmplayer_destroy_streaming_ext(player);
8571 /* release next play thread */
8572 if (player->next_play_thread) {
8573 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8574 player->next_play_thread_exit = TRUE;
8575 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8576 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8578 LOGD("waitting for next play thread exit\n");
8579 g_thread_join(player->next_play_thread);
8580 g_mutex_clear(&player->next_play_thread_mutex);
8581 g_cond_clear(&player->next_play_thread_cond);
8582 LOGD("next play thread released\n");
8585 _mmplayer_release_video_capture(player);
8587 /* de-initialize resource manager */
8588 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8589 player->resource_manager))
8590 LOGE("failed to deinitialize resource manager\n");
8592 /* release pipeline */
8593 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8594 LOGE("failed to destory pipeline\n");
8595 return MM_ERROR_PLAYER_INTERNAL;
8598 g_queue_free(player->bus_msg_q);
8600 /* release subtitle info lock and cond */
8601 g_mutex_clear(&player->subtitle_info_mutex);
8602 g_cond_clear(&player->subtitle_info_cond);
8604 __mmplayer_release_dump_list(player->dump_list);
8606 /* release miscellaneous information */
8607 __mmplayer_release_misc(player);
8609 /* release miscellaneous information.
8610 these info needs to be released after pipeline is destroyed. */
8611 __mmplayer_release_misc_post(player);
8613 /* release attributes */
8614 _mmplayer_deconstruct_attribute(handle);
8617 g_mutex_clear(&player->fsink_lock);
8620 g_mutex_clear(&player->update_tag_lock);
8622 /* release video bo lock and cond */
8623 g_mutex_clear(&player->video_bo_mutex);
8624 g_cond_clear(&player->video_bo_cond);
8626 /* release media stream callback lock */
8627 g_mutex_clear(&player->media_stream_cb_lock);
8631 return MM_ERROR_NONE;
8635 __mmplayer_realize_streaming_ext(mm_player_t* player)
8637 int ret = MM_ERROR_NONE;
8640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8642 if (MMPLAYER_IS_HTTP_PD(player)) {
8643 gboolean bret = FALSE;
8645 player->pd_downloader = _mmplayer_create_pd_downloader();
8646 if (!player->pd_downloader) {
8647 LOGE("Unable to create PD Downloader...");
8648 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8651 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8653 if (FALSE == bret) {
8654 LOGE("Unable to create PD Downloader...");
8655 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8664 _mmplayer_realize(MMHandleType hplayer)
8666 mm_player_t* player = (mm_player_t*)hplayer;
8669 MMHandleType attrs = 0;
8670 int ret = MM_ERROR_NONE;
8674 /* check player handle */
8675 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8677 /* check current state */
8678 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8680 attrs = MMPLAYER_GET_ATTRS(player);
8682 LOGE("fail to get attributes.\n");
8683 return MM_ERROR_PLAYER_INTERNAL;
8685 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8686 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8688 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8689 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8691 if (ret != MM_ERROR_NONE) {
8692 LOGE("failed to parse profile\n");
8697 if (uri && (strstr(uri, "es_buff://"))) {
8698 if (strstr(uri, "es_buff://push_mode"))
8699 player->es_player_push_mode = TRUE;
8701 player->es_player_push_mode = FALSE;
8704 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8705 LOGW("mms protocol is not supported format.\n");
8706 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8709 if (MMPLAYER_IS_STREAMING(player))
8710 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8712 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8714 player->smooth_streaming = FALSE;
8715 player->videodec_linked = 0;
8716 player->videosink_linked = 0;
8717 player->audiodec_linked = 0;
8718 player->audiosink_linked = 0;
8719 player->textsink_linked = 0;
8720 player->is_external_subtitle_present = FALSE;
8721 player->is_external_subtitle_added_now = FALSE;
8722 /* set the subtitle ON default */
8723 player->is_subtitle_off = FALSE;
8725 /* realize pipeline */
8726 ret = __gst_realize(player);
8727 if (ret != MM_ERROR_NONE)
8728 LOGE("fail to realize the player.\n");
8730 ret = __mmplayer_realize_streaming_ext(player);
8732 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8740 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8745 /* destroy can called at anytime */
8746 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8747 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8750 return MM_ERROR_NONE;
8754 _mmplayer_unrealize(MMHandleType hplayer)
8756 mm_player_t* player = (mm_player_t*)hplayer;
8757 int ret = MM_ERROR_NONE;
8761 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8763 MMPLAYER_CMD_UNLOCK(player);
8764 /* destroy the gst bus msg thread which is created during realize.
8765 this funct have to be called before getting cmd lock. */
8766 _mmplayer_bus_msg_thread_destroy(player);
8767 MMPLAYER_CMD_LOCK(player);
8769 /* check current state */
8770 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8772 /* check async state transition */
8773 __mmplayer_check_async_state_transition(player);
8775 __mmplayer_unrealize_streaming_ext(player);
8777 /* unrealize pipeline */
8778 ret = __gst_unrealize(player);
8780 /* set asm stop if success */
8781 if (MM_ERROR_NONE == ret) {
8782 if (!player->interrupted_by_resource) {
8783 if (player->video_decoder_resource != NULL) {
8784 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8785 player->video_decoder_resource);
8786 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8787 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8789 player->video_decoder_resource = NULL;
8792 if (player->video_overlay_resource != NULL) {
8793 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8794 player->video_overlay_resource);
8795 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8796 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8798 player->video_overlay_resource = NULL;
8801 ret = mm_resource_manager_commit(player->resource_manager);
8802 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8803 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8806 LOGE("failed and don't change asm state to stop");
8814 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8816 mm_player_t* player = (mm_player_t*)hplayer;
8818 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8820 return __gst_set_message_callback(player, callback, user_param);
8824 _mmplayer_get_state(MMHandleType hplayer, int* state)
8826 mm_player_t *player = (mm_player_t*)hplayer;
8828 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8830 *state = MMPLAYER_CURRENT_STATE(player);
8832 return MM_ERROR_NONE;
8837 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8839 mm_player_t* player = (mm_player_t*) hplayer;
8840 GstElement* vol_element = NULL;
8845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8847 LOGD("volume [L]=%f:[R]=%f\n",
8848 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8850 /* invalid factor range or not */
8851 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8852 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8853 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8854 return MM_ERROR_INVALID_ARGUMENT;
8858 /* not support to set other value into each channel */
8859 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8860 return MM_ERROR_INVALID_ARGUMENT;
8862 /* Save volume to handle. Currently the first array element will be saved. */
8863 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8865 /* check pipeline handle */
8866 if (!player->pipeline || !player->pipeline->audiobin) {
8867 LOGD("audiobin is not created yet\n");
8868 LOGD("but, current stored volume will be set when it's created.\n");
8870 /* NOTE : stored volume will be used in create_audiobin
8871 * returning MM_ERROR_NONE here makes application to able to
8872 * set volume at anytime.
8874 return MM_ERROR_NONE;
8877 /* setting volume to volume element */
8878 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8881 LOGD("volume is set [%f]\n", player->sound.volume);
8882 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8887 return MM_ERROR_NONE;
8892 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8894 mm_player_t* player = (mm_player_t*) hplayer;
8899 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8900 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8902 /* returning stored volume */
8903 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8904 volume->level[i] = player->sound.volume;
8908 return MM_ERROR_NONE;
8912 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8914 mm_player_t* player = (mm_player_t*) hplayer;
8915 GstElement* vol_element = NULL;
8919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8921 /* mute value shoud 0 or 1 */
8922 if (mute != 0 && mute != 1) {
8923 LOGE("bad mute value\n");
8925 /* FIXIT : definitly, we need _BAD_PARAM error code */
8926 return MM_ERROR_INVALID_ARGUMENT;
8929 player->sound.mute = mute;
8931 /* just hold mute value if pipeline is not ready */
8932 if (!player->pipeline || !player->pipeline->audiobin) {
8933 LOGD("pipeline is not ready. holding mute value\n");
8934 return MM_ERROR_NONE;
8937 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8939 /* NOTE : volume will only created when the bt is enabled */
8941 LOGD("mute : %d\n", mute);
8942 g_object_set(vol_element, "mute", mute, NULL);
8944 LOGD("volume elemnet is not created. using volume in audiosink\n");
8948 return MM_ERROR_NONE;
8952 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8954 mm_player_t* player = (mm_player_t*) hplayer;
8958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8959 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8961 /* just hold mute value if pipeline is not ready */
8962 if (!player->pipeline || !player->pipeline->audiobin) {
8963 LOGD("pipeline is not ready. returning stored value\n");
8964 *pmute = player->sound.mute;
8965 return MM_ERROR_NONE;
8968 *pmute = player->sound.mute;
8972 return MM_ERROR_NONE;
8976 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8978 mm_player_t* player = (mm_player_t*) hplayer;
8982 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8984 player->video_stream_changed_cb = callback;
8985 player->video_stream_changed_cb_user_param = user_param;
8986 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8990 return MM_ERROR_NONE;
8994 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8996 mm_player_t* player = (mm_player_t*) hplayer;
9000 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9002 player->audio_stream_changed_cb = callback;
9003 player->audio_stream_changed_cb_user_param = user_param;
9004 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9008 return MM_ERROR_NONE;
9012 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9014 mm_player_t* player = (mm_player_t*) hplayer;
9018 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9020 player->audio_stream_render_cb_ex = callback;
9021 player->audio_stream_cb_user_param = user_param;
9022 player->audio_stream_sink_sync = sync;
9023 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);
9027 return MM_ERROR_NONE;
9031 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9033 mm_player_t* player = (mm_player_t*) hplayer;
9037 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9039 if (callback && !player->bufmgr)
9040 player->bufmgr = tbm_bufmgr_init(-1);
9042 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9043 player->video_stream_cb = callback;
9044 player->video_stream_cb_user_param = user_param;
9046 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9050 return MM_ERROR_NONE;
9054 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9056 mm_player_t* player = (mm_player_t*) hplayer;
9060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9062 player->audio_stream_cb = callback;
9063 player->audio_stream_cb_user_param = user_param;
9064 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9068 return MM_ERROR_NONE;
9072 __mmplayer_start_streaming_ext(mm_player_t *player)
9074 gint ret = MM_ERROR_NONE;
9077 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9079 if (MMPLAYER_IS_HTTP_PD(player)) {
9080 if (!player->pd_downloader) {
9081 ret = __mmplayer_realize_streaming_ext(player);
9083 if (ret != MM_ERROR_NONE) {
9084 LOGE("failed to realize streaming ext\n");
9089 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9090 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9092 LOGE("ERROR while starting PD...\n");
9093 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9095 ret = MM_ERROR_NONE;
9104 _mmplayer_start(MMHandleType hplayer)
9106 mm_player_t* player = (mm_player_t*) hplayer;
9107 gint ret = MM_ERROR_NONE;
9111 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9113 /* check current state */
9114 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9116 /* PD - start streaming */
9117 ret = __mmplayer_start_streaming_ext(player);
9118 if (ret != MM_ERROR_NONE) {
9119 LOGE("failed to start streaming ext 0x%X", ret);
9123 /* start pipeline */
9124 ret = __gst_start(player);
9125 if (ret != MM_ERROR_NONE)
9126 LOGE("failed to start player.\n");
9128 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9129 LOGD("force playing start even during buffering");
9130 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
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->seek_state = MMPLAYER_SEEK_NONE;
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_nsec = 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_nsec))
9323 LOGW("getting current position failed in paused\n");
9325 player->last_position = pos_nsec;
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");
9360 /* in case of streaming, pause could take long time.*/
9362 _mmplayer_abort_pause(MMHandleType hplayer)
9364 mm_player_t* player = (mm_player_t*)hplayer;
9365 int ret = MM_ERROR_NONE;
9369 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
9371 player->pipeline->mainbin,
9372 MM_ERROR_PLAYER_NOT_INITIALIZED);
9374 LOGD("set the pipeline state to READY");
9376 /* set state to READY */
9377 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9378 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
9379 if (ret != MM_ERROR_NONE) {
9380 LOGE("fail to change state to READY");
9381 return MM_ERROR_PLAYER_INTERNAL;
9384 LOGD("succeeded in changing state to READY");
9390 _mmplayer_resume(MMHandleType hplayer)
9392 mm_player_t* player = (mm_player_t*)hplayer;
9393 int ret = MM_ERROR_NONE;
9394 gboolean async = FALSE;
9398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9400 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9401 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
9402 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
9406 /* Changing back sync mode rtspsrc to async */
9407 LOGD("async resume for rtsp case");
9411 /* check current state */
9412 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9414 ret = __gst_resume(player, async);
9415 if (ret != MM_ERROR_NONE)
9416 LOGE("failed to resume player.\n");
9418 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9419 LOGD("force resume even during buffering");
9420 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9429 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9431 mm_player_t* player = (mm_player_t*)hplayer;
9432 gint64 pos_nsec = 0;
9433 int ret = MM_ERROR_NONE;
9435 signed long long start = 0, stop = 0;
9436 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9439 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9440 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9442 /* The sound of video is not supported under 0.0 and over 2.0. */
9443 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9444 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9447 _mmplayer_set_mute(hplayer, mute);
9449 if (player->playback_rate == rate)
9450 return MM_ERROR_NONE;
9452 /* If the position is reached at start potion during fast backward, EOS is posted.
9453 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9455 player->playback_rate = rate;
9457 current_state = MMPLAYER_CURRENT_STATE(player);
9459 if (current_state != MM_PLAYER_STATE_PAUSED)
9460 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9462 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9464 if ((current_state == MM_PLAYER_STATE_PAUSED)
9465 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9466 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9467 pos_nsec = player->last_position;
9472 stop = GST_CLOCK_TIME_NONE;
9474 start = GST_CLOCK_TIME_NONE;
9478 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9479 player->playback_rate,
9481 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9482 GST_SEEK_TYPE_SET, start,
9483 GST_SEEK_TYPE_SET, stop)) {
9484 LOGE("failed to set speed playback\n");
9485 return MM_ERROR_PLAYER_SEEK;
9488 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9492 return MM_ERROR_NONE;;
9496 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9498 mm_player_t* player = (mm_player_t*)hplayer;
9499 int ret = MM_ERROR_NONE;
9503 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9505 /* check pipline building state */
9506 __mmplayer_check_pipeline(player);
9508 ret = __gst_set_position(player, format, position, FALSE);
9516 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9518 mm_player_t* player = (mm_player_t*)hplayer;
9519 int ret = MM_ERROR_NONE;
9521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9523 ret = __gst_get_position(player, format, position);
9529 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9531 mm_player_t* player = (mm_player_t*)hplayer;
9532 int ret = MM_ERROR_NONE;
9534 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9535 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9537 *duration = player->duration;
9542 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9544 mm_player_t* player = (mm_player_t*)hplayer;
9545 int ret = MM_ERROR_NONE;
9547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9549 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9555 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9557 mm_player_t* player = (mm_player_t*)hplayer;
9558 int ret = MM_ERROR_NONE;
9562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9564 ret = __gst_adjust_subtitle_position(player, format, position);
9572 __mmplayer_is_midi_type(gchar* str_caps)
9574 if ((g_strrstr(str_caps, "audio/midi")) ||
9575 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9576 (g_strrstr(str_caps, "application/x-smaf")) ||
9577 (g_strrstr(str_caps, "audio/x-imelody")) ||
9578 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9579 (g_strrstr(str_caps, "audio/xmf")) ||
9580 (g_strrstr(str_caps, "audio/mxmf"))) {
9589 __mmplayer_is_only_mp3_type(gchar *str_caps)
9591 if (g_strrstr(str_caps, "application/x-id3") ||
9592 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9598 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9600 GstStructure* caps_structure = NULL;
9601 gint samplerate = 0;
9605 MMPLAYER_RETURN_IF_FAIL(player && caps);
9607 caps_structure = gst_caps_get_structure(caps, 0);
9609 /* set stream information */
9610 gst_structure_get_int(caps_structure, "rate", &samplerate);
9611 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9613 gst_structure_get_int(caps_structure, "channels", &channels);
9614 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9616 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9620 __mmplayer_update_content_type_info(mm_player_t* player)
9623 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9625 if (__mmplayer_is_midi_type(player->type)) {
9626 player->bypass_audio_effect = TRUE;
9627 } else if (g_strrstr(player->type, "application/x-hls")) {
9628 /* If it can't know exact type when it parses uri because of redirection case,
9629 * it will be fixed by typefinder or when doing autoplugging.
9631 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9632 if (player->streamer) {
9633 player->streamer->is_adaptive_streaming = TRUE;
9634 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9635 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9637 } else if (g_strrstr(player->type, "application/dash+xml")) {
9638 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9639 if (player->streamer) {
9640 player->streamer->is_adaptive_streaming = TRUE;
9641 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9645 LOGD("uri type : %d", player->profile.uri_type);
9650 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9651 GstCaps *caps, gpointer data)
9653 mm_player_t* player = (mm_player_t*)data;
9658 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9660 /* store type string */
9661 MMPLAYER_FREEIF(player->type);
9662 player->type = gst_caps_to_string(caps);
9664 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9665 player, player->type, probability, gst_caps_get_size(caps));
9668 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9669 (g_strrstr(player->type, "audio/x-raw-int"))) {
9670 LOGE("not support media format\n");
9672 if (player->msg_posted == FALSE) {
9673 MMMessageParamType msg_param;
9674 memset(&msg_param, 0, sizeof(MMMessageParamType));
9676 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9677 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9679 /* don't post more if one was sent already */
9680 player->msg_posted = TRUE;
9685 __mmplayer_update_content_type_info(player);
9687 pad = gst_element_get_static_pad(tf, "src");
9689 LOGE("fail to get typefind src pad.\n");
9693 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9694 gboolean async = FALSE;
9695 LOGE("failed to autoplug %s\n", player->type);
9697 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9699 if (async && player->msg_posted == FALSE)
9700 __mmplayer_handle_missed_plugin(player);
9706 gst_object_unref(GST_OBJECT(pad));
9714 __mmplayer_create_decodebin(mm_player_t* player)
9716 GstElement *decodebin = NULL;
9720 /* create decodebin */
9721 decodebin = gst_element_factory_make("decodebin", NULL);
9724 LOGE("fail to create decodebin\n");
9728 /* raw pad handling signal */
9729 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9730 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9732 /* no-more-pad pad handling signal */
9733 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9734 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9736 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9737 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9739 /* This signal is emitted when a pad for which there is no further possible
9740 decoding is added to the decodebin.*/
9741 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9742 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9744 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9745 before looking for any elements that can handle that stream.*/
9746 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9747 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9749 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9750 before looking for any elements that can handle that stream.*/
9751 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9752 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9754 /* This signal is emitted once decodebin has finished decoding all the data.*/
9755 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9756 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9758 /* This signal is emitted when a element is added to the bin.*/
9759 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9760 G_CALLBACK(__mmplayer_gst_element_added), player);
9767 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9769 MMPlayerGstElement* mainbin = NULL;
9770 GstElement* decodebin = NULL;
9771 GstElement* queue2 = NULL;
9772 GstPad* sinkpad = NULL;
9773 GstPad* qsrcpad = NULL;
9774 gint64 dur_bytes = 0L;
9776 guint max_buffer_size_bytes = 0;
9777 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9780 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9782 mainbin = player->pipeline->mainbin;
9784 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9785 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9786 LOGD("creating http streaming buffering queue(queue2)\n");
9788 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9789 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9791 queue2 = gst_element_factory_make("queue2", "queue2");
9793 LOGE("failed to create buffering queue element\n");
9797 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9798 LOGE("failed to add buffering queue\n");
9802 sinkpad = gst_element_get_static_pad(queue2, "sink");
9803 qsrcpad = gst_element_get_static_pad(queue2, "src");
9805 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9806 LOGE("failed to link buffering queue");
9810 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9811 LOGE("fail to get duration");
9813 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9815 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9817 if (dur_bytes > 0) {
9818 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9819 type = MUXED_BUFFER_TYPE_FILE;
9821 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9822 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9828 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9829 * skip the pull mode(file or ring buffering) setting. */
9830 if (!g_strrstr(player->type, "video/mpegts")) {
9831 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9832 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9834 __mm_player_streaming_set_queue2(player->streamer,
9837 max_buffer_size_bytes,
9838 player->ini.http_buffering_time,
9839 1.0, /* no meaning */
9840 player->ini.http_buffering_limit, /* no meaning */
9842 player->http_file_buffering_path,
9843 (guint64)dur_bytes);
9846 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9847 LOGE("failed to sync queue2 state with parent\n");
9853 gst_object_unref(GST_OBJECT(sinkpad));
9855 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9856 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9860 /* create decodebin */
9861 decodebin = __mmplayer_create_decodebin(player);
9864 LOGE("can not create autoplug element\n");
9868 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9869 LOGE("failed to add decodebin\n");
9873 /* to force caps on the decodebin element and avoid reparsing stuff by
9874 * typefind. It also avoids a deadlock in the way typefind activates pads in
9875 * the state change */
9876 g_object_set(decodebin, "sink-caps", caps, NULL);
9878 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9880 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9881 LOGE("failed to link decodebin\n");
9885 gst_object_unref(GST_OBJECT(sinkpad));
9887 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9888 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9890 /* set decodebin property about buffer in streaming playback. *
9891 * in case of HLS/DASH, it does not need to have big buffer *
9892 * because it is kind of adaptive streaming. */
9893 if (!MMPLAYER_IS_HTTP_PD(player) &&
9894 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9895 gdouble high_percent = 0.0;
9897 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9898 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9900 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9901 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9903 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9904 "high-percent", (gint)high_percent,
9905 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9906 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9907 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9908 "max-size-buffers", 0, NULL); // disable or automatic
9911 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9912 LOGE("failed to sync decodebin state with parent\n");
9923 gst_object_unref(GST_OBJECT(sinkpad));
9926 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9927 * You need to explicitly set elements to the NULL state before
9928 * dropping the final reference, to allow them to clean up.
9930 gst_element_set_state(queue2, GST_STATE_NULL);
9932 /* And, it still has a parent "player".
9933 * You need to let the parent manage the object instead of unreffing the object directly.
9935 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9936 gst_object_unref(queue2);
9941 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9942 * You need to explicitly set elements to the NULL state before
9943 * dropping the final reference, to allow them to clean up.
9945 gst_element_set_state(decodebin, GST_STATE_NULL);
9947 /* And, it still has a parent "player".
9948 * You need to let the parent manage the object instead of unreffing the object directly.
9951 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9952 gst_object_unref(decodebin);
9960 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9965 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9967 LOGD("class : %s, mime : %s \n", factory_class, mime);
9969 /* add missing plugin */
9970 /* NOTE : msl should check missing plugin for image mime type.
9971 * Some motion jpeg clips can have playable audio track.
9972 * So, msl have to play audio after displaying popup written video format not supported.
9974 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9975 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9976 LOGD("not found demuxer\n");
9977 player->not_found_demuxer = TRUE;
9978 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9984 if (!g_strrstr(factory_class, "Demuxer")) {
9985 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9986 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9987 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9989 /* check that clip have multi tracks or not */
9990 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9991 LOGD("video plugin is already linked\n");
9993 LOGW("add VIDEO to missing plugin\n");
9994 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9995 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9997 } else if (g_str_has_prefix(mime, "audio")) {
9998 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9999 LOGD("audio plugin is already linked\n");
10001 LOGW("add AUDIO to missing plugin\n");
10002 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10003 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10011 return MM_ERROR_NONE;
10016 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10018 mm_player_t* player = (mm_player_t*)data;
10022 MMPLAYER_RETURN_IF_FAIL(player);
10024 /* remove fakesink. */
10025 if (!__mmplayer_gst_remove_fakesink(player,
10026 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10027 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10028 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10029 * source element are not same. To overcome this situation, this function will called
10030 * several places and several times. Therefore, this is not an error case.
10035 LOGD("[handle: %p] pipeline has completely constructed", player);
10037 if ((player->ini.async_start) &&
10038 (player->msg_posted == FALSE) &&
10039 (player->cmd >= MMPLAYER_COMMAND_START))
10040 __mmplayer_handle_missed_plugin(player);
10042 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10046 __mmplayer_verify_next_play_path(mm_player_t *player)
10048 MMHandleType attrs = 0;
10049 MMPlayerParseProfile profile;
10050 gint uri_idx = 0, check_cnt = 0;
10052 gint mode = MM_PLAYER_PD_MODE_NONE;
10056 guint num_of_list = 0;
10057 static int profile_tv = -1;
10061 LOGD("checking for gapless play");
10063 if (player->pipeline->textbin) {
10064 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10068 attrs = MMPLAYER_GET_ATTRS(player);
10070 LOGE("fail to get attributes.\n");
10074 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10076 if (__builtin_expect(profile_tv == -1, 0)) {
10078 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10079 switch (*profileName) {
10089 /* gapless playback is not supported in case of video at TV profile. */
10090 if (profile_tv && video) {
10091 LOGW("not support video gapless playback");
10095 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10096 if (mode == TRUE) {
10102 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10103 LOGE("can not get play count\n");
10105 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10106 LOGE("can not get gapless mode\n");
10108 if (video && !gapless) {
10109 LOGW("not enabled video gapless playback");
10113 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10117 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10121 num_of_list = g_list_length(player->uri_info.uri_list);
10123 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10125 if (num_of_list == 0) {
10126 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10127 LOGE("can not get profile_uri\n");
10132 LOGE("uri list is empty.\n");
10136 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10137 LOGD("add original path : %s ", uri);
10143 uri_idx = player->uri_info.uri_idx;
10148 if (check_cnt > num_of_list) {
10149 LOGE("there is no valid uri.");
10153 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10155 if (uri_idx < num_of_list-1) {
10158 if ((count <= 1) && (count != -1)) {
10159 LOGD("no repeat.");
10161 } else if (count > 1) {
10162 /* decrease play count */
10163 /* we succeeded to rewind. update play count and then wait for next EOS */
10166 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10168 /* commit attribute */
10169 if (mmf_attrs_commit(attrs))
10170 LOGE("failed to commit attribute\n");
10173 /* count < 0 : repeat continually */
10177 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10178 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10181 LOGW("next uri does not exist\n");
10185 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10186 LOGE("failed to parse profile\n");
10190 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10191 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10192 LOGW("uri type is not supported(%d).", profile.uri_type);
10199 player->uri_info.uri_idx = uri_idx;
10200 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10202 if (mmf_attrs_commit(player->attrs)) {
10203 LOGE("failed to commit.\n");
10207 LOGD("next uri %s(%d)\n", uri, uri_idx);
10213 LOGE("unable to play next path. EOS will be posted soon.\n");
10218 __mmplayer_initialize_next_play(mm_player_t *player)
10224 player->smooth_streaming = FALSE;
10225 player->videodec_linked = 0;
10226 player->audiodec_linked = 0;
10227 player->videosink_linked = 0;
10228 player->audiosink_linked = 0;
10229 player->textsink_linked = 0;
10230 player->is_external_subtitle_present = FALSE;
10231 player->is_external_subtitle_added_now = FALSE;
10232 player->not_supported_codec = MISSING_PLUGIN_NONE;
10233 player->can_support_codec = FOUND_PLUGIN_NONE;
10234 player->pending_seek.is_pending = FALSE;
10235 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10236 player->pending_seek.pos = 0;
10237 player->msg_posted = FALSE;
10238 player->has_many_types = FALSE;
10239 player->no_more_pad = FALSE;
10240 player->not_found_demuxer = 0;
10241 player->seek_state = MMPLAYER_SEEK_NONE;
10242 player->max_audio_channels = 0;
10243 player->is_subtitle_force_drop = FALSE;
10244 player->play_subtitle = FALSE;
10245 player->adjust_subtitle_pos = 0;
10247 player->total_bitrate = 0;
10248 player->total_maximum_bitrate = 0;
10250 _mmplayer_track_initialize(player);
10251 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10253 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10254 player->bitrate[i] = 0;
10255 player->maximum_bitrate[i] = 0;
10258 if (player->v_stream_caps) {
10259 gst_caps_unref(player->v_stream_caps);
10260 player->v_stream_caps = NULL;
10263 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10265 /* clean found parsers */
10266 if (player->parsers) {
10267 GList *parsers = player->parsers;
10268 for (; parsers; parsers = g_list_next(parsers)) {
10269 gchar *name = parsers->data;
10270 MMPLAYER_FREEIF(name);
10272 g_list_free(player->parsers);
10273 player->parsers = NULL;
10276 /* clean found audio decoders */
10277 if (player->audio_decoders) {
10278 GList *a_dec = player->audio_decoders;
10279 for (; a_dec; a_dec = g_list_next(a_dec)) {
10280 gchar *name = a_dec->data;
10281 MMPLAYER_FREEIF(name);
10283 g_list_free(player->audio_decoders);
10284 player->audio_decoders = NULL;
10291 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10293 MMPlayerGstElement *mainbin = NULL;
10294 MMMessageParamType msg_param = {0,};
10295 GstElement *element = NULL;
10296 MMHandleType attrs = 0;
10298 enum MainElementID elemId = MMPLAYER_M_NUM;
10302 if ((player == NULL) ||
10303 (player->pipeline == NULL) ||
10304 (player->pipeline->mainbin == NULL)) {
10305 LOGE("player is null.\n");
10309 mainbin = player->pipeline->mainbin;
10310 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10312 attrs = MMPLAYER_GET_ATTRS(player);
10314 LOGE("fail to get attributes.\n");
10318 /* Initialize Player values */
10319 __mmplayer_initialize_next_play(player);
10321 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10323 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10324 LOGE("failed to parse profile\n");
10325 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10329 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10330 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10331 LOGE("it's dash or hls. not support.");
10332 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10337 switch (player->profile.uri_type) {
10339 case MM_PLAYER_URI_TYPE_FILE:
10341 LOGD("using filesrc for 'file://' handler.\n");
10342 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10343 LOGE("failed to get storage info");
10347 element = gst_element_factory_make("filesrc", "source");
10350 LOGE("failed to create filesrc\n");
10354 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10357 case MM_PLAYER_URI_TYPE_URL_HTTP:
10359 gchar *user_agent, *cookies, **cookie_list;
10360 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10361 user_agent = cookies = NULL;
10362 cookie_list = NULL;
10364 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10366 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10369 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10371 /* get attribute */
10372 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10373 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10375 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10376 LOGD("get timeout from ini\n");
10377 http_timeout = player->ini.http_timeout;
10380 /* get attribute */
10381 SECURE_LOGD("location : %s\n", player->profile.uri);
10382 SECURE_LOGD("cookies : %s\n", cookies);
10383 SECURE_LOGD("user_agent : %s\n", user_agent);
10384 LOGD("timeout : %d\n", http_timeout);
10386 /* setting property to streaming source */
10387 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10388 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10389 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10391 /* parsing cookies */
10392 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10393 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10395 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10399 LOGE("not support uri type %d\n", player->profile.uri_type);
10404 LOGE("no source element was created.\n");
10408 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10409 LOGE("failed to add source element to pipeline\n");
10410 gst_object_unref(GST_OBJECT(element));
10415 /* take source element */
10416 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10417 mainbin[MMPLAYER_M_SRC].gst = element;
10421 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10422 if (player->streamer == NULL) {
10423 player->streamer = __mm_player_streaming_create();
10424 __mm_player_streaming_initialize(player->streamer);
10427 elemId = MMPLAYER_M_TYPEFIND;
10428 element = gst_element_factory_make("typefind", "typefinder");
10429 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10430 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10432 elemId = MMPLAYER_M_AUTOPLUG;
10433 element = __mmplayer_create_decodebin(player);
10436 /* check autoplug element is OK */
10438 LOGE("can not create element(%d)\n", elemId);
10442 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10443 LOGE("failed to add sinkbin to pipeline\n");
10444 gst_object_unref(GST_OBJECT(element));
10449 mainbin[elemId].id = elemId;
10450 mainbin[elemId].gst = element;
10452 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10453 LOGE("Failed to link src - autoplug(or typefind)\n");
10457 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10458 LOGE("Failed to change state of src element\n");
10462 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10463 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10464 LOGE("Failed to change state of decodebin\n");
10468 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10469 LOGE("Failed to change state of src element\n");
10474 player->gapless.stream_changed = TRUE;
10475 player->gapless.running = TRUE;
10481 MMPLAYER_PLAYBACK_UNLOCK(player);
10483 if (!player->msg_posted) {
10484 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10485 player->msg_posted = TRUE;
10492 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10494 mm_player_selector_t *selector = &player->selector[type];
10495 MMPlayerGstElement *sinkbin = NULL;
10496 enum MainElementID selectorId = MMPLAYER_M_NUM;
10497 enum MainElementID sinkId = MMPLAYER_M_NUM;
10498 GstPad *srcpad = NULL;
10499 GstPad *sinkpad = NULL;
10500 gboolean send_notice = FALSE;
10503 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10505 LOGD("type %d", type);
10508 case MM_PLAYER_TRACK_TYPE_AUDIO:
10509 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10510 sinkId = MMPLAYER_A_BIN;
10511 sinkbin = player->pipeline->audiobin;
10513 case MM_PLAYER_TRACK_TYPE_VIDEO:
10514 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10515 sinkId = MMPLAYER_V_BIN;
10516 sinkbin = player->pipeline->videobin;
10517 send_notice = TRUE;
10519 case MM_PLAYER_TRACK_TYPE_TEXT:
10520 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10521 sinkId = MMPLAYER_T_BIN;
10522 sinkbin = player->pipeline->textbin;
10525 LOGE("requested type is not supportable");
10530 if (player->pipeline->mainbin[selectorId].gst) {
10533 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10535 if (selector->event_probe_id != 0)
10536 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10537 selector->event_probe_id = 0;
10539 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10540 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10542 if (srcpad && sinkpad) {
10543 /* after getting drained signal there is no data flows, so no need to do pad_block */
10544 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10545 gst_pad_unlink(srcpad, sinkpad);
10547 /* send custom event to sink pad to handle it at video sink */
10549 LOGD("send custom event to sinkpad");
10550 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10551 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10552 gst_pad_send_event(sinkpad, event);
10556 gst_object_unref(sinkpad);
10559 gst_object_unref(srcpad);
10562 LOGD("selector release");
10564 /* release and unref requests pad from the selector */
10565 for (n = 0; n < selector->channels->len; n++) {
10566 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10567 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10569 g_ptr_array_set_size(selector->channels, 0);
10571 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10572 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10574 player->pipeline->mainbin[selectorId].gst = NULL;
10582 __mmplayer_deactivate_old_path(mm_player_t *player)
10585 MMPLAYER_RETURN_IF_FAIL(player);
10587 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10588 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10589 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10590 LOGE("deactivate selector error");
10594 _mmplayer_track_destroy(player);
10595 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10597 if (player->streamer) {
10598 __mm_player_streaming_deinitialize(player->streamer);
10599 __mm_player_streaming_destroy(player->streamer);
10600 player->streamer = NULL;
10603 MMPLAYER_PLAYBACK_LOCK(player);
10604 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10611 if (!player->msg_posted) {
10612 MMMessageParamType msg = {0,};
10615 msg.code = MM_ERROR_PLAYER_INTERNAL;
10616 LOGE("next_uri_play> deactivate error");
10618 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10619 player->msg_posted = TRUE;
10624 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10626 int result = MM_ERROR_NONE;
10627 mm_player_t* player = (mm_player_t*) hplayer;
10630 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10633 player->http_file_buffering_path = (gchar*)file_path;
10634 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10640 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10642 int result = MM_ERROR_NONE;
10643 mm_player_t* player = (mm_player_t*) hplayer;
10646 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10648 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10649 if (mmf_attrs_commit(player->attrs)) {
10650 LOGE("failed to commit the original uri.\n");
10651 result = MM_ERROR_PLAYER_INTERNAL;
10653 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10654 LOGE("failed to add the original uri in the uri list.\n");
10661 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10663 mm_player_t* player = (mm_player_t*) hplayer;
10664 guint num_of_list = 0;
10668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10669 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10671 if (player->pipeline && player->pipeline->textbin) {
10672 LOGE("subtitle path is enabled.\n");
10673 return MM_ERROR_PLAYER_INVALID_STATE;
10676 num_of_list = g_list_length(player->uri_info.uri_list);
10678 if (is_first_path == TRUE) {
10679 if (num_of_list == 0) {
10680 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10681 LOGD("add original path : %s", uri);
10683 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10684 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10686 LOGD("change original path : %s", uri);
10689 MMHandleType attrs = 0;
10690 attrs = MMPLAYER_GET_ATTRS(player);
10692 if (num_of_list == 0) {
10693 char *original_uri = NULL;
10696 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10698 if (!original_uri) {
10699 LOGE("there is no original uri.");
10700 return MM_ERROR_PLAYER_INVALID_STATE;
10703 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10704 player->uri_info.uri_idx = 0;
10706 LOGD("add original path at first : %s(%d)", original_uri);
10710 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10711 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10715 return MM_ERROR_NONE;
10718 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10720 mm_player_t* player = (mm_player_t*) hplayer;
10721 char *next_uri = NULL;
10722 guint num_of_list = 0;
10725 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10727 num_of_list = g_list_length(player->uri_info.uri_list);
10729 if (num_of_list > 0) {
10730 gint uri_idx = player->uri_info.uri_idx;
10732 if (uri_idx < num_of_list-1)
10737 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10738 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10740 *uri = g_strdup(next_uri);
10744 return MM_ERROR_NONE;
10748 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10749 GstCaps *caps, gpointer data)
10751 mm_player_t* player = (mm_player_t*)data;
10752 const gchar* klass = NULL;
10753 const gchar* mime = NULL;
10754 gchar* caps_str = NULL;
10756 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10757 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10758 caps_str = gst_caps_to_string(caps);
10760 LOGW("unknown type of caps : %s from %s",
10761 caps_str, GST_ELEMENT_NAME(elem));
10763 MMPLAYER_FREEIF(caps_str);
10765 /* There is no available codec. */
10766 __mmplayer_check_not_supported_codec(player, klass, mime);
10770 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10771 GstCaps * caps, gpointer data)
10773 mm_player_t* player = (mm_player_t*)data;
10774 const char* mime = NULL;
10775 gboolean ret = TRUE;
10777 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10778 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10780 if (g_str_has_prefix(mime, "audio")) {
10781 GstStructure* caps_structure = NULL;
10782 gint samplerate = 0;
10784 gchar *caps_str = NULL;
10786 caps_structure = gst_caps_get_structure(caps, 0);
10787 gst_structure_get_int(caps_structure, "rate", &samplerate);
10788 gst_structure_get_int(caps_structure, "channels", &channels);
10790 if ((channels > 0 && samplerate == 0)) {
10791 LOGD("exclude audio...");
10795 caps_str = gst_caps_to_string(caps);
10796 /* set it directly because not sent by TAG */
10797 if (g_strrstr(caps_str, "mobile-xmf"))
10798 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10799 MMPLAYER_FREEIF(caps_str);
10800 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10801 MMMessageParamType msg_param;
10802 memset(&msg_param, 0, sizeof(MMMessageParamType));
10803 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10804 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10805 LOGD("video file is not supported on this device");
10807 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10808 LOGD("already video linked");
10811 LOGD("found new stream");
10818 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10820 int ret = MM_ERROR_NONE;
10822 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10824 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10825 GstStructure* str = NULL;
10827 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10829 LOGD("audio codec type: %d", codec_type);
10830 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10831 /* sw codec will be skipped */
10832 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10833 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10834 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10835 ret = MM_ERROR_PLAYER_INTERNAL;
10839 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10840 /* hw codec will be skipped */
10841 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10842 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10843 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10844 ret = MM_ERROR_PLAYER_INTERNAL;
10849 str = gst_caps_get_structure(caps, 0);
10851 gst_structure_get_int(str, "channels", &channels);
10853 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10854 if (player->max_audio_channels < channels)
10855 player->max_audio_channels = channels;
10857 /* set stream information */
10858 if (!player->audiodec_linked)
10859 __mmplayer_set_audio_attrs(player, caps);
10861 /* update codec info */
10862 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10863 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10864 player->audiodec_linked = 1;
10866 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10868 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10870 LOGD("video codec type: %d", codec_type);
10871 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10872 /* sw codec is skipped */
10873 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10874 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10875 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10876 ret = MM_ERROR_PLAYER_INTERNAL;
10880 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10881 /* hw codec is skipped */
10882 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10883 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10884 ret = MM_ERROR_PLAYER_INTERNAL;
10889 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10890 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10892 /* mark video decoder for acquire */
10893 if (player->video_decoder_resource == NULL) {
10894 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10895 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10896 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10897 &player->video_decoder_resource)
10898 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10899 LOGE("could not mark video_decoder resource for acquire");
10900 ret = MM_ERROR_PLAYER_INTERNAL;
10904 LOGW("video decoder resource is already acquired, skip it.");
10905 ret = MM_ERROR_PLAYER_INTERNAL;
10909 player->interrupted_by_resource = FALSE;
10910 /* acquire resources for video playing */
10911 if (mm_resource_manager_commit(player->resource_manager)
10912 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10913 LOGE("could not acquire resources for video decoding\n");
10914 ret = MM_ERROR_PLAYER_INTERNAL;
10919 /* update codec info */
10920 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10921 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10922 player->videodec_linked = 1;
10930 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10931 GstCaps* caps, GstElementFactory* factory, gpointer data)
10933 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10934 We are defining our own and will be removed when it actually exposed */
10936 GST_AUTOPLUG_SELECT_TRY,
10937 GST_AUTOPLUG_SELECT_EXPOSE,
10938 GST_AUTOPLUG_SELECT_SKIP
10939 } GstAutoplugSelectResult;
10941 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10942 mm_player_t* player = (mm_player_t*)data;
10944 gchar* factory_name = NULL;
10945 gchar* caps_str = NULL;
10946 const gchar* klass = NULL;
10949 factory_name = GST_OBJECT_NAME(factory);
10950 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10951 caps_str = gst_caps_to_string(caps);
10953 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10955 /* store type string */
10956 if (player->type == NULL) {
10957 player->type = gst_caps_to_string(caps);
10958 __mmplayer_update_content_type_info(player);
10961 /* filtering exclude keyword */
10962 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10963 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10964 LOGW("skipping [%s] by exculde keyword [%s]\n",
10965 factory_name, player->ini.exclude_element_keyword[idx]);
10967 result = GST_AUTOPLUG_SELECT_SKIP;
10972 /* exclude webm format */
10973 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10974 * because webm format is not supportable.
10975 * If webm is disabled in "autoplug-continue", there is no state change
10976 * failure or error because the decodebin will expose the pad directly.
10977 * It make MSL invoke _prepare_async_callback.
10978 * So, we need to disable webm format in "autoplug-select" */
10979 if (caps_str && strstr(caps_str, "webm")) {
10980 LOGW("webm is not supported");
10981 result = GST_AUTOPLUG_SELECT_SKIP;
10985 /* check factory class for filtering */
10986 /* NOTE : msl don't need to use image plugins.
10987 * So, those plugins should be skipped for error handling.
10989 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10990 LOGD("skipping [%s] by not required\n", factory_name);
10991 result = GST_AUTOPLUG_SELECT_SKIP;
10995 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10996 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10997 // TO CHECK : subtitle if needed, add subparse exception.
10998 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10999 result = GST_AUTOPLUG_SELECT_SKIP;
11003 if (g_strrstr(factory_name, "mpegpsdemux")) {
11004 LOGD("skipping PS container - not support\n");
11005 result = GST_AUTOPLUG_SELECT_SKIP;
11009 if (g_strrstr(factory_name, "mssdemux"))
11010 player->smooth_streaming = TRUE;
11012 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11013 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11016 GstStructure *str = NULL;
11017 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11019 /* don't make video because of not required */
11020 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11021 (player->set_mode.media_packet_video_stream == FALSE)) {
11022 LOGD("no video because it's not required. -> return expose");
11023 result = GST_AUTOPLUG_SELECT_EXPOSE;
11027 /* get w/h for omx state-tune */
11028 /* FIXME: deprecated? */
11029 str = gst_caps_get_structure(caps, 0);
11030 gst_structure_get_int(str, "width", &width);
11033 if (player->v_stream_caps) {
11034 gst_caps_unref(player->v_stream_caps);
11035 player->v_stream_caps = NULL;
11038 player->v_stream_caps = gst_caps_copy(caps);
11039 LOGD("take caps for video state tune");
11040 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11044 if (g_strrstr(klass, "Codec/Decoder")) {
11045 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11046 LOGD("skipping %s codec", factory_name);
11047 result = GST_AUTOPLUG_SELECT_SKIP;
11053 MMPLAYER_FREEIF(caps_str);
11059 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11062 //mm_player_t* player = (mm_player_t*)data;
11063 GstCaps* caps = NULL;
11065 LOGD("[Decodebin2] pad-removed signal\n");
11067 caps = gst_pad_query_caps(new_pad, NULL);
11069 gchar* caps_str = NULL;
11070 caps_str = gst_caps_to_string(caps);
11072 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11074 MMPLAYER_FREEIF(caps_str);
11075 gst_caps_unref(caps);
11080 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11082 mm_player_t* player = (mm_player_t*)data;
11083 GstIterator *iter = NULL;
11084 GValue item = { 0, };
11085 GstPad *pad = NULL;
11086 gboolean done = FALSE;
11087 gboolean is_all_drained = TRUE;
11090 MMPLAYER_RETURN_IF_FAIL(player);
11092 LOGD("__mmplayer_gst_decode_drained");
11094 if (player->use_deinterleave == TRUE) {
11095 LOGD("group playing mode.");
11099 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11100 LOGW("Fail to get cmd lock");
11104 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11105 !__mmplayer_verify_next_play_path(player)) {
11106 LOGD("decoding is finished.");
11107 __mmplayer_reset_gapless_state(player);
11108 MMPLAYER_CMD_UNLOCK(player);
11112 player->gapless.reconfigure = TRUE;
11114 /* check decodebin src pads whether they received EOS or not */
11115 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11118 switch (gst_iterator_next(iter, &item)) {
11119 case GST_ITERATOR_OK:
11120 pad = g_value_get_object(&item);
11121 if (pad && !GST_PAD_IS_EOS(pad)) {
11122 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11123 is_all_drained = FALSE;
11126 g_value_reset(&item);
11128 case GST_ITERATOR_RESYNC:
11129 gst_iterator_resync(iter);
11131 case GST_ITERATOR_ERROR:
11132 case GST_ITERATOR_DONE:
11137 g_value_unset(&item);
11138 gst_iterator_free(iter);
11140 if (!is_all_drained) {
11141 LOGD("Wait util the all pads get EOS.");
11142 MMPLAYER_CMD_UNLOCK(player);
11147 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11148 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11150 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11151 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11152 __mmplayer_deactivate_old_path(player);
11153 MMPLAYER_CMD_UNLOCK(player);
11159 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11161 mm_player_t* player = (mm_player_t*)data;
11162 const gchar* klass = NULL;
11163 gchar* factory_name = NULL;
11165 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11166 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11168 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11170 if (__mmplayer_add_dump_buffer_probe(player, element))
11171 LOGD("add buffer probe");
11174 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11175 gchar* selected = NULL;
11176 selected = g_strdup(GST_ELEMENT_NAME(element));
11177 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11181 if (g_strrstr(klass, "Parser")) {
11182 gchar* selected = NULL;
11184 selected = g_strdup(factory_name);
11185 player->parsers = g_list_append(player->parsers, selected);
11188 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11189 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11190 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11192 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11193 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11195 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11196 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11197 "max-video-width", player->adaptive_info.limit.width,
11198 "max-video-height", player->adaptive_info.limit.height, NULL);
11200 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11201 /* FIXIT : first value will be overwritten if there's more
11202 * than 1 demuxer/parser
11205 //LOGD("plugged element is demuxer. take it\n");
11206 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11207 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11209 /*Added for multi audio support */ // Q. del?
11210 if (g_strrstr(klass, "Demux")) {
11211 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11212 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11216 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11217 int surface_type = 0;
11219 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11222 // to support trust-zone only
11223 if (g_strrstr(factory_name, "asfdemux")) {
11224 LOGD("set file-location %s\n", player->profile.uri);
11225 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11227 if (player->video_hub_download_mode == TRUE)
11228 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11229 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11230 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11231 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11232 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11233 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11234 (__mmplayer_is_only_mp3_type(player->type))) {
11235 LOGD("[mpegaudioparse] set streaming pull mode.");
11236 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11238 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11239 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11242 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11243 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11244 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11246 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11247 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11249 if (!MMPLAYER_IS_HTTP_PD(player) &&
11250 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11251 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11252 (MMPLAYER_IS_DASH_STREAMING(player)))) {
11253 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11254 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11255 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11263 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11266 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11268 if (MMPLAYER_IS_STREAMING(player))
11271 /* This callback can be set to music player only. */
11272 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11273 LOGW("audio callback is not supported for video");
11277 if (player->audio_stream_cb) {
11278 GstPad *pad = NULL;
11280 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11283 LOGE("failed to get sink pad from audiosink to probe data\n");
11286 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11287 __mmplayer_audio_stream_probe, player, NULL);
11289 gst_object_unref(pad);
11293 LOGE("There is no audio callback to configure.\n");
11303 __mmplayer_release_misc(mm_player_t* player)
11306 bool cur_mode = player->set_mode.rich_audio;
11309 MMPLAYER_RETURN_IF_FAIL(player);
11311 player->video_stream_cb = NULL;
11312 player->video_stream_cb_user_param = NULL;
11313 player->video_stream_prerolled = FALSE;
11315 player->audio_stream_cb = NULL;
11316 player->audio_stream_render_cb_ex = NULL;
11317 player->audio_stream_cb_user_param = NULL;
11318 player->audio_stream_sink_sync = false;
11320 player->video_stream_changed_cb = NULL;
11321 player->video_stream_changed_cb_user_param = NULL;
11323 player->audio_stream_changed_cb = NULL;
11324 player->audio_stream_changed_cb_user_param = NULL;
11326 player->sent_bos = FALSE;
11327 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11329 player->seek_state = MMPLAYER_SEEK_NONE;
11331 player->total_bitrate = 0;
11332 player->total_maximum_bitrate = 0;
11334 player->not_found_demuxer = 0;
11336 player->last_position = 0;
11337 player->duration = 0;
11338 player->http_content_size = 0;
11339 player->not_supported_codec = MISSING_PLUGIN_NONE;
11340 player->can_support_codec = FOUND_PLUGIN_NONE;
11341 player->pending_seek.is_pending = FALSE;
11342 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11343 player->pending_seek.pos = 0;
11344 player->msg_posted = FALSE;
11345 player->has_many_types = FALSE;
11346 player->max_audio_channels = 0;
11347 player->video_share_api_delta = 0;
11348 player->video_share_clock_delta = 0;
11349 player->is_subtitle_force_drop = FALSE;
11350 player->play_subtitle = FALSE;
11351 player->adjust_subtitle_pos = 0;
11352 player->last_multiwin_status = FALSE;
11353 player->has_closed_caption = FALSE;
11354 player->set_mode.media_packet_video_stream = FALSE;
11355 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11356 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11358 player->set_mode.rich_audio = cur_mode;
11360 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11361 player->bitrate[i] = 0;
11362 player->maximum_bitrate[i] = 0;
11365 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11367 /* remove media stream cb(appsrc cb) */
11368 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11369 player->media_stream_buffer_status_cb[i] = NULL;
11370 player->media_stream_seek_data_cb[i] = NULL;
11371 player->buffer_cb_user_param[i] = NULL;
11372 player->seek_cb_user_param[i] = NULL;
11374 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11376 /* free memory related to audio effect */
11377 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11379 if (player->adaptive_info.var_list) {
11380 g_list_free_full(player->adaptive_info.var_list, g_free);
11381 player->adaptive_info.var_list = NULL;
11384 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11385 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11386 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11388 /* Reset video360 settings to their defaults in case if the pipeline is to be
11391 player->video360_metadata.is_spherical = -1;
11392 player->is_openal_plugin_used = FALSE;
11394 player->is_content_spherical = FALSE;
11395 player->is_video360_enabled = TRUE;
11396 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11397 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11398 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11399 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11400 player->video360_zoom = 1.0f;
11401 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11402 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11404 player->sound.rg_enable = false;
11410 __mmplayer_release_misc_post(mm_player_t* player)
11412 char *original_uri = NULL;
11415 /* player->pipeline is already released before. */
11417 MMPLAYER_RETURN_IF_FAIL(player);
11419 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11421 /* clean found parsers */
11422 if (player->parsers) {
11423 GList *parsers = player->parsers;
11424 for (; parsers; parsers = g_list_next(parsers)) {
11425 gchar *name = parsers->data;
11426 MMPLAYER_FREEIF(name);
11428 g_list_free(player->parsers);
11429 player->parsers = NULL;
11432 /* clean found audio decoders */
11433 if (player->audio_decoders) {
11434 GList *a_dec = player->audio_decoders;
11435 for (; a_dec; a_dec = g_list_next(a_dec)) {
11436 gchar *name = a_dec->data;
11437 MMPLAYER_FREEIF(name);
11439 g_list_free(player->audio_decoders);
11440 player->audio_decoders = NULL;
11443 /* clean the uri list except original uri */
11444 if (player->uri_info.uri_list) {
11445 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11447 if (player->attrs) {
11448 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11449 LOGD("restore original uri = %s\n", original_uri);
11451 if (mmf_attrs_commit(player->attrs))
11452 LOGE("failed to commit the original uri.\n");
11455 GList *uri_list = player->uri_info.uri_list;
11456 for (; uri_list; uri_list = g_list_next(uri_list)) {
11457 gchar *uri = uri_list->data;
11458 MMPLAYER_FREEIF(uri);
11460 g_list_free(player->uri_info.uri_list);
11461 player->uri_info.uri_list = NULL;
11464 /* clear the audio stream buffer list */
11465 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11467 /* clear the video stream bo list */
11468 __mmplayer_video_stream_destroy_bo_list(player);
11469 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11471 if (player->profile.input_mem.buf) {
11472 free(player->profile.input_mem.buf);
11473 player->profile.input_mem.buf = NULL;
11475 player->profile.input_mem.len = 0;
11476 player->profile.input_mem.offset = 0;
11478 player->uri_info.uri_idx = 0;
11482 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11484 GstElement *element = NULL;
11487 LOGD("creating %s to plug\n", name);
11489 element = gst_element_factory_make(name, NULL);
11491 LOGE("failed to create queue\n");
11495 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11496 LOGE("failed to set state READY to %s\n", name);
11497 gst_object_unref(element);
11501 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11502 LOGE("failed to add %s\n", name);
11503 gst_object_unref(element);
11507 sinkpad = gst_element_get_static_pad(element, "sink");
11509 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11510 LOGE("failed to link %s\n", name);
11511 gst_object_unref(sinkpad);
11512 gst_object_unref(element);
11516 LOGD("linked %s to pipeline successfully\n", name);
11518 gst_object_unref(sinkpad);
11524 __mmplayer_check_subtitle(mm_player_t* player)
11526 MMHandleType attrs = 0;
11527 char *subtitle_uri = NULL;
11531 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11533 /* get subtitle attribute */
11534 attrs = MMPLAYER_GET_ATTRS(player);
11538 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11539 if (!subtitle_uri || !strlen(subtitle_uri))
11542 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11543 player->is_external_subtitle_present = TRUE;
11551 __mmplayer_can_extract_pcm(mm_player_t* player)
11553 MMHandleType attrs = 0;
11554 gboolean sound_extraction = FALSE;
11556 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11558 attrs = MMPLAYER_GET_ATTRS(player);
11560 LOGE("fail to get attributes.");
11564 /* get sound_extraction property */
11565 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11567 if (!sound_extraction) {
11568 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11576 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11579 MMMessageParamType msg_param;
11580 gchar *msg_src_element = NULL;
11581 GstStructure *s = NULL;
11582 guint error_id = 0;
11583 gchar *error_string = NULL;
11587 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11588 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11590 s = gst_structure_copy(gst_message_get_structure(message));
11593 if (!gst_structure_get_uint(s, "error_id", &error_id))
11594 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11596 switch (error_id) {
11597 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11598 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11600 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11601 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11603 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11604 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11606 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11607 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11609 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11610 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11612 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11613 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11615 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11616 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11618 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11619 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11621 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11622 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11624 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11625 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11627 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11628 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11630 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11631 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11633 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11634 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11636 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11637 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11639 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11640 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11642 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11643 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11645 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11646 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11648 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11649 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11651 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11652 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11654 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11655 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11657 case MMPLAYER_STREAMING_ERROR_GONE:
11658 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11660 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11661 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11663 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11664 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11666 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11667 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11669 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11670 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11672 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11673 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11675 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11676 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11678 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11679 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11681 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11682 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11684 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11685 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11687 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11688 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11690 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11691 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11693 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11694 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11696 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11697 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11699 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11700 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11702 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11703 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11705 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11706 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11708 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11709 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11711 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11712 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11714 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11715 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11717 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11718 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11720 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11721 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11723 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11724 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11726 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11727 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11729 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11730 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11734 gst_structure_free(s);
11735 return MM_ERROR_PLAYER_STREAMING_FAIL;
11739 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11741 msg_param.data = (void *) error_string;
11743 if (message->src) {
11744 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11746 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11747 msg_src_element, msg_param.code, (char*)msg_param.data);
11750 /* post error to application */
11751 if (!player->msg_posted) {
11752 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11754 /* don't post more if one was sent already */
11755 player->msg_posted = TRUE;
11757 LOGD("skip error post because it's sent already.\n");
11759 gst_structure_free(s);
11761 g_free(error_string);
11768 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11770 MMPLAYER_RETURN_IF_FAIL(player);
11772 /* post now if delay is zero */
11773 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11774 LOGD("eos delay is zero. posting EOS now\n");
11775 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11777 if (player->set_mode.pcm_extraction)
11778 __mmplayer_cancel_eos_timer(player);
11783 /* cancel if existing */
11784 __mmplayer_cancel_eos_timer(player);
11786 /* init new timeout */
11787 /* NOTE : consider give high priority to this timer */
11788 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11790 player->eos_timer = g_timeout_add(delay_in_ms,
11791 __mmplayer_eos_timer_cb, player);
11793 player->context.global_default = g_main_context_default();
11794 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11796 /* check timer is valid. if not, send EOS now */
11797 if (player->eos_timer == 0) {
11798 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11799 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11804 __mmplayer_cancel_eos_timer(mm_player_t* player)
11806 MMPLAYER_RETURN_IF_FAIL(player);
11808 if (player->eos_timer) {
11809 LOGD("cancel eos timer");
11810 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11811 player->eos_timer = 0;
11818 __mmplayer_eos_timer_cb(gpointer u_data)
11820 mm_player_t* player = NULL;
11821 MMHandleType attrs = 0;
11824 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11826 player = (mm_player_t*) u_data;
11827 attrs = MMPLAYER_GET_ATTRS(player);
11829 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11832 gint ret_value = 0;
11833 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11834 if (ret_value != MM_ERROR_NONE)
11835 LOGE("seeking to 0 failed in repeat play");
11838 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11841 /* we are returning FALSE as we need only one posting */
11845 /* sending event to one of sinkelements */
11847 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11849 GstEvent * event2 = NULL;
11850 GList *sinks = NULL;
11851 gboolean res = FALSE;
11854 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11855 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11857 /* While adding subtitles in live feeds seek is getting called.
11858 Adding defensive check in framework layer.*/
11859 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11860 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11861 LOGE("Should not send seek event during live playback");
11866 if (player->play_subtitle)
11867 event2 = gst_event_copy((const GstEvent *)event);
11869 sinks = player->sink_elements;
11871 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11873 if (GST_IS_ELEMENT(sink)) {
11874 /* keep ref to the event */
11875 gst_event_ref(event);
11877 if ((res = gst_element_send_event(sink, event))) {
11878 LOGD("sending event[%s] to sink element [%s] success!\n",
11879 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11881 /* rtsp case, asyn_done is not called after seek during pause state */
11882 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11883 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11884 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11885 LOGD("RTSP seek completed, after pause state..\n");
11886 player->seek_state = MMPLAYER_SEEK_NONE;
11887 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11893 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11894 sinks = g_list_next(sinks);
11901 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11902 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11905 sinks = g_list_next(sinks);
11908 /* Note : Textbin is not linked to the video or audio bin.
11909 * It needs to send the event to the text sink seperatelly.
11911 if (player->play_subtitle && player->pipeline) {
11912 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11914 if (GST_IS_ELEMENT(text_sink)) {
11915 /* keep ref to the event */
11916 gst_event_ref(event2);
11918 if ((res = gst_element_send_event(text_sink, event2)))
11919 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11920 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11922 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11923 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11925 gst_event_unref(event2);
11929 gst_event_unref(event);
11937 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11941 MMPLAYER_RETURN_IF_FAIL(player);
11942 MMPLAYER_RETURN_IF_FAIL(sink);
11944 player->sink_elements =
11945 g_list_append(player->sink_elements, sink);
11951 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11955 MMPLAYER_RETURN_IF_FAIL(player);
11956 MMPLAYER_RETURN_IF_FAIL(sink);
11958 player->sink_elements =
11959 g_list_remove(player->sink_elements, sink);
11965 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11966 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11967 gint64 cur, GstSeekType stop_type, gint64 stop)
11969 GstEvent* event = NULL;
11970 gboolean result = FALSE;
11974 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11976 if (player->pipeline && player->pipeline->textbin)
11977 __mmplayer_drop_subtitle(player, FALSE);
11979 event = gst_event_new_seek(rate, format, flags, cur_type,
11980 cur, stop_type, stop);
11982 result = __gst_send_event_to_sink(player, event);
11989 /* NOTE : be careful with calling this api. please refer to below glib comment
11990 * glib comment : Note that there is a bug in GObject that makes this function much
11991 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11992 * will no longer be called, but, the signal handler is not currently disconnected.
11993 * If the instance is itself being freed at the same time than this doesn't matter,
11994 * since the signal will automatically be removed, but if instance persists,
11995 * then the signal handler will leak. You should not remove the signal yourself
11996 * because in a future versions of GObject, the handler will automatically be
11999 * It's possible to work around this problem in a way that will continue to work
12000 * with future versions of GObject by checking that the signal handler is still
12001 * connected before disconnected it:
12003 * if (g_signal_handler_is_connected(instance, id))
12004 * g_signal_handler_disconnect(instance, id);
12007 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12009 GList* sig_list = NULL;
12010 MMPlayerSignalItem* item = NULL;
12014 MMPLAYER_RETURN_IF_FAIL(player);
12016 LOGD("release signals type : %d", type);
12018 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12019 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12020 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12021 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12022 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12023 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12027 sig_list = player->signals[type];
12029 for (; sig_list; sig_list = sig_list->next) {
12030 item = sig_list->data;
12032 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12033 if (g_signal_handler_is_connected(item->obj, item->sig))
12034 g_signal_handler_disconnect(item->obj, item->sig);
12037 MMPLAYER_FREEIF(item);
12040 g_list_free(player->signals[type]);
12041 player->signals[type] = NULL;
12048 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12050 mm_player_t* player = 0;
12051 int prev_display_surface_type = 0;
12052 void *prev_display_overlay = NULL;
12053 const gchar *klass = NULL;
12054 gchar *cur_videosink_name = NULL;
12057 int num_of_dec = 2; /* DEC1, DEC2 */
12061 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12062 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12064 player = MM_PLAYER_CAST(handle);
12066 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12067 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12069 return MM_ERROR_INVALID_ARGUMENT;
12072 /* load previous attributes */
12073 if (player->attrs) {
12074 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12075 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12076 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12077 if (prev_display_surface_type == surface_type) {
12078 LOGD("incoming display surface type is same as previous one, do nothing..");
12080 return MM_ERROR_NONE;
12083 LOGE("failed to load attributes");
12085 return MM_ERROR_PLAYER_INTERNAL;
12088 /* check videosink element is created */
12089 if (!player->pipeline || !player->pipeline->videobin ||
12090 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12091 LOGD("videosink element is not yet ready");
12093 /* videobin is not created yet, so we just set attributes related to display surface */
12094 LOGD("store display attribute for given surface type(%d)", surface_type);
12095 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12096 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12097 if (mmf_attrs_commit(player->attrs)) {
12098 LOGE("failed to commit attribute");
12100 return MM_ERROR_PLAYER_INTERNAL;
12103 return MM_ERROR_NONE;
12105 /* get player command status */
12106 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12107 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12109 return MM_ERROR_PLAYER_INVALID_STATE;
12112 /* surface change */
12113 for (i = 0 ; i < num_of_dec ; i++) {
12114 if (player->pipeline->mainbin &&
12115 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12116 GstElementFactory *decfactory;
12117 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12119 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12120 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12121 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12122 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12126 LOGW("success to changing display surface(%d)", surface_type);
12128 return MM_ERROR_NONE;
12130 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12131 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12135 LOGW("success to changing display surface(%d)", surface_type);
12137 return MM_ERROR_NONE;
12140 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12141 ret = MM_ERROR_PLAYER_INTERNAL;
12150 /* rollback to previous attributes */
12151 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12152 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12153 if (mmf_attrs_commit(player->attrs)) {
12154 LOGE("failed to commit attributes to rollback");
12156 return MM_ERROR_PLAYER_INTERNAL;
12162 /* NOTE : It does not support some use cases, eg using colorspace converter */
12164 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12166 GstPad *src_pad_dec = NULL;
12167 GstPad *sink_pad_videosink = NULL;
12168 GstPad *sink_pad_videobin = NULL;
12169 GstClock *clock = NULL;
12170 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12171 int ret = MM_ERROR_NONE;
12172 gboolean is_audiobin_created = TRUE;
12176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12177 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12178 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12180 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12181 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12183 /* get information whether if audiobin is created */
12184 if (!player->pipeline->audiobin ||
12185 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12186 LOGW("audiobin is null, this video content may not have audio data");
12187 is_audiobin_created = FALSE;
12190 /* get current state of player */
12191 previous_state = MMPLAYER_CURRENT_STATE(player);
12192 LOGD("previous state(%d)", previous_state);
12195 /* get src pad of decoder and block it */
12196 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12197 if (!src_pad_dec) {
12198 LOGE("failed to get src pad from decode in mainbin");
12199 return MM_ERROR_PLAYER_INTERNAL;
12202 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12203 LOGW("trying to block pad(video)");
12204 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12205 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12208 LOGE("failed to set block pad(video)");
12209 return MM_ERROR_PLAYER_INTERNAL;
12211 LOGW("pad is blocked(video)");
12213 /* no data flows, so no need to do pad_block */
12214 if (player->seek_state != MMPLAYER_SEEK_NONE)
12215 LOGW("not completed seek(%d), do nothing", player->seek_state);
12217 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12221 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12222 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12223 LOGE("failed to remove previous ghost_pad for videobin");
12224 return MM_ERROR_PLAYER_INTERNAL;
12227 /* change state of videobin to NULL */
12228 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12229 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12230 if (ret != GST_STATE_CHANGE_SUCCESS) {
12231 LOGE("failed to change state of videobin to NULL");
12232 return MM_ERROR_PLAYER_INTERNAL;
12235 /* unlink between decoder and videobin and remove previous videosink from videobin */
12236 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12237 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12238 LOGE("failed to remove former videosink from videobin");
12239 return MM_ERROR_PLAYER_INTERNAL;
12242 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12244 /* create a new videosink and add it to videobin */
12245 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12246 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12247 LOGE("failed to create videosink element\n");
12249 return MM_ERROR_PLAYER_INTERNAL;
12251 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12252 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12253 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12255 /* save attributes */
12256 if (player->attrs) {
12257 /* set a new display surface type */
12258 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12259 /* set a new diplay overlay */
12260 switch (surface_type) {
12261 case MM_DISPLAY_SURFACE_OVERLAY:
12262 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12263 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12266 LOGE("invalid type(%d) for changing display surface", surface_type);
12268 return MM_ERROR_INVALID_ARGUMENT;
12270 if (mmf_attrs_commit(player->attrs)) {
12271 LOGE("failed to commit");
12273 return MM_ERROR_PLAYER_INTERNAL;
12276 LOGE("player->attrs is null, failed to save attributes");
12278 return MM_ERROR_PLAYER_INTERNAL;
12281 /* update video param */
12282 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12283 LOGE("failed to update video param");
12284 return MM_ERROR_PLAYER_INTERNAL;
12287 /* change state of videobin to READY */
12288 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12289 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12290 if (ret != GST_STATE_CHANGE_SUCCESS) {
12291 LOGE("failed to change state of videobin to READY");
12292 return MM_ERROR_PLAYER_INTERNAL;
12295 /* change ghostpad */
12296 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12297 if (!sink_pad_videosink) {
12298 LOGE("failed to get sink pad from videosink element");
12299 return MM_ERROR_PLAYER_INTERNAL;
12301 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12302 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12303 LOGE("failed to set active to ghost_pad");
12304 return MM_ERROR_PLAYER_INTERNAL;
12306 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12307 LOGE("failed to change ghostpad for videobin");
12308 return MM_ERROR_PLAYER_INTERNAL;
12310 gst_object_unref(sink_pad_videosink);
12312 /* link decoder with videobin */
12313 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12314 if (!sink_pad_videobin) {
12315 LOGE("failed to get sink pad from videobin");
12316 return MM_ERROR_PLAYER_INTERNAL;
12318 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12319 LOGE("failed to link");
12320 return MM_ERROR_PLAYER_INTERNAL;
12322 gst_object_unref(sink_pad_videobin);
12324 /* clock setting for a new videosink plugin */
12325 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12326 so we set it from audiosink plugin or pipeline(system clock) */
12327 if (!is_audiobin_created) {
12328 LOGW("audiobin is not created, get clock from pipeline..");
12329 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12331 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12335 GstClockTime base_time;
12336 LOGD("set the clock to videosink");
12337 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12338 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12340 LOGD("got clock of videosink");
12341 now = gst_clock_get_time(clock);
12342 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12343 LOGD("at time %" GST_TIME_FORMAT ", base %"
12344 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12346 LOGE("failed to get clock of videosink after setting clock");
12347 return MM_ERROR_PLAYER_INTERNAL;
12350 LOGW("failed to get clock, maybe it is the time before first playing");
12352 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12353 /* change state of videobin to PAUSED */
12354 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12355 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12356 if (ret != GST_STATE_CHANGE_FAILURE) {
12357 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12359 LOGE("failed to change state of videobin to PLAYING");
12360 return MM_ERROR_PLAYER_INTERNAL;
12363 /* release blocked and unref src pad of video decoder */
12365 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12366 LOGE("failed to set pad blocked FALSE(video)");
12367 return MM_ERROR_PLAYER_INTERNAL;
12370 LOGW("pad is unblocked(video)");
12372 if (player->seek_state != MMPLAYER_SEEK_NONE)
12373 LOGW("not completed seek(%d)", player->seek_state);
12374 /* change state of videobin to PAUSED */
12375 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12376 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12377 if (ret != GST_STATE_CHANGE_FAILURE) {
12378 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12380 LOGE("failed to change state of videobin to PLAYING");
12381 return MM_ERROR_PLAYER_INTERNAL;
12384 /* already skipped pad block */
12385 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12388 /* do get/set position for new videosink plugin */
12390 gint64 position = 0;
12392 LOGD("do get/set position for new videosink plugin");
12393 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12394 LOGE("failed to get position");
12395 return MM_ERROR_PLAYER_INTERNAL;
12397 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12398 /* accurate seek */
12399 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12400 LOGE("failed to set position");
12401 return MM_ERROR_PLAYER_INTERNAL;
12404 /* key unit seek */
12405 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12406 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12407 GST_SEEK_TYPE_SET, position,
12408 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12410 LOGE("failed to set position");
12411 return MM_ERROR_PLAYER_INTERNAL;
12417 gst_object_unref(src_pad_dec);
12418 LOGD("success to change sink");
12422 return MM_ERROR_NONE;
12426 /* Note : if silent is true, then subtitle would not be displayed. :*/
12427 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12429 mm_player_t* player = (mm_player_t*) hplayer;
12433 /* check player handle */
12434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12436 player->set_mode.subtitle_off = silent;
12438 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12442 return MM_ERROR_NONE;
12445 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12447 MMPlayerGstElement* mainbin = NULL;
12448 MMPlayerGstElement* textbin = NULL;
12449 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12450 GstState current_state = GST_STATE_VOID_PENDING;
12451 GstState element_state = GST_STATE_VOID_PENDING;
12452 GstState element_pending_state = GST_STATE_VOID_PENDING;
12454 GstEvent *event = NULL;
12455 int result = MM_ERROR_NONE;
12457 GstClock *curr_clock = NULL;
12458 GstClockTime base_time, start_time, curr_time;
12463 /* check player handle */
12464 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12465 player->pipeline &&
12466 player->pipeline->mainbin &&
12467 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12469 mainbin = player->pipeline->mainbin;
12470 textbin = player->pipeline->textbin;
12472 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12474 // sync clock with current pipeline
12475 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12476 curr_time = gst_clock_get_time(curr_clock);
12478 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12479 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12481 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12482 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12484 if (current_state > GST_STATE_READY) {
12485 // sync state with current pipeline
12486 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12487 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12488 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12490 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12491 if (GST_STATE_CHANGE_FAILURE == ret) {
12492 LOGE("fail to state change.\n");
12493 result = MM_ERROR_PLAYER_INTERNAL;
12498 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12499 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12502 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12503 gst_object_unref(curr_clock);
12506 // seek to current position
12507 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12508 result = MM_ERROR_PLAYER_INVALID_STATE;
12509 LOGE("gst_element_query_position failed, invalid state\n");
12513 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12514 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);
12516 __gst_send_event_to_sink(player, event);
12518 result = MM_ERROR_PLAYER_INTERNAL;
12519 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12523 /* sync state with current pipeline */
12524 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12525 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12526 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12528 return MM_ERROR_NONE;
12531 /* release text pipeline resource */
12532 player->textsink_linked = 0;
12534 /* release signal */
12535 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12537 /* release textbin with it's childs */
12538 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12539 MMPLAYER_FREEIF(player->pipeline->textbin);
12540 player->pipeline->textbin = NULL;
12542 /* release subtitle elem */
12543 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12544 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12550 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12552 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12553 GstState current_state = GST_STATE_VOID_PENDING;
12555 MMHandleType attrs = 0;
12556 MMPlayerGstElement* mainbin = NULL;
12557 MMPlayerGstElement* textbin = NULL;
12559 gchar* subtitle_uri = NULL;
12560 int result = MM_ERROR_NONE;
12561 const gchar *charset = NULL;
12565 /* check player handle */
12566 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12567 player->pipeline &&
12568 player->pipeline->mainbin &&
12569 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12570 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12572 mainbin = player->pipeline->mainbin;
12573 textbin = player->pipeline->textbin;
12575 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12576 if (current_state < GST_STATE_READY) {
12577 result = MM_ERROR_PLAYER_INVALID_STATE;
12578 LOGE("Pipeline is not in proper state\n");
12582 attrs = MMPLAYER_GET_ATTRS(player);
12584 LOGE("cannot get content attribute\n");
12585 result = MM_ERROR_PLAYER_INTERNAL;
12589 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12590 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12591 LOGE("subtitle uri is not proper filepath\n");
12592 result = MM_ERROR_PLAYER_INVALID_URI;
12596 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12597 LOGE("failed to get storage info of subtitle path");
12598 result = MM_ERROR_PLAYER_INVALID_URI;
12602 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12603 LOGD("new subtitle file path is [%s]\n", filepath);
12605 if (!strcmp(filepath, subtitle_uri)) {
12606 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12609 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12610 if (mmf_attrs_commit(player->attrs)) {
12611 LOGE("failed to commit.\n");
12616 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12617 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12618 player->subtitle_language_list = NULL;
12619 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12621 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12622 if (ret != GST_STATE_CHANGE_SUCCESS) {
12623 LOGE("failed to change state of textbin to READY");
12624 result = MM_ERROR_PLAYER_INTERNAL;
12628 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12629 if (ret != GST_STATE_CHANGE_SUCCESS) {
12630 LOGE("failed to change state of subparse to READY");
12631 result = MM_ERROR_PLAYER_INTERNAL;
12635 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12636 if (ret != GST_STATE_CHANGE_SUCCESS) {
12637 LOGE("failed to change state of filesrc to READY");
12638 result = MM_ERROR_PLAYER_INTERNAL;
12642 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12644 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12646 charset = util_get_charset(filepath);
12648 LOGD("detected charset is %s\n", charset);
12649 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12652 result = _mmplayer_sync_subtitle_pipeline(player);
12659 /* API to switch between external subtitles */
12660 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12662 int result = MM_ERROR_NONE;
12663 mm_player_t* player = (mm_player_t*)hplayer;
12668 /* check player handle */
12669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12671 /* filepath can be null in idle state */
12673 /* check file path */
12674 if ((path = strstr(filepath, "file://")))
12675 result = util_exist_file_path(path + 7);
12677 result = util_exist_file_path(filepath);
12679 if (result != MM_ERROR_NONE) {
12680 LOGE("invalid subtitle path 0x%X", result);
12681 return result; /* file not found or permission denied */
12685 if (!player->pipeline) {
12687 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12688 if (mmf_attrs_commit(player->attrs)) {
12689 LOGE("failed to commit"); /* subtitle path will not be created */
12690 return MM_ERROR_PLAYER_INTERNAL;
12693 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12694 /* check filepath */
12695 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12697 if (!__mmplayer_check_subtitle(player)) {
12698 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12699 if (mmf_attrs_commit(player->attrs)) {
12700 LOGE("failed to commit");
12701 return MM_ERROR_PLAYER_INTERNAL;
12704 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12705 LOGE("fail to create text pipeline");
12706 return MM_ERROR_PLAYER_INTERNAL;
12709 result = _mmplayer_sync_subtitle_pipeline(player);
12711 result = __mmplayer_change_external_subtitle_language(player, filepath);
12714 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12715 player->is_external_subtitle_added_now = TRUE;
12717 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12718 if (!player->subtitle_language_list) {
12719 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12720 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12721 LOGW("subtitle language list is not updated yet");
12723 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12731 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12733 int result = MM_ERROR_NONE;
12734 gchar* change_pad_name = NULL;
12735 GstPad* sinkpad = NULL;
12736 MMPlayerGstElement* mainbin = NULL;
12737 enum MainElementID elemId = MMPLAYER_M_NUM;
12738 GstCaps* caps = NULL;
12739 gint total_track_num = 0;
12743 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12744 MM_ERROR_PLAYER_NOT_INITIALIZED);
12746 LOGD("Change Track(%d) to %d\n", type, index);
12748 mainbin = player->pipeline->mainbin;
12750 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12751 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12752 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12753 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12755 /* Changing Video Track is not supported. */
12756 LOGE("Track Type Error\n");
12760 if (mainbin[elemId].gst == NULL) {
12761 result = MM_ERROR_PLAYER_NO_OP;
12762 LOGD("Req track doesn't exist\n");
12766 total_track_num = player->selector[type].total_track_num;
12767 if (total_track_num <= 0) {
12768 result = MM_ERROR_PLAYER_NO_OP;
12769 LOGD("Language list is not available \n");
12773 if ((index < 0) || (index >= total_track_num)) {
12774 result = MM_ERROR_INVALID_ARGUMENT;
12775 LOGD("Not a proper index : %d \n", index);
12779 /*To get the new pad from the selector*/
12780 change_pad_name = g_strdup_printf("sink_%u", index);
12781 if (change_pad_name == NULL) {
12782 result = MM_ERROR_PLAYER_INTERNAL;
12783 LOGD("Pad does not exists\n");
12787 LOGD("new active pad name: %s\n", change_pad_name);
12789 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12790 if (sinkpad == NULL) {
12791 LOGD("sinkpad is NULL");
12792 result = MM_ERROR_PLAYER_INTERNAL;
12796 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12797 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12799 caps = gst_pad_get_current_caps(sinkpad);
12800 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12803 gst_object_unref(sinkpad);
12805 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12806 __mmplayer_set_audio_attrs(player, caps);
12810 MMPLAYER_FREEIF(change_pad_name);
12814 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12816 int result = MM_ERROR_NONE;
12817 mm_player_t* player = NULL;
12818 MMPlayerGstElement* mainbin = NULL;
12820 gint current_active_index = 0;
12822 GstState current_state = GST_STATE_VOID_PENDING;
12823 GstEvent* event = NULL;
12828 player = (mm_player_t*)hplayer;
12829 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12831 if (!player->pipeline) {
12832 LOGE("Track %d pre setting -> %d\n", type, index);
12834 player->selector[type].active_pad_index = index;
12838 mainbin = player->pipeline->mainbin;
12840 current_active_index = player->selector[type].active_pad_index;
12842 /*If index is same as running index no need to change the pad*/
12843 if (current_active_index == index)
12846 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12847 result = MM_ERROR_PLAYER_INVALID_STATE;
12851 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12852 if (current_state < GST_STATE_PAUSED) {
12853 result = MM_ERROR_PLAYER_INVALID_STATE;
12854 LOGW("Pipeline not in porper state\n");
12858 result = __mmplayer_change_selector_pad(player, type, index);
12859 if (result != MM_ERROR_NONE) {
12860 LOGE("change selector pad error\n");
12864 player->selector[type].active_pad_index = index;
12866 if (current_state == GST_STATE_PLAYING) {
12867 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);
12869 __gst_send_event_to_sink(player, event);
12871 result = MM_ERROR_PLAYER_INTERNAL;
12880 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12882 mm_player_t* player = (mm_player_t*) hplayer;
12886 /* check player handle */
12887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12889 *silent = player->set_mode.subtitle_off;
12891 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12895 return MM_ERROR_NONE;
12899 __is_ms_buff_src(mm_player_t* player)
12901 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12903 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12907 __has_suffix(mm_player_t* player, const gchar* suffix)
12909 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12910 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12912 gboolean ret = FALSE;
12913 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12914 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12916 if (g_str_has_suffix(player->profile.uri, suffix))
12919 MMPLAYER_FREEIF(t_url);
12920 MMPLAYER_FREEIF(t_suffix);
12926 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12928 mm_player_t* player = (mm_player_t*) hplayer;
12930 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12932 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12933 MMPLAYER_PRINT_STATE(player);
12934 LOGE("wrong-state : can't set the download mode to parse");
12935 return MM_ERROR_PLAYER_INVALID_STATE;
12938 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12939 player->video_hub_download_mode = mode;
12941 return MM_ERROR_NONE;
12945 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12947 mm_player_t* player = (mm_player_t*) hplayer;
12949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12951 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12952 player->sync_handler = enable;
12954 return MM_ERROR_NONE;
12958 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12959 gint64 video_time, gint64 media_clock, gint64 audio_time)
12961 mm_player_t* player = (mm_player_t*) hplayer;
12962 MMPlayerGstElement* mainbin = NULL;
12963 GstClockTime start_time_audio = 0, start_time_video = 0;
12964 GstClockTimeDiff base_time = 0, new_base_time = 0;
12965 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12966 gint64 api_delta = 0;
12967 gint64 position = 0, position_delta = 0;
12968 gint64 adj_base_time = 0;
12969 GstClock *curr_clock = NULL;
12970 GstClockTime curr_time = 0;
12971 gboolean query_ret = TRUE;
12972 int result = MM_ERROR_NONE;
12976 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12977 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12978 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12980 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12981 clock, clock_delta, video_time, media_clock, audio_time); */
12983 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
12984 LOGD("skip setting master clock. %lld", video_time);
12988 mainbin = player->pipeline->mainbin;
12990 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12991 curr_time = gst_clock_get_time(curr_clock);
12993 current_state = MMPLAYER_CURRENT_STATE(player);
12995 if (current_state == MM_PLAYER_STATE_PLAYING)
12996 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12998 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13000 position = player->last_position;
13001 LOGD("query fail. %"G_GINT64_FORMAT, position);
13004 clock *= GST_USECOND;
13005 clock_delta *= GST_USECOND;
13007 api_delta = clock - curr_time;
13008 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13009 player->video_share_api_delta = api_delta;
13011 clock_delta += (api_delta - player->video_share_api_delta);
13013 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13014 player->video_share_clock_delta = (gint64)clock_delta;
13016 position_delta = (position/GST_USECOND) - video_time;
13017 position_delta *= GST_USECOND;
13019 adj_base_time = position_delta;
13020 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13023 gint64 new_play_time = 0;
13024 gint64 network_delay = 0;
13026 video_time *= GST_USECOND;
13028 network_delay = clock_delta - player->video_share_clock_delta;
13029 new_play_time = video_time + network_delay;
13031 adj_base_time = position - new_play_time;
13033 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13034 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13035 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13038 /* Adjust Current Stream Time with base_time of sink
13039 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13040 * 2. Set new base time
13041 * if adj_base_time is positive value, the stream time will be decreased.
13042 * 3. If seek event is occurred, the start time will be reset. */
13043 if ((player->pipeline->audiobin) &&
13044 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13045 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13047 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13048 LOGD("audio sink : gst_element_set_start_time -> NONE");
13049 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13052 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13055 if ((player->pipeline->videobin) &&
13056 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13057 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13059 if (start_time_video != GST_CLOCK_TIME_NONE) {
13060 LOGD("video sink : gst_element_set_start_time -> NONE");
13061 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13064 // if videobin exist, get base_time from videobin.
13065 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13068 new_base_time = base_time + adj_base_time;
13070 if ((player->pipeline->audiobin) &&
13071 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13072 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13074 if ((player->pipeline->videobin) &&
13075 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13076 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13085 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13087 mm_player_t* player = (mm_player_t*) hplayer;
13088 MMPlayerGstElement* mainbin = NULL;
13089 GstClock *curr_clock = NULL;
13090 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13091 gint64 position = 0;
13092 gboolean query_ret = TRUE;
13096 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13097 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13098 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13100 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13101 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13102 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13104 mainbin = player->pipeline->mainbin;
13106 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13108 current_state = MMPLAYER_CURRENT_STATE(player);
13110 if (current_state != MM_PLAYER_STATE_PAUSED)
13111 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13113 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13115 position = player->last_position;
13117 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13119 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13122 gst_object_unref(curr_clock);
13126 return MM_ERROR_NONE;
13130 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13132 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13133 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13135 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13136 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13140 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13141 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13142 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13143 mm_player_dump_t *dump_s;
13144 dump_s = g_malloc(sizeof(mm_player_dump_t));
13146 if (dump_s == NULL) {
13147 LOGE("malloc fail");
13151 dump_s->dump_element_file = NULL;
13152 dump_s->dump_pad = NULL;
13153 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13155 if (dump_s->dump_pad) {
13156 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13157 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]);
13158 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13159 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);
13160 /* add list for removed buffer probe and close FILE */
13161 player->dump_list = g_list_append(player->dump_list, dump_s);
13162 LOGD("%s sink pad added buffer probe for dump", factory_name);
13167 LOGE("failed to get %s sink pad added", factory_name);
13176 static GstPadProbeReturn
13177 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13179 FILE *dump_data = (FILE *) u_data;
13180 // int written = 0;
13181 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13182 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13184 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13186 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13188 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13190 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13192 return GST_PAD_PROBE_OK;
13196 __mmplayer_release_dump_list(GList *dump_list)
13199 GList *d_list = dump_list;
13200 for (; d_list; d_list = g_list_next(d_list)) {
13201 mm_player_dump_t *dump_s = d_list->data;
13202 if (dump_s->dump_pad) {
13203 if (dump_s->probe_handle_id)
13204 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13206 if (dump_s->dump_element_file) {
13207 fclose(dump_s->dump_element_file);
13208 dump_s->dump_element_file = NULL;
13210 MMPLAYER_FREEIF(dump_s);
13212 g_list_free(dump_list);
13218 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13220 mm_player_t* player = (mm_player_t*) hplayer;
13224 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13225 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13227 *exist = player->has_closed_caption;
13231 return MM_ERROR_NONE;
13234 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13238 // LOGD("unref internal gst buffer %p", buffer);
13239 gst_buffer_unref((GstBuffer *)buffer);
13246 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13248 mm_player_t *player = (mm_player_t*)user_data;
13249 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13250 guint64 current_level_bytes = 0;
13252 MMPLAYER_RETURN_IF_FAIL(player);
13254 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13256 LOGI("app-src: feed audio(%llu)", current_level_bytes);
13257 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13259 if (player->media_stream_buffer_status_cb[type])
13260 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13261 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13266 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13268 mm_player_t *player = (mm_player_t*)user_data;
13269 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13270 guint64 current_level_bytes = 0;
13272 MMPLAYER_RETURN_IF_FAIL(player);
13274 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13276 LOGI("app-src: feed video(%llu)", current_level_bytes);
13278 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13279 if (player->media_stream_buffer_status_cb[type])
13280 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13281 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13285 __gst_appsrc_feed_subtitle_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_TEXT;
13289 guint64 current_level_bytes = 0;
13291 MMPLAYER_RETURN_IF_FAIL(player);
13293 LOGI("app-src: feed subtitle");
13295 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13297 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]);
13301 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13305 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13307 mm_player_t *player = (mm_player_t*)user_data;
13308 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13309 guint64 current_level_bytes = 0;
13311 MMPLAYER_RETURN_IF_FAIL(player);
13313 LOGI("app-src: audio buffer is full");
13315 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13317 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13319 if (player->media_stream_buffer_status_cb[type])
13320 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13322 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13326 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13328 mm_player_t *player = (mm_player_t*)user_data;
13329 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13330 guint64 current_level_bytes = 0;
13332 MMPLAYER_RETURN_IF_FAIL(player);
13334 LOGI("app-src: video buffer is full");
13336 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13338 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13339 if (player->media_stream_buffer_status_cb[type])
13340 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13342 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13346 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13348 mm_player_t *player = (mm_player_t*)user_data;
13349 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13351 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13353 LOGD("app-src: seek audio data %llu", position);
13354 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13356 if (player->media_stream_seek_data_cb[type])
13357 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13358 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13364 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13366 mm_player_t *player = (mm_player_t*)user_data;
13367 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13369 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13371 LOGD("app-src: seek video data %llu", position);
13372 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13373 if (player->media_stream_seek_data_cb[type])
13374 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13375 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13381 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13383 mm_player_t *player = (mm_player_t*)user_data;
13384 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13386 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13388 LOGD("app-src: seek subtitle data");
13389 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13391 if (player->media_stream_seek_data_cb[type])
13392 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13393 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13399 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13401 mm_player_t* player = (mm_player_t*) hplayer;
13405 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13407 player->pcm_samplerate = samplerate;
13408 player->pcm_channel = channel;
13411 return MM_ERROR_NONE;
13414 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13416 mm_player_t* player = (mm_player_t*) hplayer;
13420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13421 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13423 if (MMPLAYER_IS_HTTP_PD(player))
13424 *timeout = player->ini.live_state_change_timeout*2;
13425 else if (MMPLAYER_IS_STREAMING(player))
13426 *timeout = player->ini.live_state_change_timeout;
13428 *timeout = player->ini.localplayback_state_change_timeout;
13430 LOGD("timeout = %d\n", *timeout);
13433 return MM_ERROR_NONE;
13436 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13438 mm_player_t* player = (mm_player_t*) hplayer;
13442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13443 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13445 *num = player->video_num_buffers;
13446 *extra_num = player->video_extra_num_buffers;
13448 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13451 return MM_ERROR_NONE;
13455 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13459 MMPLAYER_RETURN_IF_FAIL(player);
13461 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13463 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13464 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13465 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13466 player->storage_info[i].id = -1;
13467 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13469 if (path_type != MMPLAYER_PATH_MAX)
13477 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13479 int ret = MM_ERROR_NONE;
13480 mm_player_t* player = (mm_player_t*)hplayer;
13481 MMMessageParamType msg_param = {0, };
13484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13486 LOGW("state changed storage %d:%d", id, state);
13488 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13489 return MM_ERROR_NONE;
13491 /* FIXME: text path should be handled seperately. */
13492 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13493 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13494 LOGW("external storage is removed");
13496 if (player->msg_posted == FALSE) {
13497 memset(&msg_param, 0, sizeof(MMMessageParamType));
13498 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13499 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13500 player->msg_posted = TRUE;
13503 /* unrealize the player */
13504 ret = _mmplayer_unrealize(hplayer);
13505 if (ret != MM_ERROR_NONE)
13506 LOGE("failed to unrealize");
13513 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13515 int ret = MM_ERROR_NONE;
13516 mm_player_t* player = (mm_player_t*) hplayer;
13517 int idx = 0, total = 0;
13518 gchar *result = NULL, *tmp = NULL;
13521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13522 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13524 total = *num = g_list_length(player->adaptive_info.var_list);
13526 LOGW("There is no stream variant info.");
13530 result = g_strdup("");
13531 for (idx = 0 ; idx < total ; idx++) {
13532 VariantData *v_data = NULL;
13533 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13536 gchar data[64] = {0};
13537 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13539 tmp = g_strconcat(result, data, NULL);
13543 LOGW("There is no variant data in %d", idx);
13548 *var_info = (char *)result;
13550 LOGD("variant info %d:%s", *num, *var_info);
13555 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13557 int ret = MM_ERROR_NONE;
13558 mm_player_t* player = (mm_player_t*) hplayer;
13561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13563 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13565 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13566 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13567 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13569 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13570 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13571 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13572 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13574 /* FIXME: seek to current position for applying new variant limitation */
13582 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13584 int ret = MM_ERROR_NONE;
13585 mm_player_t* player = (mm_player_t*) hplayer;
13588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13589 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13591 *bandwidth = player->adaptive_info.limit.bandwidth;
13592 *width = player->adaptive_info.limit.width;
13593 *height = player->adaptive_info.limit.height;
13595 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13601 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13603 int ret = MM_ERROR_NONE;
13604 mm_player_t* player = (mm_player_t*) hplayer;
13607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13609 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13610 LOGW("buffer_ms will not be applied.");
13613 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13615 if (player->streamer == NULL) {
13616 player->streamer = __mm_player_streaming_create();
13617 __mm_player_streaming_initialize(player->streamer);
13620 if (buffer_ms >= 0)
13621 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13623 if (rebuffer_ms >= 0)
13624 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13631 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13633 int ret = MM_ERROR_NONE;
13634 mm_player_t* player = (mm_player_t*) hplayer;
13637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13640 if (player->streamer == NULL) {
13641 player->streamer = __mm_player_streaming_create();
13642 __mm_player_streaming_initialize(player->streamer);
13645 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13646 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13648 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13654 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13656 #define IDX_FIRST_SW_CODEC 0
13657 mm_player_t* player = (mm_player_t*) hplayer;
13658 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13659 MMHandleType attrs = 0;
13662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13664 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13665 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13666 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13668 switch (stream_type) {
13669 case MM_PLAYER_STREAM_TYPE_AUDIO:
13670 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13671 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13672 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13673 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13674 LOGE("There is no a codec for codec_type %d", codec_type);
13675 return MM_ERROR_PLAYER_NO_OP;
13678 case MM_PLAYER_STREAM_TYPE_VIDEO:
13679 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13680 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13681 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13682 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13683 LOGE("There is no v codec for codec_type %d", codec_type);
13684 return MM_ERROR_PLAYER_NO_OP;
13689 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13690 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13694 LOGD("update %s codec_type to %d", attr_name, codec_type);
13696 attrs = MMPLAYER_GET_ATTRS(player);
13697 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13699 if (mmf_attrs_commit(player->attrs)) {
13700 LOGE("failed to commit codec_type attributes");
13701 return MM_ERROR_PLAYER_INTERNAL;
13705 return MM_ERROR_NONE;
13709 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13711 mm_player_t* player = (mm_player_t*) hplayer;
13712 GstElement* rg_vol_element = NULL;
13716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13718 player->sound.rg_enable = enabled;
13720 /* just hold rgvolume enable value if pipeline is not ready */
13721 if (!player->pipeline || !player->pipeline->audiobin) {
13722 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13723 return MM_ERROR_NONE;
13726 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13728 if (!rg_vol_element) {
13729 LOGD("rgvolume element is not created");
13730 return MM_ERROR_PLAYER_INTERNAL;
13734 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13736 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13740 return MM_ERROR_NONE;
13744 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13746 mm_player_t* player = (mm_player_t*) hplayer;
13747 GstElement* rg_vol_element = NULL;
13748 gboolean enable = FALSE;
13752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13753 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13755 /* just hold enable_rg value if pipeline is not ready */
13756 if (!player->pipeline || !player->pipeline->audiobin) {
13757 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13758 *enabled = player->sound.rg_enable;
13759 return MM_ERROR_NONE;
13762 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13764 if (!rg_vol_element) {
13765 LOGD("rgvolume element is not created");
13766 return MM_ERROR_PLAYER_INTERNAL;
13769 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13774 return MM_ERROR_NONE;