4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
55 /*===========================================================================================
57 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
59 ========================================================================================== */
61 /*---------------------------------------------------------------------------
62 | GLOBAL CONSTANT DEFINITIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED VARIABLE DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED FUNCTION DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
79 #define MM_VOLUME_FACTOR_DEFAULT 1.0
80 #define MM_VOLUME_FACTOR_MIN 0
81 #define MM_VOLUME_FACTOR_MAX 1.0
83 /* Don't need to sleep for sound fadeout
84 * fadeout related fucntion will be deleted(Deprecated)
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
88 #define DEFAULT_PLAYBACK_RATE 1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93 (player->ini.http_use_file_buffer) && \
94 (player->http_file_buffering_path) && \
95 (strlen(player->http_file_buffering_path) > 0))
97 #define PLAYER_DISPLAY_MODE_DST_ROI 5
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
104 #define 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, unsigned long position, gboolean internal_called);
206 static int __gst_get_position(mm_player_t* player, int format, unsigned long *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 int __mmplayer_set_pcm_extraction(mm_player_t* player);
214 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
217 static gboolean __is_ms_buff_src(mm_player_t* player);
218 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
220 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
221 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
222 static int __mmplayer_start_streaming_ext(mm_player_t *player);
223 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
224 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
226 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
227 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
228 static void __mmplayer_check_pipeline(mm_player_t* player);
229 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
230 static void __mmplayer_deactivate_old_path(mm_player_t *player);
232 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
233 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
235 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
236 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
237 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
238 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
239 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
240 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
241 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
242 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
246 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
247 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
248 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
249 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
250 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
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)) {
349 player->duration = dur_nsec;
350 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
353 if (player->duration < 0) {
354 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
355 player->duration = 0;
358 /* update streaming service type */
359 player->streaming_type = __mmplayer_get_stream_service_type(player);
361 /* check duration is OK */
362 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
363 /* FIXIT : find another way to get duration here. */
364 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
367 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
372 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
373 /* update audio params
374 NOTE : We need original audio params and it can be only obtained from src pad of audio
375 decoder. Below code only valid when we are not using 'resampler' just before
378 LOGD("try to update audio attrs");
379 has_audio_attrs = FALSE;
381 if (player->pipeline->audiobin &&
382 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
383 GstCaps *caps_a = NULL;
385 gint samplerate = 0, channels = 0;
387 pad = gst_element_get_static_pad(
388 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
391 caps_a = gst_pad_get_current_caps(pad);
394 p = gst_caps_get_structure(caps_a, 0);
396 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
398 gst_structure_get_int(p, "rate", &samplerate);
399 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
401 gst_structure_get_int(p, "channels", &channels);
402 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
404 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
406 gst_caps_unref(caps_a);
409 has_audio_attrs = TRUE;
411 LOGW("not ready to get audio caps");
413 gst_object_unref(pad);
415 LOGW("failed to get pad from audiosink");
419 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
420 LOGD("try to update video attrs");
421 has_video_attrs = FALSE;
423 if (player->pipeline->videobin &&
424 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
425 GstCaps *caps_v = NULL;
430 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
432 caps_v = gst_pad_get_current_caps(pad);
434 /* Use v_stream_caps, if fail to get video_sink sink pad*/
435 if (!caps_v && player->v_stream_caps) {
436 caps_v = player->v_stream_caps;
437 gst_caps_ref(caps_v);
441 p = gst_caps_get_structure(caps_v, 0);
442 gst_structure_get_int(p, "width", &width);
443 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
445 gst_structure_get_int(p, "height", &height);
446 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
448 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
450 SECURE_LOGD("width : %d height : %d", width, height);
452 gst_caps_unref(caps_v);
456 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
457 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
460 has_video_attrs = TRUE;
462 LOGD("no negitiated caps from videosink");
463 gst_object_unref(pad);
466 LOGD("no videosink sink pad");
471 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
474 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
475 if (player->duration) {
476 guint64 data_size = 0;
478 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
479 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
481 if (stat(path, &sb) == 0)
482 data_size = (guint64)sb.st_size;
483 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
484 data_size = player->http_content_size;
486 LOGD("try to update bitrate : data_size = %lld", data_size);
490 guint64 msec_dur = 0;
492 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
494 bitrate = data_size * 8 * 1000 / msec_dur;
495 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
496 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
500 LOGD("player duration is less than 0");
504 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
505 if (player->total_bitrate) {
506 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
514 if (mmf_attrs_commit(attrs)) {
515 LOGE("failed to update attributes\n");
524 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
526 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
530 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
532 player->pipeline->mainbin &&
533 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
534 STREAMING_SERVICE_NONE);
536 /* streaming service type if streaming */
537 if (!MMPLAYER_IS_STREAMING(player))
538 return STREAMING_SERVICE_NONE;
540 if (MMPLAYER_IS_HTTP_STREAMING(player))
541 streaming_type = (player->duration == 0) ?
542 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
544 switch (streaming_type) {
545 case STREAMING_SERVICE_LIVE:
546 LOGD("it's live streaming");
548 case STREAMING_SERVICE_VOD:
549 LOGD("it's vod streaming");
552 LOGE("should not get here");
558 return streaming_type;
562 /* this function sets the player state and also report
563 * it to applicaton by calling callback function
566 __mmplayer_set_state(mm_player_t* player, int state)
568 MMMessageParamType msg = {0, };
569 gboolean post_bos = FALSE;
571 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
573 if (MMPLAYER_CURRENT_STATE(player) == state) {
574 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
575 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
576 return MM_ERROR_NONE;
579 /* update player states */
580 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
581 MMPLAYER_CURRENT_STATE(player) = state;
583 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
584 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
587 MMPLAYER_PRINT_STATE(player);
589 switch (MMPLAYER_CURRENT_STATE(player)) {
590 case MM_PLAYER_STATE_NULL:
591 case MM_PLAYER_STATE_READY:
594 case MM_PLAYER_STATE_PAUSED:
596 if (!player->sent_bos) {
597 /* rtsp case, get content attrs by GstMessage */
598 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
599 /* it's first time to update all content attrs. */
600 _mmplayer_update_content_attrs(player, ATTR_ALL);
604 /* add audio callback probe if condition is satisfied */
605 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
606 __mmplayer_configure_audio_callback(player);
608 /* FIXIT : handle return value */
612 case MM_PLAYER_STATE_PLAYING:
614 /* try to get content metadata */
615 if (!player->sent_bos) {
616 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
617 * c-api since c-api doesn't use _start() anymore. It may not work propery with
618 * legacy mmfw-player api */
619 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
622 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
623 if (!player->sent_bos)
624 __mmplayer_handle_missed_plugin(player);
627 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
628 /* initialize because auto resume is done well. */
629 player->resumed_by_rewind = FALSE;
630 player->playback_rate = 1.0;
633 if (!player->sent_bos) {
634 /* check audio codec field is set or not
635 * we can get it from typefinder or codec's caps.
637 gchar *audio_codec = NULL;
638 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
640 /* The codec format can't be sent for audio only case like amr, mid etc.
641 * Because, parser don't make related TAG.
642 * So, if it's not set yet, fill it with found data.
645 if (g_strrstr(player->type, "audio/midi"))
646 audio_codec = g_strdup("MIDI");
647 else if (g_strrstr(player->type, "audio/x-amr"))
648 audio_codec = g_strdup("AMR");
649 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
650 audio_codec = g_strdup("AAC");
652 audio_codec = g_strdup("unknown");
653 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
655 MMPLAYER_FREEIF(audio_codec);
656 if (mmf_attrs_commit(player->attrs))
657 LOGE("failed to update attributes\n");
659 LOGD("set audio codec type with caps\n");
667 case MM_PLAYER_STATE_NONE:
669 LOGW("invalid target state, there is nothing to do.\n");
674 /* post message to application */
675 if (MMPLAYER_TARGET_STATE(player) == state) {
676 /* fill the message with state of player */
677 msg.union_type = MM_MSG_UNION_STATE;
678 msg.state.previous = MMPLAYER_PREV_STATE(player);
679 msg.state.current = MMPLAYER_CURRENT_STATE(player);
681 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
683 /* state changed by resource callback */
684 if (player->interrupted_by_resource) {
685 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
686 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
687 } else { /* state changed by usecase */
688 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
691 LOGD("intermediate state, do nothing.\n");
692 MMPLAYER_PRINT_STATE(player);
693 return MM_ERROR_NONE;
697 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
698 player->sent_bos = TRUE;
701 return MM_ERROR_NONE;
704 static gpointer __mmplayer_next_play_thread(gpointer data)
706 mm_player_t* player = (mm_player_t*) data;
707 MMPlayerGstElement *mainbin = NULL;
709 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
711 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
712 while (!player->next_play_thread_exit) {
713 LOGD("next play thread started. waiting for signal.\n");
714 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
716 LOGD("reconfigure pipeline for gapless play.\n");
718 if (player->next_play_thread_exit) {
719 if (player->gapless.reconfigure) {
720 player->gapless.reconfigure = false;
721 MMPLAYER_PLAYBACK_UNLOCK(player);
723 LOGD("exiting gapless play thread\n");
727 mainbin = player->pipeline->mainbin;
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
731 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
732 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
733 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
735 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
745 MMHandleType attrs = 0;
746 guint64 data_size = 0;
748 unsigned long pos_msec = 0;
751 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
753 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
755 attrs = MMPLAYER_GET_ATTRS(player);
757 LOGE("fail to get attributes.\n");
761 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
762 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
764 if (stat(path, &sb) == 0)
765 data_size = (guint64)sb.st_size;
766 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
767 data_size = player->http_content_size;
769 __mm_player_streaming_buffering(player->streamer,
772 player->last_position,
775 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
781 __mmplayer_handle_buffering_message(mm_player_t* player)
783 int ret = MM_ERROR_NONE;
784 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
785 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
786 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
787 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
789 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
790 LOGW("do nothing for buffering msg\n");
791 ret = MM_ERROR_PLAYER_INVALID_STATE;
795 prev_state = MMPLAYER_PREV_STATE(player);
796 current_state = MMPLAYER_CURRENT_STATE(player);
797 target_state = MMPLAYER_TARGET_STATE(player);
798 pending_state = MMPLAYER_PENDING_STATE(player);
800 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
801 MMPLAYER_STATE_GET_NAME(prev_state),
802 MMPLAYER_STATE_GET_NAME(current_state),
803 MMPLAYER_STATE_GET_NAME(pending_state),
804 MMPLAYER_STATE_GET_NAME(target_state),
805 player->streamer->is_buffering);
807 if (!player->streamer->is_buffering) {
808 /* NOTE : if buffering has done, player has to go to target state. */
809 switch (target_state) {
810 case MM_PLAYER_STATE_PAUSED:
812 switch (pending_state) {
813 case MM_PLAYER_STATE_PLAYING:
814 __gst_pause(player, TRUE);
817 case MM_PLAYER_STATE_PAUSED:
818 LOGD("player is already going to paused state, there is nothing to do.\n");
821 case MM_PLAYER_STATE_NONE:
822 case MM_PLAYER_STATE_NULL:
823 case MM_PLAYER_STATE_READY:
825 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
831 case MM_PLAYER_STATE_PLAYING:
833 switch (pending_state) {
834 case MM_PLAYER_STATE_NONE:
836 if (current_state != MM_PLAYER_STATE_PLAYING)
837 __gst_resume(player, TRUE);
841 case MM_PLAYER_STATE_PAUSED:
842 /* NOTE: It should be worked as asynchronously.
843 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
845 if (current_state == MM_PLAYER_STATE_PLAYING) {
846 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
847 * The current state should be changed to paused purposely to prevent state conflict.
849 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
851 __gst_resume(player, TRUE);
854 case MM_PLAYER_STATE_PLAYING:
855 LOGD("player is already going to playing state, there is nothing to do.\n");
858 case MM_PLAYER_STATE_NULL:
859 case MM_PLAYER_STATE_READY:
861 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
867 case MM_PLAYER_STATE_NULL:
868 case MM_PLAYER_STATE_READY:
869 case MM_PLAYER_STATE_NONE:
871 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
875 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
876 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
878 switch (pending_state) {
879 case MM_PLAYER_STATE_NONE:
881 if (current_state != MM_PLAYER_STATE_PAUSED) {
882 /* rtsp streaming pause makes rtsp server stop sending data. */
883 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
884 LOGD("set pause state during buffering\n");
885 __gst_pause(player, TRUE);
891 case MM_PLAYER_STATE_PLAYING:
892 /* rtsp streaming pause makes rtsp server stop sending data. */
893 if (!MMPLAYER_IS_RTSP_STREAMING(player))
894 __gst_pause(player, TRUE);
897 case MM_PLAYER_STATE_PAUSED:
900 case MM_PLAYER_STATE_NULL:
901 case MM_PLAYER_STATE_READY:
903 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
913 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
915 MMPlayerGstElement *textbin;
918 MMPLAYER_RETURN_IF_FAIL(player &&
920 player->pipeline->textbin);
922 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
924 textbin = player->pipeline->textbin;
927 LOGD("Drop subtitle text after getting EOS\n");
929 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
930 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
932 player->is_subtitle_force_drop = TRUE;
934 if (player->is_subtitle_force_drop == TRUE) {
935 LOGD("Enable subtitle data path without drop\n");
937 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
938 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
940 LOGD("non-connected with external display");
942 player->is_subtitle_force_drop = FALSE;
948 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
950 VariantData *var_info = NULL;
951 g_return_val_if_fail(self != NULL, NULL);
953 var_info = g_new0(VariantData, 1);
954 if (!var_info) return NULL;
955 var_info->bandwidth = self->bandwidth;
956 var_info->width = self->width;
957 var_info->height = self->height;
961 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
963 mm_player_t* player = (mm_player_t*)hplayer;
966 MMPLAYER_RETURN_IF_FAIL(player);
968 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
970 /* destroy the gst bus msg thread */
971 if (player->bus_msg_thread) {
972 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
973 player->bus_msg_thread_exit = TRUE;
974 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
975 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
977 LOGD("gst bus msg thread exit.");
978 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
979 player->bus_msg_thread = NULL;
981 g_mutex_clear(&player->bus_msg_thread_mutex);
982 g_cond_clear(&player->bus_msg_thread_cond);
988 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
990 mm_player_t *player = (mm_player_t*)(data);
991 GstMessage *msg = NULL;
995 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
997 player->pipeline->mainbin &&
998 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1001 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1003 LOGE("cannot get BUS from the pipeline");
1007 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1009 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1010 while (!player->bus_msg_thread_exit) {
1011 msg = gst_bus_pop(bus);
1013 int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1014 MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1018 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1019 /* handle the gst msg */
1020 __mmplayer_gst_callback(msg, player);
1021 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1022 gst_message_unref(msg);
1025 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1026 gst_object_unref(GST_OBJECT(bus));
1033 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1035 mm_player_t* player = (mm_player_t*)(data);
1036 static gboolean async_done = FALSE;
1038 MMPLAYER_RETURN_IF_FAIL(player);
1039 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1041 switch (GST_MESSAGE_TYPE(msg)) {
1042 case GST_MESSAGE_UNKNOWN:
1043 LOGD("unknown message received\n");
1046 case GST_MESSAGE_EOS:
1048 MMHandleType attrs = 0;
1051 LOGD("GST_MESSAGE_EOS received\n");
1053 /* NOTE : EOS event is comming multiple time. watch out it */
1054 /* check state. we only process EOS when pipeline state goes to PLAYING */
1055 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1056 LOGD("EOS received on non-playing state. ignoring it\n");
1060 if (player->pipeline) {
1061 if (player->pipeline->textbin)
1062 __mmplayer_drop_subtitle(player, TRUE);
1064 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1067 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1069 LOGD("release audio callback\n");
1071 /* release audio callback */
1072 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1073 player->audio_cb_probe_id = 0;
1074 /* audio callback should be free because it can be called even though probe remove.*/
1075 player->audio_stream_cb = NULL;
1076 player->audio_stream_cb_user_param = NULL;
1080 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1081 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1083 /* rewind if repeat count is greater then zero */
1084 /* get play count */
1085 attrs = MMPLAYER_GET_ATTRS(player);
1088 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1090 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1092 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1093 if (player->playback_rate < 0.0) {
1094 player->resumed_by_rewind = TRUE;
1095 _mmplayer_set_mute((MMHandleType)player, 0);
1096 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1099 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1102 player->sent_bos = FALSE;
1104 /* not posting eos when repeating */
1109 if (player->pipeline)
1110 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1112 /* post eos message to application */
1113 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1115 /* reset last position */
1116 player->last_position = 0;
1120 case GST_MESSAGE_ERROR:
1122 GError *error = NULL;
1123 gchar* debug = NULL;
1125 /* generating debug info before returning error */
1126 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1128 /* get error code */
1129 gst_message_parse_error(msg, &error, &debug);
1131 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1132 /* Note : the streaming error from the streaming source is handled
1133 * using __mmplayer_handle_streaming_error.
1135 __mmplayer_handle_streaming_error(player, msg);
1137 /* dump state of all element */
1138 __mmplayer_dump_pipeline_state(player);
1140 /* traslate gst error code to msl error code. then post it
1141 * to application if needed
1143 __mmplayer_handle_gst_error(player, msg, error);
1146 LOGE("error debug : %s", debug);
1149 if (MMPLAYER_IS_HTTP_PD(player))
1150 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1152 MMPLAYER_FREEIF(debug);
1153 g_error_free(error);
1157 case GST_MESSAGE_WARNING:
1160 GError* error = NULL;
1162 gst_message_parse_warning(msg, &error, &debug);
1164 LOGD("warning : %s\n", error->message);
1165 LOGD("debug : %s\n", debug);
1167 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1169 MMPLAYER_FREEIF(debug);
1170 g_error_free(error);
1174 case GST_MESSAGE_TAG:
1176 LOGD("GST_MESSAGE_TAG\n");
1177 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1178 LOGW("failed to extract tags from gstmessage\n");
1182 case GST_MESSAGE_BUFFERING:
1184 MMMessageParamType msg_param = {0, };
1185 int bRet = MM_ERROR_NONE;
1187 if (!(player->pipeline && player->pipeline->mainbin)) {
1188 LOGE("player pipeline handle is null");
1192 if (!MMPLAYER_IS_STREAMING(player))
1195 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1196 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1197 /* skip the playback control by buffering msg while user request is handled. */
1200 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1202 gst_message_parse_buffering(msg, &per);
1203 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1205 msg_param.connection.buffering = per;
1206 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1210 MMPLAYER_CMD_LOCK(player);
1213 /* ignore the prev buffering message */
1214 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1215 && (player->streamer->is_buffering_done == TRUE)) {
1216 gint buffer_percent = 0;
1218 gst_message_parse_buffering(msg, &buffer_percent);
1220 if (buffer_percent == MAX_BUFFER_PERCENT) {
1221 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1222 player->streamer->is_buffering_done = FALSE;
1224 MMPLAYER_CMD_UNLOCK(player);
1228 __mmplayer_update_buffer_setting(player, msg);
1230 bRet = __mmplayer_handle_buffering_message(player);
1232 if (bRet == MM_ERROR_NONE) {
1233 msg_param.connection.buffering = player->streamer->buffering_percent;
1234 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1236 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1237 player->pending_resume &&
1238 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1240 player->is_external_subtitle_added_now = FALSE;
1241 player->pending_resume = FALSE;
1242 _mmplayer_resume((MMHandleType)player);
1245 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1246 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1248 if (player->doing_seek) {
1249 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1250 player->doing_seek = FALSE;
1251 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1252 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1257 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1258 if (!player->streamer) {
1259 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1260 MMPLAYER_CMD_UNLOCK(player);
1264 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1266 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1267 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1269 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1270 msg_param.connection.buffering = player->streamer->buffering_percent;
1271 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1273 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1276 msg_param.connection.buffering = player->streamer->buffering_percent;
1277 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1280 MMPLAYER_CMD_UNLOCK(player);
1284 case GST_MESSAGE_STATE_CHANGED:
1286 MMPlayerGstElement *mainbin;
1287 const GValue *voldstate, *vnewstate, *vpending;
1288 GstState oldstate = GST_STATE_NULL;
1289 GstState newstate = GST_STATE_NULL;
1290 GstState pending = GST_STATE_NULL;
1292 if (!(player->pipeline && player->pipeline->mainbin)) {
1293 LOGE("player pipeline handle is null");
1297 mainbin = player->pipeline->mainbin;
1299 /* we only handle messages from pipeline */
1300 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1303 /* get state info from msg */
1304 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1305 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1306 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1308 if (!voldstate || !vnewstate) {
1309 LOGE("received msg has wrong format.");
1313 oldstate = (GstState)voldstate->data[0].v_int;
1314 newstate = (GstState)vnewstate->data[0].v_int;
1316 pending = (GstState)vpending->data[0].v_int;
1318 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1319 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1320 gst_element_state_get_name((GstState)oldstate),
1321 gst_element_state_get_name((GstState)newstate),
1322 gst_element_state_get_name((GstState)pending));
1324 if (newstate == GST_STATE_PLAYING) {
1325 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1327 int retVal = MM_ERROR_NONE;
1328 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1330 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1332 if (MM_ERROR_NONE != retVal)
1333 LOGE("failed to seek pending postion. just keep staying current position.\n");
1335 player->pending_seek.is_pending = FALSE;
1339 if (oldstate == newstate) {
1340 LOGD("pipeline reports state transition to old state");
1345 case GST_STATE_VOID_PENDING:
1348 case GST_STATE_NULL:
1351 case GST_STATE_READY:
1354 case GST_STATE_PAUSED:
1356 gboolean prepare_async = FALSE;
1357 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1359 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1360 __mmplayer_configure_audio_callback(player);
1362 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1363 // managed prepare async case
1364 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1365 LOGD("checking prepare mode for async transition - %d", prepare_async);
1368 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1369 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1371 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1372 __mm_player_streaming_set_content_bitrate(player->streamer,
1373 player->total_maximum_bitrate, player->total_bitrate);
1375 if (player->pending_seek.is_pending) {
1376 LOGW("trying to do pending seek");
1377 MMPLAYER_CMD_LOCK(player);
1378 __gst_pending_seek(player);
1379 MMPLAYER_CMD_UNLOCK(player);
1385 case GST_STATE_PLAYING:
1387 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1389 if (MMPLAYER_IS_STREAMING(player)) {
1390 // managed prepare async case when buffering is completed
1391 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1392 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1393 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1394 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1396 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1398 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1399 if (player->streamer->buffering_percent < 100) {
1401 MMMessageParamType msg_param = {0, };
1402 LOGW("Posting Buffering Completed Message to Application !!!");
1404 msg_param.connection.buffering = 100;
1405 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1410 if (player->gapless.stream_changed) {
1411 _mmplayer_update_content_attrs(player, ATTR_ALL);
1412 player->gapless.stream_changed = FALSE;
1415 if (player->doing_seek && async_done) {
1416 player->doing_seek = FALSE;
1418 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1429 case GST_MESSAGE_CLOCK_LOST:
1431 GstClock *clock = NULL;
1432 gboolean need_new_clock = FALSE;
1434 gst_message_parse_clock_lost(msg, &clock);
1435 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1437 if (!player->videodec_linked)
1438 need_new_clock = TRUE;
1439 else if (!player->ini.use_system_clock)
1440 need_new_clock = TRUE;
1442 if (need_new_clock) {
1443 LOGD("Provide clock is TRUE, do pause->resume\n");
1444 __gst_pause(player, FALSE);
1445 __gst_resume(player, FALSE);
1450 case GST_MESSAGE_NEW_CLOCK:
1452 GstClock *clock = NULL;
1453 gst_message_parse_new_clock(msg, &clock);
1454 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1458 case GST_MESSAGE_ELEMENT:
1460 const gchar *structure_name;
1461 gint count = 0, idx = 0;
1462 MMHandleType attrs = 0;
1464 attrs = MMPLAYER_GET_ATTRS(player);
1466 LOGE("cannot get content attribute");
1470 if (gst_message_get_structure(msg) == NULL)
1473 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1474 if (!structure_name)
1477 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1479 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1480 const GValue *var_info = NULL;
1482 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1483 if (var_info != NULL) {
1484 if (player->adaptive_info.var_list)
1485 g_list_free_full(player->adaptive_info.var_list, g_free);
1487 /* share addr or copy the list */
1488 player->adaptive_info.var_list =
1489 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1491 count = g_list_length(player->adaptive_info.var_list);
1493 VariantData *temp = NULL;
1495 /* print out for debug */
1496 LOGD("num of variant_info %d", count);
1497 for (idx = 0; idx < count; idx++) {
1498 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1500 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1506 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1507 gint num_buffers = 0;
1508 gint extra_num_buffers = 0;
1510 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1511 player->video_num_buffers = num_buffers;
1512 LOGD("video_num_buffers : %d", player->video_num_buffers);
1515 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1516 player->video_extra_num_buffers = extra_num_buffers;
1517 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1522 if (!strcmp(structure_name, "Language_list")) {
1523 const GValue *lang_list = NULL;
1524 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1525 if (lang_list != NULL) {
1526 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1528 LOGD("Total audio tracks(from parser) = %d \n", count);
1532 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1533 const GValue *lang_list = NULL;
1534 MMPlayerLangStruct *temp = NULL;
1536 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1537 if (lang_list != NULL) {
1538 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1540 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1541 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1542 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1543 if (mmf_attrs_commit(attrs))
1544 LOGE("failed to commit.\n");
1545 LOGD("Total subtitle tracks = %d \n", count);
1548 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1550 LOGD("value of lang_key is %s and lang_code is %s",
1551 temp->language_key, temp->language_code);
1554 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1555 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1560 /* custom message */
1561 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1562 MMMessageParamType msg_param = {0,};
1563 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1564 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1567 /* custom message for RTSP attribute :
1568 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1569 sdp which has contents info is received when rtsp connection is opened.
1570 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1571 if (!strcmp(structure_name, "rtspsrc_properties")) {
1573 gchar *audio_codec = NULL;
1574 gchar *video_codec = NULL;
1575 gchar *video_frame_size = NULL;
1577 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1578 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1579 player->streaming_type = __mmplayer_get_stream_service_type(player);
1580 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1582 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1583 LOGD("rtsp_audio_codec : %s", audio_codec);
1585 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1587 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1588 LOGD("rtsp_video_codec : %s", video_codec);
1590 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1592 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1593 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1594 if (video_frame_size) {
1596 char *seperator = strchr(video_frame_size, '-');
1599 char video_width[10] = {0,};
1600 int frame_size_len = strlen(video_frame_size);
1601 int separtor_len = strlen(seperator);
1603 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1604 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1607 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1611 if (mmf_attrs_commit(attrs))
1612 LOGE("failed to commit.\n");
1617 case GST_MESSAGE_DURATION_CHANGED:
1619 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1620 if (!__mmplayer_gst_handle_duration(player, msg))
1621 LOGW("failed to update duration");
1626 case GST_MESSAGE_ASYNC_START:
1627 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1630 case GST_MESSAGE_ASYNC_DONE:
1632 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1634 /* we only handle messages from pipeline */
1635 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1638 if (player->doing_seek) {
1639 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1640 player->doing_seek = FALSE;
1641 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1642 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1643 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1644 (player->streamer) &&
1645 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1646 (player->streamer->is_buffering == FALSE)) {
1647 GstQuery *query = NULL;
1648 gboolean busy = FALSE;
1651 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1652 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1653 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1654 gst_query_parse_buffering_percent(query, &busy, &percent);
1655 gst_query_unref(query);
1657 LOGD("buffered percent(%s): %d\n",
1658 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1661 if (percent >= 100) {
1662 player->streamer->is_buffering = FALSE;
1663 __mmplayer_handle_buffering_message(player);
1673 #if 0 /* delete unnecessary logs */
1674 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1675 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1676 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1677 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1678 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1679 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1680 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1681 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1682 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1683 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1684 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1685 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1686 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1687 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1688 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1695 /* should not call 'gst_message_unref(msg)' */
1700 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1706 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1707 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1709 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1710 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1711 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1713 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1714 LOGD("data total size of http content: %lld", bytes);
1715 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1718 /* handling audio clip which has vbr. means duration is keep changing */
1719 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1726 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1727 mm_player_spherical_metadata_t *metadata) {
1728 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1729 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1730 gst_tag_list_get_string(tags, "stitching_software",
1731 &metadata->stitching_software);
1732 gst_tag_list_get_string(tags, "projection_type",
1733 &metadata->projection_type_string);
1734 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1735 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1736 gst_tag_list_get_int(tags, "init_view_heading",
1737 &metadata->init_view_heading);
1738 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1739 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1740 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1741 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1742 &metadata->full_pano_width_pixels);
1743 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1744 &metadata->full_pano_height_pixels);
1745 gst_tag_list_get_int(tags, "cropped_area_image_width",
1746 &metadata->cropped_area_image_width);
1747 gst_tag_list_get_int(tags, "cropped_area_image_height",
1748 &metadata->cropped_area_image_height);
1749 gst_tag_list_get_int(tags, "cropped_area_left",
1750 &metadata->cropped_area_left);
1751 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1752 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1753 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1754 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1758 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1761 /* macro for better code readability */
1762 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1763 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1764 if (string != NULL) { \
1765 SECURE_LOGD("update tag string : %s\n", string); \
1766 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1767 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1768 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1769 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1770 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1771 g_free(new_string); \
1772 new_string = NULL; \
1774 mm_attrs_set_string_by_name(attribute, playertag, string); \
1781 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1783 GstSample *sample = NULL;\
1784 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1785 GstMapInfo info = GST_MAP_INFO_INIT;\
1786 buffer = gst_sample_get_buffer(sample);\
1787 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1788 LOGD("failed to get image data from tag");\
1789 gst_sample_unref(sample);\
1792 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1793 MMPLAYER_FREEIF(player->album_art);\
1794 player->album_art = (gchar *)g_malloc(info.size);\
1795 if (player->album_art) {\
1796 memcpy(player->album_art, info.data, info.size);\
1797 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1798 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1799 msg_param.data = (void *)player->album_art;\
1800 msg_param.size = info.size;\
1801 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1802 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1805 gst_buffer_unmap(buffer, &info);\
1806 gst_sample_unref(sample);\
1810 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1812 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1815 gchar *tag_list_str = NULL; \
1816 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1817 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1818 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1819 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1820 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1822 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1823 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1824 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1825 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1826 player->bitrate[track_type] = v_uint; \
1827 player->total_bitrate = 0; \
1828 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1829 player->total_bitrate += player->bitrate[i]; \
1830 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1831 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1832 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1833 player->maximum_bitrate[track_type] = v_uint; \
1834 player->total_maximum_bitrate = 0; \
1835 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1836 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1837 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1838 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1840 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1843 g_free(tag_list_str); \
1848 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1849 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1850 if (date != NULL) {\
1851 string = g_strdup_printf("%d", g_date_get_year(date));\
1852 mm_attrs_set_string_by_name(attribute, playertag, string);\
1853 SECURE_LOGD("metainfo year : %s\n", string);\
1854 MMPLAYER_FREEIF(string);\
1859 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1860 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1861 if (datetime != NULL) {\
1862 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1863 mm_attrs_set_string_by_name(attribute, playertag, string);\
1864 SECURE_LOGD("metainfo year : %s\n", string);\
1865 MMPLAYER_FREEIF(string);\
1866 gst_date_time_unref(datetime);\
1870 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1871 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1873 /* FIXIT : don't know how to store date */\
1879 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1880 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1882 /* FIXIT : don't know how to store date */\
1888 /* function start */
1889 GstTagList* tag_list = NULL;
1891 MMHandleType attrs = 0;
1893 char *string = NULL;
1896 GstDateTime *datetime = NULL;
1898 GstBuffer *buffer = NULL;
1900 MMMessageParamType msg_param = {0, };
1902 /* currently not used. but those are needed for above macro */
1903 //guint64 v_uint64 = 0;
1904 //gdouble v_double = 0;
1906 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1908 attrs = MMPLAYER_GET_ATTRS(player);
1910 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1912 /* get tag list from gst message */
1913 gst_message_parse_tag(msg, &tag_list);
1915 /* store tags to player attributes */
1916 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1917 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1918 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1920 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1922 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1923 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1924 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1925 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1927 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1928 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1929 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1930 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1931 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1932 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1933 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1937 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1938 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1940 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1941 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1942 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1943 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1944 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1945 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1946 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1947 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1948 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1949 MMPLAYER_UPDATE_TAG_LOCK(player);
1950 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1951 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1952 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1953 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1954 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1955 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1956 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1958 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1959 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1961 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1962 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1963 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1964 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1966 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1967 if (player->video360_metadata.is_spherical == -1) {
1968 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1969 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1970 player->video360_metadata.is_spherical);
1971 if (player->video360_metadata.is_spherical == 1) {
1972 LOGD("This is spherical content for 360 playback.");
1973 player->is_content_spherical = TRUE;
1975 LOGD("This is not spherical content");
1976 player->is_content_spherical = FALSE;
1979 if (player->video360_metadata.projection_type_string) {
1980 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1981 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1983 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1984 player->is_content_spherical = player->is_video360_enabled = FALSE;
1988 if (player->video360_metadata.stereo_mode_string) {
1989 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1990 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1991 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1992 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1993 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1994 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1996 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1997 player->is_content_spherical = player->is_video360_enabled = FALSE;
2003 if (mmf_attrs_commit(attrs))
2004 LOGE("failed to commit.\n");
2006 gst_tag_list_free(tag_list);
2012 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2014 mm_player_t* player = (mm_player_t*) data;
2018 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2019 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2020 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2021 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2023 * [1] audio and video will be dumped with filesink.
2024 * [2] autoplugging is done by just using pad caps.
2025 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2026 * and the video will be dumped via filesink.
2028 if (player->num_dynamic_pad == 0) {
2029 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2031 if (!__mmplayer_gst_remove_fakesink(player,
2032 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2033 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2034 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2035 * source element are not same. To overcome this situation, this function will called
2036 * several places and several times. Therefore, this is not an error case.
2041 /* create dot before error-return. for debugging */
2042 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2044 player->no_more_pad = TRUE;
2050 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2052 GstElement* parent = NULL;
2054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2056 /* if we have no fakesink. this meas we are using decodebin which doesn'
2057 t need to add extra fakesink */
2058 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2061 MMPLAYER_FSINK_LOCK(player);
2066 /* get parent of fakesink */
2067 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2069 LOGD("fakesink already removed\n");
2073 gst_element_set_locked_state(fakesink->gst, TRUE);
2075 /* setting the state to NULL never returns async
2076 * so no need to wait for completion of state transiton
2078 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2079 LOGE("fakesink state change failure!\n");
2080 /* FIXIT : should I return here? or try to proceed to next? */
2083 /* remove fakesink from it's parent */
2084 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2085 LOGE("failed to remove fakesink\n");
2087 gst_object_unref(parent);
2092 gst_object_unref(parent);
2094 LOGD("state-holder removed\n");
2096 gst_element_set_locked_state(fakesink->gst, FALSE);
2098 MMPLAYER_FSINK_UNLOCK(player);
2103 gst_element_set_locked_state(fakesink->gst, FALSE);
2105 MMPLAYER_FSINK_UNLOCK(player);
2111 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2113 GstPad *sinkpad = NULL;
2114 GstCaps* caps = NULL;
2115 GstElement* new_element = NULL;
2116 GstStructure* str = NULL;
2117 const gchar* name = NULL;
2119 mm_player_t* player = (mm_player_t*) data;
2123 MMPLAYER_RETURN_IF_FAIL(element && pad);
2124 MMPLAYER_RETURN_IF_FAIL(player &&
2126 player->pipeline->mainbin);
2129 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2130 * num_dynamic_pad will decreased after creating a sinkbin.
2132 player->num_dynamic_pad++;
2133 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2135 caps = gst_pad_query_caps(pad, NULL);
2137 MMPLAYER_CHECK_NULL(caps);
2139 /* clear previous result*/
2140 player->have_dynamic_pad = FALSE;
2142 str = gst_caps_get_structure(caps, 0);
2145 LOGE("cannot get structure from caps.\n");
2149 name = gst_structure_get_name(str);
2151 LOGE("cannot get mimetype from structure.\n");
2155 if (strstr(name, "video")) {
2157 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2159 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2160 if (player->v_stream_caps) {
2161 gst_caps_unref(player->v_stream_caps);
2162 player->v_stream_caps = NULL;
2165 new_element = gst_element_factory_make("fakesink", NULL);
2166 player->num_dynamic_pad--;
2171 /* clear previous result*/
2172 player->have_dynamic_pad = FALSE;
2174 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2175 LOGE("failed to autoplug for caps");
2179 /* check if there's dynamic pad*/
2180 if (player->have_dynamic_pad) {
2181 LOGE("using pad caps assums there's no dynamic pad !\n");
2185 gst_caps_unref(caps);
2190 /* excute new_element if created*/
2192 LOGD("adding new element to pipeline\n");
2194 /* set state to READY before add to bin */
2195 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2197 /* add new element to the pipeline */
2198 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2199 LOGE("failed to add autoplug element to bin\n");
2203 /* get pad from element */
2204 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2206 LOGE("failed to get sinkpad from autoplug element\n");
2211 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2212 LOGE("failed to link autoplug element\n");
2216 gst_object_unref(sinkpad);
2219 /* run. setting PLAYING here since streamming source is live source */
2220 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2224 gst_caps_unref(caps);
2230 STATE_CHANGE_FAILED:
2232 /* FIXIT : take care if new_element has already added to pipeline */
2234 gst_object_unref(GST_OBJECT(new_element));
2237 gst_object_unref(GST_OBJECT(sinkpad));
2240 gst_caps_unref(caps);
2242 /* FIXIT : how to inform this error to MSL ????? */
2243 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2244 * then post an error to application
2248 static GstPadProbeReturn
2249 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2251 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2252 return GST_PAD_PROBE_OK;
2255 static GstPadProbeReturn
2256 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2258 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2259 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2260 mm_player_t* player = (mm_player_t*)data;
2261 GstCaps* caps = NULL;
2262 GstStructure* str = NULL;
2263 const gchar* name = NULL;
2264 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2267 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2268 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2269 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2270 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2271 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2273 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2274 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2278 caps = gst_pad_query_caps(pad, NULL);
2280 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2284 str = gst_caps_get_structure(caps, 0);
2286 LOGE("failed to get structure from caps");
2290 name = gst_structure_get_name(str);
2292 LOGE("failed to get name from str");
2296 if (strstr(name, "audio")) {
2297 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2298 } else if (strstr(name, "video")) {
2299 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2301 /* text track is not supportable */
2302 LOGE("invalid name %s", name);
2306 switch (GST_EVENT_TYPE(event)) {
2309 /* in case of gapless, drop eos event not to send it to sink */
2310 if (player->gapless.reconfigure && !player->msg_posted) {
2311 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2312 ret = GST_PAD_PROBE_DROP;
2316 case GST_EVENT_STREAM_START:
2318 gint64 stop_running_time = 0;
2319 gint64 position_running_time = 0;
2320 gint64 position = 0;
2323 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2324 if ((player->gapless.update_segment[idx] == TRUE) ||
2325 !(player->selector[idx].event_probe_id)) {
2326 /* LOGW("[%d] skip", idx); */
2330 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2332 gst_segment_to_running_time(&player->gapless.segment[idx],
2333 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2334 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2336 gst_segment_to_running_time(&player->gapless.segment[idx],
2337 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2339 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2341 gst_segment_to_running_time(&player->gapless.segment[idx],
2342 GST_FORMAT_TIME, player->duration);
2345 position_running_time =
2346 gst_segment_to_running_time(&player->gapless.segment[idx],
2347 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2349 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2350 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2352 GST_TIME_ARGS(stop_running_time),
2353 GST_TIME_ARGS(position_running_time),
2354 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2355 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2357 position_running_time = MAX(position_running_time, stop_running_time);
2358 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2359 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2360 position_running_time = MAX(0, position_running_time);
2361 position = MAX(position, position_running_time);
2364 if (position != 0) {
2365 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2366 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2367 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2369 player->gapless.start_time[stream_type] += position;
2373 case GST_EVENT_FLUSH_STOP:
2375 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2376 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2377 player->gapless.start_time[stream_type] = 0;
2380 case GST_EVENT_SEGMENT:
2385 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2386 gst_event_copy_segment(event, &segment);
2388 if (segment.format == GST_FORMAT_TIME) {
2389 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2390 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2391 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2392 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2393 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2394 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2396 /* keep the all the segment ev to cover the seeking */
2397 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2398 player->gapless.update_segment[stream_type] = TRUE;
2400 if (!player->gapless.running)
2403 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2405 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2407 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2408 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2409 gst_event_unref(event);
2410 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2416 gdouble proportion = 0.0;
2417 GstClockTimeDiff diff = 0;
2418 GstClockTime timestamp = 0;
2419 gint64 running_time_diff = -1;
2420 GstQOSType type = 0;
2421 GstEvent *tmpev = NULL;
2423 running_time_diff = player->gapless.segment[stream_type].base;
2425 if (running_time_diff <= 0) /* don't need to adjust */
2428 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2429 gst_event_unref(event);
2431 if (timestamp < running_time_diff) {
2432 LOGW("QOS event from previous group");
2433 ret = GST_PAD_PROBE_DROP;
2437 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2438 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2439 stream_type, GST_TIME_ARGS(timestamp),
2440 GST_TIME_ARGS(running_time_diff),
2441 GST_TIME_ARGS(timestamp - running_time_diff));
2443 timestamp -= running_time_diff;
2445 /* That case is invalid for QoS events */
2446 if (diff < 0 && -diff > timestamp) {
2447 LOGW("QOS event from previous group");
2448 ret = GST_PAD_PROBE_DROP;
2452 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2453 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2463 gst_caps_unref(caps);
2468 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2470 mm_player_t* player = NULL;
2471 GstElement* pipeline = NULL;
2472 GstElement* selector = NULL;
2473 GstElement* fakesink = NULL;
2474 GstCaps* caps = NULL;
2475 GstStructure* str = NULL;
2476 const gchar* name = NULL;
2477 GstPad* sinkpad = NULL;
2478 GstPad* srcpad = NULL;
2479 gboolean first_track = FALSE;
2481 enum MainElementID elemId = MMPLAYER_M_NUM;
2482 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2485 player = (mm_player_t*)data;
2487 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2488 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2490 //LOGD("pad-added signal handling\n");
2492 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2494 /* get mimetype from caps */
2495 caps = gst_pad_query_caps(pad, NULL);
2497 LOGE("cannot get caps from pad.\n");
2501 str = gst_caps_get_structure(caps, 0);
2503 LOGE("cannot get structure from caps.\n");
2507 name = gst_structure_get_name(str);
2509 LOGE("cannot get mimetype from structure.\n");
2513 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2514 //LOGD("detected mimetype : %s\n", name);
2516 if (strstr(name, "video")) {
2519 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2520 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2522 /* don't make video because of not required, and not support multiple track */
2523 if (stype == MM_DISPLAY_SURFACE_NULL) {
2524 LOGD("no video sink by null surface");
2526 gchar *caps_str = gst_caps_to_string(caps);
2527 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2528 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2529 player->set_mode.video_zc = TRUE;
2531 MMPLAYER_FREEIF(caps_str);
2533 if (player->v_stream_caps) {
2534 gst_caps_unref(player->v_stream_caps);
2535 player->v_stream_caps = NULL;
2538 LOGD("create fakesink instead of videobin");
2541 fakesink = gst_element_factory_make("fakesink", NULL);
2542 if (fakesink == NULL) {
2543 LOGE("ERROR : fakesink create error\n");
2547 if (player->ini.set_dump_element_flag)
2548 __mmplayer_add_dump_buffer_probe(player, fakesink);
2550 player->video_fakesink = fakesink;
2552 /* store it as it's sink element */
2553 __mmplayer_add_sink(player, player->video_fakesink);
2555 gst_bin_add(GST_BIN(pipeline), fakesink);
2558 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2560 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2561 LOGW("failed to link fakesink\n");
2562 gst_object_unref(GST_OBJECT(fakesink));
2566 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2567 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2568 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2571 if (player->set_mode.media_packet_video_stream) {
2572 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2574 MMPLAYER_SIGNAL_CONNECT(player,
2576 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2578 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2581 MMPLAYER_SIGNAL_CONNECT(player,
2583 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2585 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2589 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2590 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2594 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2595 __mmplayer_gst_decode_callback(elem, pad, player);
2599 LOGD("video selector \n");
2600 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2601 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2603 if (strstr(name, "audio")) {
2604 gint samplerate = 0;
2607 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2608 __mmplayer_gst_decode_callback(elem, pad, player);
2612 LOGD("audio selector \n");
2613 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2614 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2616 gst_structure_get_int(str, "rate", &samplerate);
2617 gst_structure_get_int(str, "channels", &channels);
2619 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2621 fakesink = gst_element_factory_make("fakesink", NULL);
2622 if (fakesink == NULL) {
2623 LOGE("ERROR : fakesink create error\n");
2627 gst_bin_add(GST_BIN(pipeline), fakesink);
2630 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2632 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2633 LOGW("failed to link fakesink\n");
2634 gst_object_unref(GST_OBJECT(fakesink));
2638 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2639 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2640 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2644 } else if (strstr(name, "text")) {
2645 LOGD("text selector \n");
2646 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2647 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2649 LOGE("wrong elem id \n");
2654 selector = player->pipeline->mainbin[elemId].gst;
2655 if (selector == NULL) {
2656 selector = gst_element_factory_make("input-selector", NULL);
2657 LOGD("Creating input-selector\n");
2658 if (selector == NULL) {
2659 LOGE("ERROR : input-selector create error\n");
2662 g_object_set(selector, "sync-streams", TRUE, NULL);
2664 player->pipeline->mainbin[elemId].id = elemId;
2665 player->pipeline->mainbin[elemId].gst = selector;
2668 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2670 srcpad = gst_element_get_static_pad(selector, "src");
2672 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2673 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2674 __mmplayer_gst_selector_blocked, NULL, NULL);
2675 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2676 __mmplayer_gst_selector_event_probe, player, NULL);
2678 gst_element_set_state(selector, GST_STATE_PAUSED);
2679 gst_bin_add(GST_BIN(pipeline), selector);
2681 LOGD("input-selector is already created.\n");
2684 LOGD("Calling request pad with selector %p \n", selector);
2685 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2687 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2689 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2690 LOGW("failed to link selector\n");
2691 gst_object_unref(GST_OBJECT(selector));
2696 LOGD("this is first track --> active track \n");
2697 g_object_set(selector, "active-pad", sinkpad, NULL);
2700 _mmplayer_track_update_info(player, stream_type, sinkpad);
2707 gst_caps_unref(caps);
2710 gst_object_unref(GST_OBJECT(sinkpad));
2715 gst_object_unref(GST_OBJECT(srcpad));
2722 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2724 GstPad* srcpad = NULL;
2725 MMHandleType attrs = 0;
2726 gint active_index = 0;
2728 // [link] input-selector :: textbin
2729 srcpad = gst_element_get_static_pad(text_selector, "src");
2731 LOGE("failed to get srcpad from selector\n");
2735 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2737 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2738 if ((active_index != DEFAULT_TRACK) &&
2739 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2740 LOGW("failed to change text track\n");
2741 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2744 player->no_more_pad = TRUE;
2745 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2747 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2748 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2749 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2750 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2753 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2755 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2756 player->has_closed_caption = TRUE;
2758 attrs = MMPLAYER_GET_ATTRS(player);
2760 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2761 if (mmf_attrs_commit(attrs))
2762 LOGE("failed to commit.\n");
2764 LOGE("cannot get content attribute");
2767 gst_object_unref(GST_OBJECT(srcpad));
2773 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2775 mm_player_t* player = (mm_player_t*)data;
2776 GstElement* selector = NULL;
2777 GstElement* queue = NULL;
2779 GstPad* srcpad = NULL;
2780 GstPad* sinkpad = NULL;
2781 GstCaps* caps = NULL;
2782 gchar* caps_str = NULL;
2785 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2787 caps = gst_pad_get_current_caps(pad);
2788 caps_str = gst_caps_to_string(caps);
2789 LOGD("deinterleave new caps : %s\n", caps_str);
2790 MMPLAYER_FREEIF(caps_str);
2791 gst_caps_unref(caps);
2793 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2794 LOGE("ERROR : queue create error\n");
2798 g_object_set(G_OBJECT(queue),
2799 "max-size-buffers", 10,
2800 "max-size-bytes", 0,
2801 "max-size-time", (guint64)0,
2804 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2807 LOGE("there is no audio channel selector.\n");
2811 srcpad = gst_element_get_static_pad(queue, "src");
2812 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2814 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2816 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2817 LOGW("failed to link deinterleave - selector\n");
2821 gst_element_set_state(queue, GST_STATE_PAUSED);
2822 player->audio_mode.total_track_num++;
2827 gst_object_unref(GST_OBJECT(srcpad));
2832 gst_object_unref(GST_OBJECT(sinkpad));
2841 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2843 mm_player_t* player = NULL;
2844 GstElement* selector = NULL;
2845 GstPad* sinkpad = NULL;
2846 gint active_index = 0;
2847 gchar* change_pad_name = NULL;
2848 GstCaps* caps = NULL; // no need to unref
2849 gint default_audio_ch = 0;
2852 player = (mm_player_t*) data;
2854 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2857 LOGE("there is no audio channel selector.\n");
2861 active_index = player->audio_mode.active_pad_index;
2863 if (active_index != default_audio_ch) {
2864 gint audio_ch = default_audio_ch;
2866 /*To get the new pad from the selector*/
2867 change_pad_name = g_strdup_printf("sink%d", active_index);
2868 if (change_pad_name != NULL) {
2869 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2870 if (sinkpad != NULL) {
2871 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2872 g_object_set(selector, "active-pad", sinkpad, NULL);
2874 audio_ch = active_index;
2876 caps = gst_pad_get_current_caps(sinkpad);
2877 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2879 __mmplayer_set_audio_attrs(player, caps);
2880 gst_caps_unref(caps);
2882 MMPLAYER_FREEIF(change_pad_name);
2885 player->audio_mode.active_pad_index = audio_ch;
2886 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2892 gst_object_unref(sinkpad);
2899 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2901 mm_player_t* player = NULL;
2902 MMPlayerGstElement *mainbin = NULL;
2904 GstElement* tee = NULL;
2905 GstElement* stereo_queue = NULL;
2906 GstElement* mono_queue = NULL;
2907 GstElement* conv = NULL;
2908 GstElement* filter = NULL;
2909 GstElement* deinterleave = NULL;
2910 GstElement* selector = NULL;
2912 GstPad* srcpad = NULL;
2913 GstPad* selector_srcpad = NULL;
2914 GstPad* sinkpad = NULL;
2915 GstCaps* caps = NULL;
2916 gulong block_id = 0;
2921 player = (mm_player_t*) data;
2923 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2924 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2926 mainbin = player->pipeline->mainbin;
2929 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2930 LOGE("ERROR : tee create error\n");
2934 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2935 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2937 gst_element_set_state(tee, GST_STATE_PAUSED);
2940 srcpad = gst_element_get_request_pad(tee, "src_%u");
2941 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2942 LOGE("ERROR : stereo queue create error\n");
2946 g_object_set(G_OBJECT(stereo_queue),
2947 "max-size-buffers", 10,
2948 "max-size-bytes", 0,
2949 "max-size-time", (guint64)0,
2952 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2953 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2956 gst_object_unref(GST_OBJECT(srcpad));
2960 srcpad = gst_element_get_request_pad(tee, "src_%u");
2962 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2963 LOGE("ERROR : mono queue create error\n");
2967 g_object_set(G_OBJECT(mono_queue),
2968 "max-size-buffers", 10,
2969 "max-size-bytes", 0,
2970 "max-size-time", (guint64)0,
2973 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2974 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2976 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2977 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2980 srcpad = gst_element_get_static_pad(mono_queue, "src");
2981 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2982 LOGE("ERROR : audioconvert create error\n");
2986 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2987 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2991 gst_object_unref(GST_OBJECT(srcpad));
2994 srcpad = gst_element_get_static_pad(conv, "src");
2996 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2997 LOGE("ERROR : capsfilter create error\n");
3001 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3002 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3004 caps = gst_caps_from_string("audio/x-raw-int, "
3005 "width = (int) 16, "
3006 "depth = (int) 16, "
3007 "channels = (int) 2");
3009 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3010 gst_caps_unref(caps);
3012 gst_element_set_state(conv, GST_STATE_PAUSED);
3013 gst_element_set_state(filter, GST_STATE_PAUSED);
3017 gst_object_unref(GST_OBJECT(srcpad));
3020 srcpad = gst_element_get_static_pad(filter, "src");
3022 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3023 LOGE("ERROR : deinterleave create error\n");
3027 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3029 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3030 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3032 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3033 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3035 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3036 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3039 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3040 if (selector == NULL) {
3041 LOGE("ERROR : audio-selector create error\n");
3045 g_object_set(selector, "sync-streams", TRUE, NULL);
3046 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3048 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3049 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3051 selector_srcpad = gst_element_get_static_pad(selector, "src");
3053 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3055 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3056 __mmplayer_gst_selector_blocked, NULL, NULL);
3059 gst_object_unref(GST_OBJECT(srcpad));
3063 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3064 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3066 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3067 LOGW("failed to link queue_stereo - selector\n");
3071 player->audio_mode.total_track_num++;
3073 g_object_set(selector, "active-pad", sinkpad, NULL);
3074 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3075 gst_element_set_state(selector, GST_STATE_PAUSED);
3077 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3081 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3082 if (block_id != 0) {
3083 gst_pad_remove_probe(selector_srcpad, block_id);
3088 gst_object_unref(GST_OBJECT(sinkpad));
3093 gst_object_unref(GST_OBJECT(srcpad));
3097 if (selector_srcpad) {
3098 gst_object_unref(GST_OBJECT(selector_srcpad));
3099 selector_srcpad = NULL;
3107 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3109 mm_player_t* player = NULL;
3110 GstPad* srcpad = NULL;
3111 GstElement* video_selector = NULL;
3112 GstElement* audio_selector = NULL;
3113 GstElement* text_selector = NULL;
3114 MMHandleType attrs = 0;
3115 gint active_index = 0;
3116 gint64 dur_bytes = 0L;
3118 player = (mm_player_t*) data;
3120 LOGD("no-more-pad signal handling\n");
3122 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3123 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3124 LOGW("no need to go more");
3126 if (player->gapless.reconfigure) {
3127 player->gapless.reconfigure = FALSE;
3128 MMPLAYER_PLAYBACK_UNLOCK(player);
3134 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3135 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3136 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3137 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3138 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3140 if (NULL == player->streamer) {
3141 LOGW("invalid state for buffering");
3145 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3146 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3148 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3149 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3151 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3153 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3154 LOGE("fail to get duration.\n");
3156 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3157 // use file information was already set on Q2 when it was created.
3158 __mm_player_streaming_set_queue2(player->streamer,
3159 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3160 TRUE, // use_buffering
3162 init_buffering_time,
3164 player->ini.http_buffering_limit, // high percent
3165 MUXED_BUFFER_TYPE_MEM_QUEUE,
3167 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3170 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3171 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3172 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3173 if (video_selector) {
3174 // [link] input-selector :: videobin
3175 srcpad = gst_element_get_static_pad(video_selector, "src");
3177 LOGE("failed to get srcpad from video selector\n");
3181 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3182 if (!text_selector && !audio_selector)
3183 player->no_more_pad = TRUE;
3185 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3187 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3188 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3189 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3190 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3194 if (audio_selector) {
3195 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3196 if ((active_index != DEFAULT_TRACK) &&
3197 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3198 LOGW("failed to change audio track\n");
3199 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3202 // [link] input-selector :: audiobin
3203 srcpad = gst_element_get_static_pad(audio_selector, "src");
3205 LOGE("failed to get srcpad from selector\n");
3209 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3211 player->no_more_pad = TRUE;
3213 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3214 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3215 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3216 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3217 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3220 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3222 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3224 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3225 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3226 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3227 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3231 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3233 attrs = MMPLAYER_GET_ATTRS(player);
3235 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3236 if (mmf_attrs_commit(attrs))
3237 LOGE("failed to commit.\n");
3239 LOGE("cannot get content attribute");
3241 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3242 LOGD("There is no audio track : remove audiobin");
3244 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3245 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3247 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3248 MMPLAYER_FREEIF(player->pipeline->audiobin);
3251 if (player->num_dynamic_pad == 0)
3252 __mmplayer_pipeline_complete(NULL, player);
3255 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3257 __mmplayer_handle_text_decode_path(player, text_selector);
3264 gst_object_unref(GST_OBJECT(srcpad));
3268 if (player->gapless.reconfigure) {
3269 player->gapless.reconfigure = FALSE;
3270 MMPLAYER_PLAYBACK_UNLOCK(player);
3275 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3277 mm_player_t* player = NULL;
3278 MMHandleType attrs = 0;
3279 GstElement* pipeline = NULL;
3280 GstCaps* caps = NULL;
3281 gchar* caps_str = NULL;
3282 GstStructure* str = NULL;
3283 const gchar* name = NULL;
3284 GstPad* sinkpad = NULL;
3285 GstElement* sinkbin = NULL;
3286 gboolean reusing = FALSE;
3287 GstElement *text_selector = NULL;
3290 player = (mm_player_t*) data;
3292 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3293 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3295 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3297 attrs = MMPLAYER_GET_ATTRS(player);
3299 LOGE("cannot get content attribute\n");
3303 /* get mimetype from caps */
3304 caps = gst_pad_query_caps(pad, NULL);
3306 LOGE("cannot get caps from pad.\n");
3309 caps_str = gst_caps_to_string(caps);
3311 str = gst_caps_get_structure(caps, 0);
3313 LOGE("cannot get structure from caps.\n");
3317 name = gst_structure_get_name(str);
3319 LOGE("cannot get mimetype from structure.\n");
3323 //LOGD("detected mimetype : %s\n", name);
3325 if (strstr(name, "audio")) {
3326 if (player->pipeline->audiobin == NULL) {
3327 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3328 LOGE("failed to create audiobin. continuing without audio\n");
3332 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3333 LOGD("creating audiosink bin success\n");
3336 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3337 LOGD("reusing audiobin\n");
3338 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3341 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3342 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3344 player->audiosink_linked = 1;
3346 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3348 LOGE("failed to get pad from sinkbin\n");
3351 } else if (strstr(name, "video")) {
3352 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3353 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3354 player->set_mode.video_zc = TRUE;
3356 if (player->pipeline->videobin == NULL) {
3357 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3358 /* get video surface type */
3359 int surface_type = 0;
3360 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3361 LOGD("display_surface_type(%d)\n", surface_type);
3363 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3364 LOGD("not make videobin because it dose not want\n");
3368 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3369 /* mark video overlay for acquire */
3370 if (player->video_overlay_resource == NULL) {
3371 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3372 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3373 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3374 &player->video_overlay_resource)
3375 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3376 LOGE("could not mark video_overlay resource for acquire\n");
3382 player->interrupted_by_resource = FALSE;
3383 /* acquire resources for video overlay */
3384 if (mm_resource_manager_commit(player->resource_manager) !=
3385 MM_RESOURCE_MANAGER_ERROR_NONE) {
3386 LOGE("could not acquire resources for video playing\n");
3390 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3391 LOGE("failed to create videobin. continuing without video\n");
3395 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3396 LOGD("creating videosink bin success\n");
3399 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3400 LOGD("re-using videobin\n");
3401 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3404 player->videosink_linked = 1;
3406 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3408 LOGE("failed to get pad from sinkbin\n");
3411 } else if (strstr(name, "text")) {
3412 if (player->pipeline->textbin == NULL) {
3413 MMPlayerGstElement* mainbin = NULL;
3415 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3416 LOGE("failed to create text sink bin. continuing without text\n");
3420 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3421 LOGD("creating textsink bin success\n");
3423 /* FIXIT : track number shouldn't be hardcoded */
3424 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3426 player->textsink_linked = 1;
3427 LOGI("player->textsink_linked set to 1\n");
3429 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3431 LOGE("failed to get pad from sinkbin\n");
3435 mainbin = player->pipeline->mainbin;
3437 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3438 /* input selector */
3439 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3440 if (!text_selector) {
3441 LOGE("failed to create subtitle input selector element\n");
3444 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3446 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3447 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3450 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3451 LOGE("failed to set state(READY) to sinkbin\n");
3455 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3456 LOGW("failed to add subtitle input selector\n");
3460 LOGD("created element input-selector");
3463 LOGD("already having subtitle input selector");
3464 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3467 if (!player->textsink_linked) {
3468 LOGD("re-using textbin\n");
3471 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3473 player->textsink_linked = 1;
3474 LOGI("player->textsink_linked set to 1\n");
3476 LOGD("ignoring internal subtutle since external subtitle is available");
3479 LOGW("unknown type of elementary stream!ignoring it...\n");
3486 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3487 LOGE("failed to set state(READY) to sinkbin\n");
3491 /* Added for multi audio support to avoid adding audio bin again*/
3493 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3494 LOGE("failed to add sinkbin to pipeline\n");
3500 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3501 LOGE("failed to get pad from sinkbin\n");
3507 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3508 LOGE("failed to set state(PAUSED) to sinkbin\n");
3512 if (text_selector) {
3513 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3514 LOGE("failed to set state(PAUSED) to sinkbin\n");
3520 gst_object_unref(sinkpad);
3524 LOGD("[handle: %p] linking sink bin success", player);
3526 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3527 * streaming task. if the task blocked, then buffer will not flow to the next element
3528 *(autoplugging element). so this is special hack for streaming. please try to remove it
3530 /* dec stream count. we can remove fakesink if it's zero */
3531 if (player->num_dynamic_pad)
3532 player->num_dynamic_pad--;
3534 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3536 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3537 __mmplayer_pipeline_complete(NULL, player);
3541 MMPLAYER_FREEIF(caps_str);
3544 gst_caps_unref(caps);
3547 gst_object_unref(GST_OBJECT(sinkpad));
3549 /* flusing out new attributes */
3550 if (mmf_attrs_commit(attrs))
3551 LOGE("failed to comit attributes\n");
3557 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3559 int pro_value = 0; // in the case of expection, default will be returned.
3560 int dest_angle = rotation_angle;
3561 int rotation_type = -1;
3563 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3564 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3565 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3567 if (rotation_angle >= 360)
3568 dest_angle = rotation_angle - 360;
3570 /* chech if supported or not */
3571 if (dest_angle % 90) {
3572 LOGD("not supported rotation angle = %d", rotation_angle);
3578 * custom_convert - none (B)
3579 * videoflip - none (C)
3581 if (player->set_mode.video_zc) {
3582 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3583 rotation_type = ROTATION_USING_CUSTOM;
3585 rotation_type = ROTATION_USING_SINK;
3587 int surface_type = 0;
3588 rotation_type = ROTATION_USING_FLIP;
3590 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3591 LOGD("check display surface type attribute: %d", surface_type);
3593 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3594 rotation_type = ROTATION_USING_SINK;
3596 rotation_type = ROTATION_USING_FLIP; //C
3598 LOGD("using %d type for rotation", rotation_type);
3601 /* get property value for setting */
3602 switch (rotation_type) {
3603 case ROTATION_USING_SINK: // tizenwlsink
3605 switch (dest_angle) {
3609 pro_value = 3; // clockwise 90
3615 pro_value = 1; // counter-clockwise 90
3620 case ROTATION_USING_CUSTOM:
3622 gchar *ename = NULL;
3623 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3625 if (g_strrstr(ename, "fimcconvert")) {
3626 switch (dest_angle) {
3630 pro_value = 90; // clockwise 90
3636 pro_value = 270; // counter-clockwise 90
3642 case ROTATION_USING_FLIP: // videoflip
3644 switch (dest_angle) {
3648 pro_value = 1; // clockwise 90
3654 pro_value = 3; // counter-clockwise 90
3661 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3669 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3671 /* check video sinkbin is created */
3672 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3674 player->pipeline->videobin &&
3675 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3676 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3677 MM_ERROR_PLAYER_NOT_INITIALIZED);
3679 return MM_ERROR_NONE;
3683 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3685 int rotation_value = 0;
3686 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3690 /* check video sinkbin is created */
3691 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3694 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3696 /* get rotation value to set */
3697 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3698 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3699 LOGD("set video param : rotate %d", rotation_value);
3703 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3705 MMHandleType attrs = 0;
3709 /* check video sinkbin is created */
3710 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3713 attrs = MMPLAYER_GET_ATTRS(player);
3714 MMPLAYER_RETURN_IF_FAIL(attrs);
3716 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3717 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3718 LOGD("set video param : visible %d", visible);
3722 __mmplayer_video_param_set_display_method(mm_player_t* player)
3724 MMHandleType attrs = 0;
3725 int display_method = 0;
3728 /* check video sinkbin is created */
3729 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3732 attrs = MMPLAYER_GET_ATTRS(player);
3733 MMPLAYER_RETURN_IF_FAIL(attrs);
3735 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3736 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3737 LOGD("set video param : method %d", display_method);
3741 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3743 MMHandleType attrs = 0;
3744 void *handle = NULL;
3746 int wl_window_x = 0;
3747 int wl_window_y = 0;
3748 int wl_window_width = 0;
3749 int wl_window_height = 0;
3752 /* check video sinkbin is created */
3753 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3756 attrs = MMPLAYER_GET_ATTRS(player);
3757 MMPLAYER_RETURN_IF_FAIL(attrs);
3759 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3762 /*It should be set after setting window*/
3763 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3764 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3765 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3766 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3768 /* After setting window handle, set render rectangle */
3769 gst_video_overlay_set_render_rectangle(
3770 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3771 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3772 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3773 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3778 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3780 MMHandleType attrs = 0;
3781 void *handle = NULL;
3783 /* check video sinkbin is created */
3784 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3787 attrs = MMPLAYER_GET_ATTRS(player);
3788 MMPLAYER_RETURN_IF_FAIL(attrs);
3790 /* common case if using overlay surface */
3791 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3794 /* default is using wl_surface_id */
3795 unsigned int wl_surface_id = 0;
3796 wl_surface_id = *(int*)handle;
3797 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3798 gst_video_overlay_set_wl_window_wl_surface_id(
3799 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3802 /* FIXIT : is it error case? */
3803 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3808 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3810 bool update_all_param = FALSE;
3813 /* check video sinkbin is created */
3814 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3815 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3817 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3818 LOGE("can not find tizenwlsink");
3819 return MM_ERROR_PLAYER_INTERNAL;
3822 LOGD("param_name : %s", param_name);
3823 if (!g_strcmp0(param_name, "update_all_param"))
3824 update_all_param = TRUE;
3826 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3827 __mmplayer_video_param_set_display_overlay(player);
3828 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3829 __mmplayer_video_param_set_display_method(player);
3830 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3831 __mmplayer_video_param_set_render_rectangle(player);
3832 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3833 __mmplayer_video_param_set_display_visible(player);
3834 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3835 __mmplayer_video_param_set_display_rotation(player);
3837 return MM_ERROR_NONE;
3841 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3843 MMHandleType attrs = 0;
3844 int surface_type = 0;
3845 int ret = MM_ERROR_NONE;
3849 /* check video sinkbin is created */
3850 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3851 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3853 attrs = MMPLAYER_GET_ATTRS(player);
3855 LOGE("cannot get content attribute");
3856 return MM_ERROR_PLAYER_INTERNAL;
3858 LOGD("param_name : %s", param_name);
3860 /* update display surface */
3861 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3862 LOGD("check display surface type attribute: %d", surface_type);
3864 /* configuring display */
3865 switch (surface_type) {
3866 case MM_DISPLAY_SURFACE_OVERLAY:
3868 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3869 if (ret != MM_ERROR_NONE)
3877 return MM_ERROR_NONE;
3881 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3883 gboolean disable_overlay = FALSE;
3884 mm_player_t* player = (mm_player_t*) hplayer;
3885 int ret = MM_ERROR_NONE;
3888 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3889 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3890 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3891 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3893 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3894 LOGW("Display control is not supported");
3895 return MM_ERROR_PLAYER_INTERNAL;
3898 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3900 if (audio_only == (bool)disable_overlay) {
3901 LOGE("It's the same with current setting: (%d)", audio_only);
3902 return MM_ERROR_NONE;
3906 LOGE("disable overlay");
3907 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3909 /* release overlay resource */
3910 if (player->video_overlay_resource != NULL) {
3911 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3912 player->video_overlay_resource);
3913 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3914 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3917 player->video_overlay_resource = NULL;
3920 ret = mm_resource_manager_commit(player->resource_manager);
3921 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3922 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3926 /* mark video overlay for acquire */
3927 if (player->video_overlay_resource == NULL) {
3928 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3929 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3930 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3931 &player->video_overlay_resource);
3932 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3933 LOGE("could not prepare for video_overlay resource\n");
3938 player->interrupted_by_resource = FALSE;
3939 /* acquire resources for video overlay */
3940 ret = mm_resource_manager_commit(player->resource_manager);
3941 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3942 LOGE("could not acquire resources for video playing\n");
3946 LOGD("enable overlay");
3947 __mmplayer_video_param_set_display_overlay(player);
3948 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3953 return MM_ERROR_NONE;
3957 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3959 mm_player_t* player = (mm_player_t*) hplayer;
3960 gboolean disable_overlay = FALSE;
3964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3965 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3966 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3967 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3968 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3970 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3971 LOGW("Display control is not supported");
3972 return MM_ERROR_PLAYER_INTERNAL;
3975 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3977 *paudio_only = (bool)(disable_overlay);
3979 LOGD("audio_only : %d", *paudio_only);
3983 return MM_ERROR_NONE;
3987 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3989 GList* bucket = element_bucket;
3990 MMPlayerGstElement* element = NULL;
3991 MMPlayerGstElement* prv_element = NULL;
3992 gint successful_link_count = 0;
3996 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3998 prv_element = (MMPlayerGstElement*)bucket->data;
3999 bucket = bucket->next;
4001 for (; bucket; bucket = bucket->next) {
4002 element = (MMPlayerGstElement*)bucket->data;
4004 if (element && element->gst) {
4005 /* If next element is audio appsrc then make a separate audio pipeline */
4006 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4007 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4008 prv_element = element;
4012 if (prv_element && prv_element->gst) {
4013 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4014 LOGD("linking [%s] to [%s] success\n",
4015 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4017 successful_link_count++;
4019 LOGD("linking [%s] to [%s] failed\n",
4020 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4021 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4027 prv_element = element;
4032 return successful_link_count;
4036 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4038 GList* bucket = element_bucket;
4039 MMPlayerGstElement* element = NULL;
4040 int successful_add_count = 0;
4044 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4045 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4047 for (; bucket; bucket = bucket->next) {
4048 element = (MMPlayerGstElement*)bucket->data;
4050 if (element && element->gst) {
4051 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4052 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4053 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4054 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4057 successful_add_count++;
4063 return successful_add_count;
4066 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4068 mm_player_t* player = (mm_player_t*) data;
4069 GstCaps *caps = NULL;
4070 GstStructure *str = NULL;
4075 MMPLAYER_RETURN_IF_FAIL(pad)
4076 MMPLAYER_RETURN_IF_FAIL(unused)
4077 MMPLAYER_RETURN_IF_FAIL(data)
4079 caps = gst_pad_get_current_caps(pad);
4083 str = gst_caps_get_structure(caps, 0);
4087 name = gst_structure_get_name(str);
4091 LOGD("name = %s\n", name);
4093 if (strstr(name, "audio")) {
4094 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4096 if (player->audio_stream_changed_cb) {
4097 LOGE("call the audio stream changed cb\n");
4098 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4100 } else if (strstr(name, "video")) {
4101 if ((name = gst_structure_get_string(str, "format")))
4102 player->set_mode.video_zc = name[0] == 'S';
4104 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4106 if (player->video_stream_changed_cb) {
4107 LOGE("call the video stream changed cb\n");
4108 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4115 gst_caps_unref(caps);
4125 * This function is to create audio pipeline for playing.
4127 * @param player [in] handle of player
4129 * @return This function returns zero on success.
4131 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4133 /* macro for code readability. just for sinkbin-creation functions */
4134 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4136 x_bin[x_id].id = x_id;\
4137 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4138 if (!x_bin[x_id].gst) {\
4139 LOGE("failed to create %s \n", x_factory);\
4142 if (x_player->ini.set_dump_element_flag)\
4143 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4146 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4150 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4155 MMPLAYER_RETURN_IF_FAIL(player);
4157 if (player->audio_stream_buff_list) {
4158 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4159 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4162 LOGD("[%lld] send remained data.", tmp->channel_mask);
4163 __mmplayer_audio_stream_send_data(player, tmp);
4166 g_free(tmp->pcm_data);
4170 g_list_free(player->audio_stream_buff_list);
4171 player->audio_stream_buff_list = NULL;
4178 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4180 MMPlayerAudioStreamDataType audio_stream = { 0, };
4183 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4185 audio_stream.bitrate = a_buffer->bitrate;
4186 audio_stream.channel = a_buffer->channel;
4187 audio_stream.depth = a_buffer->depth;
4188 audio_stream.is_little_endian = a_buffer->is_little_endian;
4189 audio_stream.channel_mask = a_buffer->channel_mask;
4190 audio_stream.data_size = a_buffer->data_size;
4191 audio_stream.data = a_buffer->pcm_data;
4193 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4194 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4200 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4202 mm_player_t* player = (mm_player_t*) data;
4207 gint endianness = 0;
4208 guint64 channel_mask = 0;
4209 void *a_data = NULL;
4211 mm_player_audio_stream_buff_t *a_buffer = NULL;
4212 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4216 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4218 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4219 a_data = mapinfo.data;
4220 a_size = mapinfo.size;
4222 GstCaps *caps = gst_pad_get_current_caps(pad);
4223 GstStructure *structure = gst_caps_get_structure(caps, 0);
4225 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4226 gst_structure_get_int(structure, "rate", &rate);
4227 gst_structure_get_int(structure, "channels", &channel);
4228 gst_structure_get_int(structure, "depth", &depth);
4229 gst_structure_get_int(structure, "endianness", &endianness);
4230 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4231 gst_caps_unref(GST_CAPS(caps));
4233 /* In case of the sync is false, use buffer list. *
4234 * The num of buffer list depends on the num of audio channels */
4235 if (player->audio_stream_buff_list) {
4236 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4237 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4239 if (channel_mask == tmp->channel_mask) {
4240 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4241 if (tmp->data_size + a_size < tmp->buff_size) {
4242 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4243 tmp->data_size += a_size;
4245 /* send data to client */
4246 __mmplayer_audio_stream_send_data(player, tmp);
4248 if (a_size > tmp->buff_size) {
4249 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4250 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4251 if (tmp->pcm_data == NULL) {
4252 LOGE("failed to realloc data.");
4255 tmp->buff_size = a_size;
4257 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4258 memcpy(tmp->pcm_data, a_data, a_size);
4259 tmp->data_size = a_size;
4264 LOGE("data is empty in list.");
4270 /* create new audio stream data */
4271 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4272 if (a_buffer == NULL) {
4273 LOGE("failed to alloc data.");
4276 a_buffer->bitrate = rate;
4277 a_buffer->channel = channel;
4278 a_buffer->depth = depth;
4279 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4280 a_buffer->channel_mask = channel_mask;
4281 a_buffer->data_size = a_size;
4283 if (!player->audio_stream_sink_sync) {
4284 /* If sync is FALSE, use buffer list to reduce the IPC. */
4285 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4286 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4287 if (a_buffer->pcm_data == NULL) {
4288 LOGE("failed to alloc data.");
4292 memcpy(a_buffer->pcm_data, a_data, a_size);
4293 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4294 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4296 /* If sync is TRUE, send data directly. */
4297 a_buffer->pcm_data = a_data;
4298 __mmplayer_audio_stream_send_data(player, a_buffer);
4303 gst_buffer_unmap(buffer, &mapinfo);
4308 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4310 mm_player_t* player = (mm_player_t*)data;
4311 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4312 GstPad* sinkpad = NULL;
4313 GstElement *queue = NULL, *sink = NULL;
4316 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4318 queue = gst_element_factory_make("queue", NULL);
4319 if (queue == NULL) {
4320 LOGD("fail make queue\n");
4324 sink = gst_element_factory_make("fakesink", NULL);
4326 LOGD("fail make fakesink\n");
4330 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4332 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4333 LOGW("failed to link queue & sink\n");
4337 sinkpad = gst_element_get_static_pad(queue, "sink");
4339 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4340 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4344 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4346 gst_object_unref(sinkpad);
4347 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4348 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4350 gst_element_set_state(sink, GST_STATE_PAUSED);
4351 gst_element_set_state(queue, GST_STATE_PAUSED);
4353 MMPLAYER_SIGNAL_CONNECT(player,
4355 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4357 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4364 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4366 gst_object_unref(GST_OBJECT(queue));
4370 gst_object_unref(GST_OBJECT(sink));
4374 gst_object_unref(GST_OBJECT(sinkpad));
4381 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4383 #define MAX_PROPS_LEN 128
4384 gint latency_mode = 0;
4385 gchar *stream_type = NULL;
4386 gchar *latency = NULL;
4388 gchar stream_props[MAX_PROPS_LEN] = {0,};
4389 GstStructure *props = NULL;
4392 * It should be set after player creation through attribute.
4393 * But, it can not be changed during playing.
4396 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4397 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4400 LOGE("stream_type is null.\n");
4402 if (player->sound.focus_id)
4403 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4404 stream_type, stream_id, player->sound.focus_id);
4406 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4407 stream_type, stream_id);
4408 props = gst_structure_from_string(stream_props, NULL);
4409 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4410 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4411 stream_type, stream_id, player->sound.focus_id, stream_props);
4412 gst_structure_free(props);
4415 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4417 switch (latency_mode) {
4418 case AUDIO_LATENCY_MODE_LOW:
4419 latency = g_strndup("low", 3);
4421 case AUDIO_LATENCY_MODE_MID:
4422 latency = g_strndup("mid", 3);
4424 case AUDIO_LATENCY_MODE_HIGH:
4425 latency = g_strndup("high", 4);
4429 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4433 LOGD("audiosink property - latency=%s \n", latency);
4441 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4443 MMPlayerGstElement* first_element = NULL;
4444 MMPlayerGstElement* audiobin = NULL;
4445 MMHandleType attrs = 0;
4447 GstPad *ghostpad = NULL;
4448 GList* element_bucket = NULL;
4449 gboolean link_audio_sink_now = TRUE;
4455 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4458 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4460 LOGE("failed to allocate memory for audiobin\n");
4461 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4464 attrs = MMPLAYER_GET_ATTRS(player);
4467 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4468 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4469 if (!audiobin[MMPLAYER_A_BIN].gst) {
4470 LOGE("failed to create audiobin\n");
4475 player->pipeline->audiobin = audiobin;
4477 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4479 /* Adding audiotp plugin for reverse trickplay feature */
4480 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4483 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4485 /* replaygain volume */
4486 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4487 if (player->sound.rg_enable)
4488 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4490 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4493 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4495 if (player->set_mode.pcm_extraction) {
4496 // pcm extraction only and no sound output
4497 if (player->audio_stream_render_cb_ex) {
4498 char *caps_str = NULL;
4499 GstCaps* caps = NULL;
4500 gchar *format = NULL;
4503 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4505 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4507 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4509 caps = gst_caps_new_simple("audio/x-raw",
4510 "format", G_TYPE_STRING, format,
4511 "rate", G_TYPE_INT, player->pcm_samplerate,
4512 "channels", G_TYPE_INT, player->pcm_channel,
4514 caps_str = gst_caps_to_string(caps);
4515 LOGD("new caps : %s\n", caps_str);
4517 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4520 gst_caps_unref(caps);
4521 MMPLAYER_FREEIF(caps_str);
4523 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4525 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4526 /* raw pad handling signal */
4527 MMPLAYER_SIGNAL_CONNECT(player,
4528 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4529 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4530 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4532 int dst_samplerate = 0;
4533 int dst_channels = 0;
4535 char *caps_str = NULL;
4536 GstCaps* caps = NULL;
4538 /* get conf. values */
4539 mm_attrs_multiple_get(player->attrs,
4541 "pcm_extraction_samplerate", &dst_samplerate,
4542 "pcm_extraction_channels", &dst_channels,
4543 "pcm_extraction_depth", &dst_depth,
4547 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4548 caps = gst_caps_new_simple("audio/x-raw",
4549 "rate", G_TYPE_INT, dst_samplerate,
4550 "channels", G_TYPE_INT, dst_channels,
4551 "depth", G_TYPE_INT, dst_depth,
4553 caps_str = gst_caps_to_string(caps);
4554 LOGD("new caps : %s\n", caps_str);
4556 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4559 gst_caps_unref(caps);
4560 MMPLAYER_FREEIF(caps_str);
4563 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4566 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4570 //GstCaps* caps = NULL;
4573 /* for logical volume control */
4574 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4575 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4577 if (player->sound.mute) {
4578 LOGD("mute enabled\n");
4579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4584 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4585 caps = gst_caps_from_string("audio/x-raw-int, "
4586 "endianness = (int) LITTLE_ENDIAN, "
4587 "signed = (boolean) true, "
4588 "width = (int) 16, "
4589 "depth = (int) 16");
4590 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4591 gst_caps_unref(caps);
4594 /* check if multi-channels */
4595 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4596 GstPad *srcpad = NULL;
4597 GstCaps *caps = NULL;
4599 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4600 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4601 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4602 GstStructure *str = gst_caps_get_structure(caps, 0);
4604 gst_structure_get_int(str, "channels", &channels);
4605 gst_caps_unref(caps);
4607 gst_object_unref(srcpad);
4611 /* audio effect element. if audio effect is enabled */
4612 if ((strcmp(player->ini.audioeffect_element, ""))
4614 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4615 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4617 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4619 if ((!player->bypass_audio_effect)
4620 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4621 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4622 if (!_mmplayer_audio_effect_custom_apply(player))
4623 LOGI("apply audio effect(custom) setting success\n");
4627 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4628 && (player->set_mode.rich_audio))
4629 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4632 /* create audio sink */
4633 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4634 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4635 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4637 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4638 if (player->is_360_feature_enabled &&
4639 player->is_content_spherical &&
4641 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4642 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4643 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4645 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4649 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4650 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4652 gst_caps_unref(acaps);
4654 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4655 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4656 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4659 player->is_openal_plugin_used = TRUE;
4661 if (player->video360_yaw_radians <= M_PI &&
4662 player->video360_yaw_radians >= -M_PI &&
4663 player->video360_pitch_radians <= M_PI_2 &&
4664 player->video360_pitch_radians >= -M_PI_2) {
4665 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4666 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4667 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4668 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4669 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4670 "source-orientation-y", player->video360_metadata.init_view_heading,
4671 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4674 if (player->is_360_feature_enabled && player->is_content_spherical)
4675 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4680 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4684 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4685 (player->videodec_linked && player->ini.use_system_clock)) {
4686 LOGD("system clock will be used.\n");
4687 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4690 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4691 __mmplayer_gst_set_audiosink_property(player, attrs);
4694 if (audiobin[MMPLAYER_A_SINK].gst) {
4695 GstPad *sink_pad = NULL;
4696 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4697 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4698 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4699 gst_object_unref(GST_OBJECT(sink_pad));
4702 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4704 /* adding created elements to bin */
4705 LOGD("adding created elements to bin\n");
4706 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4707 LOGE("failed to add elements\n");
4711 /* linking elements in the bucket by added order. */
4712 LOGD("Linking elements in the bucket by added order.\n");
4713 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4714 LOGE("failed to link elements\n");
4718 /* get first element's sinkpad for creating ghostpad */
4719 first_element = (MMPlayerGstElement *)element_bucket->data;
4720 if (!first_element) {
4721 LOGE("failed to get first elem\n");
4725 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4727 LOGE("failed to get pad from first element of audiobin\n");
4731 ghostpad = gst_ghost_pad_new("sink", pad);
4733 LOGE("failed to create ghostpad\n");
4737 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4738 LOGE("failed to add ghostpad to audiobin\n");
4742 gst_object_unref(pad);
4744 g_list_free(element_bucket);
4747 return MM_ERROR_NONE;
4751 LOGD("ERROR : releasing audiobin\n");
4754 gst_object_unref(GST_OBJECT(pad));
4757 gst_object_unref(GST_OBJECT(ghostpad));
4760 g_list_free(element_bucket);
4762 /* release element which are not added to bin */
4763 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4764 /* NOTE : skip bin */
4765 if (audiobin[i].gst) {
4766 GstObject* parent = NULL;
4767 parent = gst_element_get_parent(audiobin[i].gst);
4770 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4771 audiobin[i].gst = NULL;
4773 gst_object_unref(GST_OBJECT(parent));
4777 /* release audiobin with it's childs */
4778 if (audiobin[MMPLAYER_A_BIN].gst)
4779 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4781 MMPLAYER_FREEIF(audiobin);
4783 player->pipeline->audiobin = NULL;
4785 return MM_ERROR_PLAYER_INTERNAL;
4788 static GstPadProbeReturn
4789 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4791 mm_player_t* player = (mm_player_t*) u_data;
4792 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4793 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4795 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4797 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4798 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4800 return GST_PAD_PROBE_OK;
4803 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4805 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4808 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4810 int ret = MM_ERROR_NONE;
4812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4813 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4815 MMPLAYER_VIDEO_BO_LOCK(player);
4817 if (player->video_bo_list) {
4818 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4819 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4820 if (tmp && tmp->bo == bo) {
4822 LOGD("release bo %p", bo);
4823 tbm_bo_unref(tmp->bo);
4824 MMPLAYER_VIDEO_BO_UNLOCK(player);
4825 MMPLAYER_VIDEO_BO_SIGNAL(player);
4830 /* hw codec is running or the list was reset for DRC. */
4831 LOGW("there is no bo list.");
4833 MMPLAYER_VIDEO_BO_UNLOCK(player);
4835 LOGW("failed to find bo %p", bo);
4840 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4845 MMPLAYER_RETURN_IF_FAIL(player);
4847 MMPLAYER_VIDEO_BO_LOCK(player);
4848 if (player->video_bo_list) {
4849 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4850 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4851 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4854 tbm_bo_unref(tmp->bo);
4858 g_list_free(player->video_bo_list);
4859 player->video_bo_list = NULL;
4861 player->video_bo_size = 0;
4862 MMPLAYER_VIDEO_BO_UNLOCK(player);
4869 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4872 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4873 gboolean ret = TRUE;
4875 /* check DRC, if it is, destroy the prev bo list to create again */
4876 if (player->video_bo_size != size) {
4877 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4878 __mmplayer_video_stream_destroy_bo_list(player);
4879 player->video_bo_size = size;
4882 MMPLAYER_VIDEO_BO_LOCK(player);
4884 if ((!player->video_bo_list) ||
4885 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4887 /* create bo list */
4889 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4891 if (player->video_bo_list) {
4892 /* if bo list did not created all, try it again. */
4893 idx = g_list_length(player->video_bo_list);
4894 LOGD("bo list exist(len: %d)", idx);
4897 for (; idx < player->ini.num_of_video_bo; idx++) {
4898 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4900 LOGE("Fail to alloc bo_info.");
4903 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4905 LOGE("Fail to tbm_bo_alloc.");
4909 bo_info->using = FALSE;
4910 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4913 /* update video num buffers */
4914 player->video_num_buffers = idx;
4915 if (idx == player->ini.num_of_video_bo)
4916 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4919 MMPLAYER_VIDEO_BO_UNLOCK(player);
4923 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4927 /* get bo from list*/
4928 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4929 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4930 if (tmp && (tmp->using == FALSE)) {
4931 LOGD("found bo %p to use", tmp->bo);
4933 MMPLAYER_VIDEO_BO_UNLOCK(player);
4934 return tbm_bo_ref(tmp->bo);
4938 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4939 MMPLAYER_VIDEO_BO_UNLOCK(player);
4943 if (player->ini.video_bo_timeout <= 0) {
4944 MMPLAYER_VIDEO_BO_WAIT(player);
4946 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4947 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4954 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4956 mm_player_t* player = (mm_player_t*)data;
4958 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4960 /* send prerolled pkt */
4961 player->video_stream_prerolled = FALSE;
4963 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4965 /* not to send prerolled pkt again */
4966 player->video_stream_prerolled = TRUE;
4970 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4972 mm_player_t* player = (mm_player_t*)data;
4973 GstCaps *caps = NULL;
4974 MMPlayerVideoStreamDataType *stream = NULL;
4975 MMVideoBuffer *video_buffer = NULL;
4976 GstMemory *dataBlock = NULL;
4977 GstMemory *metaBlock = NULL;
4978 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4979 GstStructure *structure = NULL;
4980 const gchar *string_format = NULL;
4981 unsigned int fourcc = 0;
4984 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4986 if (player->video_stream_prerolled) {
4987 player->video_stream_prerolled = FALSE;
4988 LOGD("skip the prerolled pkt not to send it again");
4992 caps = gst_pad_get_current_caps(pad);
4994 LOGE("Caps is NULL.");
4998 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5000 /* clear stream data structure */
5001 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5003 LOGE("failed to alloc mem for video data");
5007 structure = gst_caps_get_structure(caps, 0);
5008 gst_structure_get_int(structure, "width", &(stream->width));
5009 gst_structure_get_int(structure, "height", &(stream->height));
5010 string_format = gst_structure_get_string(structure, "format");
5012 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5013 stream->format = util_get_pixtype(fourcc);
5014 gst_caps_unref(caps);
5018 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5019 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5022 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5023 LOGE("Wrong condition!!");
5027 /* set size and timestamp */
5028 dataBlock = gst_buffer_peek_memory(buffer, 0);
5029 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5030 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5032 /* check zero-copy */
5033 if (player->set_mode.video_zc &&
5034 player->set_mode.media_packet_video_stream &&
5035 gst_buffer_n_memory(buffer) > 1) {
5036 metaBlock = gst_buffer_peek_memory(buffer, 1);
5037 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5038 video_buffer = (MMVideoBuffer *)mapinfo.data;
5041 if (video_buffer) { /* hw codec */
5043 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5046 /* copy pointer of tbm bo, stride, elevation */
5047 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5048 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5052 LOGE("Not support video buffer format");
5055 memcpy(stream->stride, video_buffer->stride_width,
5056 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5057 memcpy(stream->elevation, video_buffer->stride_height,
5058 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5060 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5061 stream->internal_buffer = gst_buffer_ref(buffer);
5062 } else { /* sw codec */
5066 int ret = TBM_SURFACE_ERROR_NONE;
5067 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5068 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5070 unsigned char *src = NULL;
5071 unsigned char *dest = NULL;
5072 tbm_bo_handle thandle;
5073 tbm_surface_h surface;
5074 tbm_surface_info_s info;
5077 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5079 LOGE("fail to gst_memory_map");
5084 if (stream->format == MM_PIXEL_FORMAT_I420) {
5085 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5087 ret = tbm_surface_get_info(surface, &info);
5089 if (ret != TBM_SURFACE_ERROR_NONE) {
5090 tbm_surface_destroy(surface);
5093 tbm_surface_destroy(surface);
5095 src_stride[0] = GST_ROUND_UP_4(stream->width);
5096 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5097 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5098 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5099 stream->stride[0] = info.planes[0].stride;
5100 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5101 stream->stride[1] = info.planes[1].stride;
5102 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5103 stream->stride[2] = info.planes[2].stride;
5104 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5105 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5106 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5107 stream->stride[0] = stream->width * 4;
5108 stream->elevation[0] = stream->height;
5109 size = stream->stride[0] * stream->height;
5111 LOGE("Not support format %d", stream->format);
5115 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5116 if (!stream->bo[0]) {
5117 LOGE("Fail to tbm_bo_alloc!!");
5121 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5122 if (thandle.ptr && mapinfo.data) {
5123 if (stream->format == MM_PIXEL_FORMAT_I420) {
5124 for (i = 0; i < 3; i++) {
5125 src = mapinfo.data + src_offset[i];
5126 dest = thandle.ptr + info.planes[i].offset;
5129 for (j = 0; j < stream->height>>k; j++) {
5130 memcpy(dest, src, stream->width>>k);
5131 src += src_stride[i];
5132 dest += stream->stride[i];
5135 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5136 memcpy(thandle.ptr, mapinfo.data, size);
5138 LOGE("Not support format %d", stream->format);
5142 LOGE("data pointer is wrong. dest : %p, src : %p",
5143 thandle.ptr, mapinfo.data);
5146 tbm_bo_unmap(stream->bo[0]);
5149 if (player->video_stream_cb) { /* This has been already checked at the entry */
5150 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5151 LOGE("failed to send video stream data.");
5157 gst_memory_unmap(metaBlock, &mapinfo);
5159 gst_memory_unmap(dataBlock, &mapinfo);
5164 LOGE("release video stream resource.");
5167 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5169 tbm_bo_unref(stream->bo[i]);
5171 gst_memory_unmap(metaBlock, &mapinfo);
5173 /* unref gst buffer */
5174 if (stream->internal_buffer)
5175 gst_buffer_unref(stream->internal_buffer);
5176 } else if (dataBlock) {
5178 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5179 gst_memory_unmap(dataBlock, &mapinfo);
5187 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5189 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5190 GList* element_bucket = NULL;
5192 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5196 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5197 LOGD("do not need to add video filters.");
5198 return MM_ERROR_NONE;
5201 /* in case of sw codec except 360 playback,
5202 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5203 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5204 LOGD("using video converter: %s", video_csc);
5206 /* set video rotator */
5207 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5209 *bucket = element_bucket;
5211 return MM_ERROR_NONE;
5213 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5214 g_list_free(element_bucket);
5218 return MM_ERROR_PLAYER_INTERNAL;
5222 * This function is to create video pipeline.
5224 * @param player [in] handle of player
5225 * caps [in] src caps of decoder
5226 * surface_type [in] surface type for video rendering
5228 * @return This function returns zero on success.
5230 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5234 * - video overlay surface(arm/x86) : tizenwlsink
5237 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5241 GList*element_bucket = NULL;
5242 MMPlayerGstElement* first_element = NULL;
5243 MMPlayerGstElement* videobin = NULL;
5244 gchar *videosink_element = NULL;
5248 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5251 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5253 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5255 player->pipeline->videobin = videobin;
5257 attrs = MMPLAYER_GET_ATTRS(player);
5259 LOGE("cannot get content attribute");
5260 return MM_ERROR_PLAYER_INTERNAL;
5264 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5265 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5266 if (!videobin[MMPLAYER_V_BIN].gst) {
5267 LOGE("failed to create videobin");
5271 int enable_video_decoded_cb = 0;
5272 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5274 if (player->is_360_feature_enabled && player->is_content_spherical) {
5275 LOGD("video360 elem will be added.");
5277 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5278 "video-360", TRUE, player);
5280 /* Set spatial media metadata and/or user settings to the element.
5282 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5283 "projection-type", player->video360_metadata.projection_type, NULL);
5285 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5286 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5288 if (player->video360_metadata.full_pano_width_pixels &&
5289 player->video360_metadata.full_pano_height_pixels &&
5290 player->video360_metadata.cropped_area_image_width &&
5291 player->video360_metadata.cropped_area_image_height) {
5292 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5293 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5294 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5295 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5296 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5297 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5298 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5302 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5303 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5304 "horizontal-fov", player->video360_horizontal_fov,
5305 "vertical-fov", player->video360_vertical_fov, NULL);
5308 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5309 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5310 "zoom", 1.0f / player->video360_zoom, NULL);
5313 if (player->video360_yaw_radians <= M_PI &&
5314 player->video360_yaw_radians >= -M_PI &&
5315 player->video360_pitch_radians <= M_PI_2 &&
5316 player->video360_pitch_radians >= -M_PI_2) {
5317 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5318 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5319 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5320 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5322 "pose-yaw", player->video360_metadata.init_view_heading,
5323 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5326 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5327 "passthrough", !player->is_video360_enabled, NULL);
5330 /* set video sink */
5331 switch (surface_type) {
5332 case MM_DISPLAY_SURFACE_OVERLAY:
5333 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5335 if (strlen(player->ini.videosink_element_overlay) > 0)
5336 videosink_element = player->ini.videosink_element_overlay;
5340 case MM_DISPLAY_SURFACE_NULL:
5341 if (strlen(player->ini.videosink_element_fake) > 0)
5342 videosink_element = player->ini.videosink_element_fake;
5346 case MM_DISPLAY_SURFACE_REMOTE:
5347 if (strlen(player->ini.videosink_element_fake) > 0)
5348 videosink_element = player->ini.videosink_element_fake;
5353 LOGE("unidentified surface type");
5356 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5358 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5360 /* additional setting for sink plug-in */
5361 switch (surface_type) {
5362 case MM_DISPLAY_SURFACE_OVERLAY:
5364 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5366 LOGD("selected videosink name: %s", videosink_element);
5368 /* support shard memory with S/W codec on HawkP */
5369 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5370 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5371 "use-tbm", use_tbm, NULL);
5377 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5380 LOGD("disable last-sample");
5381 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5385 if (player->set_mode.media_packet_video_stream) {
5387 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5389 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5391 MMPLAYER_SIGNAL_CONNECT(player,
5392 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5395 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5398 MMPLAYER_SIGNAL_CONNECT(player,
5399 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5400 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5402 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5407 case MM_DISPLAY_SURFACE_REMOTE:
5409 if (player->set_mode.media_packet_video_stream) {
5410 LOGE("add data probe at videosink");
5411 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5412 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5414 MMPLAYER_SIGNAL_CONNECT(player,
5415 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5416 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5418 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5421 MMPLAYER_SIGNAL_CONNECT(player,
5422 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5423 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5425 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5430 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5433 LOGD("disable last-sample");
5434 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5444 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5447 if (videobin[MMPLAYER_V_SINK].gst) {
5448 GstPad *sink_pad = NULL;
5449 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5451 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5452 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5453 gst_object_unref(GST_OBJECT(sink_pad));
5455 LOGW("failed to get sink pad from videosink\n");
5458 /* store it as it's sink element */
5459 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5461 /* adding created elements to bin */
5462 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5463 LOGE("failed to add elements\n");
5467 /* Linking elements in the bucket by added order */
5468 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5469 LOGE("failed to link elements\n");
5473 /* get first element's sinkpad for creating ghostpad */
5475 first_element = (MMPlayerGstElement *)element_bucket->data;
5476 if (!first_element) {
5477 LOGE("failed to get first element from bucket\n");
5481 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5483 LOGE("failed to get pad from first element\n");
5487 /* create ghostpad */
5488 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5489 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5490 LOGE("failed to add ghostpad to videobin\n");
5493 gst_object_unref(pad);
5495 /* done. free allocated variables */
5497 g_list_free(element_bucket);
5501 return MM_ERROR_NONE;
5504 LOGE("ERROR : releasing videobin\n");
5506 g_list_free(element_bucket);
5509 gst_object_unref(GST_OBJECT(pad));
5511 /* release videobin with it's childs */
5512 if (videobin[MMPLAYER_V_BIN].gst)
5513 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5516 MMPLAYER_FREEIF(videobin);
5518 player->pipeline->videobin = NULL;
5520 return MM_ERROR_PLAYER_INTERNAL;
5523 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5525 GList *element_bucket = NULL;
5526 MMPlayerGstElement *textbin = player->pipeline->textbin;
5528 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5529 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5530 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5531 "signal-handoffs", FALSE,
5534 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5535 MMPLAYER_SIGNAL_CONNECT(player,
5536 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5537 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5539 G_CALLBACK(__mmplayer_update_subtitle),
5542 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5543 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5544 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5546 if (!player->play_subtitle) {
5547 LOGD("add textbin sink as sink element of whole pipeline.\n");
5548 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5551 /* adding created elements to bin */
5552 LOGD("adding created elements to bin\n");
5553 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5554 LOGE("failed to add elements\n");
5558 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5559 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5560 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5562 /* linking elements in the bucket by added order. */
5563 LOGD("Linking elements in the bucket by added order.\n");
5564 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5565 LOGE("failed to link elements\n");
5569 /* done. free allocated variables */
5570 g_list_free(element_bucket);
5572 if (textbin[MMPLAYER_T_QUEUE].gst) {
5574 GstPad *ghostpad = NULL;
5576 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5578 LOGE("failed to get sink pad of text queue");
5582 ghostpad = gst_ghost_pad_new("text_sink", pad);
5583 gst_object_unref(pad);
5586 LOGE("failed to create ghostpad of textbin\n");
5590 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5591 LOGE("failed to add ghostpad to textbin\n");
5592 gst_object_unref(ghostpad);
5597 return MM_ERROR_NONE;
5600 g_list_free(element_bucket);
5602 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5603 LOGE("remove textbin sink from sink list");
5604 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5607 /* release element at __mmplayer_gst_create_text_sink_bin */
5608 return MM_ERROR_PLAYER_INTERNAL;
5611 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5613 MMPlayerGstElement *textbin = NULL;
5614 GList *element_bucket = NULL;
5615 int surface_type = 0;
5620 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5623 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5625 LOGE("failed to allocate memory for textbin\n");
5626 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5630 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5631 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5632 if (!textbin[MMPLAYER_T_BIN].gst) {
5633 LOGE("failed to create textbin\n");
5638 player->pipeline->textbin = textbin;
5641 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5642 LOGD("surface type for subtitle : %d", surface_type);
5643 switch (surface_type) {
5644 case MM_DISPLAY_SURFACE_OVERLAY:
5645 case MM_DISPLAY_SURFACE_NULL:
5646 case MM_DISPLAY_SURFACE_REMOTE:
5647 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5648 LOGE("failed to make plain text elements\n");
5659 return MM_ERROR_NONE;
5663 LOGD("ERROR : releasing textbin\n");
5665 g_list_free(element_bucket);
5667 /* release signal */
5668 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5670 /* release element which are not added to bin */
5671 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5672 /* NOTE : skip bin */
5673 if (textbin[i].gst) {
5674 GstObject* parent = NULL;
5675 parent = gst_element_get_parent(textbin[i].gst);
5678 gst_object_unref(GST_OBJECT(textbin[i].gst));
5679 textbin[i].gst = NULL;
5681 gst_object_unref(GST_OBJECT(parent));
5686 /* release textbin with it's childs */
5687 if (textbin[MMPLAYER_T_BIN].gst)
5688 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5690 MMPLAYER_FREEIF(player->pipeline->textbin);
5691 player->pipeline->textbin = NULL;
5694 return MM_ERROR_PLAYER_INTERNAL;
5699 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5701 MMPlayerGstElement* mainbin = NULL;
5702 MMPlayerGstElement* textbin = NULL;
5703 MMHandleType attrs = 0;
5704 GstElement *subsrc = NULL;
5705 GstElement *subparse = NULL;
5706 gchar *subtitle_uri = NULL;
5707 const gchar *charset = NULL;
5713 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5715 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5717 mainbin = player->pipeline->mainbin;
5719 attrs = MMPLAYER_GET_ATTRS(player);
5721 LOGE("cannot get content attribute\n");
5722 return MM_ERROR_PLAYER_INTERNAL;
5725 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5726 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5727 LOGE("subtitle uri is not proper filepath.\n");
5728 return MM_ERROR_PLAYER_INVALID_URI;
5731 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5732 LOGE("failed to get storage info of subtitle path");
5733 return MM_ERROR_PLAYER_INVALID_URI;
5736 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5738 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5739 player->subtitle_language_list = NULL;
5740 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5742 /* create the subtitle source */
5743 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5745 LOGE("failed to create filesrc element\n");
5748 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5750 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5751 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5753 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5754 LOGW("failed to add queue\n");
5755 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5756 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5757 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5762 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5764 LOGE("failed to create subparse element\n");
5768 charset = util_get_charset(subtitle_uri);
5770 LOGD("detected charset is %s\n", charset);
5771 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5774 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5775 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5777 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5778 LOGW("failed to add subparse\n");
5779 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5780 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5781 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5785 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5786 LOGW("failed to link subsrc and subparse\n");
5790 player->play_subtitle = TRUE;
5791 player->adjust_subtitle_pos = 0;
5793 LOGD("play subtitle using subtitle file\n");
5795 if (player->pipeline->textbin == NULL) {
5796 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5797 LOGE("failed to create text sink bin. continuing without text\n");
5801 textbin = player->pipeline->textbin;
5803 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5804 LOGW("failed to add textbin\n");
5806 /* release signal */
5807 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5809 /* release textbin with it's childs */
5810 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5811 MMPLAYER_FREEIF(player->pipeline->textbin);
5812 player->pipeline->textbin = textbin = NULL;
5816 LOGD("link text input selector and textbin ghost pad");
5818 player->textsink_linked = 1;
5819 player->external_text_idx = 0;
5820 LOGI("player->textsink_linked set to 1\n");
5822 textbin = player->pipeline->textbin;
5823 LOGD("text bin has been created. reuse it.");
5824 player->external_text_idx = 1;
5827 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5828 LOGW("failed to link subparse and textbin\n");
5832 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5834 LOGE("failed to get sink pad from textsink to probe data");
5838 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5839 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5841 gst_object_unref(pad);
5844 /* create dot. for debugging */
5845 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5848 return MM_ERROR_NONE;
5851 /* release text pipeline resource */
5852 player->textsink_linked = 0;
5854 /* release signal */
5855 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5857 if (player->pipeline->textbin) {
5858 LOGE("remove textbin");
5860 /* release textbin with it's childs */
5861 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5862 MMPLAYER_FREEIF(player->pipeline->textbin);
5863 player->pipeline->textbin = NULL;
5867 /* release subtitle elem */
5868 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5869 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5871 return MM_ERROR_PLAYER_INTERNAL;
5875 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5877 mm_player_t* player = (mm_player_t*) data;
5878 MMMessageParamType msg = {0, };
5879 GstClockTime duration = 0;
5880 gpointer text = NULL;
5881 guint text_size = 0;
5882 gboolean ret = TRUE;
5883 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5887 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5888 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5890 if (player->is_subtitle_force_drop) {
5891 LOGW("subtitle is dropped forcedly.");
5895 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5896 text = mapinfo.data;
5897 text_size = mapinfo.size;
5898 duration = GST_BUFFER_DURATION(buffer);
5900 if (player->set_mode.subtitle_off) {
5901 LOGD("subtitle is OFF.\n");
5905 if (!text || (text_size == 0)) {
5906 LOGD("There is no subtitle to be displayed.\n");
5910 msg.data = (void *) text;
5911 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5913 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5915 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5916 gst_buffer_unmap(buffer, &mapinfo);
5923 static GstPadProbeReturn
5924 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5926 mm_player_t *player = (mm_player_t *) u_data;
5927 GstClockTime cur_timestamp = 0;
5928 gint64 adjusted_timestamp = 0;
5929 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5931 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5933 if (player->set_mode.subtitle_off) {
5934 LOGD("subtitle is OFF.\n");
5938 if (player->adjust_subtitle_pos == 0) {
5939 LOGD("nothing to do");
5943 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5944 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5946 if (adjusted_timestamp < 0) {
5947 LOGD("adjusted_timestamp under zero");
5952 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5953 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5954 GST_TIME_ARGS(cur_timestamp),
5955 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5957 return GST_PAD_PROBE_OK;
5959 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5963 /* check player and subtitlebin are created */
5964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5965 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5967 if (position == 0) {
5968 LOGD("nothing to do\n");
5970 return MM_ERROR_NONE;
5974 case MM_PLAYER_POS_FORMAT_TIME:
5976 /* check current postion */
5977 player->adjust_subtitle_pos = position;
5979 LOGD("save adjust_subtitle_pos in player") ;
5985 LOGW("invalid format.\n");
5987 return MM_ERROR_INVALID_ARGUMENT;
5993 return MM_ERROR_NONE;
5995 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5998 LOGD("adjusting video_pos in player") ;
5999 int current_pos = 0;
6000 /* check player and videobin are created */
6001 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6002 if (!player->pipeline->videobin ||
6003 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6004 LOGD("no video pipeline or sink is there");
6005 return MM_ERROR_PLAYER_INVALID_STATE ;
6008 LOGD("nothing to do\n");
6010 return MM_ERROR_NONE;
6012 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6013 LOGD("failed to get current position");
6014 return MM_ERROR_PLAYER_INTERNAL;
6016 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6017 LOGD("enter video delay is valid");
6019 LOGD("enter video delay is crossing content boundary");
6020 return MM_ERROR_INVALID_ARGUMENT ;
6022 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6023 LOGD("video delay has been done");
6026 return MM_ERROR_NONE;
6030 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6032 GstElement *appsrc = element;
6033 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6034 GstBuffer *buffer = NULL;
6035 GstFlowReturn ret = GST_FLOW_OK;
6038 MMPLAYER_RETURN_IF_FAIL(element);
6039 MMPLAYER_RETURN_IF_FAIL(buf);
6041 buffer = gst_buffer_new();
6043 if (buf->offset >= buf->len) {
6044 LOGD("call eos appsrc\n");
6045 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6049 if (buf->len - buf->offset < size)
6050 len = buf->len - buf->offset;
6052 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6053 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6054 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6056 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6057 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6063 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6065 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6067 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6069 buf->offset = (int)size;
6074 static GstBusSyncReply
6075 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6077 mm_player_t *player = (mm_player_t *)data;
6078 GstBusSyncReply reply = GST_BUS_DROP;
6080 if (!(player->pipeline && player->pipeline->mainbin)) {
6081 LOGE("player pipeline handle is null");
6082 return GST_BUS_PASS;
6085 if (!__mmplayer_check_useful_message(player, message)) {
6086 gst_message_unref(message);
6087 return GST_BUS_DROP;
6090 switch (GST_MESSAGE_TYPE(message)) {
6091 case GST_MESSAGE_STATE_CHANGED:
6092 /* post directly for fast launch */
6093 if (player->sync_handler) {
6094 __mmplayer_gst_callback(message, player);
6095 reply = GST_BUS_DROP;
6097 reply = GST_BUS_PASS;
6099 case GST_MESSAGE_TAG:
6100 __mmplayer_gst_extract_tag_from_msg(player, message);
6104 GstTagList *tags = NULL;
6106 gst_message_parse_tag(message, &tags);
6108 LOGE("TAGS received from element \"%s\".\n",
6109 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6111 gst_tag_list_foreach(tags, print_tag, NULL);
6112 gst_tag_list_free(tags);
6120 case GST_MESSAGE_DURATION_CHANGED:
6121 __mmplayer_gst_handle_duration(player, message);
6123 case GST_MESSAGE_ASYNC_DONE:
6124 /* NOTE:Don't call gst_callback directly
6125 * because previous frame can be showed even though this message is received for seek.
6128 reply = GST_BUS_PASS;
6132 if (reply == GST_BUS_DROP)
6133 gst_message_unref(message);
6139 __mmplayer_gst_create_decoder(mm_player_t *player,
6140 MMPlayerTrackType track,
6142 enum MainElementID elemId,
6145 gboolean ret = TRUE;
6146 GstPad *sinkpad = NULL;
6150 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6152 player->pipeline->mainbin, FALSE);
6153 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6154 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6155 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6157 GstElement *decodebin = NULL;
6158 GstCaps *dec_caps = NULL;
6160 /* create decodebin */
6161 decodebin = gst_element_factory_make("decodebin", name);
6164 LOGE("error : fail to create decodebin for %d decoder\n", track);
6169 /* raw pad handling signal */
6170 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6171 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6173 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6174 before looking for any elements that can handle that stream.*/
6175 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6176 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6178 /* This signal is emitted when a element is added to the bin.*/
6179 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6180 G_CALLBACK(__mmplayer_gst_element_added), player);
6182 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6183 LOGE("failed to add new decodebin\n");
6188 dec_caps = gst_pad_query_caps(srcpad, NULL);
6190 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6191 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6192 gst_caps_unref(dec_caps);
6195 player->pipeline->mainbin[elemId].id = elemId;
6196 player->pipeline->mainbin[elemId].gst = decodebin;
6198 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6200 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6201 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6202 gst_object_unref(GST_OBJECT(decodebin));
6205 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6206 LOGE("failed to sync second level decodebin state with parent\n");
6208 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6212 gst_object_unref(GST_OBJECT(sinkpad));
6221 * This function is to create audio or video pipeline for playing.
6223 * @param player [in] handle of player
6225 * @return This function returns zero on success.
6230 __mmplayer_gst_create_pipeline(mm_player_t* player)
6233 MMPlayerGstElement *mainbin = NULL;
6234 MMHandleType attrs = 0;
6235 GstElement* element = NULL;
6236 GstElement* elem_src_audio = NULL;
6237 GstElement* elem_src_subtitle = NULL;
6238 GstElement* es_video_queue = NULL;
6239 GstElement* es_audio_queue = NULL;
6240 GstElement* es_subtitle_queue = NULL;
6241 GList* element_bucket = NULL;
6242 gboolean need_state_holder = TRUE;
6244 #ifdef SW_CODEC_ONLY
6245 int surface_type = 0;
6249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6251 /* get profile attribute */
6252 attrs = MMPLAYER_GET_ATTRS(player);
6254 LOGE("cannot get content attribute\n");
6258 /* create pipeline handles */
6259 if (player->pipeline) {
6260 LOGW("pipeline should be released before create new one\n");
6264 player->video360_metadata.is_spherical = -1;
6265 player->is_openal_plugin_used = FALSE;
6267 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6268 if (player->pipeline == NULL)
6271 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6273 /* create mainbin */
6274 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6275 if (mainbin == NULL)
6278 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6280 /* create pipeline */
6281 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6282 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6283 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6284 LOGE("failed to create pipeline\n");
6287 player->demux_pad_index = 0;
6288 player->subtitle_language_list = NULL;
6290 player->is_subtitle_force_drop = FALSE;
6291 player->last_multiwin_status = FALSE;
6293 _mmplayer_track_initialize(player);
6294 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6296 /* create source element */
6297 switch (player->profile.uri_type) {
6298 /* rtsp streamming */
6299 case MM_PLAYER_URI_TYPE_URL_RTSP:
6303 element = gst_element_factory_make("rtspsrc", "rtsp source");
6306 LOGE("failed to create streaming source element\n");
6314 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6316 SECURE_LOGD("user_agent : %s\n", user_agent);
6318 /* setting property to streaming source */
6319 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6321 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6323 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6324 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6325 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6326 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6331 case MM_PLAYER_URI_TYPE_URL_HTTP:
6333 gchar *user_agent, *cookies, **cookie_list;
6334 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6335 user_agent = cookies = NULL;
6337 gint mode = MM_PLAYER_PD_MODE_NONE;
6339 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6341 player->pd_mode = mode;
6343 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6345 if (!MMPLAYER_IS_HTTP_PD(player)) {
6346 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6348 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6351 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6354 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6355 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6357 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6358 LOGD("get timeout from ini\n");
6359 http_timeout = player->ini.http_timeout;
6363 SECURE_LOGD("location : %s\n", player->profile.uri);
6364 SECURE_LOGD("cookies : %s\n", cookies);
6365 SECURE_LOGD("user_agent : %s\n", user_agent);
6366 LOGD("timeout : %d\n", http_timeout);
6368 /* setting property to streaming source */
6369 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6370 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6371 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6373 /* parsing cookies */
6374 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6375 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6376 g_strfreev(cookie_list);
6379 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6381 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6382 LOGW("it's dash. and it's still experimental feature.");
6384 // progressive download
6385 gchar* location = NULL;
6387 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6390 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6392 MMPLAYER_FREEIF(player->pd_file_save_path);
6394 LOGD("PD Location : %s\n", path);
6397 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6398 LOGE("failed to get storage info");
6401 player->pd_file_save_path = g_strdup(path);
6403 LOGE("can't find pd location so, it should be set \n");
6408 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6410 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6414 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6415 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6417 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6418 g_object_get(element, "location", &location, NULL);
6419 LOGD("PD_LOCATION [%s].\n", location);
6427 case MM_PLAYER_URI_TYPE_FILE:
6429 LOGD("using filesrc for 'file://' handler.\n");
6430 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6431 LOGE("failed to get storage info");
6435 element = gst_element_factory_make("filesrc", "source");
6437 LOGE("failed to create filesrc\n");
6441 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6445 case MM_PLAYER_URI_TYPE_SS:
6447 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6448 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6450 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6454 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6455 LOGD("get timeout from ini\n");
6456 http_timeout = player->ini.http_timeout;
6459 /* setting property to streaming source */
6460 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6461 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6464 case MM_PLAYER_URI_TYPE_MS_BUFF:
6466 LOGD("MS buff src is selected\n");
6468 if (player->v_stream_caps) {
6469 element = gst_element_factory_make("appsrc", "video_appsrc");
6471 LOGF("failed to create video app source element[appsrc].\n");
6475 if (player->a_stream_caps) {
6476 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6477 if (!elem_src_audio) {
6478 LOGF("failed to create audio app source element[appsrc].\n");
6482 } else if (player->a_stream_caps) {
6483 /* no video, only audio pipeline*/
6484 element = gst_element_factory_make("appsrc", "audio_appsrc");
6486 LOGF("failed to create audio app source element[appsrc].\n");
6491 if (player->s_stream_caps) {
6492 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6493 if (!elem_src_subtitle) {
6494 LOGF("failed to create subtitle app source element[appsrc].\n");
6499 LOGD("setting app sources properties.\n");
6500 LOGD("location : %s\n", player->profile.uri);
6502 if (player->v_stream_caps && element) {
6503 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6504 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6505 "caps", player->v_stream_caps, NULL);
6507 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6508 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6509 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6510 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6512 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6513 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6514 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6515 G_CALLBACK(__gst_seek_video_data), player);
6517 if (player->a_stream_caps && elem_src_audio) {
6518 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6519 "caps", player->a_stream_caps, NULL);
6521 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6522 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6523 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6524 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6526 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6527 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6528 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6529 G_CALLBACK(__gst_seek_audio_data), player);
6531 } else if (player->a_stream_caps && element) {
6532 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6533 "caps", player->a_stream_caps, NULL);
6535 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6536 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6537 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6538 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6540 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6541 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6542 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6543 G_CALLBACK(__gst_seek_audio_data), player);
6546 if (player->s_stream_caps && elem_src_subtitle) {
6547 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6548 "caps", player->s_stream_caps, NULL);
6550 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6551 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6552 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6553 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6555 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6557 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6558 G_CALLBACK(__gst_seek_subtitle_data), player);
6561 if (player->v_stream_caps && element) {
6562 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6563 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6564 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6565 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6567 if (player->a_stream_caps && elem_src_audio) {
6568 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6569 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6570 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6571 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6573 } else if (player->a_stream_caps && element) {
6574 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6575 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6576 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6577 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6580 if (player->s_stream_caps && elem_src_subtitle)
6581 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6582 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6584 need_state_holder = FALSE;
6586 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6587 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6588 LOGE("failed to commit\n");
6592 case MM_PLAYER_URI_TYPE_MEM:
6594 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6596 LOGD("mem src is selected\n");
6598 element = gst_element_factory_make("appsrc", "mem-source");
6600 LOGE("failed to create appsrc element\n");
6604 g_object_set(element, "stream-type", stream_type, NULL);
6605 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6606 g_object_set(element, "blocksize", (guint64)20480, NULL);
6608 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6609 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6610 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6611 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6614 case MM_PLAYER_URI_TYPE_URL:
6617 case MM_PLAYER_URI_TYPE_TEMP:
6620 case MM_PLAYER_URI_TYPE_NONE:
6625 /* check source element is OK */
6627 LOGE("no source element was created.\n");
6631 /* take source element */
6632 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6633 mainbin[MMPLAYER_M_SRC].gst = element;
6634 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6636 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6637 player->streamer = __mm_player_streaming_create();
6638 __mm_player_streaming_initialize(player->streamer);
6641 if (MMPLAYER_IS_HTTP_PD(player)) {
6642 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6644 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6645 element = gst_element_factory_make("queue2", "queue2");
6647 LOGE("failed to create http streaming buffer element\n");
6652 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6653 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6654 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6656 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6658 __mm_player_streaming_set_queue2(player->streamer,
6661 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6664 player->ini.http_buffering_limit,
6665 MUXED_BUFFER_TYPE_MEM_QUEUE,
6669 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6670 if (player->v_stream_caps) {
6671 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6672 if (!es_video_queue) {
6673 LOGE("create es_video_queue for es player failed\n");
6676 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6677 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6678 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6679 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6681 /* Adding audio appsrc to bucket */
6682 if (player->a_stream_caps && elem_src_audio) {
6683 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6684 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6685 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6687 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6688 if (!es_audio_queue) {
6689 LOGE("create es_audio_queue for es player failed\n");
6692 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6694 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6695 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6696 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6698 } else if (player->a_stream_caps) {
6699 /* Only audio stream, no video */
6700 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6701 if (!es_audio_queue) {
6702 LOGE("create es_audio_queue for es player failed\n");
6705 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6706 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6707 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6710 if (player->s_stream_caps && elem_src_subtitle) {
6711 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6712 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6713 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6715 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6716 if (!es_subtitle_queue) {
6717 LOGE("create es_subtitle_queue for es player failed\n");
6720 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6721 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6722 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6726 /* create autoplugging element if src element is not a rtsp src */
6727 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6728 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6730 enum MainElementID elemId = MMPLAYER_M_NUM;
6732 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6733 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6734 elemId = MMPLAYER_M_AUTOPLUG;
6735 element = __mmplayer_create_decodebin(player);
6737 /* default size of mq in decodebin is 2M
6738 * but it can cause blocking issue during seeking depends on content. */
6739 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6741 need_state_holder = FALSE;
6743 elemId = MMPLAYER_M_TYPEFIND;
6744 element = gst_element_factory_make("typefind", "typefinder");
6745 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6746 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6750 /* check autoplug element is OK */
6752 LOGE("can not create element(%d)\n", elemId);
6756 mainbin[elemId].id = elemId;
6757 mainbin[elemId].gst = element;
6759 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6762 /* add elements to pipeline */
6763 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6764 LOGE("Failed to add elements to pipeline\n");
6769 /* linking elements in the bucket by added order. */
6770 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6771 LOGE("Failed to link some elements\n");
6776 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6777 if (need_state_holder) {
6779 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6780 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6782 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6783 LOGE("fakesink element could not be created\n");
6786 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6788 /* take ownership of fakesink. we are reusing it */
6789 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6792 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6793 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6794 LOGE("failed to add fakesink to bin\n");
6799 /* now we have completed mainbin. take it */
6800 player->pipeline->mainbin = mainbin;
6802 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6803 GstPad *srcpad = NULL;
6805 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6806 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6808 __mmplayer_gst_create_decoder(player,
6809 MM_PLAYER_TRACK_TYPE_VIDEO,
6811 MMPLAYER_M_AUTOPLUG_V_DEC,
6814 gst_object_unref(GST_OBJECT(srcpad));
6819 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6820 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6822 __mmplayer_gst_create_decoder(player,
6823 MM_PLAYER_TRACK_TYPE_AUDIO,
6825 MMPLAYER_M_AUTOPLUG_A_DEC,
6828 gst_object_unref(GST_OBJECT(srcpad));
6833 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6834 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6837 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6838 if (__mmplayer_check_subtitle(player)) {
6839 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6840 LOGE("fail to create text pipeline");
6843 /* connect bus callback */
6844 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6846 LOGE("cannot get bus from pipeline.\n");
6850 /* set sync handler to get tag synchronously */
6851 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6854 gst_object_unref(GST_OBJECT(bus));
6855 g_list_free(element_bucket);
6857 /* create gst bus_msb_cb thread */
6858 g_mutex_init(&player->bus_msg_thread_mutex);
6859 g_cond_init(&player->bus_msg_thread_cond);
6860 player->bus_msg_thread_exit = FALSE;
6861 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6862 player->bus_msg_thread =
6863 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6864 if (!player->bus_msg_thread) {
6865 LOGE("failed to create gst BUS msg thread");
6866 g_mutex_clear(&player->bus_msg_thread_mutex);
6867 g_cond_clear(&player->bus_msg_thread_cond);
6873 return MM_ERROR_NONE;
6876 __mmplayer_gst_destroy_pipeline(player);
6877 g_list_free(element_bucket);
6880 /* release element which are not added to bin */
6881 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6882 /* NOTE : skip pipeline */
6883 if (mainbin[i].gst) {
6884 GstObject* parent = NULL;
6885 parent = gst_element_get_parent(mainbin[i].gst);
6888 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6889 mainbin[i].gst = NULL;
6891 gst_object_unref(GST_OBJECT(parent));
6895 /* release pipeline with it's childs */
6896 if (mainbin[MMPLAYER_M_PIPE].gst)
6897 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6899 MMPLAYER_FREEIF(mainbin);
6902 MMPLAYER_FREEIF(player->pipeline);
6903 return MM_ERROR_PLAYER_INTERNAL;
6907 __mmplayer_reset_gapless_state(mm_player_t* player)
6910 MMPLAYER_RETURN_IF_FAIL(player
6912 && player->pipeline->audiobin
6913 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6915 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6922 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6925 int ret = MM_ERROR_NONE;
6929 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6931 /* cleanup stuffs */
6932 MMPLAYER_FREEIF(player->type);
6933 player->have_dynamic_pad = FALSE;
6934 player->no_more_pad = FALSE;
6935 player->num_dynamic_pad = 0;
6936 player->demux_pad_index = 0;
6937 player->use_deinterleave = FALSE;
6938 player->max_audio_channels = 0;
6939 player->video_share_api_delta = 0;
6940 player->video_share_clock_delta = 0;
6941 player->video_hub_download_mode = 0;
6943 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6944 player->subtitle_language_list = NULL;
6945 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6947 __mmplayer_reset_gapless_state(player);
6949 if (player->streamer) {
6950 __mm_player_streaming_deinitialize(player->streamer);
6951 __mm_player_streaming_destroy(player->streamer);
6952 player->streamer = NULL;
6955 /* cleanup unlinked mime type */
6956 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6957 MMPLAYER_FREEIF(player->unlinked_video_mime);
6958 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6960 /* cleanup running stuffs */
6961 __mmplayer_cancel_eos_timer(player);
6963 /* cleanup gst stuffs */
6964 if (player->pipeline) {
6965 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6966 GstTagList* tag_list = player->pipeline->tag_list;
6968 /* first we need to disconnect all signal hander */
6969 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6972 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6973 MMPlayerGstElement* videobin = player->pipeline->videobin;
6974 MMPlayerGstElement* textbin = player->pipeline->textbin;
6975 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6976 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6977 gst_object_unref(bus);
6979 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6980 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6981 if (ret != MM_ERROR_NONE) {
6982 LOGE("fail to change state to NULL\n");
6983 return MM_ERROR_PLAYER_INTERNAL;
6986 LOGW("succeeded in chaning state to NULL\n");
6988 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6991 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6992 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6994 /* free avsysaudiosink
6995 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6996 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6998 MMPLAYER_FREEIF(audiobin);
6999 MMPLAYER_FREEIF(videobin);
7000 MMPLAYER_FREEIF(textbin);
7001 MMPLAYER_FREEIF(mainbin);
7005 gst_tag_list_free(tag_list);
7007 MMPLAYER_FREEIF(player->pipeline);
7009 MMPLAYER_FREEIF(player->album_art);
7011 if (player->v_stream_caps) {
7012 gst_caps_unref(player->v_stream_caps);
7013 player->v_stream_caps = NULL;
7015 if (player->a_stream_caps) {
7016 gst_caps_unref(player->a_stream_caps);
7017 player->a_stream_caps = NULL;
7020 if (player->s_stream_caps) {
7021 gst_caps_unref(player->s_stream_caps);
7022 player->s_stream_caps = NULL;
7024 _mmplayer_track_destroy(player);
7026 if (player->sink_elements)
7027 g_list_free(player->sink_elements);
7028 player->sink_elements = NULL;
7030 if (player->bufmgr) {
7031 tbm_bufmgr_deinit(player->bufmgr);
7032 player->bufmgr = NULL;
7035 LOGW("finished destroy pipeline\n");
7042 static int __gst_realize(mm_player_t* player)
7045 int ret = MM_ERROR_NONE;
7049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7051 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7053 ret = __mmplayer_gst_create_pipeline(player);
7055 LOGE("failed to create pipeline\n");
7059 /* set pipeline state to READY */
7060 /* NOTE : state change to READY must be performed sync. */
7061 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7062 ret = __mmplayer_gst_set_state(player,
7063 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7065 if (ret != MM_ERROR_NONE) {
7066 /* return error if failed to set state */
7067 LOGE("failed to set READY state");
7071 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7073 /* create dot before error-return. for debugging */
7074 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7081 static int __gst_unrealize(mm_player_t* player)
7083 int ret = MM_ERROR_NONE;
7087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7089 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7090 MMPLAYER_PRINT_STATE(player);
7092 /* release miscellaneous information */
7093 __mmplayer_release_misc(player);
7095 /* destroy pipeline */
7096 ret = __mmplayer_gst_destroy_pipeline(player);
7097 if (ret != MM_ERROR_NONE) {
7098 LOGE("failed to destory pipeline\n");
7102 /* release miscellaneous information.
7103 these info needs to be released after pipeline is destroyed. */
7104 __mmplayer_release_misc_post(player);
7106 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7113 static int __gst_pending_seek(mm_player_t* player)
7115 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7116 int ret = MM_ERROR_NONE;
7120 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7122 if (!player->pending_seek.is_pending) {
7123 LOGD("pending seek is not reserved. nothing to do.\n");
7127 /* check player state if player could pending seek or not. */
7128 current_state = MMPLAYER_CURRENT_STATE(player);
7130 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7131 LOGW("try to pending seek in %s state, try next time. \n",
7132 MMPLAYER_STATE_GET_NAME(current_state));
7136 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7138 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7140 if (MM_ERROR_NONE != ret)
7141 LOGE("failed to seek pending postion. just keep staying current position.\n");
7143 player->pending_seek.is_pending = FALSE;
7150 static int __gst_start(mm_player_t* player)
7152 gboolean sound_extraction = 0;
7153 int ret = MM_ERROR_NONE;
7154 gboolean async = FALSE;
7158 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7160 /* get sound_extraction property */
7161 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7163 /* NOTE : if SetPosition was called before Start. do it now */
7164 /* streaming doesn't support it. so it should be always sync */
7165 /* !!create one more api to check if there is pending seek rather than checking variables */
7166 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7167 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7168 ret = __gst_pause(player, FALSE);
7169 if (ret != MM_ERROR_NONE) {
7170 LOGE("failed to set state to PAUSED for pending seek\n");
7174 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7176 if (sound_extraction) {
7177 LOGD("setting pcm extraction\n");
7179 ret = __mmplayer_set_pcm_extraction(player);
7180 if (MM_ERROR_NONE != ret) {
7181 LOGW("failed to set pcm extraction\n");
7185 if (MM_ERROR_NONE != __gst_pending_seek(player))
7186 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7190 LOGD("current state before doing transition");
7191 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7192 MMPLAYER_PRINT_STATE(player);
7194 /* set pipeline state to PLAYING */
7195 if (player->es_player_push_mode)
7197 /* set pipeline state to PLAYING */
7198 ret = __mmplayer_gst_set_state(player,
7199 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7201 if (ret == MM_ERROR_NONE) {
7202 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7204 LOGE("failed to set state to PLAYING");
7208 /* generating debug info before returning error */
7209 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7216 static int __gst_stop(mm_player_t* player)
7218 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7219 MMHandleType attrs = 0;
7220 gboolean rewind = FALSE;
7222 int ret = MM_ERROR_NONE;
7223 gboolean async = FALSE;
7227 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7230 LOGD("current state before doing transition");
7231 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7232 MMPLAYER_PRINT_STATE(player);
7234 attrs = MMPLAYER_GET_ATTRS(player);
7236 LOGE("cannot get content attribute\n");
7237 return MM_ERROR_PLAYER_INTERNAL;
7240 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7241 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7243 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7244 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7247 if (player->es_player_push_mode)
7250 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7252 /* return if set_state has failed */
7253 if (ret != MM_ERROR_NONE) {
7254 LOGE("failed to set state.\n");
7260 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7261 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7262 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7263 LOGW("failed to rewind\n");
7264 ret = MM_ERROR_PLAYER_SEEK;
7269 player->sent_bos = FALSE;
7271 if (player->es_player_push_mode) //for cloudgame
7274 /* wait for seek to complete */
7275 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7276 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7277 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7279 LOGE("fail to stop player.\n");
7280 ret = MM_ERROR_PLAYER_INTERNAL;
7281 __mmplayer_dump_pipeline_state(player);
7284 /* generate dot file if enabled */
7285 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7292 int __gst_pause(mm_player_t* player, gboolean async)
7294 int ret = MM_ERROR_NONE;
7298 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7299 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7301 LOGD("current state before doing transition");
7302 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7303 MMPLAYER_PRINT_STATE(player);
7305 /* set pipeline status to PAUSED */
7306 ret = __mmplayer_gst_set_state(player,
7307 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7309 if (FALSE == async) {
7310 if (ret != MM_ERROR_NONE) {
7311 GstMessage *msg = NULL;
7312 GTimer *timer = NULL;
7313 gdouble MAX_TIMEOUT_SEC = 3;
7315 LOGE("failed to set state to PAUSED");
7317 if (player->msg_posted) {
7318 LOGE("error msg is already posted.");
7322 timer = g_timer_new();
7323 g_timer_start(timer);
7325 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7328 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7330 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7331 GError *error = NULL;
7333 /* parse error code */
7334 gst_message_parse_error(msg, &error, NULL);
7336 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7337 /* Note : the streaming error from the streaming source is handled
7338 * using __mmplayer_handle_streaming_error.
7340 __mmplayer_handle_streaming_error(player, msg);
7343 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7345 if (error->domain == GST_STREAM_ERROR)
7346 ret = __gst_handle_stream_error(player, error, msg);
7347 else if (error->domain == GST_RESOURCE_ERROR)
7348 ret = __gst_handle_resource_error(player, error->code, NULL);
7349 else if (error->domain == GST_LIBRARY_ERROR)
7350 ret = __gst_handle_library_error(player, error->code);
7351 else if (error->domain == GST_CORE_ERROR)
7352 ret = __gst_handle_core_error(player, error->code);
7354 g_error_free(error);
7356 player->msg_posted = TRUE;
7358 gst_message_unref(msg);
7360 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7362 gst_object_unref(bus);
7363 g_timer_stop(timer);
7364 g_timer_destroy(timer);
7368 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7369 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7371 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7373 } else if (ret == MM_ERROR_NONE) {
7375 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7379 /* generate dot file before returning error */
7380 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7387 int __gst_resume(mm_player_t* player, gboolean async)
7389 int ret = MM_ERROR_NONE;
7394 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7395 MM_ERROR_PLAYER_NOT_INITIALIZED);
7397 LOGD("current state before doing transition");
7398 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7399 MMPLAYER_PRINT_STATE(player);
7401 /* generate dot file before returning error */
7402 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7405 LOGD("do async state transition to PLAYING.\n");
7407 /* set pipeline state to PLAYING */
7408 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7410 ret = __mmplayer_gst_set_state(player,
7411 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7412 if (ret != MM_ERROR_NONE) {
7413 LOGE("failed to set state to PLAYING\n");
7416 if (async == FALSE) {
7417 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7418 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7419 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7423 /* generate dot file before returning error */
7424 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7432 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7434 unsigned long dur_msec = 0;
7435 gint64 dur_nsec = 0;
7436 gint64 pos_nsec = 0;
7437 gboolean ret = TRUE;
7438 gboolean accurated = FALSE;
7439 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7443 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7445 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7446 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7449 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7450 /* check duration */
7451 /* NOTE : duration cannot be zero except live streaming.
7452 * Since some element could have some timing problemn with quering duration, try again.
7454 if (!player->duration) {
7455 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7456 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7457 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7458 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7459 player->pending_seek.is_pending = TRUE;
7460 player->pending_seek.format = format;
7461 player->pending_seek.pos = position;
7462 player->doing_seek = FALSE;
7463 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7464 return MM_ERROR_NONE;
7469 player->duration = dur_nsec;
7472 if (player->duration) {
7473 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7475 LOGE("could not get the duration. fail to seek.\n");
7479 LOGD("playback rate: %f\n", player->playback_rate);
7481 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7483 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7485 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7489 case MM_PLAYER_POS_FORMAT_TIME:
7491 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7492 GstQuery *query = NULL;
7493 gboolean seekable = FALSE;
7495 /* check position is valid or not */
7496 if (position > dur_msec)
7499 query = gst_query_new_seeking(GST_FORMAT_TIME);
7500 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7501 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7502 gst_query_unref(query);
7505 LOGW("non-seekable content");
7506 player->doing_seek = FALSE;
7507 return MM_ERROR_PLAYER_NO_OP;
7510 LOGW("failed to get seeking query");
7511 gst_query_unref(query); /* keep seeking operation */
7514 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7516 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7517 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7518 This causes problem is position calculation during normal pause resume scenarios also.
7519 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7520 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7521 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7522 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7523 LOGW("getting current position failed in seek\n");
7525 player->last_position = pos_nsec;
7526 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7529 if (player->doing_seek) {
7530 LOGD("not completed seek");
7531 return MM_ERROR_PLAYER_DOING_SEEK;
7535 if (!internal_called)
7536 player->doing_seek = TRUE;
7538 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7540 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7541 gint64 cur_time = 0;
7543 /* get current position */
7544 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7547 GstEvent *event = gst_event_new_seek(1.0,
7549 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7550 GST_SEEK_TYPE_SET, cur_time,
7551 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7553 __gst_send_event_to_sink(player, event);
7555 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7556 __gst_pause(player, FALSE);
7559 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7560 that's why set position through property. */
7561 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7562 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7563 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7564 (!player->videodec_linked) && (!player->audiodec_linked)) {
7566 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7567 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7568 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7569 player->doing_seek = FALSE;
7570 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7572 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7573 GST_FORMAT_TIME, seek_flags,
7574 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7578 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7584 case MM_PLAYER_POS_FORMAT_PERCENT:
7586 LOGD("seeking to(%lu)%% \n", position);
7588 if (player->doing_seek) {
7589 LOGD("not completed seek");
7590 return MM_ERROR_PLAYER_DOING_SEEK;
7593 if (!internal_called)
7594 player->doing_seek = TRUE;
7596 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7597 pos_nsec = (gint64)((position * player->duration) / 100);
7598 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7599 GST_FORMAT_TIME, seek_flags,
7600 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7602 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7612 /* NOTE : store last seeking point to overcome some bad operation
7613 * (returning zero when getting current position) of some elements
7615 player->last_position = pos_nsec;
7617 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7618 if (player->playback_rate > 1.0)
7619 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7622 return MM_ERROR_NONE;
7625 player->pending_seek.is_pending = TRUE;
7626 player->pending_seek.format = format;
7627 player->pending_seek.pos = position;
7629 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7630 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7632 return MM_ERROR_NONE;
7635 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7636 return MM_ERROR_INVALID_ARGUMENT;
7639 player->doing_seek = FALSE;
7640 return MM_ERROR_PLAYER_SEEK;
7643 #define TRICKPLAY_OFFSET GST_MSECOND
7646 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7648 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7649 gint64 pos_msec = 0;
7650 gboolean ret = TRUE;
7652 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7653 MM_ERROR_PLAYER_NOT_INITIALIZED);
7655 current_state = MMPLAYER_CURRENT_STATE(player);
7657 /* NOTE : query position except paused state to overcome some bad operation
7658 * please refer to below comments in details
7660 if (current_state != MM_PLAYER_STATE_PAUSED)
7661 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7663 /* NOTE : get last point to overcome some bad operation of some elements
7664 *(returning zero when getting current position in paused state
7665 * and when failed to get postion during seeking
7667 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7668 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7670 if (player->playback_rate < 0.0)
7671 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7673 pos_msec = player->last_position;
7676 pos_msec = player->last_position;
7678 player->last_position = pos_msec;
7680 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7683 if (player->duration > 0 && pos_msec > player->duration)
7684 pos_msec = player->duration;
7686 player->last_position = pos_msec;
7690 case MM_PLAYER_POS_FORMAT_TIME:
7691 *position = GST_TIME_AS_MSECONDS(pos_msec);
7694 case MM_PLAYER_POS_FORMAT_PERCENT:
7696 if (player->duration <= 0) {
7697 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7700 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7701 *position = pos_msec * 100 / player->duration;
7706 return MM_ERROR_PLAYER_INTERNAL;
7709 return MM_ERROR_NONE;
7713 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7715 #define STREAMING_IS_FINISHED 0
7716 #define BUFFERING_MAX_PER 100
7717 #define DEFAULT_PER_VALUE -1
7718 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7720 MMPlayerGstElement *mainbin = NULL;
7721 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7722 gint64 buffered_total = 0;
7723 unsigned long position = 0;
7724 gint buffered_sec = -1;
7725 GstBufferingMode mode = GST_BUFFERING_STREAM;
7726 gint64 content_size_time = player->duration;
7727 guint64 content_size_bytes = player->http_content_size;
7729 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7731 player->pipeline->mainbin,
7732 MM_ERROR_PLAYER_NOT_INITIALIZED);
7734 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7739 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7740 /* and rtsp is not ready yet. */
7741 LOGW("it's only used for http streaming case.\n");
7742 return MM_ERROR_PLAYER_NO_OP;
7745 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7746 LOGW("Time format is not supported yet.\n");
7747 return MM_ERROR_INVALID_ARGUMENT;
7750 if (content_size_time <= 0 || content_size_bytes <= 0) {
7751 LOGW("there is no content size.");
7752 return MM_ERROR_NONE;
7755 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7756 LOGW("fail to get current position.");
7757 return MM_ERROR_NONE;
7760 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7761 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7763 mainbin = player->pipeline->mainbin;
7764 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7766 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7767 GstQuery *query = NULL;
7768 gint byte_in_rate = 0, byte_out_rate = 0;
7769 gint64 estimated_total = 0;
7771 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7772 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7773 LOGW("fail to get buffering query from queue2");
7775 gst_query_unref(query);
7776 return MM_ERROR_NONE;
7779 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7780 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7782 if (mode == GST_BUFFERING_STREAM) {
7783 /* using only queue in case of push mode(ts / mp3) */
7784 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7785 GST_FORMAT_BYTES, &buffered_total)) {
7786 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7787 stop_per = 100 * buffered_total / content_size_bytes;
7790 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7792 guint num_of_ranges = 0;
7793 gint64 start_byte = 0, stop_byte = 0;
7795 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7796 if (estimated_total != STREAMING_IS_FINISHED) {
7797 /* buffered size info from queue2 */
7798 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7799 for (idx = 0; idx < num_of_ranges; idx++) {
7800 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7801 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7803 buffered_total += (stop_byte - start_byte);
7806 stop_per = BUFFERING_MAX_PER;
7808 gst_query_unref(query);
7811 if (stop_per == DEFAULT_PER_VALUE) {
7812 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7814 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7816 /* buffered size info from multiqueue */
7817 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7818 guint curr_size_bytes = 0;
7819 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7820 "curr-size-bytes", &curr_size_bytes, NULL);
7821 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7822 buffered_total += curr_size_bytes;
7825 if (avg_byterate > 0)
7826 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7827 else if (player->total_maximum_bitrate > 0)
7828 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7829 else if (player->total_bitrate > 0)
7830 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7832 if (buffered_sec >= 0)
7833 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7837 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7838 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7840 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7841 buffered_total, buffered_sec, *start_pos, *stop_pos);
7843 return MM_ERROR_NONE;
7847 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7852 LOGW("set_message_callback is called with invalid player handle\n");
7853 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7856 player->msg_cb = callback;
7857 player->msg_cb_param = user_param;
7859 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7863 return MM_ERROR_NONE;
7866 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7868 int ret = MM_ERROR_PLAYER_INVALID_URI;
7873 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7874 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7875 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7877 memset(data, 0, sizeof(MMPlayerParseProfile));
7879 if ((path = strstr(uri, "es_buff://"))) {
7881 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7883 ret = MM_ERROR_NONE;
7885 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7887 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7888 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7889 ret = MM_ERROR_NONE;
7891 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7894 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7895 tmp = g_ascii_strdown(uri, strlen(uri));
7897 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7898 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7900 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7902 ret = MM_ERROR_NONE;
7905 } else if ((path = strstr(uri, "rtspu://"))) {
7907 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7908 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7909 ret = MM_ERROR_NONE;
7911 } else if ((path = strstr(uri, "rtspr://"))) {
7912 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7913 char *separater = strstr(path, "*");
7917 char *urgent = separater + strlen("*");
7919 if ((urgent_len = strlen(urgent))) {
7920 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7921 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7922 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7923 ret = MM_ERROR_NONE;
7926 } else if ((path = strstr(uri, "mms://"))) {
7928 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7929 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7930 ret = MM_ERROR_NONE;
7932 } else if ((path = strstr(uri, "mem://"))) {
7935 char *buffer = NULL;
7936 char *seperator = strchr(path, ',');
7937 char ext[100] = {0,}, size[100] = {0,};
7940 if ((buffer = strstr(path, "ext="))) {
7941 buffer += strlen("ext=");
7943 if (strlen(buffer)) {
7944 strncpy(ext, buffer, 99);
7946 if ((seperator = strchr(ext, ','))
7947 || (seperator = strchr(ext, ' '))
7948 || (seperator = strchr(ext, '\0'))) {
7949 seperator[0] = '\0';
7954 if ((buffer = strstr(path, "size="))) {
7955 buffer += strlen("size=");
7957 if (strlen(buffer) > 0) {
7958 strncpy(size, buffer, 99);
7960 if ((seperator = strchr(size, ','))
7961 || (seperator = strchr(size, ' '))
7962 || (seperator = strchr(size, '\0'))) {
7963 seperator[0] = '\0';
7966 mem_size = atoi(size);
7971 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7972 if (mem_size && param) {
7973 if (data->input_mem.buf)
7974 free(data->input_mem.buf);
7975 data->input_mem.buf = malloc(mem_size);
7977 if (data->input_mem.buf) {
7978 memcpy(data->input_mem.buf, param, mem_size);
7979 data->input_mem.len = mem_size;
7980 ret = MM_ERROR_NONE;
7982 LOGE("failed to alloc mem %d", mem_size);
7983 ret = MM_ERROR_PLAYER_INTERNAL;
7986 data->input_mem.offset = 0;
7987 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7991 gchar *location = NULL;
7994 if ((path = strstr(uri, "file://"))) {
7996 location = g_filename_from_uri(uri, NULL, &err);
7998 if (!location || (err != NULL)) {
7999 LOGE("Invalid URI '%s' for filesrc: %s", path,
8000 (err != NULL) ? err->message : "unknown error");
8002 if (err) g_error_free(err);
8003 if (location) g_free(location);
8005 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8009 LOGD("path from uri: %s", location);
8012 path = (location != NULL) ? (location) : ((char*)uri);
8013 int file_stat = MM_ERROR_NONE;
8015 file_stat = util_exist_file_path(path);
8017 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8018 if (file_stat == MM_ERROR_NONE) {
8019 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8021 if (util_is_sdp_file(path)) {
8022 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8023 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8025 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8027 ret = MM_ERROR_NONE;
8028 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8029 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8031 LOGE("invalid uri, could not play..\n");
8032 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8035 if (location) g_free(location);
8039 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8040 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8041 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8042 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8044 /* dump parse result */
8045 SECURE_LOGW("incomming uri : %s\n", uri);
8046 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8047 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8055 __mmplayer_can_do_interrupt(mm_player_t *player)
8057 if (!player || !player->pipeline || !player->attrs) {
8058 LOGW("not initialized");
8062 if (player->set_mode.pcm_extraction) {
8063 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8067 /* check if seeking */
8068 if (player->doing_seek) {
8069 MMMessageParamType msg_param;
8070 memset(&msg_param, 0, sizeof(MMMessageParamType));
8071 msg_param.code = MM_ERROR_PLAYER_SEEK;
8072 player->doing_seek = FALSE;
8073 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8077 /* check other thread */
8078 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8079 LOGW("locked already, cmd state : %d", player->cmd);
8081 /* check application command */
8082 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8083 LOGW("playing.. should wait cmd lock then, will be interrupted");
8085 /* lock will be released at mrp_resource_release_cb() */
8086 MMPLAYER_CMD_LOCK(player);
8089 LOGW("nothing to do");
8092 LOGW("can interrupt immediately");
8096 FAILED: /* with CMD UNLOCKED */
8099 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8104 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8107 mm_player_t *player = NULL;
8111 if (user_data == NULL) {
8112 LOGE("- user_data is null\n");
8115 player = (mm_player_t *)user_data;
8117 /* do something to release resource here.
8118 * player stop and interrupt forwarding */
8119 if (!__mmplayer_can_do_interrupt(player)) {
8120 LOGW("no need to interrupt, so leave");
8122 MMMessageParamType msg = {0, };
8123 unsigned long pos = 0;
8125 player->interrupted_by_resource = TRUE;
8127 /* get last play position */
8128 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8129 LOGW("failed to get play position.");
8131 msg.union_type = MM_MSG_UNION_TIME;
8132 msg.time.elapsed = (unsigned int)pos;
8133 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8135 LOGD("video resource conflict so, resource will be freed by unrealizing");
8136 if (_mmplayer_unrealize((MMHandleType)player))
8137 LOGW("failed to unrealize");
8139 /* lock is called in __mmplayer_can_do_interrupt() */
8140 MMPLAYER_CMD_UNLOCK(player);
8143 if (res == player->video_overlay_resource)
8144 player->video_overlay_resource = FALSE;
8146 player->video_decoder_resource = FALSE;
8154 _mmplayer_create_player(MMHandleType handle)
8156 int ret = MM_ERROR_PLAYER_INTERNAL;
8157 bool enabled = false;
8159 mm_player_t* player = MM_PLAYER_CAST(handle);
8163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8165 /* initialize player state */
8166 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8167 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8168 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8169 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8171 /* check current state */
8172 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8174 /* construct attributes */
8175 player->attrs = _mmplayer_construct_attribute(handle);
8177 if (!player->attrs) {
8178 LOGE("Failed to construct attributes\n");
8182 /* initialize gstreamer with configured parameter */
8183 if (!__mmplayer_init_gstreamer(player)) {
8184 LOGE("Initializing gstreamer failed\n");
8185 _mmplayer_deconstruct_attribute(handle);
8189 /* create lock. note that g_tread_init() has already called in gst_init() */
8190 g_mutex_init(&player->fsink_lock);
8192 /* create update tag lock */
8193 g_mutex_init(&player->update_tag_lock);
8195 /* create next play mutex */
8196 g_mutex_init(&player->next_play_thread_mutex);
8198 /* create next play cond */
8199 g_cond_init(&player->next_play_thread_cond);
8201 /* create next play thread */
8202 player->next_play_thread =
8203 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8204 if (!player->next_play_thread) {
8205 LOGE("failed to create next play thread");
8206 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8207 g_mutex_clear(&player->next_play_thread_mutex);
8208 g_cond_clear(&player->next_play_thread_cond);
8212 ret = _mmplayer_initialize_video_capture(player);
8213 if (ret != MM_ERROR_NONE) {
8214 LOGE("failed to initialize video capture\n");
8218 /* initialize resource manager */
8219 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8220 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8221 &player->resource_manager)) {
8222 LOGE("failed to initialize resource manager\n");
8226 if (MMPLAYER_IS_HTTP_PD(player)) {
8227 player->pd_downloader = NULL;
8228 player->pd_file_save_path = NULL;
8231 /* create video bo lock and cond */
8232 g_mutex_init(&player->video_bo_mutex);
8233 g_cond_init(&player->video_bo_cond);
8235 /* create media stream callback mutex */
8236 g_mutex_init(&player->media_stream_cb_lock);
8238 /* create subtitle info lock and cond */
8239 g_mutex_init(&player->subtitle_info_mutex);
8240 g_cond_init(&player->subtitle_info_cond);
8242 player->streaming_type = STREAMING_SERVICE_NONE;
8244 /* give default value of audio effect setting */
8245 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8246 player->sound.rg_enable = false;
8247 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8249 player->play_subtitle = FALSE;
8250 player->use_deinterleave = FALSE;
8251 player->max_audio_channels = 0;
8252 player->video_share_api_delta = 0;
8253 player->video_share_clock_delta = 0;
8254 player->has_closed_caption = FALSE;
8255 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8256 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8257 player->pending_resume = FALSE;
8258 if (player->ini.dump_element_keyword[0][0] == '\0')
8259 player->ini.set_dump_element_flag = FALSE;
8261 player->ini.set_dump_element_flag = TRUE;
8263 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8264 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8265 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8267 /* Set video360 settings to their defaults for just-created player.
8270 player->is_360_feature_enabled = FALSE;
8271 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8272 LOGI("spherical feature info: %d", enabled);
8274 player->is_360_feature_enabled = TRUE;
8276 LOGE("failed to get spherical feature info");
8279 player->is_content_spherical = FALSE;
8280 player->is_video360_enabled = TRUE;
8281 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8282 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8283 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8284 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8285 player->video360_zoom = 1.0f;
8286 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8287 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8289 /* set player state to null */
8290 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8291 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8293 return MM_ERROR_NONE;
8297 g_mutex_clear(&player->fsink_lock);
8299 /* free update tag lock */
8300 g_mutex_clear(&player->update_tag_lock);
8302 /* free next play thread */
8303 if (player->next_play_thread) {
8304 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8305 player->next_play_thread_exit = TRUE;
8306 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8307 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8309 g_thread_join(player->next_play_thread);
8310 player->next_play_thread = NULL;
8312 g_mutex_clear(&player->next_play_thread_mutex);
8313 g_cond_clear(&player->next_play_thread_cond);
8316 /* release attributes */
8317 _mmplayer_deconstruct_attribute(handle);
8325 __mmplayer_init_gstreamer(mm_player_t* player)
8327 static gboolean initialized = FALSE;
8328 static const int max_argc = 50;
8330 gchar** argv = NULL;
8331 gchar** argv2 = NULL;
8337 LOGD("gstreamer already initialized.\n");
8342 argc = malloc(sizeof(int));
8343 argv = malloc(sizeof(gchar*) * max_argc);
8344 argv2 = malloc(sizeof(gchar*) * max_argc);
8346 if (!argc || !argv || !argv2)
8349 memset(argv, 0, sizeof(gchar*) * max_argc);
8350 memset(argv2, 0, sizeof(gchar*) * max_argc);
8354 argv[0] = g_strdup("mmplayer");
8357 for (i = 0; i < 5; i++) {
8358 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8359 if (strlen(player->ini.gst_param[i]) > 0) {
8360 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8365 /* we would not do fork for scanning plugins */
8366 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8369 /* check disable registry scan */
8370 if (player->ini.skip_rescan) {
8371 argv[*argc] = g_strdup("--gst-disable-registry-update");
8375 /* check disable segtrap */
8376 if (player->ini.disable_segtrap) {
8377 argv[*argc] = g_strdup("--gst-disable-segtrap");
8381 LOGD("initializing gstreamer with following parameter\n");
8382 LOGD("argc : %d\n", *argc);
8385 for (i = 0; i < arg_count; i++) {
8387 LOGD("argv[%d] : %s\n", i, argv2[i]);
8390 /* initializing gstreamer */
8391 if (!gst_init_check(argc, &argv, &err)) {
8392 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8399 for (i = 0; i < arg_count; i++) {
8400 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8401 MMPLAYER_FREEIF(argv2[i]);
8404 MMPLAYER_FREEIF(argv);
8405 MMPLAYER_FREEIF(argv2);
8406 MMPLAYER_FREEIF(argc);
8416 for (i = 0; i < arg_count; i++) {
8417 LOGD("free[%d] : %s\n", i, argv2[i]);
8418 MMPLAYER_FREEIF(argv2[i]);
8421 MMPLAYER_FREEIF(argv);
8422 MMPLAYER_FREEIF(argv2);
8423 MMPLAYER_FREEIF(argc);
8429 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8433 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8434 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8435 MMPLAYER_FREEIF(player->pd_file_save_path);
8438 return MM_ERROR_NONE;
8442 __mmplayer_check_async_state_transition(mm_player_t* player)
8444 GstState element_state = GST_STATE_VOID_PENDING;
8445 GstState element_pending_state = GST_STATE_VOID_PENDING;
8446 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8447 GstElement * element = NULL;
8448 gboolean async = FALSE;
8450 /* check player handle */
8451 MMPLAYER_RETURN_IF_FAIL(player &&
8453 player->pipeline->mainbin &&
8454 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8457 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8459 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8460 LOGD("don't need to check the pipeline state");
8464 MMPLAYER_PRINT_STATE(player);
8466 /* wait for state transition */
8467 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8468 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8470 if (ret == GST_STATE_CHANGE_FAILURE) {
8471 LOGE(" [%s] state : %s pending : %s \n",
8472 GST_ELEMENT_NAME(element),
8473 gst_element_state_get_name(element_state),
8474 gst_element_state_get_name(element_pending_state));
8476 /* dump state of all element */
8477 __mmplayer_dump_pipeline_state(player);
8482 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8487 _mmplayer_destroy(MMHandleType handle)
8489 mm_player_t* player = MM_PLAYER_CAST(handle);
8493 /* check player handle */
8494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8496 /* destroy can called at anytime */
8497 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8499 /* check async state transition */
8500 __mmplayer_check_async_state_transition(player);
8502 __mmplayer_destroy_streaming_ext(player);
8504 /* release next play thread */
8505 if (player->next_play_thread) {
8506 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8507 player->next_play_thread_exit = TRUE;
8508 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8509 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8511 LOGD("waitting for next play thread exit\n");
8512 g_thread_join(player->next_play_thread);
8513 g_mutex_clear(&player->next_play_thread_mutex);
8514 g_cond_clear(&player->next_play_thread_cond);
8515 LOGD("next play thread released\n");
8518 _mmplayer_release_video_capture(player);
8520 /* de-initialize resource manager */
8521 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8522 player->resource_manager))
8523 LOGE("failed to deinitialize resource manager\n");
8525 /* release pipeline */
8526 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8527 LOGE("failed to destory pipeline\n");
8528 return MM_ERROR_PLAYER_INTERNAL;
8531 /* release subtitle info lock and cond */
8532 g_mutex_clear(&player->subtitle_info_mutex);
8533 g_cond_clear(&player->subtitle_info_cond);
8535 __mmplayer_release_dump_list(player->dump_list);
8537 /* release miscellaneous information */
8538 __mmplayer_release_misc(player);
8540 /* release miscellaneous information.
8541 these info needs to be released after pipeline is destroyed. */
8542 __mmplayer_release_misc_post(player);
8544 /* release attributes */
8545 _mmplayer_deconstruct_attribute(handle);
8548 g_mutex_clear(&player->fsink_lock);
8551 g_mutex_clear(&player->update_tag_lock);
8553 /* release video bo lock and cond */
8554 g_mutex_clear(&player->video_bo_mutex);
8555 g_cond_clear(&player->video_bo_cond);
8557 /* release media stream callback lock */
8558 g_mutex_clear(&player->media_stream_cb_lock);
8562 return MM_ERROR_NONE;
8566 __mmplayer_realize_streaming_ext(mm_player_t* player)
8568 int ret = MM_ERROR_NONE;
8571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8573 if (MMPLAYER_IS_HTTP_PD(player)) {
8574 gboolean bret = FALSE;
8576 player->pd_downloader = _mmplayer_create_pd_downloader();
8577 if (!player->pd_downloader) {
8578 LOGE("Unable to create PD Downloader...");
8579 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8582 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8584 if (FALSE == bret) {
8585 LOGE("Unable to create PD Downloader...");
8586 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8595 _mmplayer_realize(MMHandleType hplayer)
8597 mm_player_t* player = (mm_player_t*)hplayer;
8600 MMHandleType attrs = 0;
8601 int ret = MM_ERROR_NONE;
8605 /* check player handle */
8606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8608 /* check current state */
8609 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8611 attrs = MMPLAYER_GET_ATTRS(player);
8613 LOGE("fail to get attributes.\n");
8614 return MM_ERROR_PLAYER_INTERNAL;
8616 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8617 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8619 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8620 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8622 if (ret != MM_ERROR_NONE) {
8623 LOGE("failed to parse profile\n");
8628 if (uri && (strstr(uri, "es_buff://"))) {
8629 if (strstr(uri, "es_buff://push_mode"))
8630 player->es_player_push_mode = TRUE;
8632 player->es_player_push_mode = FALSE;
8635 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8636 LOGW("mms protocol is not supported format.\n");
8637 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8640 if (MMPLAYER_IS_STREAMING(player))
8641 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8643 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8645 player->smooth_streaming = FALSE;
8646 player->videodec_linked = 0;
8647 player->videosink_linked = 0;
8648 player->audiodec_linked = 0;
8649 player->audiosink_linked = 0;
8650 player->textsink_linked = 0;
8651 player->is_external_subtitle_present = FALSE;
8652 player->is_external_subtitle_added_now = FALSE;
8653 /* set the subtitle ON default */
8654 player->is_subtitle_off = FALSE;
8656 /* realize pipeline */
8657 ret = __gst_realize(player);
8658 if (ret != MM_ERROR_NONE)
8659 LOGE("fail to realize the player.\n");
8661 ret = __mmplayer_realize_streaming_ext(player);
8663 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8664 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8672 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8675 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8677 /* destroy can called at anytime */
8678 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8679 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8682 return MM_ERROR_NONE;
8686 _mmplayer_unrealize(MMHandleType hplayer)
8688 mm_player_t* player = (mm_player_t*)hplayer;
8689 int ret = MM_ERROR_NONE;
8693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8695 MMPLAYER_CMD_UNLOCK(player);
8696 /* destroy the gst bus msg thread which is created during realize.
8697 this funct have to be called before getting cmd lock. */
8698 _mmplayer_bus_msg_thread_destroy(player);
8699 MMPLAYER_CMD_LOCK(player);
8701 /* check current state */
8702 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8704 /* check async state transition */
8705 __mmplayer_check_async_state_transition(player);
8707 __mmplayer_unrealize_streaming_ext(player);
8709 /* unrealize pipeline */
8710 ret = __gst_unrealize(player);
8712 /* set asm stop if success */
8713 if (MM_ERROR_NONE == ret) {
8714 if (!player->interrupted_by_resource) {
8715 if (player->video_decoder_resource != NULL) {
8716 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8717 player->video_decoder_resource);
8718 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8719 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8721 player->video_decoder_resource = NULL;
8724 if (player->video_overlay_resource != NULL) {
8725 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8726 player->video_overlay_resource);
8727 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8728 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8730 player->video_overlay_resource = NULL;
8733 ret = mm_resource_manager_commit(player->resource_manager);
8734 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8735 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8738 LOGE("failed and don't change asm state to stop");
8746 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8748 mm_player_t* player = (mm_player_t*)hplayer;
8750 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8752 return __gst_set_message_callback(player, callback, user_param);
8756 _mmplayer_get_state(MMHandleType hplayer, int* state)
8758 mm_player_t *player = (mm_player_t*)hplayer;
8760 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8762 *state = MMPLAYER_CURRENT_STATE(player);
8764 return MM_ERROR_NONE;
8769 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8771 mm_player_t* player = (mm_player_t*) hplayer;
8772 GstElement* vol_element = NULL;
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8779 LOGD("volume [L]=%f:[R]=%f\n",
8780 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8782 /* invalid factor range or not */
8783 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8784 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8785 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8786 return MM_ERROR_INVALID_ARGUMENT;
8790 /* not support to set other value into each channel */
8791 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8792 return MM_ERROR_INVALID_ARGUMENT;
8794 /* Save volume to handle. Currently the first array element will be saved. */
8795 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8797 /* check pipeline handle */
8798 if (!player->pipeline || !player->pipeline->audiobin) {
8799 LOGD("audiobin is not created yet\n");
8800 LOGD("but, current stored volume will be set when it's created.\n");
8802 /* NOTE : stored volume will be used in create_audiobin
8803 * returning MM_ERROR_NONE here makes application to able to
8804 * set volume at anytime.
8806 return MM_ERROR_NONE;
8809 /* setting volume to volume element */
8810 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8813 LOGD("volume is set [%f]\n", player->sound.volume);
8814 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8819 return MM_ERROR_NONE;
8824 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8826 mm_player_t* player = (mm_player_t*) hplayer;
8831 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8832 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8834 /* returning stored volume */
8835 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8836 volume->level[i] = player->sound.volume;
8840 return MM_ERROR_NONE;
8844 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8846 mm_player_t* player = (mm_player_t*) hplayer;
8847 GstElement* vol_element = NULL;
8851 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8853 /* mute value shoud 0 or 1 */
8854 if (mute != 0 && mute != 1) {
8855 LOGE("bad mute value\n");
8857 /* FIXIT : definitly, we need _BAD_PARAM error code */
8858 return MM_ERROR_INVALID_ARGUMENT;
8861 player->sound.mute = mute;
8863 /* just hold mute value if pipeline is not ready */
8864 if (!player->pipeline || !player->pipeline->audiobin) {
8865 LOGD("pipeline is not ready. holding mute value\n");
8866 return MM_ERROR_NONE;
8869 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8871 /* NOTE : volume will only created when the bt is enabled */
8873 LOGD("mute : %d\n", mute);
8874 g_object_set(vol_element, "mute", mute, NULL);
8876 LOGD("volume elemnet is not created. using volume in audiosink\n");
8880 return MM_ERROR_NONE;
8884 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8886 mm_player_t* player = (mm_player_t*) hplayer;
8890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8891 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8893 /* just hold mute value if pipeline is not ready */
8894 if (!player->pipeline || !player->pipeline->audiobin) {
8895 LOGD("pipeline is not ready. returning stored value\n");
8896 *pmute = player->sound.mute;
8897 return MM_ERROR_NONE;
8900 *pmute = player->sound.mute;
8904 return MM_ERROR_NONE;
8908 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8910 mm_player_t* player = (mm_player_t*) hplayer;
8914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916 player->video_stream_changed_cb = callback;
8917 player->video_stream_changed_cb_user_param = user_param;
8918 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8922 return MM_ERROR_NONE;
8926 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8928 mm_player_t* player = (mm_player_t*) hplayer;
8932 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8934 player->audio_stream_changed_cb = callback;
8935 player->audio_stream_changed_cb_user_param = user_param;
8936 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8940 return MM_ERROR_NONE;
8944 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8946 mm_player_t* player = (mm_player_t*) hplayer;
8950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8952 player->audio_stream_render_cb_ex = callback;
8953 player->audio_stream_cb_user_param = user_param;
8954 player->audio_stream_sink_sync = sync;
8955 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);
8959 return MM_ERROR_NONE;
8963 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8965 mm_player_t* player = (mm_player_t*) hplayer;
8969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8971 if (callback && !player->bufmgr)
8972 player->bufmgr = tbm_bufmgr_init(-1);
8974 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8975 player->video_stream_cb = callback;
8976 player->video_stream_cb_user_param = user_param;
8978 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8982 return MM_ERROR_NONE;
8986 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8988 mm_player_t* player = (mm_player_t*) hplayer;
8992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8994 player->audio_stream_cb = callback;
8995 player->audio_stream_cb_user_param = user_param;
8996 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9000 return MM_ERROR_NONE;
9004 __mmplayer_start_streaming_ext(mm_player_t *player)
9006 gint ret = MM_ERROR_NONE;
9009 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9011 if (MMPLAYER_IS_HTTP_PD(player)) {
9012 if (!player->pd_downloader) {
9013 ret = __mmplayer_realize_streaming_ext(player);
9015 if (ret != MM_ERROR_NONE) {
9016 LOGE("failed to realize streaming ext\n");
9021 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9022 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9024 LOGE("ERROR while starting PD...\n");
9025 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9027 ret = MM_ERROR_NONE;
9036 _mmplayer_start(MMHandleType hplayer)
9038 mm_player_t* player = (mm_player_t*) hplayer;
9039 gint ret = MM_ERROR_NONE;
9043 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9045 /* check current state */
9046 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9048 /* NOTE : we should check and create pipeline again if not created as we destroy
9049 * whole pipeline when stopping in streamming playback
9051 if (!player->pipeline) {
9052 ret = __gst_realize(player);
9053 if (MM_ERROR_NONE != ret) {
9054 LOGE("failed to realize before starting. only in streamming\n");
9060 ret = __mmplayer_start_streaming_ext(player);
9061 if (ret != MM_ERROR_NONE) {
9062 LOGE("failed to start streaming ext 0x%X", ret);
9066 /* start pipeline */
9067 ret = __gst_start(player);
9068 if (ret != MM_ERROR_NONE)
9069 LOGE("failed to start player.\n");
9076 /* NOTE: post "not supported codec message" to application
9077 * when one codec is not found during AUTOPLUGGING in MSL.
9078 * So, it's separated with error of __mmplayer_gst_callback().
9079 * And, if any codec is not found, don't send message here.
9080 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9083 __mmplayer_handle_missed_plugin(mm_player_t* player)
9085 MMMessageParamType msg_param;
9086 memset(&msg_param, 0, sizeof(MMMessageParamType));
9087 gboolean post_msg_direct = FALSE;
9091 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9093 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9094 player->not_supported_codec, player->can_support_codec);
9096 if (player->not_found_demuxer) {
9097 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9098 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9100 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9101 MMPLAYER_FREEIF(msg_param.data);
9103 return MM_ERROR_NONE;
9106 if (player->not_supported_codec) {
9107 if (player->can_support_codec) {
9108 // There is one codec to play
9109 post_msg_direct = TRUE;
9111 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9112 post_msg_direct = TRUE;
9115 if (post_msg_direct) {
9116 MMMessageParamType msg_param;
9117 memset(&msg_param, 0, sizeof(MMMessageParamType));
9119 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9120 LOGW("not found AUDIO codec, posting error code to application.\n");
9122 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9123 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9124 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9125 LOGW("not found VIDEO codec, posting error code to application.\n");
9127 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9128 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9131 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9133 MMPLAYER_FREEIF(msg_param.data);
9135 return MM_ERROR_NONE;
9137 // no any supported codec case
9138 LOGW("not found any codec, posting error code to application.\n");
9140 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9141 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9142 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9144 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9145 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9148 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9150 MMPLAYER_FREEIF(msg_param.data);
9156 return MM_ERROR_NONE;
9159 static void __mmplayer_check_pipeline(mm_player_t* player)
9161 GstState element_state = GST_STATE_VOID_PENDING;
9162 GstState element_pending_state = GST_STATE_VOID_PENDING;
9164 int ret = MM_ERROR_NONE;
9166 if (player->gapless.reconfigure) {
9167 LOGW("pipeline is under construction.\n");
9169 MMPLAYER_PLAYBACK_LOCK(player);
9170 MMPLAYER_PLAYBACK_UNLOCK(player);
9172 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9174 /* wait for state transition */
9175 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9177 if (ret == GST_STATE_CHANGE_FAILURE)
9178 LOGE("failed to change pipeline state within %d sec\n", timeout);
9182 /* NOTE : it should be able to call 'stop' anytime*/
9184 _mmplayer_stop(MMHandleType hplayer)
9186 mm_player_t* player = (mm_player_t*)hplayer;
9187 int ret = MM_ERROR_NONE;
9191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9193 /* check current state */
9194 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9196 /* check pipline building state */
9197 __mmplayer_check_pipeline(player);
9198 __mmplayer_reset_gapless_state(player);
9200 /* NOTE : application should not wait for EOS after calling STOP */
9201 __mmplayer_cancel_eos_timer(player);
9203 __mmplayer_unrealize_streaming_ext(player);
9206 player->doing_seek = FALSE;
9209 ret = __gst_stop(player);
9211 if (ret != MM_ERROR_NONE)
9212 LOGE("failed to stop player.\n");
9220 _mmplayer_pause(MMHandleType hplayer)
9222 mm_player_t* player = (mm_player_t*)hplayer;
9223 gint64 pos_msec = 0;
9224 gboolean async = FALSE;
9225 gint ret = MM_ERROR_NONE;
9229 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9231 /* check current state */
9232 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9234 /* check pipline building state */
9235 __mmplayer_check_pipeline(player);
9237 switch (MMPLAYER_CURRENT_STATE(player)) {
9238 case MM_PLAYER_STATE_READY:
9240 /* check prepare async or not.
9241 * In the case of streaming playback, it's recommned to avoid blocking wait.
9243 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9244 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9246 /* Changing back sync of rtspsrc to async */
9247 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9248 LOGD("async prepare working mode for rtsp");
9254 case MM_PLAYER_STATE_PLAYING:
9256 /* NOTE : store current point to overcome some bad operation
9257 *(returning zero when getting current position in paused state) of some
9260 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9261 LOGW("getting current position failed in paused\n");
9263 player->last_position = pos_msec;
9265 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9266 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9267 This causes problem is position calculation during normal pause resume scenarios also.
9268 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9269 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9270 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9271 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9277 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9278 LOGD("doing async pause in case of ms buff src");
9282 /* pause pipeline */
9283 ret = __gst_pause(player, async);
9285 if (ret != MM_ERROR_NONE)
9286 LOGE("failed to pause player. ret : 0x%x\n", ret);
9288 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9289 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9290 LOGE("failed to update display_rotation");
9299 _mmplayer_resume(MMHandleType hplayer)
9301 mm_player_t* player = (mm_player_t*)hplayer;
9302 int ret = MM_ERROR_NONE;
9303 gboolean async = FALSE;
9307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9309 /* Changing back sync mode rtspsrc to async */
9310 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9311 LOGD("async resume for rtsp case");
9315 /* check current state */
9316 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9318 ret = __gst_resume(player, async);
9320 if (ret != MM_ERROR_NONE)
9321 LOGE("failed to resume player.\n");
9329 __mmplayer_set_pcm_extraction(mm_player_t* player)
9331 gint64 start_nsec = 0;
9332 gint64 end_nsec = 0;
9333 gint64 dur_nsec = 0;
9334 gint64 dur_msec = 0;
9335 int required_start = 0;
9336 int required_end = 0;
9341 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9343 mm_attrs_multiple_get(player->attrs,
9345 "pcm_extraction_start_msec", &required_start,
9346 "pcm_extraction_end_msec", &required_end,
9349 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9351 if (required_start == 0 && required_end == 0) {
9352 LOGD("extracting entire stream");
9353 return MM_ERROR_NONE;
9354 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9355 LOGD("invalid range for pcm extraction");
9356 return MM_ERROR_INVALID_ARGUMENT;
9360 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9362 LOGE("failed to get duration");
9363 return MM_ERROR_PLAYER_INTERNAL;
9365 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9367 if (dur_msec < required_end) {
9369 LOGD("invalid end pos for pcm extraction");
9370 return MM_ERROR_INVALID_ARGUMENT;
9373 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9374 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9376 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9379 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9380 GST_SEEK_TYPE_SET, start_nsec,
9381 GST_SEEK_TYPE_SET, end_nsec))) {
9382 LOGE("failed to seek for pcm extraction\n");
9384 return MM_ERROR_PLAYER_SEEK;
9387 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9391 return MM_ERROR_NONE;
9395 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9397 mm_player_t* player = (mm_player_t*)hplayer;
9398 gint64 pos_msec = 0;
9399 int ret = MM_ERROR_NONE;
9401 signed long long start = 0, stop = 0;
9402 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9405 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9406 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9408 /* The sound of video is not supported under 0.0 and over 2.0. */
9409 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9410 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9413 _mmplayer_set_mute(hplayer, mute);
9415 if (player->playback_rate == rate)
9416 return MM_ERROR_NONE;
9418 /* If the position is reached at start potion during fast backward, EOS is posted.
9419 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9421 player->playback_rate = rate;
9423 current_state = MMPLAYER_CURRENT_STATE(player);
9425 if (current_state != MM_PLAYER_STATE_PAUSED)
9426 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9428 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9430 if ((current_state == MM_PLAYER_STATE_PAUSED)
9431 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9432 LOGW("returning last point : %lld\n", player->last_position);
9433 pos_msec = player->last_position;
9438 stop = GST_CLOCK_TIME_NONE;
9440 start = GST_CLOCK_TIME_NONE;
9444 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9445 player->playback_rate,
9447 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9448 GST_SEEK_TYPE_SET, start,
9449 GST_SEEK_TYPE_SET, stop)) {
9450 LOGE("failed to set speed playback\n");
9451 return MM_ERROR_PLAYER_SEEK;
9454 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9458 return MM_ERROR_NONE;;
9462 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9464 mm_player_t* player = (mm_player_t*)hplayer;
9465 int ret = MM_ERROR_NONE;
9469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9471 /* check pipline building state */
9472 __mmplayer_check_pipeline(player);
9474 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9482 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9484 mm_player_t* player = (mm_player_t*)hplayer;
9485 int ret = MM_ERROR_NONE;
9487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9489 ret = __gst_get_position(player, format, position);
9495 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9497 mm_player_t* player = (mm_player_t*)hplayer;
9498 int ret = MM_ERROR_NONE;
9500 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9502 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9508 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9510 mm_player_t* player = (mm_player_t*)hplayer;
9511 int ret = MM_ERROR_NONE;
9515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9517 ret = __gst_adjust_subtitle_position(player, format, position);
9524 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9526 mm_player_t* player = (mm_player_t*)hplayer;
9527 int ret = MM_ERROR_NONE;
9531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9533 ret = __gst_adjust_video_position(player, offset);
9541 __mmplayer_is_midi_type(gchar* str_caps)
9543 if ((g_strrstr(str_caps, "audio/midi")) ||
9544 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9545 (g_strrstr(str_caps, "application/x-smaf")) ||
9546 (g_strrstr(str_caps, "audio/x-imelody")) ||
9547 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9548 (g_strrstr(str_caps, "audio/xmf")) ||
9549 (g_strrstr(str_caps, "audio/mxmf"))) {
9558 __mmplayer_is_only_mp3_type(gchar *str_caps)
9560 if (g_strrstr(str_caps, "application/x-id3") ||
9561 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9567 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9569 GstStructure* caps_structure = NULL;
9570 gint samplerate = 0;
9574 MMPLAYER_RETURN_IF_FAIL(player && caps);
9576 caps_structure = gst_caps_get_structure(caps, 0);
9578 /* set stream information */
9579 gst_structure_get_int(caps_structure, "rate", &samplerate);
9580 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9582 gst_structure_get_int(caps_structure, "channels", &channels);
9583 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9585 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9589 __mmplayer_update_content_type_info(mm_player_t* player)
9592 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9594 if (__mmplayer_is_midi_type(player->type)) {
9595 player->bypass_audio_effect = TRUE;
9596 } else if (g_strrstr(player->type, "application/x-hls")) {
9597 /* If it can't know exact type when it parses uri because of redirection case,
9598 * it will be fixed by typefinder or when doing autoplugging.
9600 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9601 if (player->streamer) {
9602 player->streamer->is_adaptive_streaming = TRUE;
9603 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9604 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9606 } else if (g_strrstr(player->type, "application/dash+xml")) {
9607 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9614 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9615 GstCaps *caps, gpointer data)
9617 mm_player_t* player = (mm_player_t*)data;
9622 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9624 /* store type string */
9625 MMPLAYER_FREEIF(player->type);
9626 player->type = gst_caps_to_string(caps);
9628 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9629 player, player->type, probability, gst_caps_get_size(caps));
9632 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9633 (g_strrstr(player->type, "audio/x-raw-int"))) {
9634 LOGE("not support media format\n");
9636 if (player->msg_posted == FALSE) {
9637 MMMessageParamType msg_param;
9638 memset(&msg_param, 0, sizeof(MMMessageParamType));
9640 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9641 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9643 /* don't post more if one was sent already */
9644 player->msg_posted = TRUE;
9649 __mmplayer_update_content_type_info(player);
9651 pad = gst_element_get_static_pad(tf, "src");
9653 LOGE("fail to get typefind src pad.\n");
9657 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9658 gboolean async = FALSE;
9659 LOGE("failed to autoplug %s\n", player->type);
9661 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9663 if (async && player->msg_posted == FALSE)
9664 __mmplayer_handle_missed_plugin(player);
9670 gst_object_unref(GST_OBJECT(pad));
9678 __mmplayer_create_decodebin(mm_player_t* player)
9680 GstElement *decodebin = NULL;
9684 /* create decodebin */
9685 decodebin = gst_element_factory_make("decodebin", NULL);
9688 LOGE("fail to create decodebin\n");
9692 /* raw pad handling signal */
9693 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9694 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9696 /* no-more-pad pad handling signal */
9697 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9698 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9700 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9701 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9703 /* This signal is emitted when a pad for which there is no further possible
9704 decoding is added to the decodebin.*/
9705 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9706 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9708 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9709 before looking for any elements that can handle that stream.*/
9710 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9711 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9713 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9714 before looking for any elements that can handle that stream.*/
9715 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9716 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9718 /* This signal is emitted once decodebin has finished decoding all the data.*/
9719 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9720 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9722 /* This signal is emitted when a element is added to the bin.*/
9723 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9724 G_CALLBACK(__mmplayer_gst_element_added), player);
9731 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9733 MMPlayerGstElement* mainbin = NULL;
9734 GstElement* decodebin = NULL;
9735 GstElement* queue2 = NULL;
9736 GstPad* sinkpad = NULL;
9737 GstPad* qsrcpad = NULL;
9738 gint64 dur_bytes = 0L;
9740 guint max_buffer_size_bytes = 0;
9741 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9744 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9746 mainbin = player->pipeline->mainbin;
9748 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9749 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9750 LOGD("creating http streaming buffering queue(queue2)\n");
9752 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9753 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9755 queue2 = gst_element_factory_make("queue2", "queue2");
9757 LOGE("failed to create buffering queue element\n");
9761 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9762 LOGE("failed to add buffering queue\n");
9766 sinkpad = gst_element_get_static_pad(queue2, "sink");
9767 qsrcpad = gst_element_get_static_pad(queue2, "src");
9769 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9770 LOGE("failed to link buffering queue\n");
9774 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9775 LOGE("fail to get duration.\n");
9777 LOGD("dur_bytes = %lld\n", dur_bytes);
9779 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9781 if (dur_bytes > 0) {
9782 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9783 type = MUXED_BUFFER_TYPE_FILE;
9785 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9786 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9792 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9793 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9794 if (!g_strrstr(player->type, "video/mpegts")) {
9795 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9796 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9798 // FIXME : pass ini setting directly. is this ok?
9799 __mm_player_streaming_set_queue2(player->streamer,
9802 max_buffer_size_bytes,
9803 player->ini.http_buffering_time,
9805 player->ini.http_buffering_limit, // no meaning
9807 player->http_file_buffering_path,
9808 (guint64)dur_bytes);
9811 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9812 LOGE("failed to sync queue2 state with parent\n");
9818 gst_object_unref(GST_OBJECT(sinkpad));
9820 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9821 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9825 /* create decodebin */
9826 decodebin = __mmplayer_create_decodebin(player);
9829 LOGE("can not create autoplug element\n");
9833 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9834 LOGE("failed to add decodebin\n");
9838 /* to force caps on the decodebin element and avoid reparsing stuff by
9839 * typefind. It also avoids a deadlock in the way typefind activates pads in
9840 * the state change */
9841 g_object_set(decodebin, "sink-caps", caps, NULL);
9843 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9845 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9846 LOGE("failed to link decodebin\n");
9850 gst_object_unref(GST_OBJECT(sinkpad));
9852 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9853 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9855 /* set decodebin property about buffer in streaming playback. *
9856 * in case of HLS/DASH, it does not need to have big buffer *
9857 * because it is kind of adaptive streaming. */
9858 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9859 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9860 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9861 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9863 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9864 || MMPLAYER_IS_DASH_STREAMING(player)) {
9865 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9866 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9869 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9870 "high-percent", (gint)player->ini.http_buffering_limit,
9871 "low-percent", 1, // 1%
9872 "max-size-bytes", max_size_bytes,
9873 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9874 "max-size-buffers", 0, NULL); // disable or automatic
9877 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9878 LOGE("failed to sync decodebin state with parent\n");
9889 gst_object_unref(GST_OBJECT(sinkpad));
9892 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9893 * You need to explicitly set elements to the NULL state before
9894 * dropping the final reference, to allow them to clean up.
9896 gst_element_set_state(queue2, GST_STATE_NULL);
9898 /* And, it still has a parent "player".
9899 * You need to let the parent manage the object instead of unreffing the object directly.
9901 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9902 gst_object_unref(queue2);
9907 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9908 * You need to explicitly set elements to the NULL state before
9909 * dropping the final reference, to allow them to clean up.
9911 gst_element_set_state(decodebin, GST_STATE_NULL);
9913 /* And, it still has a parent "player".
9914 * You need to let the parent manage the object instead of unreffing the object directly.
9917 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9918 gst_object_unref(decodebin);
9926 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9930 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9931 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9933 LOGD("class : %s, mime : %s \n", factory_class, mime);
9935 /* add missing plugin */
9936 /* NOTE : msl should check missing plugin for image mime type.
9937 * Some motion jpeg clips can have playable audio track.
9938 * So, msl have to play audio after displaying popup written video format not supported.
9940 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9941 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9942 LOGD("not found demuxer\n");
9943 player->not_found_demuxer = TRUE;
9944 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9950 if (!g_strrstr(factory_class, "Demuxer")) {
9951 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9952 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9953 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9955 /* check that clip have multi tracks or not */
9956 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9957 LOGD("video plugin is already linked\n");
9959 LOGW("add VIDEO to missing plugin\n");
9960 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9961 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9963 } else if (g_str_has_prefix(mime, "audio")) {
9964 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9965 LOGD("audio plugin is already linked\n");
9967 LOGW("add AUDIO to missing plugin\n");
9968 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9969 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9977 return MM_ERROR_NONE;
9982 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9984 mm_player_t* player = (mm_player_t*)data;
9988 MMPLAYER_RETURN_IF_FAIL(player);
9990 /* remove fakesink. */
9991 if (!__mmplayer_gst_remove_fakesink(player,
9992 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9993 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9994 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9995 * source element are not same. To overcome this situation, this function will called
9996 * several places and several times. Therefore, this is not an error case.
10001 LOGD("[handle: %p] pipeline has completely constructed", player);
10003 if ((player->ini.async_start) &&
10004 (player->msg_posted == FALSE) &&
10005 (player->cmd >= MMPLAYER_COMMAND_START))
10006 __mmplayer_handle_missed_plugin(player);
10008 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10012 __mmplayer_verify_next_play_path(mm_player_t *player)
10014 MMHandleType attrs = 0;
10015 MMPlayerParseProfile profile;
10016 gint uri_idx = 0, check_cnt = 0;
10018 gint mode = MM_PLAYER_PD_MODE_NONE;
10022 guint num_of_list = 0;
10023 static int profile_tv = -1;
10027 LOGD("checking for gapless play");
10029 if (player->pipeline->textbin) {
10030 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10034 attrs = MMPLAYER_GET_ATTRS(player);
10036 LOGE("fail to get attributes.\n");
10040 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10042 if (__builtin_expect(profile_tv == -1, 0)) {
10044 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10045 switch (*profileName) {
10055 /* gapless playback is not supported in case of video at TV profile. */
10056 if (profile_tv && video) {
10057 LOGW("not support video gapless playback");
10061 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10062 if (mode == TRUE) {
10068 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10069 LOGE("can not get play count\n");
10071 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10072 LOGE("can not get gapless mode\n");
10074 if (video && !gapless) {
10075 LOGW("not enabled video gapless playback");
10079 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10083 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10087 num_of_list = g_list_length(player->uri_info.uri_list);
10089 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10091 if (num_of_list == 0) {
10092 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10093 LOGE("can not get profile_uri\n");
10098 LOGE("uri list is empty.\n");
10102 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10103 LOGD("add original path : %s ", uri);
10109 uri_idx = player->uri_info.uri_idx;
10114 if (check_cnt > num_of_list) {
10115 LOGE("there is no valid uri.");
10119 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10121 if (uri_idx < num_of_list-1) {
10124 if ((count <= 1) && (count != -1)) {
10125 LOGD("no repeat.");
10127 } else if (count > 1) {
10128 /* decrease play count */
10129 /* we succeeded to rewind. update play count and then wait for next EOS */
10132 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10134 /* commit attribute */
10135 if (mmf_attrs_commit(attrs))
10136 LOGE("failed to commit attribute\n");
10139 /* count < 0 : repeat continually */
10143 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10144 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10147 LOGW("next uri does not exist\n");
10151 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10152 LOGE("failed to parse profile\n");
10156 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10157 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10158 LOGW("uri type is not supported(%d).", profile.uri_type);
10165 player->uri_info.uri_idx = uri_idx;
10166 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10168 if (mmf_attrs_commit(player->attrs)) {
10169 LOGE("failed to commit.\n");
10173 LOGD("next uri %s(%d)\n", uri, uri_idx);
10179 LOGE("unable to play next path. EOS will be posted soon.\n");
10184 __mmplayer_initialize_next_play(mm_player_t *player)
10190 player->smooth_streaming = FALSE;
10191 player->videodec_linked = 0;
10192 player->audiodec_linked = 0;
10193 player->videosink_linked = 0;
10194 player->audiosink_linked = 0;
10195 player->textsink_linked = 0;
10196 player->is_external_subtitle_present = FALSE;
10197 player->is_external_subtitle_added_now = FALSE;
10198 player->not_supported_codec = MISSING_PLUGIN_NONE;
10199 player->can_support_codec = FOUND_PLUGIN_NONE;
10200 player->pending_seek.is_pending = FALSE;
10201 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10202 player->pending_seek.pos = 0;
10203 player->msg_posted = FALSE;
10204 player->has_many_types = FALSE;
10205 player->no_more_pad = FALSE;
10206 player->not_found_demuxer = 0;
10207 player->doing_seek = FALSE;
10208 player->max_audio_channels = 0;
10209 player->is_subtitle_force_drop = FALSE;
10210 player->play_subtitle = FALSE;
10211 player->adjust_subtitle_pos = 0;
10213 player->total_bitrate = 0;
10214 player->total_maximum_bitrate = 0;
10216 _mmplayer_track_initialize(player);
10217 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10219 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10220 player->bitrate[i] = 0;
10221 player->maximum_bitrate[i] = 0;
10224 if (player->v_stream_caps) {
10225 gst_caps_unref(player->v_stream_caps);
10226 player->v_stream_caps = NULL;
10229 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10231 /* clean found parsers */
10232 if (player->parsers) {
10233 GList *parsers = player->parsers;
10234 for (; parsers; parsers = g_list_next(parsers)) {
10235 gchar *name = parsers->data;
10236 MMPLAYER_FREEIF(name);
10238 g_list_free(player->parsers);
10239 player->parsers = NULL;
10242 /* clean found audio decoders */
10243 if (player->audio_decoders) {
10244 GList *a_dec = player->audio_decoders;
10245 for (; a_dec; a_dec = g_list_next(a_dec)) {
10246 gchar *name = a_dec->data;
10247 MMPLAYER_FREEIF(name);
10249 g_list_free(player->audio_decoders);
10250 player->audio_decoders = NULL;
10257 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10259 MMPlayerGstElement *mainbin = NULL;
10260 MMMessageParamType msg_param = {0,};
10261 GstElement *element = NULL;
10262 MMHandleType attrs = 0;
10264 enum MainElementID elemId = MMPLAYER_M_NUM;
10268 if ((player == NULL) ||
10269 (player->pipeline == NULL) ||
10270 (player->pipeline->mainbin == NULL)) {
10271 LOGE("player is null.\n");
10275 mainbin = player->pipeline->mainbin;
10276 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10278 attrs = MMPLAYER_GET_ATTRS(player);
10280 LOGE("fail to get attributes.\n");
10284 /* Initialize Player values */
10285 __mmplayer_initialize_next_play(player);
10287 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10289 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10290 LOGE("failed to parse profile\n");
10291 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10295 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10296 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10297 LOGE("it's dash or hls. not support.");
10298 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10303 switch (player->profile.uri_type) {
10305 case MM_PLAYER_URI_TYPE_FILE:
10307 LOGD("using filesrc for 'file://' handler.\n");
10308 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10309 LOGE("failed to get storage info");
10313 element = gst_element_factory_make("filesrc", "source");
10316 LOGE("failed to create filesrc\n");
10320 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10323 case MM_PLAYER_URI_TYPE_URL_HTTP:
10325 gchar *user_agent, *cookies, **cookie_list;
10326 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10327 user_agent = cookies = NULL;
10328 cookie_list = NULL;
10330 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10332 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10335 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10337 /* get attribute */
10338 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10339 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10341 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10342 LOGD("get timeout from ini\n");
10343 http_timeout = player->ini.http_timeout;
10346 /* get attribute */
10347 SECURE_LOGD("location : %s\n", player->profile.uri);
10348 SECURE_LOGD("cookies : %s\n", cookies);
10349 SECURE_LOGD("user_agent : %s\n", user_agent);
10350 LOGD("timeout : %d\n", http_timeout);
10352 /* setting property to streaming source */
10353 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10354 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10355 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10357 /* parsing cookies */
10358 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10359 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10361 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10365 LOGE("not support uri type %d\n", player->profile.uri_type);
10370 LOGE("no source element was created.\n");
10374 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10375 LOGE("failed to add source element to pipeline\n");
10376 gst_object_unref(GST_OBJECT(element));
10381 /* take source element */
10382 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10383 mainbin[MMPLAYER_M_SRC].gst = element;
10387 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10388 if (player->streamer == NULL) {
10389 player->streamer = __mm_player_streaming_create();
10390 __mm_player_streaming_initialize(player->streamer);
10393 elemId = MMPLAYER_M_TYPEFIND;
10394 element = gst_element_factory_make("typefind", "typefinder");
10395 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10396 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10398 elemId = MMPLAYER_M_AUTOPLUG;
10399 element = __mmplayer_create_decodebin(player);
10402 /* check autoplug element is OK */
10404 LOGE("can not create element(%d)\n", elemId);
10408 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10409 LOGE("failed to add sinkbin to pipeline\n");
10410 gst_object_unref(GST_OBJECT(element));
10415 mainbin[elemId].id = elemId;
10416 mainbin[elemId].gst = element;
10418 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10419 LOGE("Failed to link src - autoplug(or typefind)\n");
10423 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10424 LOGE("Failed to change state of src element\n");
10428 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10429 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10430 LOGE("Failed to change state of decodebin\n");
10434 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10435 LOGE("Failed to change state of src element\n");
10440 player->gapless.stream_changed = TRUE;
10441 player->gapless.running = TRUE;
10447 MMPLAYER_PLAYBACK_UNLOCK(player);
10449 if (!player->msg_posted) {
10450 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10451 player->msg_posted = TRUE;
10458 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10460 mm_player_selector_t *selector = &player->selector[type];
10461 MMPlayerGstElement *sinkbin = NULL;
10462 enum MainElementID selectorId = MMPLAYER_M_NUM;
10463 enum MainElementID sinkId = MMPLAYER_M_NUM;
10464 GstPad *srcpad = NULL;
10465 GstPad *sinkpad = NULL;
10466 gboolean send_notice = FALSE;
10469 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10471 LOGD("type %d", type);
10474 case MM_PLAYER_TRACK_TYPE_AUDIO:
10475 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10476 sinkId = MMPLAYER_A_BIN;
10477 sinkbin = player->pipeline->audiobin;
10479 case MM_PLAYER_TRACK_TYPE_VIDEO:
10480 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10481 sinkId = MMPLAYER_V_BIN;
10482 sinkbin = player->pipeline->videobin;
10483 send_notice = TRUE;
10485 case MM_PLAYER_TRACK_TYPE_TEXT:
10486 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10487 sinkId = MMPLAYER_T_BIN;
10488 sinkbin = player->pipeline->textbin;
10491 LOGE("requested type is not supportable");
10496 if (player->pipeline->mainbin[selectorId].gst) {
10499 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10501 if (selector->event_probe_id != 0)
10502 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10503 selector->event_probe_id = 0;
10505 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10506 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10508 if (srcpad && sinkpad) {
10509 /* after getting drained signal there is no data flows, so no need to do pad_block */
10510 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10511 gst_pad_unlink(srcpad, sinkpad);
10513 /* send custom event to sink pad to handle it at video sink */
10515 LOGD("send custom event to sinkpad");
10516 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10517 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10518 gst_pad_send_event(sinkpad, event);
10522 gst_object_unref(sinkpad);
10525 gst_object_unref(srcpad);
10528 LOGD("selector release");
10530 /* release and unref requests pad from the selector */
10531 for (n = 0; n < selector->channels->len; n++) {
10532 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10533 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10535 g_ptr_array_set_size(selector->channels, 0);
10537 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10538 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10540 player->pipeline->mainbin[selectorId].gst = NULL;
10548 __mmplayer_deactivate_old_path(mm_player_t *player)
10551 MMPLAYER_RETURN_IF_FAIL(player);
10553 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10554 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10555 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10556 LOGE("deactivate selector error");
10560 _mmplayer_track_destroy(player);
10561 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10563 if (player->streamer) {
10564 __mm_player_streaming_deinitialize(player->streamer);
10565 __mm_player_streaming_destroy(player->streamer);
10566 player->streamer = NULL;
10569 MMPLAYER_PLAYBACK_LOCK(player);
10570 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10577 if (!player->msg_posted) {
10578 MMMessageParamType msg = {0,};
10581 msg.code = MM_ERROR_PLAYER_INTERNAL;
10582 LOGE("next_uri_play> deactivate error");
10584 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10585 player->msg_posted = TRUE;
10590 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10592 int result = MM_ERROR_NONE;
10593 mm_player_t* player = (mm_player_t*) hplayer;
10596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10599 player->http_file_buffering_path = (gchar*)file_path;
10600 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10606 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10608 int result = MM_ERROR_NONE;
10609 mm_player_t* player = (mm_player_t*) hplayer;
10612 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10614 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10615 if (mmf_attrs_commit(player->attrs)) {
10616 LOGE("failed to commit the original uri.\n");
10617 result = MM_ERROR_PLAYER_INTERNAL;
10619 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10620 LOGE("failed to add the original uri in the uri list.\n");
10627 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10629 mm_player_t* player = (mm_player_t*) hplayer;
10630 guint num_of_list = 0;
10634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10635 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10637 if (player->pipeline && player->pipeline->textbin) {
10638 LOGE("subtitle path is enabled.\n");
10639 return MM_ERROR_PLAYER_INVALID_STATE;
10642 num_of_list = g_list_length(player->uri_info.uri_list);
10644 if (is_first_path == TRUE) {
10645 if (num_of_list == 0) {
10646 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10647 LOGD("add original path : %s", uri);
10649 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10650 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10652 LOGD("change original path : %s", uri);
10655 MMHandleType attrs = 0;
10656 attrs = MMPLAYER_GET_ATTRS(player);
10658 if (num_of_list == 0) {
10659 char *original_uri = NULL;
10662 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10664 if (!original_uri) {
10665 LOGE("there is no original uri.");
10666 return MM_ERROR_PLAYER_INVALID_STATE;
10669 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10670 player->uri_info.uri_idx = 0;
10672 LOGD("add original path at first : %s(%d)", original_uri);
10676 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10677 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10681 return MM_ERROR_NONE;
10684 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10686 mm_player_t* player = (mm_player_t*) hplayer;
10687 char *next_uri = NULL;
10688 guint num_of_list = 0;
10691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10693 num_of_list = g_list_length(player->uri_info.uri_list);
10695 if (num_of_list > 0) {
10696 gint uri_idx = player->uri_info.uri_idx;
10698 if (uri_idx < num_of_list-1)
10703 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10704 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10706 *uri = g_strdup(next_uri);
10710 return MM_ERROR_NONE;
10714 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10715 GstCaps *caps, gpointer data)
10717 mm_player_t* player = (mm_player_t*)data;
10718 const gchar* klass = NULL;
10719 const gchar* mime = NULL;
10720 gchar* caps_str = NULL;
10722 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10723 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10724 caps_str = gst_caps_to_string(caps);
10726 LOGW("unknown type of caps : %s from %s",
10727 caps_str, GST_ELEMENT_NAME(elem));
10729 MMPLAYER_FREEIF(caps_str);
10731 /* There is no available codec. */
10732 __mmplayer_check_not_supported_codec(player, klass, mime);
10736 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10737 GstCaps * caps, gpointer data)
10739 mm_player_t* player = (mm_player_t*)data;
10740 const char* mime = NULL;
10741 gboolean ret = TRUE;
10743 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10744 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10746 if (g_str_has_prefix(mime, "audio")) {
10747 GstStructure* caps_structure = NULL;
10748 gint samplerate = 0;
10750 gchar *caps_str = NULL;
10752 caps_structure = gst_caps_get_structure(caps, 0);
10753 gst_structure_get_int(caps_structure, "rate", &samplerate);
10754 gst_structure_get_int(caps_structure, "channels", &channels);
10756 if ((channels > 0 && samplerate == 0)) {
10757 LOGD("exclude audio...");
10761 caps_str = gst_caps_to_string(caps);
10762 /* set it directly because not sent by TAG */
10763 if (g_strrstr(caps_str, "mobile-xmf"))
10764 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10765 MMPLAYER_FREEIF(caps_str);
10766 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10767 MMMessageParamType msg_param;
10768 memset(&msg_param, 0, sizeof(MMMessageParamType));
10769 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10770 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10771 LOGD("video file is not supported on this device");
10773 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10774 LOGD("already video linked");
10777 LOGD("found new stream");
10784 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10786 int ret = MM_ERROR_NONE;
10788 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10790 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10791 GstStructure* str = NULL;
10793 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10795 LOGD("audio codec type: %d", codec_type);
10796 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10797 /* sw codec will be skipped */
10798 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10799 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10800 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10801 ret = MM_ERROR_PLAYER_INTERNAL;
10805 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10806 /* hw codec will be skipped */
10807 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10808 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10809 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10810 ret = MM_ERROR_PLAYER_INTERNAL;
10815 str = gst_caps_get_structure(caps, 0);
10817 gst_structure_get_int(str, "channels", &channels);
10819 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10820 if (player->max_audio_channels < channels)
10821 player->max_audio_channels = channels;
10823 /* set stream information */
10824 if (!player->audiodec_linked)
10825 __mmplayer_set_audio_attrs(player, caps);
10827 /* update codec info */
10828 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10829 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10830 player->audiodec_linked = 1;
10832 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10834 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10836 LOGD("video codec type: %d", codec_type);
10837 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10838 /* sw codec is skipped */
10839 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10840 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10841 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10842 ret = MM_ERROR_PLAYER_INTERNAL;
10846 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10847 /* hw codec is skipped */
10848 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10849 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10850 ret = MM_ERROR_PLAYER_INTERNAL;
10855 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10856 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10858 /* mark video decoder for acquire */
10859 if (player->video_decoder_resource == NULL) {
10860 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10861 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10862 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10863 &player->video_decoder_resource)
10864 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10865 LOGE("could not mark video_decoder resource for acquire");
10866 ret = MM_ERROR_PLAYER_INTERNAL;
10870 LOGW("video decoder resource is already acquired, skip it.");
10871 ret = MM_ERROR_PLAYER_INTERNAL;
10875 player->interrupted_by_resource = FALSE;
10876 /* acquire resources for video playing */
10877 if (mm_resource_manager_commit(player->resource_manager)
10878 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10879 LOGE("could not acquire resources for video decoding\n");
10880 ret = MM_ERROR_PLAYER_INTERNAL;
10885 /* update codec info */
10886 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10887 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10888 player->videodec_linked = 1;
10896 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10897 GstCaps* caps, GstElementFactory* factory, gpointer data)
10899 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10900 We are defining our own and will be removed when it actually exposed */
10902 GST_AUTOPLUG_SELECT_TRY,
10903 GST_AUTOPLUG_SELECT_EXPOSE,
10904 GST_AUTOPLUG_SELECT_SKIP
10905 } GstAutoplugSelectResult;
10907 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10908 mm_player_t* player = (mm_player_t*)data;
10910 gchar* factory_name = NULL;
10911 gchar* caps_str = NULL;
10912 const gchar* klass = NULL;
10915 factory_name = GST_OBJECT_NAME(factory);
10916 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10917 caps_str = gst_caps_to_string(caps);
10919 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10921 /* store type string */
10922 if (player->type == NULL) {
10923 player->type = gst_caps_to_string(caps);
10924 __mmplayer_update_content_type_info(player);
10927 /* filtering exclude keyword */
10928 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10929 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10930 LOGW("skipping [%s] by exculde keyword [%s]\n",
10931 factory_name, player->ini.exclude_element_keyword[idx]);
10933 result = GST_AUTOPLUG_SELECT_SKIP;
10938 /* exclude webm format */
10939 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10940 * because webm format is not supportable.
10941 * If webm is disabled in "autoplug-continue", there is no state change
10942 * failure or error because the decodebin will expose the pad directly.
10943 * It make MSL invoke _prepare_async_callback.
10944 * So, we need to disable webm format in "autoplug-select" */
10945 if (caps_str && strstr(caps_str, "webm")) {
10946 LOGW("webm is not supported");
10947 result = GST_AUTOPLUG_SELECT_SKIP;
10951 /* check factory class for filtering */
10952 /* NOTE : msl don't need to use image plugins.
10953 * So, those plugins should be skipped for error handling.
10955 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10956 LOGD("skipping [%s] by not required\n", factory_name);
10957 result = GST_AUTOPLUG_SELECT_SKIP;
10961 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10962 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10963 // TO CHECK : subtitle if needed, add subparse exception.
10964 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10965 result = GST_AUTOPLUG_SELECT_SKIP;
10969 if (g_strrstr(factory_name, "mpegpsdemux")) {
10970 LOGD("skipping PS container - not support\n");
10971 result = GST_AUTOPLUG_SELECT_SKIP;
10975 if (g_strrstr(factory_name, "mssdemux"))
10976 player->smooth_streaming = TRUE;
10978 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10979 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10982 GstStructure *str = NULL;
10983 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10985 /* don't make video because of not required */
10986 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10987 (player->set_mode.media_packet_video_stream == FALSE)) {
10988 LOGD("no video because it's not required. -> return expose");
10989 result = GST_AUTOPLUG_SELECT_EXPOSE;
10993 /* get w/h for omx state-tune */
10994 /* FIXME: deprecated? */
10995 str = gst_caps_get_structure(caps, 0);
10996 gst_structure_get_int(str, "width", &width);
10999 if (player->v_stream_caps) {
11000 gst_caps_unref(player->v_stream_caps);
11001 player->v_stream_caps = NULL;
11004 player->v_stream_caps = gst_caps_copy(caps);
11005 LOGD("take caps for video state tune");
11006 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11010 if (g_strrstr(klass, "Codec/Decoder")) {
11011 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11012 LOGD("skipping %s codec", factory_name);
11013 result = GST_AUTOPLUG_SELECT_SKIP;
11019 MMPLAYER_FREEIF(caps_str);
11025 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11028 //mm_player_t* player = (mm_player_t*)data;
11029 GstCaps* caps = NULL;
11031 LOGD("[Decodebin2] pad-removed signal\n");
11033 caps = gst_pad_query_caps(new_pad, NULL);
11035 gchar* caps_str = NULL;
11036 caps_str = gst_caps_to_string(caps);
11038 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11040 MMPLAYER_FREEIF(caps_str);
11041 gst_caps_unref(caps);
11046 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11048 mm_player_t* player = (mm_player_t*)data;
11049 GstIterator *iter = NULL;
11050 GValue item = { 0, };
11051 GstPad *pad = NULL;
11052 gboolean done = FALSE;
11053 gboolean is_all_drained = TRUE;
11056 MMPLAYER_RETURN_IF_FAIL(player);
11058 LOGD("__mmplayer_gst_decode_drained");
11060 if (player->use_deinterleave == TRUE) {
11061 LOGD("group playing mode.");
11065 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11066 LOGW("Fail to get cmd lock");
11070 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11071 !__mmplayer_verify_next_play_path(player)) {
11072 LOGD("decoding is finished.");
11073 __mmplayer_reset_gapless_state(player);
11074 MMPLAYER_CMD_UNLOCK(player);
11078 player->gapless.reconfigure = TRUE;
11080 /* check decodebin src pads whether they received EOS or not */
11081 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11084 switch (gst_iterator_next(iter, &item)) {
11085 case GST_ITERATOR_OK:
11086 pad = g_value_get_object(&item);
11087 if (pad && !GST_PAD_IS_EOS(pad)) {
11088 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11089 is_all_drained = FALSE;
11092 g_value_reset(&item);
11094 case GST_ITERATOR_RESYNC:
11095 gst_iterator_resync(iter);
11097 case GST_ITERATOR_ERROR:
11098 case GST_ITERATOR_DONE:
11103 g_value_unset(&item);
11104 gst_iterator_free(iter);
11106 if (!is_all_drained) {
11107 LOGD("Wait util the all pads get EOS.");
11108 MMPLAYER_CMD_UNLOCK(player);
11113 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11114 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11116 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11117 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11118 __mmplayer_deactivate_old_path(player);
11119 MMPLAYER_CMD_UNLOCK(player);
11125 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11127 mm_player_t* player = (mm_player_t*)data;
11128 const gchar* klass = NULL;
11129 gchar* factory_name = NULL;
11131 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11132 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11134 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11136 if (__mmplayer_add_dump_buffer_probe(player, element))
11137 LOGD("add buffer probe");
11140 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11141 gchar* selected = NULL;
11142 selected = g_strdup(GST_ELEMENT_NAME(element));
11143 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11147 if (g_strrstr(klass, "Parser")) {
11148 gchar* selected = NULL;
11150 selected = g_strdup(factory_name);
11151 player->parsers = g_list_append(player->parsers, selected);
11154 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11155 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11156 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11158 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11159 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11161 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11162 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11163 "max-video-width", player->adaptive_info.limit.width,
11164 "max-video-height", player->adaptive_info.limit.height, NULL);
11166 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11167 /* FIXIT : first value will be overwritten if there's more
11168 * than 1 demuxer/parser
11171 //LOGD("plugged element is demuxer. take it\n");
11172 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11173 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11175 /*Added for multi audio support */ // Q. del?
11176 if (g_strrstr(klass, "Demux")) {
11177 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11178 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11182 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11183 int surface_type = 0;
11185 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11188 // to support trust-zone only
11189 if (g_strrstr(factory_name, "asfdemux")) {
11190 LOGD("set file-location %s\n", player->profile.uri);
11191 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11193 if (player->video_hub_download_mode == TRUE)
11194 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11195 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11196 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11197 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11198 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11199 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11200 (__mmplayer_is_only_mp3_type(player->type))) {
11201 LOGD("[mpegaudioparse] set streaming pull mode.");
11202 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11204 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11205 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11208 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11209 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11210 LOGD("plugged element is multiqueue. take it\n");
11212 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11213 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11215 if (!MMPLAYER_IS_HTTP_PD(player) &&
11216 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11217 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11218 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11219 __mm_player_streaming_set_multiqueue(player->streamer,
11222 player->ini.http_buffering_time,
11224 player->ini.http_buffering_limit);
11226 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11233 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11236 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11238 if (MMPLAYER_IS_STREAMING(player))
11241 /* This callback can be set to music player only. */
11242 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11243 LOGW("audio callback is not supported for video");
11247 if (player->audio_stream_cb) {
11248 GstPad *pad = NULL;
11250 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11253 LOGE("failed to get sink pad from audiosink to probe data\n");
11256 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11257 __mmplayer_audio_stream_probe, player, NULL);
11259 gst_object_unref(pad);
11263 LOGE("There is no audio callback to configure.\n");
11273 __mmplayer_release_misc(mm_player_t* player)
11276 bool cur_mode = player->set_mode.rich_audio;
11279 MMPLAYER_RETURN_IF_FAIL(player);
11281 player->video_stream_cb = NULL;
11282 player->video_stream_cb_user_param = NULL;
11283 player->video_stream_prerolled = FALSE;
11285 player->audio_stream_cb = NULL;
11286 player->audio_stream_render_cb_ex = NULL;
11287 player->audio_stream_cb_user_param = NULL;
11288 player->audio_stream_sink_sync = false;
11290 player->video_stream_changed_cb = NULL;
11291 player->video_stream_changed_cb_user_param = NULL;
11293 player->audio_stream_changed_cb = NULL;
11294 player->audio_stream_changed_cb_user_param = NULL;
11296 player->sent_bos = FALSE;
11297 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11299 player->doing_seek = FALSE;
11301 player->total_bitrate = 0;
11302 player->total_maximum_bitrate = 0;
11304 player->not_found_demuxer = 0;
11306 player->last_position = 0;
11307 player->duration = 0;
11308 player->http_content_size = 0;
11309 player->not_supported_codec = MISSING_PLUGIN_NONE;
11310 player->can_support_codec = FOUND_PLUGIN_NONE;
11311 player->pending_seek.is_pending = FALSE;
11312 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11313 player->pending_seek.pos = 0;
11314 player->msg_posted = FALSE;
11315 player->has_many_types = FALSE;
11316 player->max_audio_channels = 0;
11317 player->video_share_api_delta = 0;
11318 player->video_share_clock_delta = 0;
11319 player->is_subtitle_force_drop = FALSE;
11320 player->play_subtitle = FALSE;
11321 player->adjust_subtitle_pos = 0;
11322 player->last_multiwin_status = FALSE;
11323 player->has_closed_caption = FALSE;
11324 player->set_mode.media_packet_video_stream = FALSE;
11325 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11326 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11328 player->set_mode.rich_audio = cur_mode;
11330 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11331 player->bitrate[i] = 0;
11332 player->maximum_bitrate[i] = 0;
11335 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11337 /* remove media stream cb(appsrc cb) */
11338 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11339 player->media_stream_buffer_status_cb[i] = NULL;
11340 player->media_stream_seek_data_cb[i] = NULL;
11341 player->buffer_cb_user_param[i] = NULL;
11342 player->seek_cb_user_param[i] = NULL;
11344 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11346 /* free memory related to audio effect */
11347 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11349 if (player->adaptive_info.var_list) {
11350 g_list_free_full(player->adaptive_info.var_list, g_free);
11351 player->adaptive_info.var_list = NULL;
11354 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11355 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11356 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11358 /* Reset video360 settings to their defaults in case if the pipeline is to be
11361 player->video360_metadata.is_spherical = -1;
11362 player->is_openal_plugin_used = FALSE;
11364 player->is_content_spherical = FALSE;
11365 player->is_video360_enabled = TRUE;
11366 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11367 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11368 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11369 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11370 player->video360_zoom = 1.0f;
11371 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11372 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11374 player->sound.rg_enable = false;
11380 __mmplayer_release_misc_post(mm_player_t* player)
11382 char *original_uri = NULL;
11385 /* player->pipeline is already released before. */
11387 MMPLAYER_RETURN_IF_FAIL(player);
11389 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11391 /* clean found parsers */
11392 if (player->parsers) {
11393 GList *parsers = player->parsers;
11394 for (; parsers; parsers = g_list_next(parsers)) {
11395 gchar *name = parsers->data;
11396 MMPLAYER_FREEIF(name);
11398 g_list_free(player->parsers);
11399 player->parsers = NULL;
11402 /* clean found audio decoders */
11403 if (player->audio_decoders) {
11404 GList *a_dec = player->audio_decoders;
11405 for (; a_dec; a_dec = g_list_next(a_dec)) {
11406 gchar *name = a_dec->data;
11407 MMPLAYER_FREEIF(name);
11409 g_list_free(player->audio_decoders);
11410 player->audio_decoders = NULL;
11413 /* clean the uri list except original uri */
11414 if (player->uri_info.uri_list) {
11415 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11417 if (player->attrs) {
11418 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11419 LOGD("restore original uri = %s\n", original_uri);
11421 if (mmf_attrs_commit(player->attrs))
11422 LOGE("failed to commit the original uri.\n");
11425 GList *uri_list = player->uri_info.uri_list;
11426 for (; uri_list; uri_list = g_list_next(uri_list)) {
11427 gchar *uri = uri_list->data;
11428 MMPLAYER_FREEIF(uri);
11430 g_list_free(player->uri_info.uri_list);
11431 player->uri_info.uri_list = NULL;
11434 /* clear the audio stream buffer list */
11435 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11437 /* clear the video stream bo list */
11438 __mmplayer_video_stream_destroy_bo_list(player);
11439 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11441 if (player->profile.input_mem.buf) {
11442 free(player->profile.input_mem.buf);
11443 player->profile.input_mem.buf = NULL;
11445 player->profile.input_mem.len = 0;
11446 player->profile.input_mem.offset = 0;
11448 player->uri_info.uri_idx = 0;
11452 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11454 GstElement *element = NULL;
11457 LOGD("creating %s to plug\n", name);
11459 element = gst_element_factory_make(name, NULL);
11461 LOGE("failed to create queue\n");
11465 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11466 LOGE("failed to set state READY to %s\n", name);
11467 gst_object_unref(element);
11471 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11472 LOGE("failed to add %s\n", name);
11473 gst_object_unref(element);
11477 sinkpad = gst_element_get_static_pad(element, "sink");
11479 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11480 LOGE("failed to link %s\n", name);
11481 gst_object_unref(sinkpad);
11482 gst_object_unref(element);
11486 LOGD("linked %s to pipeline successfully\n", name);
11488 gst_object_unref(sinkpad);
11494 __mmplayer_check_subtitle(mm_player_t* player)
11496 MMHandleType attrs = 0;
11497 char *subtitle_uri = NULL;
11501 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11503 /* get subtitle attribute */
11504 attrs = MMPLAYER_GET_ATTRS(player);
11508 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11509 if (!subtitle_uri || !strlen(subtitle_uri))
11512 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11513 player->is_external_subtitle_present = TRUE;
11521 __mmplayer_can_extract_pcm(mm_player_t* player)
11523 MMHandleType attrs = 0;
11524 gboolean sound_extraction = FALSE;
11526 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11528 attrs = MMPLAYER_GET_ATTRS(player);
11530 LOGE("fail to get attributes.");
11534 /* get sound_extraction property */
11535 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11537 if (!sound_extraction) {
11538 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11546 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11549 MMMessageParamType msg_param;
11550 gchar *msg_src_element = NULL;
11551 GstStructure *s = NULL;
11552 guint error_id = 0;
11553 gchar *error_string = NULL;
11557 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11558 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11560 s = gst_structure_copy(gst_message_get_structure(message));
11563 if (!gst_structure_get_uint(s, "error_id", &error_id))
11564 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11566 switch (error_id) {
11567 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11568 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11570 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11571 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11573 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11574 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11576 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11577 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11579 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11580 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11582 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11583 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11585 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11588 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11589 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11591 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11592 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11594 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11595 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11597 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11598 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11600 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11601 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11603 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11604 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11606 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11607 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11609 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11610 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11612 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11613 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11615 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11616 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11618 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11619 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11621 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11622 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11624 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11625 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11627 case MMPLAYER_STREAMING_ERROR_GONE:
11628 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11630 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11631 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11633 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11634 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11636 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11637 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11639 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11640 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11642 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11643 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11645 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11646 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11648 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11649 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11651 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11652 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11654 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11655 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11657 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11658 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11660 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11661 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11663 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11664 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11666 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11667 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11669 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11670 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11672 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11673 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11675 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11676 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11678 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11679 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11681 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11682 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11684 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11685 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11687 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11688 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11690 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11691 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11693 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11694 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11696 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11697 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11699 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11700 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11704 gst_structure_free(s);
11705 return MM_ERROR_PLAYER_STREAMING_FAIL;
11709 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11711 msg_param.data = (void *) error_string;
11713 if (message->src) {
11714 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11716 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11717 msg_src_element, msg_param.code, (char*)msg_param.data);
11720 /* post error to application */
11721 if (!player->msg_posted) {
11722 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11724 /* don't post more if one was sent already */
11725 player->msg_posted = TRUE;
11727 LOGD("skip error post because it's sent already.\n");
11729 gst_structure_free(s);
11731 g_free(error_string);
11738 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11740 MMPLAYER_RETURN_IF_FAIL(player);
11742 /* post now if delay is zero */
11743 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11744 LOGD("eos delay is zero. posting EOS now\n");
11745 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11747 if (player->set_mode.pcm_extraction)
11748 __mmplayer_cancel_eos_timer(player);
11753 /* cancel if existing */
11754 __mmplayer_cancel_eos_timer(player);
11756 /* init new timeout */
11757 /* NOTE : consider give high priority to this timer */
11758 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11760 player->eos_timer = g_timeout_add(delay_in_ms,
11761 __mmplayer_eos_timer_cb, player);
11763 player->global_default = g_main_context_default();
11764 LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11766 /* check timer is valid. if not, send EOS now */
11767 if (player->eos_timer == 0) {
11768 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11769 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11774 __mmplayer_cancel_eos_timer(mm_player_t* player)
11776 MMPLAYER_RETURN_IF_FAIL(player);
11778 if (player->eos_timer) {
11779 LOGD("cancel eos timer");
11780 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11781 player->eos_timer = 0;
11788 __mmplayer_eos_timer_cb(gpointer u_data)
11790 mm_player_t* player = NULL;
11791 MMHandleType attrs = 0;
11794 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11796 player = (mm_player_t*) u_data;
11797 attrs = MMPLAYER_GET_ATTRS(player);
11799 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11802 gint ret_value = 0;
11803 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11804 if (ret_value != MM_ERROR_NONE)
11805 LOGE("seeking to 0 failed in repeat play");
11808 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11811 /* we are returning FALSE as we need only one posting */
11815 /* sending event to one of sinkelements */
11817 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11819 GstEvent * event2 = NULL;
11820 GList *sinks = NULL;
11821 gboolean res = FALSE;
11824 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11825 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11827 /* While adding subtitles in live feeds seek is getting called.
11828 Adding defensive check in framework layer.*/
11829 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11830 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11831 LOGE("Should not send seek event during live playback");
11836 if (player->play_subtitle)
11837 event2 = gst_event_copy((const GstEvent *)event);
11839 sinks = player->sink_elements;
11841 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11843 if (GST_IS_ELEMENT(sink)) {
11844 /* keep ref to the event */
11845 gst_event_ref(event);
11847 if ((res = gst_element_send_event(sink, event))) {
11848 LOGD("sending event[%s] to sink element [%s] success!\n",
11849 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11851 /* rtsp case, asyn_done is not called after seek during pause state */
11852 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11853 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11854 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11855 LOGD("RTSP seek completed, after pause state..\n");
11856 player->doing_seek = FALSE;
11857 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11863 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11864 sinks = g_list_next(sinks);
11871 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11872 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11875 sinks = g_list_next(sinks);
11878 /* Note : Textbin is not linked to the video or audio bin.
11879 * It needs to send the event to the text sink seperatelly.
11881 if (player->play_subtitle && player->pipeline) {
11882 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11884 if (GST_IS_ELEMENT(text_sink)) {
11885 /* keep ref to the event */
11886 gst_event_ref(event2);
11888 if ((res = gst_element_send_event(text_sink, event2)))
11889 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11890 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11892 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11893 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11895 gst_event_unref(event2);
11899 gst_event_unref(event);
11907 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11911 MMPLAYER_RETURN_IF_FAIL(player);
11912 MMPLAYER_RETURN_IF_FAIL(sink);
11914 player->sink_elements =
11915 g_list_append(player->sink_elements, sink);
11921 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11925 MMPLAYER_RETURN_IF_FAIL(player);
11926 MMPLAYER_RETURN_IF_FAIL(sink);
11928 player->sink_elements =
11929 g_list_remove(player->sink_elements, sink);
11935 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11936 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11937 gint64 cur, GstSeekType stop_type, gint64 stop)
11939 GstEvent* event = NULL;
11940 gboolean result = FALSE;
11944 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11946 if (player->pipeline && player->pipeline->textbin)
11947 __mmplayer_drop_subtitle(player, FALSE);
11949 event = gst_event_new_seek(rate, format, flags, cur_type,
11950 cur, stop_type, stop);
11952 result = __gst_send_event_to_sink(player, event);
11959 /* NOTE : be careful with calling this api. please refer to below glib comment
11960 * glib comment : Note that there is a bug in GObject that makes this function much
11961 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11962 * will no longer be called, but, the signal handler is not currently disconnected.
11963 * If the instance is itself being freed at the same time than this doesn't matter,
11964 * since the signal will automatically be removed, but if instance persists,
11965 * then the signal handler will leak. You should not remove the signal yourself
11966 * because in a future versions of GObject, the handler will automatically be
11969 * It's possible to work around this problem in a way that will continue to work
11970 * with future versions of GObject by checking that the signal handler is still
11971 * connected before disconnected it:
11973 * if (g_signal_handler_is_connected(instance, id))
11974 * g_signal_handler_disconnect(instance, id);
11977 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11979 GList* sig_list = NULL;
11980 MMPlayerSignalItem* item = NULL;
11984 MMPLAYER_RETURN_IF_FAIL(player);
11986 LOGD("release signals type : %d", type);
11988 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11989 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11990 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11991 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11992 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11993 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11997 sig_list = player->signals[type];
11999 for (; sig_list; sig_list = sig_list->next) {
12000 item = sig_list->data;
12002 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12003 if (g_signal_handler_is_connected(item->obj, item->sig))
12004 g_signal_handler_disconnect(item->obj, item->sig);
12007 MMPLAYER_FREEIF(item);
12010 g_list_free(player->signals[type]);
12011 player->signals[type] = NULL;
12018 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12020 mm_player_t* player = 0;
12021 int prev_display_surface_type = 0;
12022 void *prev_display_overlay = NULL;
12023 const gchar *klass = NULL;
12024 gchar *cur_videosink_name = NULL;
12027 int num_of_dec = 2; /* DEC1, DEC2 */
12031 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12032 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12034 player = MM_PLAYER_CAST(handle);
12036 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12037 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12039 return MM_ERROR_INVALID_ARGUMENT;
12042 /* load previous attributes */
12043 if (player->attrs) {
12044 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12045 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12046 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12047 if (prev_display_surface_type == surface_type) {
12048 LOGD("incoming display surface type is same as previous one, do nothing..");
12050 return MM_ERROR_NONE;
12053 LOGE("failed to load attributes");
12055 return MM_ERROR_PLAYER_INTERNAL;
12058 /* check videosink element is created */
12059 if (!player->pipeline || !player->pipeline->videobin ||
12060 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12061 LOGD("videosink element is not yet ready");
12063 /* videobin is not created yet, so we just set attributes related to display surface */
12064 LOGD("store display attribute for given surface type(%d)", surface_type);
12065 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12066 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12067 if (mmf_attrs_commit(player->attrs)) {
12068 LOGE("failed to commit attribute");
12070 return MM_ERROR_PLAYER_INTERNAL;
12073 return MM_ERROR_NONE;
12075 /* get player command status */
12076 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12077 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12079 return MM_ERROR_PLAYER_INVALID_STATE;
12082 /* surface change */
12083 for (i = 0 ; i < num_of_dec ; i++) {
12084 if (player->pipeline->mainbin &&
12085 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12086 GstElementFactory *decfactory;
12087 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12089 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12090 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12091 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12092 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12096 LOGW("success to changing display surface(%d)", surface_type);
12098 return MM_ERROR_NONE;
12100 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12101 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12105 LOGW("success to changing display surface(%d)", surface_type);
12107 return MM_ERROR_NONE;
12110 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12111 ret = MM_ERROR_PLAYER_INTERNAL;
12120 /* rollback to previous attributes */
12121 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12122 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12123 if (mmf_attrs_commit(player->attrs)) {
12124 LOGE("failed to commit attributes to rollback");
12126 return MM_ERROR_PLAYER_INTERNAL;
12132 /* NOTE : It does not support some use cases, eg using colorspace converter */
12134 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12136 GstPad *src_pad_dec = NULL;
12137 GstPad *sink_pad_videosink = NULL;
12138 GstPad *sink_pad_videobin = NULL;
12139 GstClock *clock = NULL;
12140 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12141 int ret = MM_ERROR_NONE;
12142 gboolean is_audiobin_created = TRUE;
12146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12147 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12148 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12150 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12151 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12153 /* get information whether if audiobin is created */
12154 if (!player->pipeline->audiobin ||
12155 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12156 LOGW("audiobin is null, this video content may not have audio data");
12157 is_audiobin_created = FALSE;
12160 /* get current state of player */
12161 previous_state = MMPLAYER_CURRENT_STATE(player);
12162 LOGD("previous state(%d)", previous_state);
12165 /* get src pad of decoder and block it */
12166 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12167 if (!src_pad_dec) {
12168 LOGE("failed to get src pad from decode in mainbin");
12169 return MM_ERROR_PLAYER_INTERNAL;
12172 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12173 LOGW("trying to block pad(video)");
12174 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12175 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12178 LOGE("failed to set block pad(video)");
12179 return MM_ERROR_PLAYER_INTERNAL;
12181 LOGW("pad is blocked(video)");
12183 /* no data flows, so no need to do pad_block */
12184 if (player->doing_seek)
12185 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12187 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12191 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12192 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12193 LOGE("failed to remove previous ghost_pad for videobin");
12194 return MM_ERROR_PLAYER_INTERNAL;
12197 /* change state of videobin to NULL */
12198 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12199 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12200 if (ret != GST_STATE_CHANGE_SUCCESS) {
12201 LOGE("failed to change state of videobin to NULL");
12202 return MM_ERROR_PLAYER_INTERNAL;
12205 /* unlink between decoder and videobin and remove previous videosink from videobin */
12206 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12207 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12208 LOGE("failed to remove former videosink from videobin");
12209 return MM_ERROR_PLAYER_INTERNAL;
12212 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12214 /* create a new videosink and add it to videobin */
12215 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12216 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12217 LOGE("failed to create videosink element\n");
12219 return MM_ERROR_PLAYER_INTERNAL;
12221 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12222 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12223 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12225 /* save attributes */
12226 if (player->attrs) {
12227 /* set a new display surface type */
12228 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12229 /* set a new diplay overlay */
12230 switch (surface_type) {
12231 case MM_DISPLAY_SURFACE_OVERLAY:
12232 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12233 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12236 LOGE("invalid type(%d) for changing display surface", surface_type);
12238 return MM_ERROR_INVALID_ARGUMENT;
12240 if (mmf_attrs_commit(player->attrs)) {
12241 LOGE("failed to commit");
12243 return MM_ERROR_PLAYER_INTERNAL;
12246 LOGE("player->attrs is null, failed to save attributes");
12248 return MM_ERROR_PLAYER_INTERNAL;
12251 /* update video param */
12252 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12253 LOGE("failed to update video param");
12254 return MM_ERROR_PLAYER_INTERNAL;
12257 /* change state of videobin to READY */
12258 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12259 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12260 if (ret != GST_STATE_CHANGE_SUCCESS) {
12261 LOGE("failed to change state of videobin to READY");
12262 return MM_ERROR_PLAYER_INTERNAL;
12265 /* change ghostpad */
12266 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12267 if (!sink_pad_videosink) {
12268 LOGE("failed to get sink pad from videosink element");
12269 return MM_ERROR_PLAYER_INTERNAL;
12271 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12272 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12273 LOGE("failed to set active to ghost_pad");
12274 return MM_ERROR_PLAYER_INTERNAL;
12276 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12277 LOGE("failed to change ghostpad for videobin");
12278 return MM_ERROR_PLAYER_INTERNAL;
12280 gst_object_unref(sink_pad_videosink);
12282 /* link decoder with videobin */
12283 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12284 if (!sink_pad_videobin) {
12285 LOGE("failed to get sink pad from videobin");
12286 return MM_ERROR_PLAYER_INTERNAL;
12288 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12289 LOGE("failed to link");
12290 return MM_ERROR_PLAYER_INTERNAL;
12292 gst_object_unref(sink_pad_videobin);
12294 /* clock setting for a new videosink plugin */
12295 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12296 so we set it from audiosink plugin or pipeline(system clock) */
12297 if (!is_audiobin_created) {
12298 LOGW("audiobin is not created, get clock from pipeline..");
12299 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12301 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12305 GstClockTime base_time;
12306 LOGD("set the clock to videosink");
12307 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12308 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12310 LOGD("got clock of videosink");
12311 now = gst_clock_get_time(clock);
12312 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12313 LOGD("at time %" GST_TIME_FORMAT ", base %"
12314 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12316 LOGE("failed to get clock of videosink after setting clock");
12317 return MM_ERROR_PLAYER_INTERNAL;
12320 LOGW("failed to get clock, maybe it is the time before first playing");
12322 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12323 /* change state of videobin to PAUSED */
12324 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12325 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12326 if (ret != GST_STATE_CHANGE_FAILURE) {
12327 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12329 LOGE("failed to change state of videobin to PLAYING");
12330 return MM_ERROR_PLAYER_INTERNAL;
12333 /* release blocked and unref src pad of video decoder */
12335 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12336 LOGE("failed to set pad blocked FALSE(video)");
12337 return MM_ERROR_PLAYER_INTERNAL;
12340 LOGW("pad is unblocked(video)");
12342 if (player->doing_seek)
12343 LOGW("not completed seek(%d)", player->doing_seek);
12344 /* change state of videobin to PAUSED */
12345 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12346 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12347 if (ret != GST_STATE_CHANGE_FAILURE) {
12348 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12350 LOGE("failed to change state of videobin to PLAYING");
12351 return MM_ERROR_PLAYER_INTERNAL;
12354 /* already skipped pad block */
12355 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12358 /* do get/set position for new videosink plugin */
12360 unsigned long position = 0;
12361 gint64 pos_msec = 0;
12363 LOGD("do get/set position for new videosink plugin");
12364 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12365 LOGE("failed to get position");
12366 return MM_ERROR_PLAYER_INTERNAL;
12368 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12369 /* accurate seek */
12370 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12371 LOGE("failed to set position");
12372 return MM_ERROR_PLAYER_INTERNAL;
12375 /* key unit seek */
12376 pos_msec = position * G_GINT64_CONSTANT(1000000);
12377 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12378 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12379 GST_SEEK_TYPE_SET, pos_msec,
12380 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12382 LOGE("failed to set position");
12383 return MM_ERROR_PLAYER_INTERNAL;
12389 gst_object_unref(src_pad_dec);
12390 LOGD("success to change sink");
12394 return MM_ERROR_NONE;
12398 /* Note : if silent is true, then subtitle would not be displayed. :*/
12399 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12401 mm_player_t* player = (mm_player_t*) hplayer;
12405 /* check player handle */
12406 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12408 player->set_mode.subtitle_off = silent;
12410 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12414 return MM_ERROR_NONE;
12417 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12419 MMPlayerGstElement* mainbin = NULL;
12420 MMPlayerGstElement* textbin = NULL;
12421 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12422 GstState current_state = GST_STATE_VOID_PENDING;
12423 GstState element_state = GST_STATE_VOID_PENDING;
12424 GstState element_pending_state = GST_STATE_VOID_PENDING;
12426 GstEvent *event = NULL;
12427 int result = MM_ERROR_NONE;
12429 GstClock *curr_clock = NULL;
12430 GstClockTime base_time, start_time, curr_time;
12435 /* check player handle */
12436 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12437 player->pipeline &&
12438 player->pipeline->mainbin &&
12439 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12441 mainbin = player->pipeline->mainbin;
12442 textbin = player->pipeline->textbin;
12444 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12446 // sync clock with current pipeline
12447 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12448 curr_time = gst_clock_get_time(curr_clock);
12450 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12451 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12453 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12454 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12456 if (current_state > GST_STATE_READY) {
12457 // sync state with current pipeline
12458 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12459 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12460 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12462 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12463 if (GST_STATE_CHANGE_FAILURE == ret) {
12464 LOGE("fail to state change.\n");
12465 result = MM_ERROR_PLAYER_INTERNAL;
12470 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12471 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12474 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12475 gst_object_unref(curr_clock);
12478 // seek to current position
12479 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12480 result = MM_ERROR_PLAYER_INVALID_STATE;
12481 LOGE("gst_element_query_position failed, invalid state\n");
12485 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12486 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);
12488 __gst_send_event_to_sink(player, event);
12490 result = MM_ERROR_PLAYER_INTERNAL;
12491 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12495 /* sync state with current pipeline */
12496 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12497 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12498 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12500 return MM_ERROR_NONE;
12503 /* release text pipeline resource */
12504 player->textsink_linked = 0;
12506 /* release signal */
12507 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12509 /* release textbin with it's childs */
12510 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12511 MMPLAYER_FREEIF(player->pipeline->textbin);
12512 player->pipeline->textbin = NULL;
12514 /* release subtitle elem */
12515 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12516 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12522 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12524 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12525 GstState current_state = GST_STATE_VOID_PENDING;
12527 MMHandleType attrs = 0;
12528 MMPlayerGstElement* mainbin = NULL;
12529 MMPlayerGstElement* textbin = NULL;
12531 gchar* subtitle_uri = NULL;
12532 int result = MM_ERROR_NONE;
12533 const gchar *charset = NULL;
12537 /* check player handle */
12538 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12539 player->pipeline &&
12540 player->pipeline->mainbin &&
12541 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12542 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12544 mainbin = player->pipeline->mainbin;
12545 textbin = player->pipeline->textbin;
12547 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12548 if (current_state < GST_STATE_READY) {
12549 result = MM_ERROR_PLAYER_INVALID_STATE;
12550 LOGE("Pipeline is not in proper state\n");
12554 attrs = MMPLAYER_GET_ATTRS(player);
12556 LOGE("cannot get content attribute\n");
12557 result = MM_ERROR_PLAYER_INTERNAL;
12561 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12562 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12563 LOGE("subtitle uri is not proper filepath\n");
12564 result = MM_ERROR_PLAYER_INVALID_URI;
12568 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12569 LOGE("failed to get storage info of subtitle path");
12570 result = MM_ERROR_PLAYER_INVALID_URI;
12574 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12575 LOGD("new subtitle file path is [%s]\n", filepath);
12577 if (!strcmp(filepath, subtitle_uri)) {
12578 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12581 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12582 if (mmf_attrs_commit(player->attrs)) {
12583 LOGE("failed to commit.\n");
12588 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12589 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12590 player->subtitle_language_list = NULL;
12591 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12593 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12594 if (ret != GST_STATE_CHANGE_SUCCESS) {
12595 LOGE("failed to change state of textbin to READY");
12596 result = MM_ERROR_PLAYER_INTERNAL;
12600 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12601 if (ret != GST_STATE_CHANGE_SUCCESS) {
12602 LOGE("failed to change state of subparse to READY");
12603 result = MM_ERROR_PLAYER_INTERNAL;
12607 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12608 if (ret != GST_STATE_CHANGE_SUCCESS) {
12609 LOGE("failed to change state of filesrc to READY");
12610 result = MM_ERROR_PLAYER_INTERNAL;
12614 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12616 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12618 charset = util_get_charset(filepath);
12620 LOGD("detected charset is %s\n", charset);
12621 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12624 result = _mmplayer_sync_subtitle_pipeline(player);
12631 /* API to switch between external subtitles */
12632 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12634 int result = MM_ERROR_NONE;
12635 mm_player_t* player = (mm_player_t*)hplayer;
12640 /* check player handle */
12641 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12643 /* filepath can be null in idle state */
12645 /* check file path */
12646 if ((path = strstr(filepath, "file://")))
12647 result = util_exist_file_path(path + 7);
12649 result = util_exist_file_path(filepath);
12651 if (result != MM_ERROR_NONE) {
12652 LOGE("invalid subtitle path 0x%X", result);
12653 return result; /* file not found or permission denied */
12657 if (!player->pipeline) {
12659 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12660 if (mmf_attrs_commit(player->attrs)) {
12661 LOGE("failed to commit"); /* subtitle path will not be created */
12662 return MM_ERROR_PLAYER_INTERNAL;
12665 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12666 /* check filepath */
12667 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12669 if (!__mmplayer_check_subtitle(player)) {
12670 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12671 if (mmf_attrs_commit(player->attrs)) {
12672 LOGE("failed to commit");
12673 return MM_ERROR_PLAYER_INTERNAL;
12676 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12677 LOGE("fail to create text pipeline");
12678 return MM_ERROR_PLAYER_INTERNAL;
12681 result = _mmplayer_sync_subtitle_pipeline(player);
12683 result = __mmplayer_change_external_subtitle_language(player, filepath);
12686 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12687 player->is_external_subtitle_added_now = TRUE;
12689 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12690 if (!player->subtitle_language_list) {
12691 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12692 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12693 LOGW("subtitle language list is not updated yet");
12695 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12703 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12705 int result = MM_ERROR_NONE;
12706 gchar* change_pad_name = NULL;
12707 GstPad* sinkpad = NULL;
12708 MMPlayerGstElement* mainbin = NULL;
12709 enum MainElementID elemId = MMPLAYER_M_NUM;
12710 GstCaps* caps = NULL;
12711 gint total_track_num = 0;
12715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12716 MM_ERROR_PLAYER_NOT_INITIALIZED);
12718 LOGD("Change Track(%d) to %d\n", type, index);
12720 mainbin = player->pipeline->mainbin;
12722 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12723 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12724 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12725 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12727 /* Changing Video Track is not supported. */
12728 LOGE("Track Type Error\n");
12732 if (mainbin[elemId].gst == NULL) {
12733 result = MM_ERROR_PLAYER_NO_OP;
12734 LOGD("Req track doesn't exist\n");
12738 total_track_num = player->selector[type].total_track_num;
12739 if (total_track_num <= 0) {
12740 result = MM_ERROR_PLAYER_NO_OP;
12741 LOGD("Language list is not available \n");
12745 if ((index < 0) || (index >= total_track_num)) {
12746 result = MM_ERROR_INVALID_ARGUMENT;
12747 LOGD("Not a proper index : %d \n", index);
12751 /*To get the new pad from the selector*/
12752 change_pad_name = g_strdup_printf("sink_%u", index);
12753 if (change_pad_name == NULL) {
12754 result = MM_ERROR_PLAYER_INTERNAL;
12755 LOGD("Pad does not exists\n");
12759 LOGD("new active pad name: %s\n", change_pad_name);
12761 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12762 if (sinkpad == NULL) {
12763 LOGD("sinkpad is NULL");
12764 result = MM_ERROR_PLAYER_INTERNAL;
12768 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12769 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12771 caps = gst_pad_get_current_caps(sinkpad);
12772 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12775 gst_object_unref(sinkpad);
12777 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12778 __mmplayer_set_audio_attrs(player, caps);
12782 MMPLAYER_FREEIF(change_pad_name);
12786 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12788 int result = MM_ERROR_NONE;
12789 mm_player_t* player = NULL;
12790 MMPlayerGstElement* mainbin = NULL;
12792 gint current_active_index = 0;
12794 GstState current_state = GST_STATE_VOID_PENDING;
12795 GstEvent* event = NULL;
12800 player = (mm_player_t*)hplayer;
12801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12803 if (!player->pipeline) {
12804 LOGE("Track %d pre setting -> %d\n", type, index);
12806 player->selector[type].active_pad_index = index;
12810 mainbin = player->pipeline->mainbin;
12812 current_active_index = player->selector[type].active_pad_index;
12814 /*If index is same as running index no need to change the pad*/
12815 if (current_active_index == index)
12818 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12819 result = MM_ERROR_PLAYER_INVALID_STATE;
12823 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12824 if (current_state < GST_STATE_PAUSED) {
12825 result = MM_ERROR_PLAYER_INVALID_STATE;
12826 LOGW("Pipeline not in porper state\n");
12830 result = __mmplayer_change_selector_pad(player, type, index);
12831 if (result != MM_ERROR_NONE) {
12832 LOGE("change selector pad error\n");
12836 player->selector[type].active_pad_index = index;
12838 if (current_state == GST_STATE_PLAYING) {
12839 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);
12841 __gst_send_event_to_sink(player, event);
12843 result = MM_ERROR_PLAYER_INTERNAL;
12852 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12854 mm_player_t* player = (mm_player_t*) hplayer;
12858 /* check player handle */
12859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12861 *silent = player->set_mode.subtitle_off;
12863 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12867 return MM_ERROR_NONE;
12871 __is_ms_buff_src(mm_player_t* player)
12873 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12875 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12879 __has_suffix(mm_player_t* player, const gchar* suffix)
12881 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12882 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12884 gboolean ret = FALSE;
12885 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12886 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12888 if (g_str_has_suffix(player->profile.uri, suffix))
12891 MMPLAYER_FREEIF(t_url);
12892 MMPLAYER_FREEIF(t_suffix);
12898 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12900 mm_player_t* player = (mm_player_t*) hplayer;
12902 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12904 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12905 MMPLAYER_PRINT_STATE(player);
12906 LOGE("wrong-state : can't set the download mode to parse");
12907 return MM_ERROR_PLAYER_INVALID_STATE;
12910 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12911 player->video_hub_download_mode = mode;
12913 return MM_ERROR_NONE;
12917 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12919 mm_player_t* player = (mm_player_t*) hplayer;
12921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12923 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12924 player->sync_handler = enable;
12926 return MM_ERROR_NONE;
12930 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12932 long long clock_delta,
12933 long long video_time,
12934 long long media_clock,
12935 long long audio_time)
12937 mm_player_t* player = (mm_player_t*) hplayer;
12938 MMPlayerGstElement* mainbin = NULL;
12939 GstClockTime start_time_audio = 0, start_time_video = 0;
12940 GstClockTimeDiff base_time = 0, new_base_time = 0;
12941 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12942 gint64 api_delta = 0;
12943 gint64 position = 0, position_delta = 0;
12944 gint64 adj_base_time = 0;
12945 GstClock *curr_clock = NULL;
12946 GstClockTime curr_time = 0;
12947 gboolean query_ret = TRUE;
12948 int result = MM_ERROR_NONE;
12952 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12953 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12954 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12956 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12958 if ((video_time < 0) || (player->doing_seek)) {
12959 LOGD("skip setting master clock. %lld", video_time);
12963 mainbin = player->pipeline->mainbin;
12965 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12966 curr_time = gst_clock_get_time(curr_clock);
12968 current_state = MMPLAYER_CURRENT_STATE(player);
12970 if (current_state == MM_PLAYER_STATE_PLAYING)
12971 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12973 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12975 position = player->last_position;
12976 LOGD("query fail. %lld", position);
12979 clock *= GST_USECOND;
12980 clock_delta *= GST_USECOND;
12982 api_delta = clock - curr_time;
12983 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12984 player->video_share_api_delta = api_delta;
12986 clock_delta += (api_delta - player->video_share_api_delta);
12988 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12989 player->video_share_clock_delta = (gint64)clock_delta;
12991 position_delta = (position/GST_USECOND) - video_time;
12992 position_delta *= GST_USECOND;
12994 adj_base_time = position_delta;
12995 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12998 gint64 new_play_time = 0;
12999 gint64 network_delay = 0;
13001 video_time *= GST_USECOND;
13003 network_delay = clock_delta - player->video_share_clock_delta;
13004 new_play_time = video_time + network_delay;
13006 adj_base_time = position - new_play_time;
13008 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13009 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13012 /* Adjust Current Stream Time with base_time of sink
13013 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13014 * 2. Set new base time
13015 * if adj_base_time is positive value, the stream time will be decreased.
13016 * 3. If seek event is occurred, the start time will be reset. */
13017 if ((player->pipeline->audiobin) &&
13018 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13019 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13021 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13022 LOGD("audio sink : gst_element_set_start_time -> NONE");
13023 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13026 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13029 if ((player->pipeline->videobin) &&
13030 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13031 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13033 if (start_time_video != GST_CLOCK_TIME_NONE) {
13034 LOGD("video sink : gst_element_set_start_time -> NONE");
13035 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13038 // if videobin exist, get base_time from videobin.
13039 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13042 new_base_time = base_time + adj_base_time;
13044 if ((player->pipeline->audiobin) &&
13045 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13046 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13048 if ((player->pipeline->videobin) &&
13049 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13050 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13059 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13060 long long *video_time,
13061 long long *media_clock,
13062 long long *audio_time)
13064 mm_player_t* player = (mm_player_t*) hplayer;
13065 MMPlayerGstElement* mainbin = NULL;
13066 GstClock *curr_clock = NULL;
13067 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13068 gint64 position = 0;
13069 gboolean query_ret = TRUE;
13073 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13075 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13077 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13078 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13079 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13081 mainbin = player->pipeline->mainbin;
13083 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13085 current_state = MMPLAYER_CURRENT_STATE(player);
13087 if (current_state != MM_PLAYER_STATE_PAUSED)
13088 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13090 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13092 position = player->last_position;
13094 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13096 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13099 gst_object_unref(curr_clock);
13103 return MM_ERROR_NONE;
13107 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13109 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13110 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13112 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13113 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13117 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13118 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13119 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13120 mm_player_dump_t *dump_s;
13121 dump_s = g_malloc(sizeof(mm_player_dump_t));
13123 if (dump_s == NULL) {
13124 LOGE("malloc fail");
13128 dump_s->dump_element_file = NULL;
13129 dump_s->dump_pad = NULL;
13130 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13132 if (dump_s->dump_pad) {
13133 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13134 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]);
13135 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13136 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);
13137 /* add list for removed buffer probe and close FILE */
13138 player->dump_list = g_list_append(player->dump_list, dump_s);
13139 LOGD("%s sink pad added buffer probe for dump", factory_name);
13144 LOGE("failed to get %s sink pad added", factory_name);
13153 static GstPadProbeReturn
13154 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13156 FILE *dump_data = (FILE *) u_data;
13157 // int written = 0;
13158 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13159 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13161 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13163 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13165 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13167 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13169 return GST_PAD_PROBE_OK;
13173 __mmplayer_release_dump_list(GList *dump_list)
13176 GList *d_list = dump_list;
13177 for (; d_list; d_list = g_list_next(d_list)) {
13178 mm_player_dump_t *dump_s = d_list->data;
13179 if (dump_s->dump_pad) {
13180 if (dump_s->probe_handle_id)
13181 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13183 if (dump_s->dump_element_file) {
13184 fclose(dump_s->dump_element_file);
13185 dump_s->dump_element_file = NULL;
13187 MMPLAYER_FREEIF(dump_s);
13189 g_list_free(dump_list);
13195 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13197 mm_player_t* player = (mm_player_t*) hplayer;
13201 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13202 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13204 *exist = player->has_closed_caption;
13208 return MM_ERROR_NONE;
13211 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13215 // LOGD("unref internal gst buffer %p", buffer);
13216 gst_buffer_unref((GstBuffer *)buffer);
13223 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13225 mm_player_t *player = (mm_player_t*)user_data;
13226 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13227 guint64 current_level_bytes = 0;
13229 MMPLAYER_RETURN_IF_FAIL(player);
13231 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13233 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13234 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13236 if (player->media_stream_buffer_status_cb[type])
13237 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13238 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13243 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13245 mm_player_t *player = (mm_player_t*)user_data;
13246 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13247 guint64 current_level_bytes = 0;
13249 MMPLAYER_RETURN_IF_FAIL(player);
13251 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13253 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13255 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13256 if (player->media_stream_buffer_status_cb[type])
13257 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13258 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13262 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13264 mm_player_t *player = (mm_player_t*)user_data;
13265 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13266 guint64 current_level_bytes = 0;
13268 MMPLAYER_RETURN_IF_FAIL(player);
13270 LOGI("app-src: feed subtitle\n");
13272 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13274 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13275 if (player->media_stream_buffer_status_cb[type])
13276 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13278 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13282 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13284 mm_player_t *player = (mm_player_t*)user_data;
13285 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13286 guint64 current_level_bytes = 0;
13288 MMPLAYER_RETURN_IF_FAIL(player);
13290 LOGI("app-src: audio buffer is full.\n");
13292 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13294 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13296 if (player->media_stream_buffer_status_cb[type])
13297 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13299 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13303 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13305 mm_player_t *player = (mm_player_t*)user_data;
13306 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13307 guint64 current_level_bytes = 0;
13309 MMPLAYER_RETURN_IF_FAIL(player);
13311 LOGI("app-src: video buffer is full.\n");
13313 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13315 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13316 if (player->media_stream_buffer_status_cb[type])
13317 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13319 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13323 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13325 mm_player_t *player = (mm_player_t*)user_data;
13326 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13328 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13330 LOGD("app-src: seek audio data %llu\n", position);
13331 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13333 if (player->media_stream_seek_data_cb[type])
13334 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13335 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13341 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13343 mm_player_t *player = (mm_player_t*)user_data;
13344 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13346 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13348 LOGD("app-src: seek video data %llu\n", position);
13349 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13350 if (player->media_stream_seek_data_cb[type])
13351 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13352 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13358 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13360 mm_player_t *player = (mm_player_t*)user_data;
13361 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13363 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13365 LOGD("app-src: seek subtitle data\n");
13366 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13368 if (player->media_stream_seek_data_cb[type])
13369 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13370 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13376 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13378 mm_player_t* player = (mm_player_t*) hplayer;
13382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13384 player->pcm_samplerate = samplerate;
13385 player->pcm_channel = channel;
13388 return MM_ERROR_NONE;
13391 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13393 mm_player_t* player = (mm_player_t*) hplayer;
13397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13398 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13400 if (MMPLAYER_IS_STREAMING(player))
13401 *timeout = player->ini.live_state_change_timeout;
13403 *timeout = player->ini.localplayback_state_change_timeout;
13405 LOGD("timeout = %d\n", *timeout);
13408 return MM_ERROR_NONE;
13411 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13413 mm_player_t* player = (mm_player_t*) hplayer;
13417 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13418 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13420 *num = player->video_num_buffers;
13421 *extra_num = player->video_extra_num_buffers;
13423 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13426 return MM_ERROR_NONE;
13430 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13434 MMPLAYER_RETURN_IF_FAIL(player);
13436 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13438 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13439 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13440 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13441 player->storage_info[i].id = -1;
13442 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13444 if (path_type != MMPLAYER_PATH_MAX)
13452 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13454 int ret = MM_ERROR_NONE;
13455 mm_player_t* player = (mm_player_t*)hplayer;
13456 MMMessageParamType msg_param = {0, };
13459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13461 LOGW("state changed storage %d:%d", id, state);
13463 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13464 return MM_ERROR_NONE;
13466 /* FIXME: text path should be handled seperately. */
13467 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13468 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13469 LOGW("external storage is removed");
13471 if (player->msg_posted == FALSE) {
13472 memset(&msg_param, 0, sizeof(MMMessageParamType));
13473 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13475 player->msg_posted = TRUE;
13478 /* unrealize the player */
13479 ret = _mmplayer_unrealize(hplayer);
13480 if (ret != MM_ERROR_NONE)
13481 LOGE("failed to unrealize");
13488 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13490 int ret = MM_ERROR_NONE;
13491 mm_player_t* player = (mm_player_t*) hplayer;
13492 int idx = 0, total = 0;
13493 gchar *result = NULL, *tmp = NULL;
13496 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13497 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13499 total = *num = g_list_length(player->adaptive_info.var_list);
13501 LOGW("There is no stream variant info.");
13505 result = g_strdup("");
13506 for (idx = 0 ; idx < total ; idx++) {
13507 VariantData *v_data = NULL;
13508 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13511 gchar data[64] = {0};
13512 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13514 tmp = g_strconcat(result, data, NULL);
13518 LOGW("There is no variant data in %d", idx);
13523 *var_info = (char *)result;
13525 LOGD("variant info %d:%s", *num, *var_info);
13530 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13532 int ret = MM_ERROR_NONE;
13533 mm_player_t* player = (mm_player_t*) hplayer;
13536 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13538 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13540 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13541 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13542 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13544 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13545 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13546 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13547 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13549 /* FIXME: seek to current position for applying new variant limitation */
13557 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13559 int ret = MM_ERROR_NONE;
13560 mm_player_t* player = (mm_player_t*) hplayer;
13563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13564 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13566 *bandwidth = player->adaptive_info.limit.bandwidth;
13567 *width = player->adaptive_info.limit.width;
13568 *height = player->adaptive_info.limit.height;
13570 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13576 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13578 int ret = MM_ERROR_NONE;
13579 mm_player_t* player = (mm_player_t*) hplayer;
13582 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13584 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13585 LOGW("buffer_ms will not be applied.");
13588 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13590 if (player->streamer == NULL) {
13591 player->streamer = __mm_player_streaming_create();
13592 __mm_player_streaming_initialize(player->streamer);
13595 if (buffer_ms >= 0)
13596 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13598 if (rebuffer_ms >= 0)
13599 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13606 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13608 int ret = MM_ERROR_NONE;
13609 mm_player_t* player = (mm_player_t*) hplayer;
13612 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13613 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13615 if (player->streamer == NULL) {
13616 player->streamer = __mm_player_streaming_create();
13617 __mm_player_streaming_initialize(player->streamer);
13620 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13621 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13623 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13629 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13631 #define IDX_FIRST_SW_CODEC 0
13632 mm_player_t* player = (mm_player_t*) hplayer;
13633 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13634 MMHandleType attrs = 0;
13637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13639 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13640 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13641 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13643 switch (stream_type) {
13644 case MM_PLAYER_STREAM_TYPE_AUDIO:
13645 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13646 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13647 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13648 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13649 LOGE("There is no a codec for codec_type %d", codec_type);
13650 return MM_ERROR_PLAYER_NO_OP;
13653 case MM_PLAYER_STREAM_TYPE_VIDEO:
13654 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13655 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13656 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13657 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13658 LOGE("There is no v codec for codec_type %d", codec_type);
13659 return MM_ERROR_PLAYER_NO_OP;
13664 LOGE("Invalid stream type %d", stream_type);
13665 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13669 LOGD("update %s codec_type to %d", attr_name, codec_type);
13671 attrs = MMPLAYER_GET_ATTRS(player);
13672 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13674 if (mmf_attrs_commit(player->attrs)) {
13675 LOGE("failed to commit codec_type attributes");
13676 return MM_ERROR_PLAYER_INTERNAL;
13680 return MM_ERROR_NONE;
13684 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13686 mm_player_t* player = (mm_player_t*) hplayer;
13687 GstElement* rg_vol_element = NULL;
13691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13693 player->sound.rg_enable = enabled;
13695 /* just hold rgvolume enable value if pipeline is not ready */
13696 if (!player->pipeline || !player->pipeline->audiobin) {
13697 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13698 return MM_ERROR_NONE;
13701 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13703 if (!rg_vol_element) {
13704 LOGD("rgvolume element is not created");
13705 return MM_ERROR_PLAYER_INTERNAL;
13709 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13711 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13715 return MM_ERROR_NONE;
13719 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13721 mm_player_t* player = (mm_player_t*) hplayer;
13722 GstElement* rg_vol_element = NULL;
13723 gboolean enable = FALSE;
13727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13728 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13730 /* just hold enable_rg value if pipeline is not ready */
13731 if (!player->pipeline || !player->pipeline->audiobin) {
13732 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13733 *enabled = player->sound.rg_enable;
13734 return MM_ERROR_NONE;
13737 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13739 if (!rg_vol_element) {
13740 LOGD("rgvolume element is not created");
13741 return MM_ERROR_PLAYER_INTERNAL;
13744 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13749 return MM_ERROR_NONE;