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;
964 GstMessage *msg = NULL;
965 GQueue *queue = NULL;
968 MMPLAYER_RETURN_IF_FAIL(player);
970 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
972 /* destroy the gst bus msg thread */
973 if (player->bus_msg_thread) {
974 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
975 player->bus_msg_thread_exit = TRUE;
976 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
977 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
979 LOGD("gst bus msg thread exit.");
980 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
981 player->bus_msg_thread = NULL;
983 g_mutex_clear(&player->bus_msg_thread_mutex);
984 g_cond_clear(&player->bus_msg_thread_cond);
987 g_mutex_lock(&player->bus_msg_q_lock);
988 queue = player->bus_msg_q;
989 while (!g_queue_is_empty(queue)) {
990 msg = (GstMessage *)g_queue_pop_head(queue);
991 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
992 gst_message_unref(msg);
994 g_mutex_unlock(&player->bus_msg_q_lock);
999 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1001 mm_player_t *player = (mm_player_t *) data;
1003 g_return_val_if_fail(player, FALSE);
1004 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1006 gst_message_ref(msg);
1008 g_mutex_lock(&player->bus_msg_q_lock);
1009 g_queue_push_tail(player->bus_msg_q, msg);
1010 g_mutex_unlock(&player->bus_msg_q_lock);
1012 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1013 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1014 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1018 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1020 mm_player_t *player = (mm_player_t*)(data);
1021 GstMessage *msg = NULL;
1025 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1027 player->pipeline->mainbin &&
1028 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1031 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1033 LOGE("cannot get BUS from the pipeline");
1037 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1039 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1040 while (!player->bus_msg_thread_exit) {
1041 g_mutex_lock(&player->bus_msg_q_lock);
1042 msg = g_queue_pop_head(player->bus_msg_q);
1043 g_mutex_unlock(&player->bus_msg_q_lock);
1045 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1048 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1049 /* handle the gst msg */
1050 __mmplayer_gst_callback(msg, player);
1051 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1052 gst_message_unref(msg);
1055 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1056 gst_object_unref(GST_OBJECT(bus));
1063 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1065 mm_player_t* player = (mm_player_t*)(data);
1066 static gboolean async_done = FALSE;
1068 MMPLAYER_RETURN_IF_FAIL(player);
1069 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1071 switch (GST_MESSAGE_TYPE(msg)) {
1072 case GST_MESSAGE_UNKNOWN:
1073 LOGD("unknown message received\n");
1076 case GST_MESSAGE_EOS:
1078 MMHandleType attrs = 0;
1081 LOGD("GST_MESSAGE_EOS received\n");
1083 /* NOTE : EOS event is comming multiple time. watch out it */
1084 /* check state. we only process EOS when pipeline state goes to PLAYING */
1085 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1086 LOGD("EOS received on non-playing state. ignoring it\n");
1090 if (player->pipeline) {
1091 if (player->pipeline->textbin)
1092 __mmplayer_drop_subtitle(player, TRUE);
1094 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1097 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1099 LOGD("release audio callback\n");
1101 /* release audio callback */
1102 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1103 player->audio_cb_probe_id = 0;
1104 /* audio callback should be free because it can be called even though probe remove.*/
1105 player->audio_stream_cb = NULL;
1106 player->audio_stream_cb_user_param = NULL;
1110 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1111 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1113 /* rewind if repeat count is greater then zero */
1114 /* get play count */
1115 attrs = MMPLAYER_GET_ATTRS(player);
1118 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1120 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1122 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1123 if (player->playback_rate < 0.0) {
1124 player->resumed_by_rewind = TRUE;
1125 _mmplayer_set_mute((MMHandleType)player, 0);
1126 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1129 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1132 player->sent_bos = FALSE;
1134 /* not posting eos when repeating */
1139 if (player->pipeline)
1140 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1142 /* post eos message to application */
1143 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1145 /* reset last position */
1146 player->last_position = 0;
1150 case GST_MESSAGE_ERROR:
1152 GError *error = NULL;
1153 gchar* debug = NULL;
1155 /* generating debug info before returning error */
1156 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1158 /* get error code */
1159 gst_message_parse_error(msg, &error, &debug);
1161 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1162 /* Note : the streaming error from the streaming source is handled
1163 * using __mmplayer_handle_streaming_error.
1165 __mmplayer_handle_streaming_error(player, msg);
1167 /* dump state of all element */
1168 __mmplayer_dump_pipeline_state(player);
1170 /* traslate gst error code to msl error code. then post it
1171 * to application if needed
1173 __mmplayer_handle_gst_error(player, msg, error);
1176 LOGE("error debug : %s", debug);
1179 if (MMPLAYER_IS_HTTP_PD(player))
1180 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1182 MMPLAYER_FREEIF(debug);
1183 g_error_free(error);
1187 case GST_MESSAGE_WARNING:
1190 GError* error = NULL;
1192 gst_message_parse_warning(msg, &error, &debug);
1194 LOGD("warning : %s\n", error->message);
1195 LOGD("debug : %s\n", debug);
1197 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1199 MMPLAYER_FREEIF(debug);
1200 g_error_free(error);
1204 case GST_MESSAGE_TAG:
1206 LOGD("GST_MESSAGE_TAG\n");
1207 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1208 LOGW("failed to extract tags from gstmessage\n");
1212 case GST_MESSAGE_BUFFERING:
1214 MMMessageParamType msg_param = {0, };
1215 int bRet = MM_ERROR_NONE;
1217 if (!(player->pipeline && player->pipeline->mainbin)) {
1218 LOGE("player pipeline handle is null");
1222 if (!MMPLAYER_IS_STREAMING(player))
1225 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1226 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1227 /* skip the playback control by buffering msg while user request is handled. */
1230 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1232 gst_message_parse_buffering(msg, &per);
1233 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1235 msg_param.connection.buffering = per;
1236 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1240 MMPLAYER_CMD_LOCK(player);
1243 /* ignore the prev buffering message */
1244 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1245 && (player->streamer->is_buffering_done == TRUE)) {
1246 gint buffer_percent = 0;
1248 gst_message_parse_buffering(msg, &buffer_percent);
1250 if (buffer_percent == MAX_BUFFER_PERCENT) {
1251 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1252 player->streamer->is_buffering_done = FALSE;
1254 MMPLAYER_CMD_UNLOCK(player);
1258 __mmplayer_update_buffer_setting(player, msg);
1260 bRet = __mmplayer_handle_buffering_message(player);
1262 if (bRet == MM_ERROR_NONE) {
1263 msg_param.connection.buffering = player->streamer->buffering_percent;
1264 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1266 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1267 player->pending_resume &&
1268 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1270 player->is_external_subtitle_added_now = FALSE;
1271 player->pending_resume = FALSE;
1272 _mmplayer_resume((MMHandleType)player);
1275 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1276 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1278 if (player->doing_seek) {
1279 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1280 player->doing_seek = FALSE;
1281 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1282 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1287 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1288 if (!player->streamer) {
1289 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1290 MMPLAYER_CMD_UNLOCK(player);
1294 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1296 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1297 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1299 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1300 msg_param.connection.buffering = player->streamer->buffering_percent;
1301 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1303 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1306 msg_param.connection.buffering = player->streamer->buffering_percent;
1307 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1310 MMPLAYER_CMD_UNLOCK(player);
1314 case GST_MESSAGE_STATE_CHANGED:
1316 MMPlayerGstElement *mainbin;
1317 const GValue *voldstate, *vnewstate, *vpending;
1318 GstState oldstate = GST_STATE_NULL;
1319 GstState newstate = GST_STATE_NULL;
1320 GstState pending = GST_STATE_NULL;
1322 if (!(player->pipeline && player->pipeline->mainbin)) {
1323 LOGE("player pipeline handle is null");
1327 mainbin = player->pipeline->mainbin;
1329 /* we only handle messages from pipeline */
1330 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1333 /* get state info from msg */
1334 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1335 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1336 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1338 if (!voldstate || !vnewstate) {
1339 LOGE("received msg has wrong format.");
1343 oldstate = (GstState)voldstate->data[0].v_int;
1344 newstate = (GstState)vnewstate->data[0].v_int;
1346 pending = (GstState)vpending->data[0].v_int;
1348 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1349 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1350 gst_element_state_get_name((GstState)oldstate),
1351 gst_element_state_get_name((GstState)newstate),
1352 gst_element_state_get_name((GstState)pending));
1354 if (newstate == GST_STATE_PLAYING) {
1355 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1357 int retVal = MM_ERROR_NONE;
1358 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1360 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1362 if (MM_ERROR_NONE != retVal)
1363 LOGE("failed to seek pending postion. just keep staying current position.\n");
1365 player->pending_seek.is_pending = FALSE;
1369 if (oldstate == newstate) {
1370 LOGD("pipeline reports state transition to old state");
1375 case GST_STATE_VOID_PENDING:
1378 case GST_STATE_NULL:
1381 case GST_STATE_READY:
1384 case GST_STATE_PAUSED:
1386 gboolean prepare_async = FALSE;
1387 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1389 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1390 __mmplayer_configure_audio_callback(player);
1392 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1393 // managed prepare async case
1394 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1395 LOGD("checking prepare mode for async transition - %d", prepare_async);
1398 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1399 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1401 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1402 __mm_player_streaming_set_content_bitrate(player->streamer,
1403 player->total_maximum_bitrate, player->total_bitrate);
1405 if (player->pending_seek.is_pending) {
1406 LOGW("trying to do pending seek");
1407 MMPLAYER_CMD_LOCK(player);
1408 __gst_pending_seek(player);
1409 MMPLAYER_CMD_UNLOCK(player);
1415 case GST_STATE_PLAYING:
1417 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1419 if (MMPLAYER_IS_STREAMING(player)) {
1420 // managed prepare async case when buffering is completed
1421 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1422 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1423 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1424 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1426 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1428 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1429 if (player->streamer->buffering_percent < 100) {
1431 MMMessageParamType msg_param = {0, };
1432 LOGW("Posting Buffering Completed Message to Application !!!");
1434 msg_param.connection.buffering = 100;
1435 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1440 if (player->gapless.stream_changed) {
1441 _mmplayer_update_content_attrs(player, ATTR_ALL);
1442 player->gapless.stream_changed = FALSE;
1445 if (player->doing_seek && async_done) {
1446 player->doing_seek = FALSE;
1448 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1459 case GST_MESSAGE_CLOCK_LOST:
1461 GstClock *clock = NULL;
1462 gboolean need_new_clock = FALSE;
1464 gst_message_parse_clock_lost(msg, &clock);
1465 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1467 if (!player->videodec_linked)
1468 need_new_clock = TRUE;
1469 else if (!player->ini.use_system_clock)
1470 need_new_clock = TRUE;
1472 if (need_new_clock) {
1473 LOGD("Provide clock is TRUE, do pause->resume\n");
1474 __gst_pause(player, FALSE);
1475 __gst_resume(player, FALSE);
1480 case GST_MESSAGE_NEW_CLOCK:
1482 GstClock *clock = NULL;
1483 gst_message_parse_new_clock(msg, &clock);
1484 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1488 case GST_MESSAGE_ELEMENT:
1490 const gchar *structure_name;
1491 gint count = 0, idx = 0;
1492 MMHandleType attrs = 0;
1494 attrs = MMPLAYER_GET_ATTRS(player);
1496 LOGE("cannot get content attribute");
1500 if (gst_message_get_structure(msg) == NULL)
1503 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1504 if (!structure_name)
1507 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1509 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1510 const GValue *var_info = NULL;
1512 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1513 if (var_info != NULL) {
1514 if (player->adaptive_info.var_list)
1515 g_list_free_full(player->adaptive_info.var_list, g_free);
1517 /* share addr or copy the list */
1518 player->adaptive_info.var_list =
1519 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1521 count = g_list_length(player->adaptive_info.var_list);
1523 VariantData *temp = NULL;
1525 /* print out for debug */
1526 LOGD("num of variant_info %d", count);
1527 for (idx = 0; idx < count; idx++) {
1528 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1530 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1536 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1537 gint num_buffers = 0;
1538 gint extra_num_buffers = 0;
1540 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1541 player->video_num_buffers = num_buffers;
1542 LOGD("video_num_buffers : %d", player->video_num_buffers);
1545 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1546 player->video_extra_num_buffers = extra_num_buffers;
1547 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1552 if (!strcmp(structure_name, "Language_list")) {
1553 const GValue *lang_list = NULL;
1554 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1555 if (lang_list != NULL) {
1556 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1558 LOGD("Total audio tracks(from parser) = %d \n", count);
1562 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1563 const GValue *lang_list = NULL;
1564 MMPlayerLangStruct *temp = NULL;
1566 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1567 if (lang_list != NULL) {
1568 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1570 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1571 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1572 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1573 if (mmf_attrs_commit(attrs))
1574 LOGE("failed to commit.\n");
1575 LOGD("Total subtitle tracks = %d \n", count);
1578 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1580 LOGD("value of lang_key is %s and lang_code is %s",
1581 temp->language_key, temp->language_code);
1584 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1585 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1590 /* custom message */
1591 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1592 MMMessageParamType msg_param = {0,};
1593 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1594 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1597 /* custom message for RTSP attribute :
1598 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1599 sdp which has contents info is received when rtsp connection is opened.
1600 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1601 if (!strcmp(structure_name, "rtspsrc_properties")) {
1603 gchar *audio_codec = NULL;
1604 gchar *video_codec = NULL;
1605 gchar *video_frame_size = NULL;
1607 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1608 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1609 player->streaming_type = __mmplayer_get_stream_service_type(player);
1610 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1612 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1613 LOGD("rtsp_audio_codec : %s", audio_codec);
1615 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1617 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1618 LOGD("rtsp_video_codec : %s", video_codec);
1620 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1622 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1623 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1624 if (video_frame_size) {
1626 char *seperator = strchr(video_frame_size, '-');
1629 char video_width[10] = {0,};
1630 int frame_size_len = strlen(video_frame_size);
1631 int separtor_len = strlen(seperator);
1633 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1634 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1637 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1641 if (mmf_attrs_commit(attrs))
1642 LOGE("failed to commit.\n");
1647 case GST_MESSAGE_DURATION_CHANGED:
1649 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1650 if (!__mmplayer_gst_handle_duration(player, msg))
1651 LOGW("failed to update duration");
1656 case GST_MESSAGE_ASYNC_START:
1657 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1660 case GST_MESSAGE_ASYNC_DONE:
1662 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1664 /* we only handle messages from pipeline */
1665 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1668 if (player->doing_seek) {
1669 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1670 player->doing_seek = FALSE;
1671 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1672 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1673 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1674 (player->streamer) &&
1675 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1676 (player->streamer->is_buffering == FALSE)) {
1677 GstQuery *query = NULL;
1678 gboolean busy = FALSE;
1681 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1682 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1683 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1684 gst_query_parse_buffering_percent(query, &busy, &percent);
1685 gst_query_unref(query);
1687 LOGD("buffered percent(%s): %d\n",
1688 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1691 if (percent >= 100) {
1692 player->streamer->is_buffering = FALSE;
1693 __mmplayer_handle_buffering_message(player);
1703 #if 0 /* delete unnecessary logs */
1704 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1705 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1706 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1707 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1708 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1709 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1710 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1711 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1712 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1713 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1714 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1715 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1716 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1717 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1718 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1725 /* should not call 'gst_message_unref(msg)' */
1730 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1736 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1737 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1739 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1740 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1741 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1743 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1744 LOGD("data total size of http content: %lld", bytes);
1745 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1748 /* handling audio clip which has vbr. means duration is keep changing */
1749 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1756 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1757 mm_player_spherical_metadata_t *metadata) {
1758 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1759 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1760 gst_tag_list_get_string(tags, "stitching_software",
1761 &metadata->stitching_software);
1762 gst_tag_list_get_string(tags, "projection_type",
1763 &metadata->projection_type_string);
1764 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1765 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1766 gst_tag_list_get_int(tags, "init_view_heading",
1767 &metadata->init_view_heading);
1768 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1769 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1770 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1771 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1772 &metadata->full_pano_width_pixels);
1773 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1774 &metadata->full_pano_height_pixels);
1775 gst_tag_list_get_int(tags, "cropped_area_image_width",
1776 &metadata->cropped_area_image_width);
1777 gst_tag_list_get_int(tags, "cropped_area_image_height",
1778 &metadata->cropped_area_image_height);
1779 gst_tag_list_get_int(tags, "cropped_area_left",
1780 &metadata->cropped_area_left);
1781 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1782 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1783 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1784 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1788 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1791 /* macro for better code readability */
1792 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1793 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1794 if (string != NULL) { \
1795 SECURE_LOGD("update tag string : %s\n", string); \
1796 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1797 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1798 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1799 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1800 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1801 g_free(new_string); \
1802 new_string = NULL; \
1804 mm_attrs_set_string_by_name(attribute, playertag, string); \
1811 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1813 GstSample *sample = NULL;\
1814 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1815 GstMapInfo info = GST_MAP_INFO_INIT;\
1816 buffer = gst_sample_get_buffer(sample);\
1817 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1818 LOGD("failed to get image data from tag");\
1819 gst_sample_unref(sample);\
1822 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1823 MMPLAYER_FREEIF(player->album_art);\
1824 player->album_art = (gchar *)g_malloc(info.size);\
1825 if (player->album_art) {\
1826 memcpy(player->album_art, info.data, info.size);\
1827 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1828 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1829 msg_param.data = (void *)player->album_art;\
1830 msg_param.size = info.size;\
1831 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1832 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1835 gst_buffer_unmap(buffer, &info);\
1836 gst_sample_unref(sample);\
1840 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1842 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1845 gchar *tag_list_str = NULL; \
1846 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1847 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1848 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1849 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1850 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1852 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1853 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1854 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1855 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1856 player->bitrate[track_type] = v_uint; \
1857 player->total_bitrate = 0; \
1858 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1859 player->total_bitrate += player->bitrate[i]; \
1860 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1861 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1862 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1863 player->maximum_bitrate[track_type] = v_uint; \
1864 player->total_maximum_bitrate = 0; \
1865 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1866 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1867 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1868 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1870 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1873 g_free(tag_list_str); \
1878 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1879 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1880 if (date != NULL) {\
1881 string = g_strdup_printf("%d", g_date_get_year(date));\
1882 mm_attrs_set_string_by_name(attribute, playertag, string);\
1883 SECURE_LOGD("metainfo year : %s\n", string);\
1884 MMPLAYER_FREEIF(string);\
1889 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1890 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1891 if (datetime != NULL) {\
1892 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1893 mm_attrs_set_string_by_name(attribute, playertag, string);\
1894 SECURE_LOGD("metainfo year : %s\n", string);\
1895 MMPLAYER_FREEIF(string);\
1896 gst_date_time_unref(datetime);\
1900 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1901 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1903 /* FIXIT : don't know how to store date */\
1909 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1910 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1912 /* FIXIT : don't know how to store date */\
1918 /* function start */
1919 GstTagList* tag_list = NULL;
1921 MMHandleType attrs = 0;
1923 char *string = NULL;
1926 GstDateTime *datetime = NULL;
1928 GstBuffer *buffer = NULL;
1930 MMMessageParamType msg_param = {0, };
1932 /* currently not used. but those are needed for above macro */
1933 //guint64 v_uint64 = 0;
1934 //gdouble v_double = 0;
1936 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1938 attrs = MMPLAYER_GET_ATTRS(player);
1940 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1942 /* get tag list from gst message */
1943 gst_message_parse_tag(msg, &tag_list);
1945 /* store tags to player attributes */
1946 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1947 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1948 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1949 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1950 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1951 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1952 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1953 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1954 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1955 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1956 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1958 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1959 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1961 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1962 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1963 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1964 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1966 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1967 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1970 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1972 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1973 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1974 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1975 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1976 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1977 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1978 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1979 MMPLAYER_UPDATE_TAG_LOCK(player);
1980 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1981 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1982 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1983 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1984 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1985 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1992 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1993 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1994 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1996 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1997 if (player->video360_metadata.is_spherical == -1) {
1998 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1999 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2000 player->video360_metadata.is_spherical);
2001 if (player->video360_metadata.is_spherical == 1) {
2002 LOGD("This is spherical content for 360 playback.");
2003 player->is_content_spherical = TRUE;
2005 LOGD("This is not spherical content");
2006 player->is_content_spherical = FALSE;
2009 if (player->video360_metadata.projection_type_string) {
2010 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2011 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2013 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2014 player->is_content_spherical = player->is_video360_enabled = FALSE;
2018 if (player->video360_metadata.stereo_mode_string) {
2019 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2020 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2021 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2022 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2023 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2024 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2026 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2027 player->is_content_spherical = player->is_video360_enabled = FALSE;
2033 if (mmf_attrs_commit(attrs))
2034 LOGE("failed to commit.\n");
2036 gst_tag_list_free(tag_list);
2042 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2044 mm_player_t* player = (mm_player_t*) data;
2048 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2049 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2050 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2051 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2053 * [1] audio and video will be dumped with filesink.
2054 * [2] autoplugging is done by just using pad caps.
2055 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2056 * and the video will be dumped via filesink.
2058 if (player->num_dynamic_pad == 0) {
2059 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2061 if (!__mmplayer_gst_remove_fakesink(player,
2062 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2063 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2064 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2065 * source element are not same. To overcome this situation, this function will called
2066 * several places and several times. Therefore, this is not an error case.
2071 /* create dot before error-return. for debugging */
2072 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2074 player->no_more_pad = TRUE;
2080 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2082 GstElement* parent = NULL;
2084 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2086 /* if we have no fakesink. this meas we are using decodebin which doesn'
2087 t need to add extra fakesink */
2088 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2091 MMPLAYER_FSINK_LOCK(player);
2096 /* get parent of fakesink */
2097 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2099 LOGD("fakesink already removed\n");
2103 gst_element_set_locked_state(fakesink->gst, TRUE);
2105 /* setting the state to NULL never returns async
2106 * so no need to wait for completion of state transiton
2108 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2109 LOGE("fakesink state change failure!\n");
2110 /* FIXIT : should I return here? or try to proceed to next? */
2113 /* remove fakesink from it's parent */
2114 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2115 LOGE("failed to remove fakesink\n");
2117 gst_object_unref(parent);
2122 gst_object_unref(parent);
2124 LOGD("state-holder removed\n");
2126 gst_element_set_locked_state(fakesink->gst, FALSE);
2128 MMPLAYER_FSINK_UNLOCK(player);
2133 gst_element_set_locked_state(fakesink->gst, FALSE);
2135 MMPLAYER_FSINK_UNLOCK(player);
2141 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2143 GstPad *sinkpad = NULL;
2144 GstCaps* caps = NULL;
2145 GstElement* new_element = NULL;
2146 GstStructure* str = NULL;
2147 const gchar* name = NULL;
2149 mm_player_t* player = (mm_player_t*) data;
2153 MMPLAYER_RETURN_IF_FAIL(element && pad);
2154 MMPLAYER_RETURN_IF_FAIL(player &&
2156 player->pipeline->mainbin);
2159 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2160 * num_dynamic_pad will decreased after creating a sinkbin.
2162 player->num_dynamic_pad++;
2163 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2165 caps = gst_pad_query_caps(pad, NULL);
2167 MMPLAYER_CHECK_NULL(caps);
2169 /* clear previous result*/
2170 player->have_dynamic_pad = FALSE;
2172 str = gst_caps_get_structure(caps, 0);
2175 LOGE("cannot get structure from caps.\n");
2179 name = gst_structure_get_name(str);
2181 LOGE("cannot get mimetype from structure.\n");
2185 if (strstr(name, "video")) {
2187 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2189 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2190 if (player->v_stream_caps) {
2191 gst_caps_unref(player->v_stream_caps);
2192 player->v_stream_caps = NULL;
2195 new_element = gst_element_factory_make("fakesink", NULL);
2196 player->num_dynamic_pad--;
2201 /* clear previous result*/
2202 player->have_dynamic_pad = FALSE;
2204 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2205 LOGE("failed to autoplug for caps");
2209 /* check if there's dynamic pad*/
2210 if (player->have_dynamic_pad) {
2211 LOGE("using pad caps assums there's no dynamic pad !\n");
2215 gst_caps_unref(caps);
2220 /* excute new_element if created*/
2222 LOGD("adding new element to pipeline\n");
2224 /* set state to READY before add to bin */
2225 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2227 /* add new element to the pipeline */
2228 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2229 LOGE("failed to add autoplug element to bin\n");
2233 /* get pad from element */
2234 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2236 LOGE("failed to get sinkpad from autoplug element\n");
2241 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2242 LOGE("failed to link autoplug element\n");
2246 gst_object_unref(sinkpad);
2249 /* run. setting PLAYING here since streamming source is live source */
2250 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2254 gst_caps_unref(caps);
2260 STATE_CHANGE_FAILED:
2262 /* FIXIT : take care if new_element has already added to pipeline */
2264 gst_object_unref(GST_OBJECT(new_element));
2267 gst_object_unref(GST_OBJECT(sinkpad));
2270 gst_caps_unref(caps);
2272 /* FIXIT : how to inform this error to MSL ????? */
2273 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2274 * then post an error to application
2278 static GstPadProbeReturn
2279 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2281 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2282 return GST_PAD_PROBE_OK;
2285 static GstPadProbeReturn
2286 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2288 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2289 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2290 mm_player_t* player = (mm_player_t*)data;
2291 GstCaps* caps = NULL;
2292 GstStructure* str = NULL;
2293 const gchar* name = NULL;
2294 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2297 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2298 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2299 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2300 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2301 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2303 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2304 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2308 caps = gst_pad_query_caps(pad, NULL);
2310 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2314 str = gst_caps_get_structure(caps, 0);
2316 LOGE("failed to get structure from caps");
2320 name = gst_structure_get_name(str);
2322 LOGE("failed to get name from str");
2326 if (strstr(name, "audio")) {
2327 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2328 } else if (strstr(name, "video")) {
2329 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2331 /* text track is not supportable */
2332 LOGE("invalid name %s", name);
2336 switch (GST_EVENT_TYPE(event)) {
2339 /* in case of gapless, drop eos event not to send it to sink */
2340 if (player->gapless.reconfigure && !player->msg_posted) {
2341 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2342 ret = GST_PAD_PROBE_DROP;
2346 case GST_EVENT_STREAM_START:
2348 gint64 stop_running_time = 0;
2349 gint64 position_running_time = 0;
2350 gint64 position = 0;
2353 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2354 if ((player->gapless.update_segment[idx] == TRUE) ||
2355 !(player->selector[idx].event_probe_id)) {
2356 /* LOGW("[%d] skip", idx); */
2360 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2362 gst_segment_to_running_time(&player->gapless.segment[idx],
2363 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2364 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2366 gst_segment_to_running_time(&player->gapless.segment[idx],
2367 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2369 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2371 gst_segment_to_running_time(&player->gapless.segment[idx],
2372 GST_FORMAT_TIME, player->duration);
2375 position_running_time =
2376 gst_segment_to_running_time(&player->gapless.segment[idx],
2377 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2379 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2380 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2382 GST_TIME_ARGS(stop_running_time),
2383 GST_TIME_ARGS(position_running_time),
2384 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2385 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2387 position_running_time = MAX(position_running_time, stop_running_time);
2388 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2389 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2390 position_running_time = MAX(0, position_running_time);
2391 position = MAX(position, position_running_time);
2394 if (position != 0) {
2395 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2396 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2397 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2399 player->gapless.start_time[stream_type] += position;
2403 case GST_EVENT_FLUSH_STOP:
2405 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2406 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2407 player->gapless.start_time[stream_type] = 0;
2410 case GST_EVENT_SEGMENT:
2415 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2416 gst_event_copy_segment(event, &segment);
2418 if (segment.format == GST_FORMAT_TIME) {
2419 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2420 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2421 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2422 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2423 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2424 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2426 /* keep the all the segment ev to cover the seeking */
2427 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2428 player->gapless.update_segment[stream_type] = TRUE;
2430 if (!player->gapless.running)
2433 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2435 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2437 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2438 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2439 gst_event_unref(event);
2440 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2446 gdouble proportion = 0.0;
2447 GstClockTimeDiff diff = 0;
2448 GstClockTime timestamp = 0;
2449 gint64 running_time_diff = -1;
2450 GstQOSType type = 0;
2451 GstEvent *tmpev = NULL;
2453 running_time_diff = player->gapless.segment[stream_type].base;
2455 if (running_time_diff <= 0) /* don't need to adjust */
2458 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2459 gst_event_unref(event);
2461 if (timestamp < running_time_diff) {
2462 LOGW("QOS event from previous group");
2463 ret = GST_PAD_PROBE_DROP;
2467 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2468 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2469 stream_type, GST_TIME_ARGS(timestamp),
2470 GST_TIME_ARGS(running_time_diff),
2471 GST_TIME_ARGS(timestamp - running_time_diff));
2473 timestamp -= running_time_diff;
2475 /* That case is invalid for QoS events */
2476 if (diff < 0 && -diff > timestamp) {
2477 LOGW("QOS event from previous group");
2478 ret = GST_PAD_PROBE_DROP;
2482 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2483 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2493 gst_caps_unref(caps);
2498 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2500 mm_player_t* player = NULL;
2501 GstElement* pipeline = NULL;
2502 GstElement* selector = NULL;
2503 GstElement* fakesink = NULL;
2504 GstCaps* caps = NULL;
2505 GstStructure* str = NULL;
2506 const gchar* name = NULL;
2507 GstPad* sinkpad = NULL;
2508 GstPad* srcpad = NULL;
2509 gboolean first_track = FALSE;
2511 enum MainElementID elemId = MMPLAYER_M_NUM;
2512 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2515 player = (mm_player_t*)data;
2517 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2518 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2520 //LOGD("pad-added signal handling\n");
2522 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2524 /* get mimetype from caps */
2525 caps = gst_pad_query_caps(pad, NULL);
2527 LOGE("cannot get caps from pad.\n");
2531 str = gst_caps_get_structure(caps, 0);
2533 LOGE("cannot get structure from caps.\n");
2537 name = gst_structure_get_name(str);
2539 LOGE("cannot get mimetype from structure.\n");
2543 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2544 //LOGD("detected mimetype : %s\n", name);
2546 if (strstr(name, "video")) {
2549 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2550 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2552 /* don't make video because of not required, and not support multiple track */
2553 if (stype == MM_DISPLAY_SURFACE_NULL) {
2554 LOGD("no video sink by null surface");
2556 gchar *caps_str = gst_caps_to_string(caps);
2557 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2558 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2559 player->set_mode.video_zc = TRUE;
2561 MMPLAYER_FREEIF(caps_str);
2563 if (player->v_stream_caps) {
2564 gst_caps_unref(player->v_stream_caps);
2565 player->v_stream_caps = NULL;
2568 LOGD("create fakesink instead of videobin");
2571 fakesink = gst_element_factory_make("fakesink", NULL);
2572 if (fakesink == NULL) {
2573 LOGE("ERROR : fakesink create error\n");
2577 if (player->ini.set_dump_element_flag)
2578 __mmplayer_add_dump_buffer_probe(player, fakesink);
2580 player->video_fakesink = fakesink;
2582 /* store it as it's sink element */
2583 __mmplayer_add_sink(player, player->video_fakesink);
2585 gst_bin_add(GST_BIN(pipeline), fakesink);
2588 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2590 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2591 LOGW("failed to link fakesink\n");
2592 gst_object_unref(GST_OBJECT(fakesink));
2596 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2597 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2598 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2601 if (player->set_mode.media_packet_video_stream) {
2602 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2604 MMPLAYER_SIGNAL_CONNECT(player,
2606 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2608 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2611 MMPLAYER_SIGNAL_CONNECT(player,
2613 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2615 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2619 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2620 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2624 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2625 __mmplayer_gst_decode_callback(elem, pad, player);
2629 LOGD("video selector \n");
2630 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2631 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2633 if (strstr(name, "audio")) {
2634 gint samplerate = 0;
2637 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2638 __mmplayer_gst_decode_callback(elem, pad, player);
2642 LOGD("audio selector \n");
2643 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2644 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2646 gst_structure_get_int(str, "rate", &samplerate);
2647 gst_structure_get_int(str, "channels", &channels);
2649 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2651 fakesink = gst_element_factory_make("fakesink", NULL);
2652 if (fakesink == NULL) {
2653 LOGE("ERROR : fakesink create error\n");
2657 gst_bin_add(GST_BIN(pipeline), fakesink);
2660 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2662 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2663 LOGW("failed to link fakesink\n");
2664 gst_object_unref(GST_OBJECT(fakesink));
2668 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2669 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2670 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2674 } else if (strstr(name, "text")) {
2675 LOGD("text selector \n");
2676 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2677 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2679 LOGE("wrong elem id \n");
2684 selector = player->pipeline->mainbin[elemId].gst;
2685 if (selector == NULL) {
2686 selector = gst_element_factory_make("input-selector", NULL);
2687 LOGD("Creating input-selector\n");
2688 if (selector == NULL) {
2689 LOGE("ERROR : input-selector create error\n");
2692 g_object_set(selector, "sync-streams", TRUE, NULL);
2694 player->pipeline->mainbin[elemId].id = elemId;
2695 player->pipeline->mainbin[elemId].gst = selector;
2698 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2700 srcpad = gst_element_get_static_pad(selector, "src");
2702 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2703 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2704 __mmplayer_gst_selector_blocked, NULL, NULL);
2705 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2706 __mmplayer_gst_selector_event_probe, player, NULL);
2708 gst_element_set_state(selector, GST_STATE_PAUSED);
2709 gst_bin_add(GST_BIN(pipeline), selector);
2711 LOGD("input-selector is already created.\n");
2714 LOGD("Calling request pad with selector %p \n", selector);
2715 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2717 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2719 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2720 LOGW("failed to link selector\n");
2721 gst_object_unref(GST_OBJECT(selector));
2726 LOGD("this is first track --> active track \n");
2727 g_object_set(selector, "active-pad", sinkpad, NULL);
2730 _mmplayer_track_update_info(player, stream_type, sinkpad);
2737 gst_caps_unref(caps);
2740 gst_object_unref(GST_OBJECT(sinkpad));
2745 gst_object_unref(GST_OBJECT(srcpad));
2752 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2754 GstPad* srcpad = NULL;
2755 MMHandleType attrs = 0;
2756 gint active_index = 0;
2758 // [link] input-selector :: textbin
2759 srcpad = gst_element_get_static_pad(text_selector, "src");
2761 LOGE("failed to get srcpad from selector\n");
2765 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2767 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2768 if ((active_index != DEFAULT_TRACK) &&
2769 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2770 LOGW("failed to change text track\n");
2771 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2774 player->no_more_pad = TRUE;
2775 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2777 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2778 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2779 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2780 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2783 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2785 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2786 player->has_closed_caption = TRUE;
2788 attrs = MMPLAYER_GET_ATTRS(player);
2790 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2791 if (mmf_attrs_commit(attrs))
2792 LOGE("failed to commit.\n");
2794 LOGE("cannot get content attribute");
2797 gst_object_unref(GST_OBJECT(srcpad));
2803 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2805 mm_player_t* player = (mm_player_t*)data;
2806 GstElement* selector = NULL;
2807 GstElement* queue = NULL;
2809 GstPad* srcpad = NULL;
2810 GstPad* sinkpad = NULL;
2811 GstCaps* caps = NULL;
2812 gchar* caps_str = NULL;
2815 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2817 caps = gst_pad_get_current_caps(pad);
2818 caps_str = gst_caps_to_string(caps);
2819 LOGD("deinterleave new caps : %s\n", caps_str);
2820 MMPLAYER_FREEIF(caps_str);
2821 gst_caps_unref(caps);
2823 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2824 LOGE("ERROR : queue create error\n");
2828 g_object_set(G_OBJECT(queue),
2829 "max-size-buffers", 10,
2830 "max-size-bytes", 0,
2831 "max-size-time", (guint64)0,
2834 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2837 LOGE("there is no audio channel selector.\n");
2841 srcpad = gst_element_get_static_pad(queue, "src");
2842 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2844 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2846 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2847 LOGW("failed to link deinterleave - selector\n");
2851 gst_element_set_state(queue, GST_STATE_PAUSED);
2852 player->audio_mode.total_track_num++;
2857 gst_object_unref(GST_OBJECT(srcpad));
2862 gst_object_unref(GST_OBJECT(sinkpad));
2871 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2873 mm_player_t* player = NULL;
2874 GstElement* selector = NULL;
2875 GstPad* sinkpad = NULL;
2876 gint active_index = 0;
2877 gchar* change_pad_name = NULL;
2878 GstCaps* caps = NULL; // no need to unref
2879 gint default_audio_ch = 0;
2882 player = (mm_player_t*) data;
2884 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2887 LOGE("there is no audio channel selector.\n");
2891 active_index = player->audio_mode.active_pad_index;
2893 if (active_index != default_audio_ch) {
2894 gint audio_ch = default_audio_ch;
2896 /*To get the new pad from the selector*/
2897 change_pad_name = g_strdup_printf("sink%d", active_index);
2898 if (change_pad_name != NULL) {
2899 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2900 if (sinkpad != NULL) {
2901 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2902 g_object_set(selector, "active-pad", sinkpad, NULL);
2904 audio_ch = active_index;
2906 caps = gst_pad_get_current_caps(sinkpad);
2907 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2909 __mmplayer_set_audio_attrs(player, caps);
2910 gst_caps_unref(caps);
2912 MMPLAYER_FREEIF(change_pad_name);
2915 player->audio_mode.active_pad_index = audio_ch;
2916 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2922 gst_object_unref(sinkpad);
2929 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2931 mm_player_t* player = NULL;
2932 MMPlayerGstElement *mainbin = NULL;
2934 GstElement* tee = NULL;
2935 GstElement* stereo_queue = NULL;
2936 GstElement* mono_queue = NULL;
2937 GstElement* conv = NULL;
2938 GstElement* filter = NULL;
2939 GstElement* deinterleave = NULL;
2940 GstElement* selector = NULL;
2942 GstPad* srcpad = NULL;
2943 GstPad* selector_srcpad = NULL;
2944 GstPad* sinkpad = NULL;
2945 GstCaps* caps = NULL;
2946 gulong block_id = 0;
2951 player = (mm_player_t*) data;
2953 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2954 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2956 mainbin = player->pipeline->mainbin;
2959 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2960 LOGE("ERROR : tee create error\n");
2964 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2965 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2967 gst_element_set_state(tee, GST_STATE_PAUSED);
2970 srcpad = gst_element_get_request_pad(tee, "src_%u");
2971 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2972 LOGE("ERROR : stereo queue create error\n");
2976 g_object_set(G_OBJECT(stereo_queue),
2977 "max-size-buffers", 10,
2978 "max-size-bytes", 0,
2979 "max-size-time", (guint64)0,
2982 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2983 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2986 gst_object_unref(GST_OBJECT(srcpad));
2990 srcpad = gst_element_get_request_pad(tee, "src_%u");
2992 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2993 LOGE("ERROR : mono queue create error\n");
2997 g_object_set(G_OBJECT(mono_queue),
2998 "max-size-buffers", 10,
2999 "max-size-bytes", 0,
3000 "max-size-time", (guint64)0,
3003 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3004 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3006 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3007 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3010 srcpad = gst_element_get_static_pad(mono_queue, "src");
3011 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3012 LOGE("ERROR : audioconvert create error\n");
3016 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3017 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3021 gst_object_unref(GST_OBJECT(srcpad));
3024 srcpad = gst_element_get_static_pad(conv, "src");
3026 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3027 LOGE("ERROR : capsfilter create error\n");
3031 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3032 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3034 caps = gst_caps_from_string("audio/x-raw-int, "
3035 "width = (int) 16, "
3036 "depth = (int) 16, "
3037 "channels = (int) 2");
3039 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3040 gst_caps_unref(caps);
3042 gst_element_set_state(conv, GST_STATE_PAUSED);
3043 gst_element_set_state(filter, GST_STATE_PAUSED);
3047 gst_object_unref(GST_OBJECT(srcpad));
3050 srcpad = gst_element_get_static_pad(filter, "src");
3052 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3053 LOGE("ERROR : deinterleave create error\n");
3057 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3059 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3060 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3062 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3063 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3065 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3066 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3069 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3070 if (selector == NULL) {
3071 LOGE("ERROR : audio-selector create error\n");
3075 g_object_set(selector, "sync-streams", TRUE, NULL);
3076 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3078 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3079 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3081 selector_srcpad = gst_element_get_static_pad(selector, "src");
3083 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3085 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3086 __mmplayer_gst_selector_blocked, NULL, NULL);
3089 gst_object_unref(GST_OBJECT(srcpad));
3093 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3094 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3096 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3097 LOGW("failed to link queue_stereo - selector\n");
3101 player->audio_mode.total_track_num++;
3103 g_object_set(selector, "active-pad", sinkpad, NULL);
3104 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3105 gst_element_set_state(selector, GST_STATE_PAUSED);
3107 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3111 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3112 if (block_id != 0) {
3113 gst_pad_remove_probe(selector_srcpad, block_id);
3118 gst_object_unref(GST_OBJECT(sinkpad));
3123 gst_object_unref(GST_OBJECT(srcpad));
3127 if (selector_srcpad) {
3128 gst_object_unref(GST_OBJECT(selector_srcpad));
3129 selector_srcpad = NULL;
3137 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3139 mm_player_t* player = NULL;
3140 GstPad* srcpad = NULL;
3141 GstElement* video_selector = NULL;
3142 GstElement* audio_selector = NULL;
3143 GstElement* text_selector = NULL;
3144 MMHandleType attrs = 0;
3145 gint active_index = 0;
3146 gint64 dur_bytes = 0L;
3148 player = (mm_player_t*) data;
3150 LOGD("no-more-pad signal handling\n");
3152 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3153 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3154 LOGW("no need to go more");
3156 if (player->gapless.reconfigure) {
3157 player->gapless.reconfigure = FALSE;
3158 MMPLAYER_PLAYBACK_UNLOCK(player);
3164 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3165 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3166 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3167 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3168 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3170 if (NULL == player->streamer) {
3171 LOGW("invalid state for buffering");
3175 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3176 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3178 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3179 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3181 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3183 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3184 LOGE("fail to get duration.\n");
3186 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3187 // use file information was already set on Q2 when it was created.
3188 __mm_player_streaming_set_queue2(player->streamer,
3189 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3190 TRUE, // use_buffering
3192 init_buffering_time,
3194 player->ini.http_buffering_limit, // high percent
3195 MUXED_BUFFER_TYPE_MEM_QUEUE,
3197 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3200 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3201 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3202 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3203 if (video_selector) {
3204 // [link] input-selector :: videobin
3205 srcpad = gst_element_get_static_pad(video_selector, "src");
3207 LOGE("failed to get srcpad from video selector\n");
3211 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3212 if (!text_selector && !audio_selector)
3213 player->no_more_pad = TRUE;
3215 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3217 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3218 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3219 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3220 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3224 if (audio_selector) {
3225 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3226 if ((active_index != DEFAULT_TRACK) &&
3227 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3228 LOGW("failed to change audio track\n");
3229 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3232 // [link] input-selector :: audiobin
3233 srcpad = gst_element_get_static_pad(audio_selector, "src");
3235 LOGE("failed to get srcpad from selector\n");
3239 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3241 player->no_more_pad = TRUE;
3243 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3244 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3245 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3246 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3247 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3250 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3252 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3254 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3256 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3257 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3261 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3263 attrs = MMPLAYER_GET_ATTRS(player);
3265 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3266 if (mmf_attrs_commit(attrs))
3267 LOGE("failed to commit.\n");
3269 LOGE("cannot get content attribute");
3271 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3272 LOGD("There is no audio track : remove audiobin");
3274 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3275 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3277 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3278 MMPLAYER_FREEIF(player->pipeline->audiobin);
3281 if (player->num_dynamic_pad == 0)
3282 __mmplayer_pipeline_complete(NULL, player);
3285 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3287 __mmplayer_handle_text_decode_path(player, text_selector);
3294 gst_object_unref(GST_OBJECT(srcpad));
3298 if (player->gapless.reconfigure) {
3299 player->gapless.reconfigure = FALSE;
3300 MMPLAYER_PLAYBACK_UNLOCK(player);
3305 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3307 mm_player_t* player = NULL;
3308 MMHandleType attrs = 0;
3309 GstElement* pipeline = NULL;
3310 GstCaps* caps = NULL;
3311 gchar* caps_str = NULL;
3312 GstStructure* str = NULL;
3313 const gchar* name = NULL;
3314 GstPad* sinkpad = NULL;
3315 GstElement* sinkbin = NULL;
3316 gboolean reusing = FALSE;
3317 GstElement *text_selector = NULL;
3320 player = (mm_player_t*) data;
3322 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3323 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3325 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3327 attrs = MMPLAYER_GET_ATTRS(player);
3329 LOGE("cannot get content attribute\n");
3333 /* get mimetype from caps */
3334 caps = gst_pad_query_caps(pad, NULL);
3336 LOGE("cannot get caps from pad.\n");
3339 caps_str = gst_caps_to_string(caps);
3341 str = gst_caps_get_structure(caps, 0);
3343 LOGE("cannot get structure from caps.\n");
3347 name = gst_structure_get_name(str);
3349 LOGE("cannot get mimetype from structure.\n");
3353 //LOGD("detected mimetype : %s\n", name);
3355 if (strstr(name, "audio")) {
3356 if (player->pipeline->audiobin == NULL) {
3357 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3358 LOGE("failed to create audiobin. continuing without audio\n");
3362 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3363 LOGD("creating audiosink bin success\n");
3366 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3367 LOGD("reusing audiobin\n");
3368 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3371 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3372 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3374 player->audiosink_linked = 1;
3376 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3378 LOGE("failed to get pad from sinkbin\n");
3381 } else if (strstr(name, "video")) {
3382 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3383 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3384 player->set_mode.video_zc = TRUE;
3386 if (player->pipeline->videobin == NULL) {
3387 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3388 /* get video surface type */
3389 int surface_type = 0;
3390 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3391 LOGD("display_surface_type(%d)\n", surface_type);
3393 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3394 LOGD("not make videobin because it dose not want\n");
3398 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3399 /* mark video overlay for acquire */
3400 if (player->video_overlay_resource == NULL) {
3401 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3402 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3403 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3404 &player->video_overlay_resource)
3405 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3406 LOGE("could not mark video_overlay resource for acquire\n");
3412 player->interrupted_by_resource = FALSE;
3413 /* acquire resources for video overlay */
3414 if (mm_resource_manager_commit(player->resource_manager) !=
3415 MM_RESOURCE_MANAGER_ERROR_NONE) {
3416 LOGE("could not acquire resources for video playing\n");
3420 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3421 LOGE("failed to create videobin. continuing without video\n");
3425 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3426 LOGD("creating videosink bin success\n");
3429 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3430 LOGD("re-using videobin\n");
3431 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3434 player->videosink_linked = 1;
3436 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3438 LOGE("failed to get pad from sinkbin\n");
3441 } else if (strstr(name, "text")) {
3442 if (player->pipeline->textbin == NULL) {
3443 MMPlayerGstElement* mainbin = NULL;
3445 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3446 LOGE("failed to create text sink bin. continuing without text\n");
3450 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3451 LOGD("creating textsink bin success\n");
3453 /* FIXIT : track number shouldn't be hardcoded */
3454 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3456 player->textsink_linked = 1;
3457 LOGI("player->textsink_linked set to 1\n");
3459 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3461 LOGE("failed to get pad from sinkbin\n");
3465 mainbin = player->pipeline->mainbin;
3467 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3468 /* input selector */
3469 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3470 if (!text_selector) {
3471 LOGE("failed to create subtitle input selector element\n");
3474 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3476 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3477 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3480 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3481 LOGE("failed to set state(READY) to sinkbin\n");
3485 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3486 LOGW("failed to add subtitle input selector\n");
3490 LOGD("created element input-selector");
3493 LOGD("already having subtitle input selector");
3494 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3497 if (!player->textsink_linked) {
3498 LOGD("re-using textbin\n");
3501 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3503 player->textsink_linked = 1;
3504 LOGI("player->textsink_linked set to 1\n");
3506 LOGD("ignoring internal subtutle since external subtitle is available");
3509 LOGW("unknown type of elementary stream!ignoring it...\n");
3516 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3517 LOGE("failed to set state(READY) to sinkbin\n");
3521 /* Added for multi audio support to avoid adding audio bin again*/
3523 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3524 LOGE("failed to add sinkbin to pipeline\n");
3530 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3531 LOGE("failed to get pad from sinkbin\n");
3537 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3538 LOGE("failed to set state(PAUSED) to sinkbin\n");
3542 if (text_selector) {
3543 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3544 LOGE("failed to set state(PAUSED) to sinkbin\n");
3550 gst_object_unref(sinkpad);
3554 LOGD("[handle: %p] linking sink bin success", player);
3556 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3557 * streaming task. if the task blocked, then buffer will not flow to the next element
3558 *(autoplugging element). so this is special hack for streaming. please try to remove it
3560 /* dec stream count. we can remove fakesink if it's zero */
3561 if (player->num_dynamic_pad)
3562 player->num_dynamic_pad--;
3564 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3566 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3567 __mmplayer_pipeline_complete(NULL, player);
3571 MMPLAYER_FREEIF(caps_str);
3574 gst_caps_unref(caps);
3577 gst_object_unref(GST_OBJECT(sinkpad));
3579 /* flusing out new attributes */
3580 if (mmf_attrs_commit(attrs))
3581 LOGE("failed to comit attributes\n");
3587 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3589 int pro_value = 0; // in the case of expection, default will be returned.
3590 int dest_angle = rotation_angle;
3591 int rotation_type = -1;
3593 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3594 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3595 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3597 if (rotation_angle >= 360)
3598 dest_angle = rotation_angle - 360;
3600 /* chech if supported or not */
3601 if (dest_angle % 90) {
3602 LOGD("not supported rotation angle = %d", rotation_angle);
3608 * custom_convert - none (B)
3609 * videoflip - none (C)
3611 if (player->set_mode.video_zc) {
3612 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3613 rotation_type = ROTATION_USING_CUSTOM;
3615 rotation_type = ROTATION_USING_SINK;
3617 int surface_type = 0;
3618 rotation_type = ROTATION_USING_FLIP;
3620 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3621 LOGD("check display surface type attribute: %d", surface_type);
3623 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3624 rotation_type = ROTATION_USING_SINK;
3626 rotation_type = ROTATION_USING_FLIP; //C
3628 LOGD("using %d type for rotation", rotation_type);
3631 /* get property value for setting */
3632 switch (rotation_type) {
3633 case ROTATION_USING_SINK: // tizenwlsink
3635 switch (dest_angle) {
3639 pro_value = 3; // clockwise 90
3645 pro_value = 1; // counter-clockwise 90
3650 case ROTATION_USING_CUSTOM:
3652 gchar *ename = NULL;
3653 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3655 if (g_strrstr(ename, "fimcconvert")) {
3656 switch (dest_angle) {
3660 pro_value = 90; // clockwise 90
3666 pro_value = 270; // counter-clockwise 90
3672 case ROTATION_USING_FLIP: // videoflip
3674 switch (dest_angle) {
3678 pro_value = 1; // clockwise 90
3684 pro_value = 3; // counter-clockwise 90
3691 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3699 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3701 /* check video sinkbin is created */
3702 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3704 player->pipeline->videobin &&
3705 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3706 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3707 MM_ERROR_PLAYER_NOT_INITIALIZED);
3709 return MM_ERROR_NONE;
3713 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3715 int rotation_value = 0;
3716 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3720 /* check video sinkbin is created */
3721 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3724 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3726 /* get rotation value to set */
3727 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3728 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3729 LOGD("set video param : rotate %d", rotation_value);
3733 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3735 MMHandleType attrs = 0;
3739 /* check video sinkbin is created */
3740 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3743 attrs = MMPLAYER_GET_ATTRS(player);
3744 MMPLAYER_RETURN_IF_FAIL(attrs);
3746 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3747 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3748 LOGD("set video param : visible %d", visible);
3752 __mmplayer_video_param_set_display_method(mm_player_t* player)
3754 MMHandleType attrs = 0;
3755 int display_method = 0;
3758 /* check video sinkbin is created */
3759 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3762 attrs = MMPLAYER_GET_ATTRS(player);
3763 MMPLAYER_RETURN_IF_FAIL(attrs);
3765 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3766 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3767 LOGD("set video param : method %d", display_method);
3771 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3773 MMHandleType attrs = 0;
3774 void *handle = NULL;
3776 int wl_window_x = 0;
3777 int wl_window_y = 0;
3778 int wl_window_width = 0;
3779 int wl_window_height = 0;
3782 /* check video sinkbin is created */
3783 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3786 attrs = MMPLAYER_GET_ATTRS(player);
3787 MMPLAYER_RETURN_IF_FAIL(attrs);
3789 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3792 /*It should be set after setting window*/
3793 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3794 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3795 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3796 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3798 /* After setting window handle, set render rectangle */
3799 gst_video_overlay_set_render_rectangle(
3800 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3801 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3802 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3803 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3808 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3810 MMHandleType attrs = 0;
3811 void *handle = NULL;
3813 /* check video sinkbin is created */
3814 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3817 attrs = MMPLAYER_GET_ATTRS(player);
3818 MMPLAYER_RETURN_IF_FAIL(attrs);
3820 /* common case if using overlay surface */
3821 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3824 /* default is using wl_surface_id */
3825 unsigned int wl_surface_id = 0;
3826 wl_surface_id = *(int*)handle;
3827 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3828 gst_video_overlay_set_wl_window_wl_surface_id(
3829 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3832 /* FIXIT : is it error case? */
3833 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3838 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3840 bool update_all_param = FALSE;
3843 /* check video sinkbin is created */
3844 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3845 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3847 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3848 LOGE("can not find tizenwlsink");
3849 return MM_ERROR_PLAYER_INTERNAL;
3852 LOGD("param_name : %s", param_name);
3853 if (!g_strcmp0(param_name, "update_all_param"))
3854 update_all_param = TRUE;
3856 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3857 __mmplayer_video_param_set_display_overlay(player);
3858 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3859 __mmplayer_video_param_set_display_method(player);
3860 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3861 __mmplayer_video_param_set_render_rectangle(player);
3862 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3863 __mmplayer_video_param_set_display_visible(player);
3864 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3865 __mmplayer_video_param_set_display_rotation(player);
3867 return MM_ERROR_NONE;
3871 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3873 MMHandleType attrs = 0;
3874 int surface_type = 0;
3875 int ret = MM_ERROR_NONE;
3879 /* check video sinkbin is created */
3880 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3881 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3883 attrs = MMPLAYER_GET_ATTRS(player);
3885 LOGE("cannot get content attribute");
3886 return MM_ERROR_PLAYER_INTERNAL;
3888 LOGD("param_name : %s", param_name);
3890 /* update display surface */
3891 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3892 LOGD("check display surface type attribute: %d", surface_type);
3894 /* configuring display */
3895 switch (surface_type) {
3896 case MM_DISPLAY_SURFACE_OVERLAY:
3898 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3899 if (ret != MM_ERROR_NONE)
3907 return MM_ERROR_NONE;
3911 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3913 gboolean disable_overlay = FALSE;
3914 mm_player_t* player = (mm_player_t*) hplayer;
3915 int ret = MM_ERROR_NONE;
3918 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3919 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3920 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3921 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3923 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3924 LOGW("Display control is not supported");
3925 return MM_ERROR_PLAYER_INTERNAL;
3928 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3930 if (audio_only == (bool)disable_overlay) {
3931 LOGE("It's the same with current setting: (%d)", audio_only);
3932 return MM_ERROR_NONE;
3936 LOGE("disable overlay");
3937 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3939 /* release overlay resource */
3940 if (player->video_overlay_resource != NULL) {
3941 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3942 player->video_overlay_resource);
3943 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3944 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3947 player->video_overlay_resource = NULL;
3950 ret = mm_resource_manager_commit(player->resource_manager);
3951 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3952 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3956 /* mark video overlay for acquire */
3957 if (player->video_overlay_resource == NULL) {
3958 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3959 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3960 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3961 &player->video_overlay_resource);
3962 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3963 LOGE("could not prepare for video_overlay resource\n");
3968 player->interrupted_by_resource = FALSE;
3969 /* acquire resources for video overlay */
3970 ret = mm_resource_manager_commit(player->resource_manager);
3971 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3972 LOGE("could not acquire resources for video playing\n");
3976 LOGD("enable overlay");
3977 __mmplayer_video_param_set_display_overlay(player);
3978 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3983 return MM_ERROR_NONE;
3987 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3989 mm_player_t* player = (mm_player_t*) hplayer;
3990 gboolean disable_overlay = FALSE;
3994 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3995 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3996 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3997 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3998 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4000 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4001 LOGW("Display control is not supported");
4002 return MM_ERROR_PLAYER_INTERNAL;
4005 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4007 *paudio_only = (bool)(disable_overlay);
4009 LOGD("audio_only : %d", *paudio_only);
4013 return MM_ERROR_NONE;
4017 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4019 GList* bucket = element_bucket;
4020 MMPlayerGstElement* element = NULL;
4021 MMPlayerGstElement* prv_element = NULL;
4022 gint successful_link_count = 0;
4026 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4028 prv_element = (MMPlayerGstElement*)bucket->data;
4029 bucket = bucket->next;
4031 for (; bucket; bucket = bucket->next) {
4032 element = (MMPlayerGstElement*)bucket->data;
4034 if (element && element->gst) {
4035 /* If next element is audio appsrc then make a separate audio pipeline */
4036 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4037 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4038 prv_element = element;
4042 if (prv_element && prv_element->gst) {
4043 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4044 LOGD("linking [%s] to [%s] success\n",
4045 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4046 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4047 successful_link_count++;
4049 LOGD("linking [%s] to [%s] failed\n",
4050 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4051 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4057 prv_element = element;
4062 return successful_link_count;
4066 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4068 GList* bucket = element_bucket;
4069 MMPlayerGstElement* element = NULL;
4070 int successful_add_count = 0;
4074 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4075 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4077 for (; bucket; bucket = bucket->next) {
4078 element = (MMPlayerGstElement*)bucket->data;
4080 if (element && element->gst) {
4081 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4082 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4083 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4084 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4087 successful_add_count++;
4093 return successful_add_count;
4096 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4098 mm_player_t* player = (mm_player_t*) data;
4099 GstCaps *caps = NULL;
4100 GstStructure *str = NULL;
4105 MMPLAYER_RETURN_IF_FAIL(pad)
4106 MMPLAYER_RETURN_IF_FAIL(unused)
4107 MMPLAYER_RETURN_IF_FAIL(data)
4109 caps = gst_pad_get_current_caps(pad);
4113 str = gst_caps_get_structure(caps, 0);
4117 name = gst_structure_get_name(str);
4121 LOGD("name = %s\n", name);
4123 if (strstr(name, "audio")) {
4124 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4126 if (player->audio_stream_changed_cb) {
4127 LOGE("call the audio stream changed cb\n");
4128 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4130 } else if (strstr(name, "video")) {
4131 if ((name = gst_structure_get_string(str, "format")))
4132 player->set_mode.video_zc = name[0] == 'S';
4134 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4136 if (player->video_stream_changed_cb) {
4137 LOGE("call the video stream changed cb\n");
4138 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4145 gst_caps_unref(caps);
4155 * This function is to create audio pipeline for playing.
4157 * @param player [in] handle of player
4159 * @return This function returns zero on success.
4161 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4163 /* macro for code readability. just for sinkbin-creation functions */
4164 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4166 x_bin[x_id].id = x_id;\
4167 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4168 if (!x_bin[x_id].gst) {\
4169 LOGE("failed to create %s \n", x_factory);\
4172 if (x_player->ini.set_dump_element_flag)\
4173 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4176 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4180 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4185 MMPLAYER_RETURN_IF_FAIL(player);
4187 if (player->audio_stream_buff_list) {
4188 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4189 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4192 LOGD("[%lld] send remained data.", tmp->channel_mask);
4193 __mmplayer_audio_stream_send_data(player, tmp);
4196 g_free(tmp->pcm_data);
4200 g_list_free(player->audio_stream_buff_list);
4201 player->audio_stream_buff_list = NULL;
4208 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4210 MMPlayerAudioStreamDataType audio_stream = { 0, };
4213 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4215 audio_stream.bitrate = a_buffer->bitrate;
4216 audio_stream.channel = a_buffer->channel;
4217 audio_stream.depth = a_buffer->depth;
4218 audio_stream.is_little_endian = a_buffer->is_little_endian;
4219 audio_stream.channel_mask = a_buffer->channel_mask;
4220 audio_stream.data_size = a_buffer->data_size;
4221 audio_stream.data = a_buffer->pcm_data;
4223 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4224 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4230 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4232 mm_player_t* player = (mm_player_t*) data;
4237 gint endianness = 0;
4238 guint64 channel_mask = 0;
4239 void *a_data = NULL;
4241 mm_player_audio_stream_buff_t *a_buffer = NULL;
4242 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4246 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4248 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4249 a_data = mapinfo.data;
4250 a_size = mapinfo.size;
4252 GstCaps *caps = gst_pad_get_current_caps(pad);
4253 GstStructure *structure = gst_caps_get_structure(caps, 0);
4255 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4256 gst_structure_get_int(structure, "rate", &rate);
4257 gst_structure_get_int(structure, "channels", &channel);
4258 gst_structure_get_int(structure, "depth", &depth);
4259 gst_structure_get_int(structure, "endianness", &endianness);
4260 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4261 gst_caps_unref(GST_CAPS(caps));
4263 /* In case of the sync is false, use buffer list. *
4264 * The num of buffer list depends on the num of audio channels */
4265 if (player->audio_stream_buff_list) {
4266 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4267 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4269 if (channel_mask == tmp->channel_mask) {
4270 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4271 if (tmp->data_size + a_size < tmp->buff_size) {
4272 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4273 tmp->data_size += a_size;
4275 /* send data to client */
4276 __mmplayer_audio_stream_send_data(player, tmp);
4278 if (a_size > tmp->buff_size) {
4279 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4280 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4281 if (tmp->pcm_data == NULL) {
4282 LOGE("failed to realloc data.");
4285 tmp->buff_size = a_size;
4287 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4288 memcpy(tmp->pcm_data, a_data, a_size);
4289 tmp->data_size = a_size;
4294 LOGE("data is empty in list.");
4300 /* create new audio stream data */
4301 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4302 if (a_buffer == NULL) {
4303 LOGE("failed to alloc data.");
4306 a_buffer->bitrate = rate;
4307 a_buffer->channel = channel;
4308 a_buffer->depth = depth;
4309 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4310 a_buffer->channel_mask = channel_mask;
4311 a_buffer->data_size = a_size;
4313 if (!player->audio_stream_sink_sync) {
4314 /* If sync is FALSE, use buffer list to reduce the IPC. */
4315 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4316 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4317 if (a_buffer->pcm_data == NULL) {
4318 LOGE("failed to alloc data.");
4322 memcpy(a_buffer->pcm_data, a_data, a_size);
4323 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4324 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4326 /* If sync is TRUE, send data directly. */
4327 a_buffer->pcm_data = a_data;
4328 __mmplayer_audio_stream_send_data(player, a_buffer);
4333 gst_buffer_unmap(buffer, &mapinfo);
4338 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4340 mm_player_t* player = (mm_player_t*)data;
4341 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4342 GstPad* sinkpad = NULL;
4343 GstElement *queue = NULL, *sink = NULL;
4346 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4348 queue = gst_element_factory_make("queue", NULL);
4349 if (queue == NULL) {
4350 LOGD("fail make queue\n");
4354 sink = gst_element_factory_make("fakesink", NULL);
4356 LOGD("fail make fakesink\n");
4360 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4362 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4363 LOGW("failed to link queue & sink\n");
4367 sinkpad = gst_element_get_static_pad(queue, "sink");
4369 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4370 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4374 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4376 gst_object_unref(sinkpad);
4377 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4378 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4380 gst_element_set_state(sink, GST_STATE_PAUSED);
4381 gst_element_set_state(queue, GST_STATE_PAUSED);
4383 MMPLAYER_SIGNAL_CONNECT(player,
4385 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4387 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4394 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4396 gst_object_unref(GST_OBJECT(queue));
4400 gst_object_unref(GST_OBJECT(sink));
4404 gst_object_unref(GST_OBJECT(sinkpad));
4411 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4413 #define MAX_PROPS_LEN 128
4414 gint latency_mode = 0;
4415 gchar *stream_type = NULL;
4416 gchar *latency = NULL;
4418 gchar stream_props[MAX_PROPS_LEN] = {0,};
4419 GstStructure *props = NULL;
4422 * It should be set after player creation through attribute.
4423 * But, it can not be changed during playing.
4426 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4427 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4430 LOGE("stream_type is null.\n");
4432 if (player->sound.focus_id)
4433 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4434 stream_type, stream_id, player->sound.focus_id);
4436 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4437 stream_type, stream_id);
4438 props = gst_structure_from_string(stream_props, NULL);
4439 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4440 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4441 stream_type, stream_id, player->sound.focus_id, stream_props);
4442 gst_structure_free(props);
4445 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4447 switch (latency_mode) {
4448 case AUDIO_LATENCY_MODE_LOW:
4449 latency = g_strndup("low", 3);
4451 case AUDIO_LATENCY_MODE_MID:
4452 latency = g_strndup("mid", 3);
4454 case AUDIO_LATENCY_MODE_HIGH:
4455 latency = g_strndup("high", 4);
4459 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4463 LOGD("audiosink property - latency=%s \n", latency);
4471 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4473 MMPlayerGstElement* first_element = NULL;
4474 MMPlayerGstElement* audiobin = NULL;
4475 MMHandleType attrs = 0;
4477 GstPad *ghostpad = NULL;
4478 GList* element_bucket = NULL;
4479 gboolean link_audio_sink_now = TRUE;
4485 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4488 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4490 LOGE("failed to allocate memory for audiobin\n");
4491 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4494 attrs = MMPLAYER_GET_ATTRS(player);
4497 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4498 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4499 if (!audiobin[MMPLAYER_A_BIN].gst) {
4500 LOGE("failed to create audiobin\n");
4505 player->pipeline->audiobin = audiobin;
4507 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4509 /* Adding audiotp plugin for reverse trickplay feature */
4510 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4513 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4515 /* replaygain volume */
4516 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4517 if (player->sound.rg_enable)
4518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4520 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4523 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4525 if (player->set_mode.pcm_extraction) {
4526 // pcm extraction only and no sound output
4527 if (player->audio_stream_render_cb_ex) {
4528 char *caps_str = NULL;
4529 GstCaps* caps = NULL;
4530 gchar *format = NULL;
4533 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4535 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4537 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4539 caps = gst_caps_new_simple("audio/x-raw",
4540 "format", G_TYPE_STRING, format,
4541 "rate", G_TYPE_INT, player->pcm_samplerate,
4542 "channels", G_TYPE_INT, player->pcm_channel,
4544 caps_str = gst_caps_to_string(caps);
4545 LOGD("new caps : %s\n", caps_str);
4547 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4550 gst_caps_unref(caps);
4551 MMPLAYER_FREEIF(caps_str);
4553 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4556 /* raw pad handling signal */
4557 MMPLAYER_SIGNAL_CONNECT(player,
4558 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4559 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4560 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4562 int dst_samplerate = 0;
4563 int dst_channels = 0;
4565 char *caps_str = NULL;
4566 GstCaps* caps = NULL;
4568 /* get conf. values */
4569 mm_attrs_multiple_get(player->attrs,
4571 "pcm_extraction_samplerate", &dst_samplerate,
4572 "pcm_extraction_channels", &dst_channels,
4573 "pcm_extraction_depth", &dst_depth,
4577 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4578 caps = gst_caps_new_simple("audio/x-raw",
4579 "rate", G_TYPE_INT, dst_samplerate,
4580 "channels", G_TYPE_INT, dst_channels,
4581 "depth", G_TYPE_INT, dst_depth,
4583 caps_str = gst_caps_to_string(caps);
4584 LOGD("new caps : %s\n", caps_str);
4586 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4589 gst_caps_unref(caps);
4590 MMPLAYER_FREEIF(caps_str);
4593 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4596 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4600 //GstCaps* caps = NULL;
4603 /* for logical volume control */
4604 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4605 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4607 if (player->sound.mute) {
4608 LOGD("mute enabled\n");
4609 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4615 caps = gst_caps_from_string("audio/x-raw-int, "
4616 "endianness = (int) LITTLE_ENDIAN, "
4617 "signed = (boolean) true, "
4618 "width = (int) 16, "
4619 "depth = (int) 16");
4620 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4621 gst_caps_unref(caps);
4624 /* check if multi-channels */
4625 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4626 GstPad *srcpad = NULL;
4627 GstCaps *caps = NULL;
4629 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4630 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4631 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4632 GstStructure *str = gst_caps_get_structure(caps, 0);
4634 gst_structure_get_int(str, "channels", &channels);
4635 gst_caps_unref(caps);
4637 gst_object_unref(srcpad);
4641 /* audio effect element. if audio effect is enabled */
4642 if ((strcmp(player->ini.audioeffect_element, ""))
4644 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4647 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4649 if ((!player->bypass_audio_effect)
4650 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4651 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4652 if (!_mmplayer_audio_effect_custom_apply(player))
4653 LOGI("apply audio effect(custom) setting success\n");
4657 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4658 && (player->set_mode.rich_audio))
4659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4662 /* create audio sink */
4663 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4664 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4665 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4667 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4668 if (player->is_360_feature_enabled &&
4669 player->is_content_spherical &&
4671 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4672 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4673 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4675 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4677 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4680 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4682 gst_caps_unref(acaps);
4684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4685 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4686 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4687 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4689 player->is_openal_plugin_used = TRUE;
4691 if (player->video360_yaw_radians <= M_PI &&
4692 player->video360_yaw_radians >= -M_PI &&
4693 player->video360_pitch_radians <= M_PI_2 &&
4694 player->video360_pitch_radians >= -M_PI_2) {
4695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4696 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4697 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4698 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4699 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4700 "source-orientation-y", player->video360_metadata.init_view_heading,
4701 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4704 if (player->is_360_feature_enabled && player->is_content_spherical)
4705 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4714 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4715 (player->videodec_linked && player->ini.use_system_clock)) {
4716 LOGD("system clock will be used.\n");
4717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4720 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4721 __mmplayer_gst_set_audiosink_property(player, attrs);
4724 if (audiobin[MMPLAYER_A_SINK].gst) {
4725 GstPad *sink_pad = NULL;
4726 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4727 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4728 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4729 gst_object_unref(GST_OBJECT(sink_pad));
4732 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4734 /* adding created elements to bin */
4735 LOGD("adding created elements to bin\n");
4736 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4737 LOGE("failed to add elements\n");
4741 /* linking elements in the bucket by added order. */
4742 LOGD("Linking elements in the bucket by added order.\n");
4743 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4744 LOGE("failed to link elements\n");
4748 /* get first element's sinkpad for creating ghostpad */
4749 first_element = (MMPlayerGstElement *)element_bucket->data;
4750 if (!first_element) {
4751 LOGE("failed to get first elem\n");
4755 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4757 LOGE("failed to get pad from first element of audiobin\n");
4761 ghostpad = gst_ghost_pad_new("sink", pad);
4763 LOGE("failed to create ghostpad\n");
4767 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4768 LOGE("failed to add ghostpad to audiobin\n");
4772 gst_object_unref(pad);
4774 g_list_free(element_bucket);
4777 return MM_ERROR_NONE;
4781 LOGD("ERROR : releasing audiobin\n");
4784 gst_object_unref(GST_OBJECT(pad));
4787 gst_object_unref(GST_OBJECT(ghostpad));
4790 g_list_free(element_bucket);
4792 /* release element which are not added to bin */
4793 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4794 /* NOTE : skip bin */
4795 if (audiobin[i].gst) {
4796 GstObject* parent = NULL;
4797 parent = gst_element_get_parent(audiobin[i].gst);
4800 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4801 audiobin[i].gst = NULL;
4803 gst_object_unref(GST_OBJECT(parent));
4807 /* release audiobin with it's childs */
4808 if (audiobin[MMPLAYER_A_BIN].gst)
4809 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4811 MMPLAYER_FREEIF(audiobin);
4813 player->pipeline->audiobin = NULL;
4815 return MM_ERROR_PLAYER_INTERNAL;
4818 static GstPadProbeReturn
4819 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4821 mm_player_t* player = (mm_player_t*) u_data;
4822 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4823 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4825 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4827 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4828 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4830 return GST_PAD_PROBE_OK;
4833 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4835 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4838 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4840 int ret = MM_ERROR_NONE;
4842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4843 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4845 MMPLAYER_VIDEO_BO_LOCK(player);
4847 if (player->video_bo_list) {
4848 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4849 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4850 if (tmp && tmp->bo == bo) {
4852 LOGD("release bo %p", bo);
4853 tbm_bo_unref(tmp->bo);
4854 MMPLAYER_VIDEO_BO_UNLOCK(player);
4855 MMPLAYER_VIDEO_BO_SIGNAL(player);
4860 /* hw codec is running or the list was reset for DRC. */
4861 LOGW("there is no bo list.");
4863 MMPLAYER_VIDEO_BO_UNLOCK(player);
4865 LOGW("failed to find bo %p", bo);
4870 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4875 MMPLAYER_RETURN_IF_FAIL(player);
4877 MMPLAYER_VIDEO_BO_LOCK(player);
4878 if (player->video_bo_list) {
4879 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4880 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4881 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4884 tbm_bo_unref(tmp->bo);
4888 g_list_free(player->video_bo_list);
4889 player->video_bo_list = NULL;
4891 player->video_bo_size = 0;
4892 MMPLAYER_VIDEO_BO_UNLOCK(player);
4899 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4902 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4903 gboolean ret = TRUE;
4905 /* check DRC, if it is, destroy the prev bo list to create again */
4906 if (player->video_bo_size != size) {
4907 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4908 __mmplayer_video_stream_destroy_bo_list(player);
4909 player->video_bo_size = size;
4912 MMPLAYER_VIDEO_BO_LOCK(player);
4914 if ((!player->video_bo_list) ||
4915 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4917 /* create bo list */
4919 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4921 if (player->video_bo_list) {
4922 /* if bo list did not created all, try it again. */
4923 idx = g_list_length(player->video_bo_list);
4924 LOGD("bo list exist(len: %d)", idx);
4927 for (; idx < player->ini.num_of_video_bo; idx++) {
4928 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4930 LOGE("Fail to alloc bo_info.");
4933 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4935 LOGE("Fail to tbm_bo_alloc.");
4939 bo_info->using = FALSE;
4940 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4943 /* update video num buffers */
4944 player->video_num_buffers = idx;
4945 if (idx == player->ini.num_of_video_bo)
4946 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4949 MMPLAYER_VIDEO_BO_UNLOCK(player);
4953 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4957 /* get bo from list*/
4958 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4959 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4960 if (tmp && (tmp->using == FALSE)) {
4961 LOGD("found bo %p to use", tmp->bo);
4963 MMPLAYER_VIDEO_BO_UNLOCK(player);
4964 return tbm_bo_ref(tmp->bo);
4968 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4969 MMPLAYER_VIDEO_BO_UNLOCK(player);
4973 if (player->ini.video_bo_timeout <= 0) {
4974 MMPLAYER_VIDEO_BO_WAIT(player);
4976 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4977 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4984 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4986 mm_player_t* player = (mm_player_t*)data;
4988 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4990 /* send prerolled pkt */
4991 player->video_stream_prerolled = FALSE;
4993 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4995 /* not to send prerolled pkt again */
4996 player->video_stream_prerolled = TRUE;
5000 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5002 mm_player_t* player = (mm_player_t*)data;
5003 GstCaps *caps = NULL;
5004 MMPlayerVideoStreamDataType *stream = NULL;
5005 MMVideoBuffer *video_buffer = NULL;
5006 GstMemory *dataBlock = NULL;
5007 GstMemory *metaBlock = NULL;
5008 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5009 GstStructure *structure = NULL;
5010 const gchar *string_format = NULL;
5011 unsigned int fourcc = 0;
5014 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5016 if (player->video_stream_prerolled) {
5017 player->video_stream_prerolled = FALSE;
5018 LOGD("skip the prerolled pkt not to send it again");
5022 caps = gst_pad_get_current_caps(pad);
5024 LOGE("Caps is NULL.");
5028 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5030 /* clear stream data structure */
5031 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5033 LOGE("failed to alloc mem for video data");
5037 structure = gst_caps_get_structure(caps, 0);
5038 gst_structure_get_int(structure, "width", &(stream->width));
5039 gst_structure_get_int(structure, "height", &(stream->height));
5040 string_format = gst_structure_get_string(structure, "format");
5042 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5043 stream->format = util_get_pixtype(fourcc);
5044 gst_caps_unref(caps);
5048 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5049 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5052 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5053 LOGE("Wrong condition!!");
5057 /* set size and timestamp */
5058 dataBlock = gst_buffer_peek_memory(buffer, 0);
5059 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5060 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5062 /* check zero-copy */
5063 if (player->set_mode.video_zc &&
5064 player->set_mode.media_packet_video_stream &&
5065 gst_buffer_n_memory(buffer) > 1) {
5066 metaBlock = gst_buffer_peek_memory(buffer, 1);
5067 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5068 video_buffer = (MMVideoBuffer *)mapinfo.data;
5071 if (video_buffer) { /* hw codec */
5073 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5076 /* copy pointer of tbm bo, stride, elevation */
5077 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5078 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5082 LOGE("Not support video buffer format");
5085 memcpy(stream->stride, video_buffer->stride_width,
5086 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5087 memcpy(stream->elevation, video_buffer->stride_height,
5088 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5090 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5091 stream->internal_buffer = gst_buffer_ref(buffer);
5092 } else { /* sw codec */
5096 int ret = TBM_SURFACE_ERROR_NONE;
5097 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5098 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5100 unsigned char *src = NULL;
5101 unsigned char *dest = NULL;
5102 tbm_bo_handle thandle;
5103 tbm_surface_h surface;
5104 tbm_surface_info_s info;
5107 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5109 LOGE("fail to gst_memory_map");
5114 if (stream->format == MM_PIXEL_FORMAT_I420) {
5115 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5117 ret = tbm_surface_get_info(surface, &info);
5119 if (ret != TBM_SURFACE_ERROR_NONE) {
5120 tbm_surface_destroy(surface);
5123 tbm_surface_destroy(surface);
5125 src_stride[0] = GST_ROUND_UP_4(stream->width);
5126 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5127 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5128 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5129 stream->stride[0] = info.planes[0].stride;
5130 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5131 stream->stride[1] = info.planes[1].stride;
5132 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5133 stream->stride[2] = info.planes[2].stride;
5134 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5135 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5136 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5137 stream->stride[0] = stream->width * 4;
5138 stream->elevation[0] = stream->height;
5139 size = stream->stride[0] * stream->height;
5141 LOGE("Not support format %d", stream->format);
5145 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5146 if (!stream->bo[0]) {
5147 LOGE("Fail to tbm_bo_alloc!!");
5151 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5152 if (thandle.ptr && mapinfo.data) {
5153 if (stream->format == MM_PIXEL_FORMAT_I420) {
5154 for (i = 0; i < 3; i++) {
5155 src = mapinfo.data + src_offset[i];
5156 dest = thandle.ptr + info.planes[i].offset;
5159 for (j = 0; j < stream->height>>k; j++) {
5160 memcpy(dest, src, stream->width>>k);
5161 src += src_stride[i];
5162 dest += stream->stride[i];
5165 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5166 memcpy(thandle.ptr, mapinfo.data, size);
5168 LOGE("Not support format %d", stream->format);
5172 LOGE("data pointer is wrong. dest : %p, src : %p",
5173 thandle.ptr, mapinfo.data);
5176 tbm_bo_unmap(stream->bo[0]);
5179 if (player->video_stream_cb) { /* This has been already checked at the entry */
5180 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5181 LOGE("failed to send video stream data.");
5187 gst_memory_unmap(metaBlock, &mapinfo);
5189 gst_memory_unmap(dataBlock, &mapinfo);
5194 LOGE("release video stream resource.");
5197 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5199 tbm_bo_unref(stream->bo[i]);
5201 gst_memory_unmap(metaBlock, &mapinfo);
5203 /* unref gst buffer */
5204 if (stream->internal_buffer)
5205 gst_buffer_unref(stream->internal_buffer);
5206 } else if (dataBlock) {
5208 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5209 gst_memory_unmap(dataBlock, &mapinfo);
5217 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5219 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5220 GList* element_bucket = NULL;
5222 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5226 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5227 LOGD("do not need to add video filters.");
5228 return MM_ERROR_NONE;
5231 /* in case of sw codec except 360 playback,
5232 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5233 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5234 LOGD("using video converter: %s", video_csc);
5236 /* set video rotator */
5237 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5239 *bucket = element_bucket;
5241 return MM_ERROR_NONE;
5243 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5244 g_list_free(element_bucket);
5248 return MM_ERROR_PLAYER_INTERNAL;
5252 * This function is to create video pipeline.
5254 * @param player [in] handle of player
5255 * caps [in] src caps of decoder
5256 * surface_type [in] surface type for video rendering
5258 * @return This function returns zero on success.
5260 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5264 * - video overlay surface(arm/x86) : tizenwlsink
5267 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5271 GList*element_bucket = NULL;
5272 MMPlayerGstElement* first_element = NULL;
5273 MMPlayerGstElement* videobin = NULL;
5274 gchar *videosink_element = NULL;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5283 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5285 player->pipeline->videobin = videobin;
5287 attrs = MMPLAYER_GET_ATTRS(player);
5289 LOGE("cannot get content attribute");
5290 return MM_ERROR_PLAYER_INTERNAL;
5294 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5295 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5296 if (!videobin[MMPLAYER_V_BIN].gst) {
5297 LOGE("failed to create videobin");
5301 int enable_video_decoded_cb = 0;
5302 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5304 if (player->is_360_feature_enabled && player->is_content_spherical) {
5305 LOGD("video360 elem will be added.");
5307 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5308 "video-360", TRUE, player);
5310 /* Set spatial media metadata and/or user settings to the element.
5312 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5313 "projection-type", player->video360_metadata.projection_type, NULL);
5315 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5318 if (player->video360_metadata.full_pano_width_pixels &&
5319 player->video360_metadata.full_pano_height_pixels &&
5320 player->video360_metadata.cropped_area_image_width &&
5321 player->video360_metadata.cropped_area_image_height) {
5322 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5323 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5324 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5325 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5326 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5327 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5328 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5332 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5333 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5334 "horizontal-fov", player->video360_horizontal_fov,
5335 "vertical-fov", player->video360_vertical_fov, NULL);
5338 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5339 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5340 "zoom", 1.0f / player->video360_zoom, NULL);
5343 if (player->video360_yaw_radians <= M_PI &&
5344 player->video360_yaw_radians >= -M_PI &&
5345 player->video360_pitch_radians <= M_PI_2 &&
5346 player->video360_pitch_radians >= -M_PI_2) {
5347 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5348 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5349 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5350 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5351 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352 "pose-yaw", player->video360_metadata.init_view_heading,
5353 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5357 "passthrough", !player->is_video360_enabled, NULL);
5360 /* set video sink */
5361 switch (surface_type) {
5362 case MM_DISPLAY_SURFACE_OVERLAY:
5363 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5365 if (strlen(player->ini.videosink_element_overlay) > 0)
5366 videosink_element = player->ini.videosink_element_overlay;
5370 case MM_DISPLAY_SURFACE_NULL:
5371 if (strlen(player->ini.videosink_element_fake) > 0)
5372 videosink_element = player->ini.videosink_element_fake;
5376 case MM_DISPLAY_SURFACE_REMOTE:
5377 if (strlen(player->ini.videosink_element_fake) > 0)
5378 videosink_element = player->ini.videosink_element_fake;
5383 LOGE("unidentified surface type");
5386 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5388 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5390 /* additional setting for sink plug-in */
5391 switch (surface_type) {
5392 case MM_DISPLAY_SURFACE_OVERLAY:
5394 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5396 LOGD("selected videosink name: %s", videosink_element);
5398 /* support shard memory with S/W codec on HawkP */
5399 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5400 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5401 "use-tbm", use_tbm, NULL);
5407 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5410 LOGD("disable last-sample");
5411 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5415 if (player->set_mode.media_packet_video_stream) {
5417 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5419 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
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_render_cb),
5428 MMPLAYER_SIGNAL_CONNECT(player,
5429 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5430 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5432 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5437 case MM_DISPLAY_SURFACE_REMOTE:
5439 if (player->set_mode.media_packet_video_stream) {
5440 LOGE("add data probe at videosink");
5441 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5442 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5444 MMPLAYER_SIGNAL_CONNECT(player,
5445 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5446 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5448 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5451 MMPLAYER_SIGNAL_CONNECT(player,
5452 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5453 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5455 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5460 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5463 LOGD("disable last-sample");
5464 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5474 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5477 if (videobin[MMPLAYER_V_SINK].gst) {
5478 GstPad *sink_pad = NULL;
5479 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5481 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5482 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5483 gst_object_unref(GST_OBJECT(sink_pad));
5485 LOGW("failed to get sink pad from videosink\n");
5488 /* store it as it's sink element */
5489 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5491 /* adding created elements to bin */
5492 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5493 LOGE("failed to add elements\n");
5497 /* Linking elements in the bucket by added order */
5498 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5499 LOGE("failed to link elements\n");
5503 /* get first element's sinkpad for creating ghostpad */
5505 first_element = (MMPlayerGstElement *)element_bucket->data;
5506 if (!first_element) {
5507 LOGE("failed to get first element from bucket\n");
5511 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5513 LOGE("failed to get pad from first element\n");
5517 /* create ghostpad */
5518 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5519 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5520 LOGE("failed to add ghostpad to videobin\n");
5523 gst_object_unref(pad);
5525 /* done. free allocated variables */
5527 g_list_free(element_bucket);
5531 return MM_ERROR_NONE;
5534 LOGE("ERROR : releasing videobin\n");
5536 g_list_free(element_bucket);
5539 gst_object_unref(GST_OBJECT(pad));
5541 /* release videobin with it's childs */
5542 if (videobin[MMPLAYER_V_BIN].gst)
5543 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5546 MMPLAYER_FREEIF(videobin);
5548 player->pipeline->videobin = NULL;
5550 return MM_ERROR_PLAYER_INTERNAL;
5553 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5555 GList *element_bucket = NULL;
5556 MMPlayerGstElement *textbin = player->pipeline->textbin;
5558 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5559 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5560 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5561 "signal-handoffs", FALSE,
5564 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5565 MMPLAYER_SIGNAL_CONNECT(player,
5566 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5567 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5569 G_CALLBACK(__mmplayer_update_subtitle),
5572 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5573 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5574 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5576 if (!player->play_subtitle) {
5577 LOGD("add textbin sink as sink element of whole pipeline.\n");
5578 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5581 /* adding created elements to bin */
5582 LOGD("adding created elements to bin\n");
5583 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5584 LOGE("failed to add elements\n");
5588 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5589 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5590 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5592 /* linking elements in the bucket by added order. */
5593 LOGD("Linking elements in the bucket by added order.\n");
5594 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5595 LOGE("failed to link elements\n");
5599 /* done. free allocated variables */
5600 g_list_free(element_bucket);
5602 if (textbin[MMPLAYER_T_QUEUE].gst) {
5604 GstPad *ghostpad = NULL;
5606 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5608 LOGE("failed to get sink pad of text queue");
5612 ghostpad = gst_ghost_pad_new("text_sink", pad);
5613 gst_object_unref(pad);
5616 LOGE("failed to create ghostpad of textbin\n");
5620 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5621 LOGE("failed to add ghostpad to textbin\n");
5622 gst_object_unref(ghostpad);
5627 return MM_ERROR_NONE;
5630 g_list_free(element_bucket);
5632 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5633 LOGE("remove textbin sink from sink list");
5634 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5637 /* release element at __mmplayer_gst_create_text_sink_bin */
5638 return MM_ERROR_PLAYER_INTERNAL;
5641 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5643 MMPlayerGstElement *textbin = NULL;
5644 GList *element_bucket = NULL;
5645 int surface_type = 0;
5650 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5653 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5655 LOGE("failed to allocate memory for textbin\n");
5656 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5660 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5661 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5662 if (!textbin[MMPLAYER_T_BIN].gst) {
5663 LOGE("failed to create textbin\n");
5668 player->pipeline->textbin = textbin;
5671 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5672 LOGD("surface type for subtitle : %d", surface_type);
5673 switch (surface_type) {
5674 case MM_DISPLAY_SURFACE_OVERLAY:
5675 case MM_DISPLAY_SURFACE_NULL:
5676 case MM_DISPLAY_SURFACE_REMOTE:
5677 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5678 LOGE("failed to make plain text elements\n");
5689 return MM_ERROR_NONE;
5693 LOGD("ERROR : releasing textbin\n");
5695 g_list_free(element_bucket);
5697 /* release signal */
5698 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5700 /* release element which are not added to bin */
5701 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5702 /* NOTE : skip bin */
5703 if (textbin[i].gst) {
5704 GstObject* parent = NULL;
5705 parent = gst_element_get_parent(textbin[i].gst);
5708 gst_object_unref(GST_OBJECT(textbin[i].gst));
5709 textbin[i].gst = NULL;
5711 gst_object_unref(GST_OBJECT(parent));
5716 /* release textbin with it's childs */
5717 if (textbin[MMPLAYER_T_BIN].gst)
5718 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5720 MMPLAYER_FREEIF(player->pipeline->textbin);
5721 player->pipeline->textbin = NULL;
5724 return MM_ERROR_PLAYER_INTERNAL;
5729 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5731 MMPlayerGstElement* mainbin = NULL;
5732 MMPlayerGstElement* textbin = NULL;
5733 MMHandleType attrs = 0;
5734 GstElement *subsrc = NULL;
5735 GstElement *subparse = NULL;
5736 gchar *subtitle_uri = NULL;
5737 const gchar *charset = NULL;
5743 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5745 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5747 mainbin = player->pipeline->mainbin;
5749 attrs = MMPLAYER_GET_ATTRS(player);
5751 LOGE("cannot get content attribute\n");
5752 return MM_ERROR_PLAYER_INTERNAL;
5755 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5756 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5757 LOGE("subtitle uri is not proper filepath.\n");
5758 return MM_ERROR_PLAYER_INVALID_URI;
5761 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5762 LOGE("failed to get storage info of subtitle path");
5763 return MM_ERROR_PLAYER_INVALID_URI;
5766 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5768 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5769 player->subtitle_language_list = NULL;
5770 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5772 /* create the subtitle source */
5773 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5775 LOGE("failed to create filesrc element\n");
5778 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5780 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5781 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5783 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5784 LOGW("failed to add queue\n");
5785 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5786 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5787 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5792 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5794 LOGE("failed to create subparse element\n");
5798 charset = util_get_charset(subtitle_uri);
5800 LOGD("detected charset is %s\n", charset);
5801 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5804 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5805 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5807 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5808 LOGW("failed to add subparse\n");
5809 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5810 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5811 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5815 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5816 LOGW("failed to link subsrc and subparse\n");
5820 player->play_subtitle = TRUE;
5821 player->adjust_subtitle_pos = 0;
5823 LOGD("play subtitle using subtitle file\n");
5825 if (player->pipeline->textbin == NULL) {
5826 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5827 LOGE("failed to create text sink bin. continuing without text\n");
5831 textbin = player->pipeline->textbin;
5833 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5834 LOGW("failed to add textbin\n");
5836 /* release signal */
5837 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5839 /* release textbin with it's childs */
5840 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5841 MMPLAYER_FREEIF(player->pipeline->textbin);
5842 player->pipeline->textbin = textbin = NULL;
5846 LOGD("link text input selector and textbin ghost pad");
5848 player->textsink_linked = 1;
5849 player->external_text_idx = 0;
5850 LOGI("player->textsink_linked set to 1\n");
5852 textbin = player->pipeline->textbin;
5853 LOGD("text bin has been created. reuse it.");
5854 player->external_text_idx = 1;
5857 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5858 LOGW("failed to link subparse and textbin\n");
5862 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5864 LOGE("failed to get sink pad from textsink to probe data");
5868 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5869 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5871 gst_object_unref(pad);
5874 /* create dot. for debugging */
5875 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5878 return MM_ERROR_NONE;
5881 /* release text pipeline resource */
5882 player->textsink_linked = 0;
5884 /* release signal */
5885 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5887 if (player->pipeline->textbin) {
5888 LOGE("remove textbin");
5890 /* release textbin with it's childs */
5891 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5892 MMPLAYER_FREEIF(player->pipeline->textbin);
5893 player->pipeline->textbin = NULL;
5897 /* release subtitle elem */
5898 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5899 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5901 return MM_ERROR_PLAYER_INTERNAL;
5905 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5907 mm_player_t* player = (mm_player_t*) data;
5908 MMMessageParamType msg = {0, };
5909 GstClockTime duration = 0;
5910 gpointer text = NULL;
5911 guint text_size = 0;
5912 gboolean ret = TRUE;
5913 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5917 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5918 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5920 if (player->is_subtitle_force_drop) {
5921 LOGW("subtitle is dropped forcedly.");
5925 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5926 text = mapinfo.data;
5927 text_size = mapinfo.size;
5928 duration = GST_BUFFER_DURATION(buffer);
5930 if (player->set_mode.subtitle_off) {
5931 LOGD("subtitle is OFF.\n");
5935 if (!text || (text_size == 0)) {
5936 LOGD("There is no subtitle to be displayed.\n");
5940 msg.data = (void *) text;
5941 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5943 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5945 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5946 gst_buffer_unmap(buffer, &mapinfo);
5953 static GstPadProbeReturn
5954 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5956 mm_player_t *player = (mm_player_t *) u_data;
5957 GstClockTime cur_timestamp = 0;
5958 gint64 adjusted_timestamp = 0;
5959 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5961 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5963 if (player->set_mode.subtitle_off) {
5964 LOGD("subtitle is OFF.\n");
5968 if (player->adjust_subtitle_pos == 0) {
5969 LOGD("nothing to do");
5973 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5974 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5976 if (adjusted_timestamp < 0) {
5977 LOGD("adjusted_timestamp under zero");
5982 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5983 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5984 GST_TIME_ARGS(cur_timestamp),
5985 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5987 return GST_PAD_PROBE_OK;
5989 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5993 /* check player and subtitlebin are created */
5994 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5995 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5997 if (position == 0) {
5998 LOGD("nothing to do\n");
6000 return MM_ERROR_NONE;
6004 case MM_PLAYER_POS_FORMAT_TIME:
6006 /* check current postion */
6007 player->adjust_subtitle_pos = position;
6009 LOGD("save adjust_subtitle_pos in player") ;
6015 LOGW("invalid format.\n");
6017 return MM_ERROR_INVALID_ARGUMENT;
6023 return MM_ERROR_NONE;
6025 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6028 LOGD("adjusting video_pos in player") ;
6029 int current_pos = 0;
6030 /* check player and videobin are created */
6031 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6032 if (!player->pipeline->videobin ||
6033 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6034 LOGD("no video pipeline or sink is there");
6035 return MM_ERROR_PLAYER_INVALID_STATE ;
6038 LOGD("nothing to do\n");
6040 return MM_ERROR_NONE;
6042 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6043 LOGD("failed to get current position");
6044 return MM_ERROR_PLAYER_INTERNAL;
6046 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6047 LOGD("enter video delay is valid");
6049 LOGD("enter video delay is crossing content boundary");
6050 return MM_ERROR_INVALID_ARGUMENT ;
6052 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6053 LOGD("video delay has been done");
6056 return MM_ERROR_NONE;
6060 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6062 GstElement *appsrc = element;
6063 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6064 GstBuffer *buffer = NULL;
6065 GstFlowReturn ret = GST_FLOW_OK;
6068 MMPLAYER_RETURN_IF_FAIL(element);
6069 MMPLAYER_RETURN_IF_FAIL(buf);
6071 buffer = gst_buffer_new();
6073 if (buf->offset >= buf->len) {
6074 LOGD("call eos appsrc\n");
6075 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6079 if (buf->len - buf->offset < size)
6080 len = buf->len - buf->offset;
6082 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6083 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6084 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6086 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6087 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6093 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6095 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6097 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6099 buf->offset = (int)size;
6104 static GstBusSyncReply
6105 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6107 mm_player_t *player = (mm_player_t *)data;
6108 GstBusSyncReply reply = GST_BUS_DROP;
6110 if (!(player->pipeline && player->pipeline->mainbin)) {
6111 LOGE("player pipeline handle is null");
6112 return GST_BUS_PASS;
6115 if (!__mmplayer_check_useful_message(player, message)) {
6116 gst_message_unref(message);
6117 return GST_BUS_DROP;
6120 switch (GST_MESSAGE_TYPE(message)) {
6121 case GST_MESSAGE_STATE_CHANGED:
6122 /* post directly for fast launch */
6123 if (player->sync_handler) {
6124 __mmplayer_gst_callback(message, player);
6125 reply = GST_BUS_DROP;
6127 reply = GST_BUS_PASS;
6129 case GST_MESSAGE_TAG:
6130 __mmplayer_gst_extract_tag_from_msg(player, message);
6134 GstTagList *tags = NULL;
6136 gst_message_parse_tag(message, &tags);
6138 LOGE("TAGS received from element \"%s\".\n",
6139 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6141 gst_tag_list_foreach(tags, print_tag, NULL);
6142 gst_tag_list_free(tags);
6150 case GST_MESSAGE_DURATION_CHANGED:
6151 __mmplayer_gst_handle_duration(player, message);
6153 case GST_MESSAGE_ASYNC_DONE:
6154 /* NOTE:Don't call gst_callback directly
6155 * because previous frame can be showed even though this message is received for seek.
6158 reply = GST_BUS_PASS;
6162 if (reply == GST_BUS_DROP)
6163 gst_message_unref(message);
6169 __mmplayer_gst_create_decoder(mm_player_t *player,
6170 MMPlayerTrackType track,
6172 enum MainElementID elemId,
6175 gboolean ret = TRUE;
6176 GstPad *sinkpad = NULL;
6180 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6182 player->pipeline->mainbin, FALSE);
6183 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6184 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6185 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6187 GstElement *decodebin = NULL;
6188 GstCaps *dec_caps = NULL;
6190 /* create decodebin */
6191 decodebin = gst_element_factory_make("decodebin", name);
6194 LOGE("error : fail to create decodebin for %d decoder\n", track);
6199 /* raw pad handling signal */
6200 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6201 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6203 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6204 before looking for any elements that can handle that stream.*/
6205 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6206 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6208 /* This signal is emitted when a element is added to the bin.*/
6209 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6210 G_CALLBACK(__mmplayer_gst_element_added), player);
6212 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6213 LOGE("failed to add new decodebin\n");
6218 dec_caps = gst_pad_query_caps(srcpad, NULL);
6220 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6221 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6222 gst_caps_unref(dec_caps);
6225 player->pipeline->mainbin[elemId].id = elemId;
6226 player->pipeline->mainbin[elemId].gst = decodebin;
6228 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6230 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6231 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6232 gst_object_unref(GST_OBJECT(decodebin));
6235 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6236 LOGE("failed to sync second level decodebin state with parent\n");
6238 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6242 gst_object_unref(GST_OBJECT(sinkpad));
6251 * This function is to create audio or video pipeline for playing.
6253 * @param player [in] handle of player
6255 * @return This function returns zero on success.
6260 __mmplayer_gst_create_pipeline(mm_player_t* player)
6263 MMPlayerGstElement *mainbin = NULL;
6264 MMHandleType attrs = 0;
6265 GstElement* element = NULL;
6266 GstElement* elem_src_audio = NULL;
6267 GstElement* elem_src_subtitle = NULL;
6268 GstElement* es_video_queue = NULL;
6269 GstElement* es_audio_queue = NULL;
6270 GstElement* es_subtitle_queue = NULL;
6271 GList* element_bucket = NULL;
6272 gboolean need_state_holder = TRUE;
6274 #ifdef SW_CODEC_ONLY
6275 int surface_type = 0;
6279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6281 /* get profile attribute */
6282 attrs = MMPLAYER_GET_ATTRS(player);
6284 LOGE("cannot get content attribute\n");
6288 /* create pipeline handles */
6289 if (player->pipeline) {
6290 LOGW("pipeline should be released before create new one\n");
6294 player->video360_metadata.is_spherical = -1;
6295 player->is_openal_plugin_used = FALSE;
6297 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6298 if (player->pipeline == NULL)
6301 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6303 /* create mainbin */
6304 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6305 if (mainbin == NULL)
6308 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6310 /* create pipeline */
6311 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6312 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6313 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6314 LOGE("failed to create pipeline\n");
6317 player->demux_pad_index = 0;
6318 player->subtitle_language_list = NULL;
6320 player->is_subtitle_force_drop = FALSE;
6321 player->last_multiwin_status = FALSE;
6323 _mmplayer_track_initialize(player);
6324 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6326 /* create source element */
6327 switch (player->profile.uri_type) {
6328 /* rtsp streamming */
6329 case MM_PLAYER_URI_TYPE_URL_RTSP:
6333 element = gst_element_factory_make("rtspsrc", "rtsp source");
6336 LOGE("failed to create streaming source element\n");
6344 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6346 SECURE_LOGD("user_agent : %s\n", user_agent);
6348 /* setting property to streaming source */
6349 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6351 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6353 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6354 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6355 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6356 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6361 case MM_PLAYER_URI_TYPE_URL_HTTP:
6363 gchar *user_agent, *cookies, **cookie_list;
6364 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6365 user_agent = cookies = NULL;
6367 gint mode = MM_PLAYER_PD_MODE_NONE;
6369 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6371 player->pd_mode = mode;
6373 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6375 if (!MMPLAYER_IS_HTTP_PD(player)) {
6376 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6378 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6381 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6384 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6385 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6387 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6388 LOGD("get timeout from ini\n");
6389 http_timeout = player->ini.http_timeout;
6393 SECURE_LOGD("location : %s\n", player->profile.uri);
6394 SECURE_LOGD("cookies : %s\n", cookies);
6395 SECURE_LOGD("user_agent : %s\n", user_agent);
6396 LOGD("timeout : %d\n", http_timeout);
6398 /* setting property to streaming source */
6399 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6400 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6401 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6403 /* parsing cookies */
6404 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6405 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6406 g_strfreev(cookie_list);
6409 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6411 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6412 LOGW("it's dash. and it's still experimental feature.");
6414 // progressive download
6415 gchar* location = NULL;
6417 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6420 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6422 MMPLAYER_FREEIF(player->pd_file_save_path);
6424 LOGD("PD Location : %s\n", path);
6427 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6428 LOGE("failed to get storage info");
6431 player->pd_file_save_path = g_strdup(path);
6433 LOGE("can't find pd location so, it should be set \n");
6438 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6440 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6444 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6445 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6447 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6448 g_object_get(element, "location", &location, NULL);
6449 LOGD("PD_LOCATION [%s].\n", location);
6457 case MM_PLAYER_URI_TYPE_FILE:
6459 LOGD("using filesrc for 'file://' handler.\n");
6460 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6461 LOGE("failed to get storage info");
6465 element = gst_element_factory_make("filesrc", "source");
6467 LOGE("failed to create filesrc\n");
6471 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6475 case MM_PLAYER_URI_TYPE_SS:
6477 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6478 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6480 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6484 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6485 LOGD("get timeout from ini\n");
6486 http_timeout = player->ini.http_timeout;
6489 /* setting property to streaming source */
6490 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6491 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6494 case MM_PLAYER_URI_TYPE_MS_BUFF:
6496 LOGD("MS buff src is selected\n");
6498 if (player->v_stream_caps) {
6499 element = gst_element_factory_make("appsrc", "video_appsrc");
6501 LOGF("failed to create video app source element[appsrc].\n");
6505 if (player->a_stream_caps) {
6506 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6507 if (!elem_src_audio) {
6508 LOGF("failed to create audio app source element[appsrc].\n");
6512 } else if (player->a_stream_caps) {
6513 /* no video, only audio pipeline*/
6514 element = gst_element_factory_make("appsrc", "audio_appsrc");
6516 LOGF("failed to create audio app source element[appsrc].\n");
6521 if (player->s_stream_caps) {
6522 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6523 if (!elem_src_subtitle) {
6524 LOGF("failed to create subtitle app source element[appsrc].\n");
6529 LOGD("setting app sources properties.\n");
6530 LOGD("location : %s\n", player->profile.uri);
6532 if (player->v_stream_caps && element) {
6533 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6534 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6535 "caps", player->v_stream_caps, NULL);
6537 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6538 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6539 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6540 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6542 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6543 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6544 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6545 G_CALLBACK(__gst_seek_video_data), player);
6547 if (player->a_stream_caps && elem_src_audio) {
6548 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6549 "caps", player->a_stream_caps, NULL);
6551 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6552 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6553 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6554 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6557 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6558 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6559 G_CALLBACK(__gst_seek_audio_data), player);
6561 } else if (player->a_stream_caps && element) {
6562 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6563 "caps", player->a_stream_caps, NULL);
6565 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6566 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6567 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6568 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6570 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6571 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6572 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6573 G_CALLBACK(__gst_seek_audio_data), player);
6576 if (player->s_stream_caps && elem_src_subtitle) {
6577 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6578 "caps", player->s_stream_caps, NULL);
6580 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6581 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6582 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6583 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6585 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6587 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6588 G_CALLBACK(__gst_seek_subtitle_data), player);
6591 if (player->v_stream_caps && element) {
6592 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6593 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6594 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6595 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6597 if (player->a_stream_caps && elem_src_audio) {
6598 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6599 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6600 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6601 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6603 } else if (player->a_stream_caps && element) {
6604 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6605 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6606 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6607 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6610 if (player->s_stream_caps && elem_src_subtitle)
6611 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6612 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6614 need_state_holder = FALSE;
6616 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6617 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6618 LOGE("failed to commit\n");
6622 case MM_PLAYER_URI_TYPE_MEM:
6624 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6626 LOGD("mem src is selected\n");
6628 element = gst_element_factory_make("appsrc", "mem-source");
6630 LOGE("failed to create appsrc element\n");
6634 g_object_set(element, "stream-type", stream_type, NULL);
6635 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6636 g_object_set(element, "blocksize", (guint64)20480, NULL);
6638 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6639 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6640 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6641 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6644 case MM_PLAYER_URI_TYPE_URL:
6647 case MM_PLAYER_URI_TYPE_TEMP:
6650 case MM_PLAYER_URI_TYPE_NONE:
6655 /* check source element is OK */
6657 LOGE("no source element was created.\n");
6661 /* take source element */
6662 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6663 mainbin[MMPLAYER_M_SRC].gst = element;
6664 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6666 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6667 player->streamer = __mm_player_streaming_create();
6668 __mm_player_streaming_initialize(player->streamer);
6671 if (MMPLAYER_IS_HTTP_PD(player)) {
6672 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6674 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6675 element = gst_element_factory_make("queue2", "queue2");
6677 LOGE("failed to create http streaming buffer element\n");
6682 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6683 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6684 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6686 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6688 __mm_player_streaming_set_queue2(player->streamer,
6691 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6694 player->ini.http_buffering_limit,
6695 MUXED_BUFFER_TYPE_MEM_QUEUE,
6699 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6700 if (player->v_stream_caps) {
6701 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6702 if (!es_video_queue) {
6703 LOGE("create es_video_queue for es player failed\n");
6706 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6707 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6708 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6709 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6711 /* Adding audio appsrc to bucket */
6712 if (player->a_stream_caps && elem_src_audio) {
6713 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6714 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6715 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6717 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6718 if (!es_audio_queue) {
6719 LOGE("create es_audio_queue for es player failed\n");
6722 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6724 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6725 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6726 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6728 } else if (player->a_stream_caps) {
6729 /* Only audio stream, no video */
6730 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6731 if (!es_audio_queue) {
6732 LOGE("create es_audio_queue for es player failed\n");
6735 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6736 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6737 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6740 if (player->s_stream_caps && elem_src_subtitle) {
6741 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6742 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6743 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6745 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6746 if (!es_subtitle_queue) {
6747 LOGE("create es_subtitle_queue for es player failed\n");
6750 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6751 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6752 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6756 /* create autoplugging element if src element is not a rtsp src */
6757 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6758 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6760 enum MainElementID elemId = MMPLAYER_M_NUM;
6762 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6763 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6764 elemId = MMPLAYER_M_AUTOPLUG;
6765 element = __mmplayer_create_decodebin(player);
6767 /* default size of mq in decodebin is 2M
6768 * but it can cause blocking issue during seeking depends on content. */
6769 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6771 need_state_holder = FALSE;
6773 elemId = MMPLAYER_M_TYPEFIND;
6774 element = gst_element_factory_make("typefind", "typefinder");
6775 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6776 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6780 /* check autoplug element is OK */
6782 LOGE("can not create element(%d)\n", elemId);
6786 mainbin[elemId].id = elemId;
6787 mainbin[elemId].gst = element;
6789 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6792 /* add elements to pipeline */
6793 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6794 LOGE("Failed to add elements to pipeline\n");
6799 /* linking elements in the bucket by added order. */
6800 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6801 LOGE("Failed to link some elements\n");
6806 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6807 if (need_state_holder) {
6809 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6810 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6812 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6813 LOGE("fakesink element could not be created\n");
6816 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6818 /* take ownership of fakesink. we are reusing it */
6819 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6822 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6823 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6824 LOGE("failed to add fakesink to bin\n");
6829 /* now we have completed mainbin. take it */
6830 player->pipeline->mainbin = mainbin;
6832 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6833 GstPad *srcpad = NULL;
6835 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6836 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6838 __mmplayer_gst_create_decoder(player,
6839 MM_PLAYER_TRACK_TYPE_VIDEO,
6841 MMPLAYER_M_AUTOPLUG_V_DEC,
6844 gst_object_unref(GST_OBJECT(srcpad));
6849 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6850 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6852 __mmplayer_gst_create_decoder(player,
6853 MM_PLAYER_TRACK_TYPE_AUDIO,
6855 MMPLAYER_M_AUTOPLUG_A_DEC,
6858 gst_object_unref(GST_OBJECT(srcpad));
6863 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6864 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6867 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6868 if (__mmplayer_check_subtitle(player)) {
6869 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6870 LOGE("fail to create text pipeline");
6873 /* connect bus callback */
6874 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6876 LOGE("cannot get bus from pipeline.\n");
6880 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6882 player->context.thread_default = g_main_context_get_thread_default();
6884 if (player->context.thread_default == NULL) {
6885 player->context.thread_default = g_main_context_default();
6886 LOGD("thread-default context is the global default context");
6888 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6890 /* set sync handler to get tag synchronously */
6891 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6894 gst_object_unref(GST_OBJECT(bus));
6895 g_list_free(element_bucket);
6897 /* create gst bus_msb_cb thread */
6898 g_mutex_init(&player->bus_msg_thread_mutex);
6899 g_cond_init(&player->bus_msg_thread_cond);
6900 player->bus_msg_thread_exit = FALSE;
6901 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6902 player->bus_msg_thread =
6903 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6904 if (!player->bus_msg_thread) {
6905 LOGE("failed to create gst BUS msg thread");
6906 g_mutex_clear(&player->bus_msg_thread_mutex);
6907 g_cond_clear(&player->bus_msg_thread_cond);
6913 return MM_ERROR_NONE;
6916 __mmplayer_gst_destroy_pipeline(player);
6917 g_list_free(element_bucket);
6920 /* release element which are not added to bin */
6921 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6922 /* NOTE : skip pipeline */
6923 if (mainbin[i].gst) {
6924 GstObject* parent = NULL;
6925 parent = gst_element_get_parent(mainbin[i].gst);
6928 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6929 mainbin[i].gst = NULL;
6931 gst_object_unref(GST_OBJECT(parent));
6935 /* release pipeline with it's childs */
6936 if (mainbin[MMPLAYER_M_PIPE].gst)
6937 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6939 MMPLAYER_FREEIF(mainbin);
6942 MMPLAYER_FREEIF(player->pipeline);
6943 return MM_ERROR_PLAYER_INTERNAL;
6947 __mmplayer_reset_gapless_state(mm_player_t* player)
6950 MMPLAYER_RETURN_IF_FAIL(player
6952 && player->pipeline->audiobin
6953 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6955 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6962 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6965 int ret = MM_ERROR_NONE;
6969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6971 /* cleanup stuffs */
6972 MMPLAYER_FREEIF(player->type);
6973 player->have_dynamic_pad = FALSE;
6974 player->no_more_pad = FALSE;
6975 player->num_dynamic_pad = 0;
6976 player->demux_pad_index = 0;
6977 player->use_deinterleave = FALSE;
6978 player->max_audio_channels = 0;
6979 player->video_share_api_delta = 0;
6980 player->video_share_clock_delta = 0;
6981 player->video_hub_download_mode = 0;
6983 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6984 player->subtitle_language_list = NULL;
6985 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6987 __mmplayer_reset_gapless_state(player);
6989 if (player->streamer) {
6990 __mm_player_streaming_deinitialize(player->streamer);
6991 __mm_player_streaming_destroy(player->streamer);
6992 player->streamer = NULL;
6995 /* cleanup unlinked mime type */
6996 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6997 MMPLAYER_FREEIF(player->unlinked_video_mime);
6998 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7000 /* cleanup running stuffs */
7001 __mmplayer_cancel_eos_timer(player);
7003 /* cleanup gst stuffs */
7004 if (player->pipeline) {
7005 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7006 GstTagList* tag_list = player->pipeline->tag_list;
7008 /* first we need to disconnect all signal hander */
7009 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7011 if (player->bus_watcher)
7012 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7013 player->bus_watcher = 0;
7016 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7017 MMPlayerGstElement* videobin = player->pipeline->videobin;
7018 MMPlayerGstElement* textbin = player->pipeline->textbin;
7019 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7020 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7021 gst_object_unref(bus);
7023 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7024 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7025 if (ret != MM_ERROR_NONE) {
7026 LOGE("fail to change state to NULL\n");
7027 return MM_ERROR_PLAYER_INTERNAL;
7030 LOGW("succeeded in chaning state to NULL\n");
7032 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7035 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7036 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7038 /* free avsysaudiosink
7039 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7040 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7042 MMPLAYER_FREEIF(audiobin);
7043 MMPLAYER_FREEIF(videobin);
7044 MMPLAYER_FREEIF(textbin);
7045 MMPLAYER_FREEIF(mainbin);
7049 gst_tag_list_free(tag_list);
7051 MMPLAYER_FREEIF(player->pipeline);
7053 MMPLAYER_FREEIF(player->album_art);
7055 if (player->v_stream_caps) {
7056 gst_caps_unref(player->v_stream_caps);
7057 player->v_stream_caps = NULL;
7059 if (player->a_stream_caps) {
7060 gst_caps_unref(player->a_stream_caps);
7061 player->a_stream_caps = NULL;
7064 if (player->s_stream_caps) {
7065 gst_caps_unref(player->s_stream_caps);
7066 player->s_stream_caps = NULL;
7068 _mmplayer_track_destroy(player);
7070 if (player->sink_elements)
7071 g_list_free(player->sink_elements);
7072 player->sink_elements = NULL;
7074 if (player->bufmgr) {
7075 tbm_bufmgr_deinit(player->bufmgr);
7076 player->bufmgr = NULL;
7079 LOGW("finished destroy pipeline\n");
7086 static int __gst_realize(mm_player_t* player)
7089 int ret = MM_ERROR_NONE;
7093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7095 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7097 ret = __mmplayer_gst_create_pipeline(player);
7099 LOGE("failed to create pipeline\n");
7103 /* set pipeline state to READY */
7104 /* NOTE : state change to READY must be performed sync. */
7105 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7106 ret = __mmplayer_gst_set_state(player,
7107 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7109 if (ret != MM_ERROR_NONE) {
7110 /* return error if failed to set state */
7111 LOGE("failed to set READY state");
7115 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7117 /* create dot before error-return. for debugging */
7118 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7125 static int __gst_unrealize(mm_player_t* player)
7127 int ret = MM_ERROR_NONE;
7131 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7133 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7134 MMPLAYER_PRINT_STATE(player);
7136 /* release miscellaneous information */
7137 __mmplayer_release_misc(player);
7139 /* destroy pipeline */
7140 ret = __mmplayer_gst_destroy_pipeline(player);
7141 if (ret != MM_ERROR_NONE) {
7142 LOGE("failed to destory pipeline\n");
7146 /* release miscellaneous information.
7147 these info needs to be released after pipeline is destroyed. */
7148 __mmplayer_release_misc_post(player);
7150 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7157 static int __gst_pending_seek(mm_player_t* player)
7159 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7160 int ret = MM_ERROR_NONE;
7164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7166 if (!player->pending_seek.is_pending) {
7167 LOGD("pending seek is not reserved. nothing to do.\n");
7171 /* check player state if player could pending seek or not. */
7172 current_state = MMPLAYER_CURRENT_STATE(player);
7174 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7175 LOGW("try to pending seek in %s state, try next time. \n",
7176 MMPLAYER_STATE_GET_NAME(current_state));
7180 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7182 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7184 if (MM_ERROR_NONE != ret)
7185 LOGE("failed to seek pending postion. just keep staying current position.\n");
7187 player->pending_seek.is_pending = FALSE;
7194 static int __gst_start(mm_player_t* player)
7196 gboolean sound_extraction = 0;
7197 int ret = MM_ERROR_NONE;
7198 gboolean async = FALSE;
7202 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7204 /* get sound_extraction property */
7205 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7207 /* NOTE : if SetPosition was called before Start. do it now */
7208 /* streaming doesn't support it. so it should be always sync */
7209 /* !!create one more api to check if there is pending seek rather than checking variables */
7210 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7211 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7212 ret = __gst_pause(player, FALSE);
7213 if (ret != MM_ERROR_NONE) {
7214 LOGE("failed to set state to PAUSED for pending seek\n");
7218 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7220 if (sound_extraction) {
7221 LOGD("setting pcm extraction\n");
7223 ret = __mmplayer_set_pcm_extraction(player);
7224 if (MM_ERROR_NONE != ret) {
7225 LOGW("failed to set pcm extraction\n");
7229 if (MM_ERROR_NONE != __gst_pending_seek(player))
7230 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7234 LOGD("current state before doing transition");
7235 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7236 MMPLAYER_PRINT_STATE(player);
7238 /* set pipeline state to PLAYING */
7239 if (player->es_player_push_mode)
7241 /* set pipeline state to PLAYING */
7242 ret = __mmplayer_gst_set_state(player,
7243 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7245 if (ret == MM_ERROR_NONE) {
7246 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7248 LOGE("failed to set state to PLAYING");
7252 /* generating debug info before returning error */
7253 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7260 static int __gst_stop(mm_player_t* player)
7262 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7263 MMHandleType attrs = 0;
7264 gboolean rewind = FALSE;
7266 int ret = MM_ERROR_NONE;
7267 gboolean async = FALSE;
7271 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7272 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7274 LOGD("current state before doing transition");
7275 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7276 MMPLAYER_PRINT_STATE(player);
7278 attrs = MMPLAYER_GET_ATTRS(player);
7280 LOGE("cannot get content attribute\n");
7281 return MM_ERROR_PLAYER_INTERNAL;
7284 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7285 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7287 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7288 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7291 if (player->es_player_push_mode)
7294 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7296 /* return if set_state has failed */
7297 if (ret != MM_ERROR_NONE) {
7298 LOGE("failed to set state.\n");
7304 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7305 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7306 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7307 LOGW("failed to rewind\n");
7308 ret = MM_ERROR_PLAYER_SEEK;
7313 player->sent_bos = FALSE;
7315 if (player->es_player_push_mode) //for cloudgame
7318 /* wait for seek to complete */
7319 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7320 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7321 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7323 LOGE("fail to stop player.\n");
7324 ret = MM_ERROR_PLAYER_INTERNAL;
7325 __mmplayer_dump_pipeline_state(player);
7328 /* generate dot file if enabled */
7329 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7336 int __gst_pause(mm_player_t* player, gboolean async)
7338 int ret = MM_ERROR_NONE;
7342 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7343 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7345 LOGD("current state before doing transition");
7346 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7347 MMPLAYER_PRINT_STATE(player);
7349 /* set pipeline status to PAUSED */
7350 ret = __mmplayer_gst_set_state(player,
7351 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7353 if (FALSE == async) {
7354 if (ret != MM_ERROR_NONE) {
7355 GstMessage *msg = NULL;
7356 GTimer *timer = NULL;
7357 gdouble MAX_TIMEOUT_SEC = 3;
7359 LOGE("failed to set state to PAUSED");
7361 if (player->msg_posted) {
7362 LOGE("error msg is already posted.");
7366 timer = g_timer_new();
7367 g_timer_start(timer);
7369 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7372 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7374 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7375 GError *error = NULL;
7377 /* parse error code */
7378 gst_message_parse_error(msg, &error, NULL);
7380 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7381 /* Note : the streaming error from the streaming source is handled
7382 * using __mmplayer_handle_streaming_error.
7384 __mmplayer_handle_streaming_error(player, msg);
7387 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7389 if (error->domain == GST_STREAM_ERROR)
7390 ret = __gst_handle_stream_error(player, error, msg);
7391 else if (error->domain == GST_RESOURCE_ERROR)
7392 ret = __gst_handle_resource_error(player, error->code, NULL);
7393 else if (error->domain == GST_LIBRARY_ERROR)
7394 ret = __gst_handle_library_error(player, error->code);
7395 else if (error->domain == GST_CORE_ERROR)
7396 ret = __gst_handle_core_error(player, error->code);
7398 g_error_free(error);
7400 player->msg_posted = TRUE;
7402 gst_message_unref(msg);
7404 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7406 gst_object_unref(bus);
7407 g_timer_stop(timer);
7408 g_timer_destroy(timer);
7412 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7413 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7415 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7417 } else if (ret == MM_ERROR_NONE) {
7419 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7423 /* generate dot file before returning error */
7424 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7431 int __gst_resume(mm_player_t* player, gboolean async)
7433 int ret = MM_ERROR_NONE;
7438 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7439 MM_ERROR_PLAYER_NOT_INITIALIZED);
7441 LOGD("current state before doing transition");
7442 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7443 MMPLAYER_PRINT_STATE(player);
7445 /* generate dot file before returning error */
7446 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7449 LOGD("do async state transition to PLAYING.\n");
7451 /* set pipeline state to PLAYING */
7452 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7454 ret = __mmplayer_gst_set_state(player,
7455 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7456 if (ret != MM_ERROR_NONE) {
7457 LOGE("failed to set state to PLAYING\n");
7460 if (async == FALSE) {
7461 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7462 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7463 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7467 /* generate dot file before returning error */
7468 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7476 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7478 unsigned long dur_msec = 0;
7479 gint64 dur_nsec = 0;
7480 gint64 pos_nsec = 0;
7481 gboolean ret = TRUE;
7482 gboolean accurated = FALSE;
7483 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7486 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7487 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7489 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7490 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7493 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7494 /* check duration */
7495 /* NOTE : duration cannot be zero except live streaming.
7496 * Since some element could have some timing problemn with quering duration, try again.
7498 if (!player->duration) {
7499 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7500 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7501 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7502 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7503 player->pending_seek.is_pending = TRUE;
7504 player->pending_seek.format = format;
7505 player->pending_seek.pos = position;
7506 player->doing_seek = FALSE;
7507 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7508 return MM_ERROR_NONE;
7513 player->duration = dur_nsec;
7516 if (player->duration) {
7517 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7519 LOGE("could not get the duration. fail to seek.\n");
7523 LOGD("playback rate: %f\n", player->playback_rate);
7525 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7527 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7529 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7533 case MM_PLAYER_POS_FORMAT_TIME:
7535 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7536 GstQuery *query = NULL;
7537 gboolean seekable = FALSE;
7539 /* check position is valid or not */
7540 if (position > dur_msec)
7543 query = gst_query_new_seeking(GST_FORMAT_TIME);
7544 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7545 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7546 gst_query_unref(query);
7549 LOGW("non-seekable content");
7550 player->doing_seek = FALSE;
7551 return MM_ERROR_PLAYER_NO_OP;
7554 LOGW("failed to get seeking query");
7555 gst_query_unref(query); /* keep seeking operation */
7558 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7560 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7561 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7562 This causes problem is position calculation during normal pause resume scenarios also.
7563 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7564 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7565 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7566 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7567 LOGW("getting current position failed in seek\n");
7569 player->last_position = pos_nsec;
7570 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7573 if (player->doing_seek) {
7574 LOGD("not completed seek");
7575 return MM_ERROR_PLAYER_DOING_SEEK;
7579 if (!internal_called)
7580 player->doing_seek = TRUE;
7582 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7584 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7585 gint64 cur_time = 0;
7587 /* get current position */
7588 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7591 GstEvent *event = gst_event_new_seek(1.0,
7593 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7594 GST_SEEK_TYPE_SET, cur_time,
7595 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7597 __gst_send_event_to_sink(player, event);
7599 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7600 __gst_pause(player, FALSE);
7603 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7604 that's why set position through property. */
7605 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7606 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7607 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7608 (!player->videodec_linked) && (!player->audiodec_linked)) {
7610 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7611 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7612 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7613 player->doing_seek = FALSE;
7614 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7616 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7617 GST_FORMAT_TIME, seek_flags,
7618 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7622 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7628 case MM_PLAYER_POS_FORMAT_PERCENT:
7630 LOGD("seeking to(%lu)%% \n", position);
7632 if (player->doing_seek) {
7633 LOGD("not completed seek");
7634 return MM_ERROR_PLAYER_DOING_SEEK;
7637 if (!internal_called)
7638 player->doing_seek = TRUE;
7640 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7641 pos_nsec = (gint64)((position * player->duration) / 100);
7642 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7643 GST_FORMAT_TIME, seek_flags,
7644 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7646 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7656 /* NOTE : store last seeking point to overcome some bad operation
7657 * (returning zero when getting current position) of some elements
7659 player->last_position = pos_nsec;
7661 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7662 if (player->playback_rate > 1.0)
7663 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7666 return MM_ERROR_NONE;
7669 player->pending_seek.is_pending = TRUE;
7670 player->pending_seek.format = format;
7671 player->pending_seek.pos = position;
7673 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7674 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7676 return MM_ERROR_NONE;
7679 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7680 return MM_ERROR_INVALID_ARGUMENT;
7683 player->doing_seek = FALSE;
7684 return MM_ERROR_PLAYER_SEEK;
7687 #define TRICKPLAY_OFFSET GST_MSECOND
7690 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7692 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7693 gint64 pos_msec = 0;
7694 gboolean ret = TRUE;
7696 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7697 MM_ERROR_PLAYER_NOT_INITIALIZED);
7699 current_state = MMPLAYER_CURRENT_STATE(player);
7701 /* NOTE : query position except paused state to overcome some bad operation
7702 * please refer to below comments in details
7704 if (current_state != MM_PLAYER_STATE_PAUSED)
7705 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7707 /* NOTE : get last point to overcome some bad operation of some elements
7708 *(returning zero when getting current position in paused state
7709 * and when failed to get postion during seeking
7711 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7712 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7714 if (player->playback_rate < 0.0)
7715 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7717 pos_msec = player->last_position;
7720 pos_msec = player->last_position;
7722 player->last_position = pos_msec;
7724 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7727 if (player->duration > 0 && pos_msec > player->duration)
7728 pos_msec = player->duration;
7730 player->last_position = pos_msec;
7734 case MM_PLAYER_POS_FORMAT_TIME:
7735 *position = GST_TIME_AS_MSECONDS(pos_msec);
7738 case MM_PLAYER_POS_FORMAT_PERCENT:
7740 if (player->duration <= 0) {
7741 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7744 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7745 *position = pos_msec * 100 / player->duration;
7750 return MM_ERROR_PLAYER_INTERNAL;
7753 return MM_ERROR_NONE;
7757 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7759 #define STREAMING_IS_FINISHED 0
7760 #define BUFFERING_MAX_PER 100
7761 #define DEFAULT_PER_VALUE -1
7762 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7764 MMPlayerGstElement *mainbin = NULL;
7765 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7766 gint64 buffered_total = 0;
7767 unsigned long position = 0;
7768 gint buffered_sec = -1;
7769 GstBufferingMode mode = GST_BUFFERING_STREAM;
7770 gint64 content_size_time = player->duration;
7771 guint64 content_size_bytes = player->http_content_size;
7773 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7775 player->pipeline->mainbin,
7776 MM_ERROR_PLAYER_NOT_INITIALIZED);
7778 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7783 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7784 /* and rtsp is not ready yet. */
7785 LOGW("it's only used for http streaming case.\n");
7786 return MM_ERROR_PLAYER_NO_OP;
7789 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7790 LOGW("Time format is not supported yet.\n");
7791 return MM_ERROR_INVALID_ARGUMENT;
7794 if (content_size_time <= 0 || content_size_bytes <= 0) {
7795 LOGW("there is no content size.");
7796 return MM_ERROR_NONE;
7799 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7800 LOGW("fail to get current position.");
7801 return MM_ERROR_NONE;
7804 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7805 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7807 mainbin = player->pipeline->mainbin;
7808 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7810 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7811 GstQuery *query = NULL;
7812 gint byte_in_rate = 0, byte_out_rate = 0;
7813 gint64 estimated_total = 0;
7815 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7816 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7817 LOGW("fail to get buffering query from queue2");
7819 gst_query_unref(query);
7820 return MM_ERROR_NONE;
7823 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7824 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7826 if (mode == GST_BUFFERING_STREAM) {
7827 /* using only queue in case of push mode(ts / mp3) */
7828 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7829 GST_FORMAT_BYTES, &buffered_total)) {
7830 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7831 stop_per = 100 * buffered_total / content_size_bytes;
7834 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7836 guint num_of_ranges = 0;
7837 gint64 start_byte = 0, stop_byte = 0;
7839 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7840 if (estimated_total != STREAMING_IS_FINISHED) {
7841 /* buffered size info from queue2 */
7842 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7843 for (idx = 0; idx < num_of_ranges; idx++) {
7844 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7845 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7847 buffered_total += (stop_byte - start_byte);
7850 stop_per = BUFFERING_MAX_PER;
7852 gst_query_unref(query);
7855 if (stop_per == DEFAULT_PER_VALUE) {
7856 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7858 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7860 /* buffered size info from multiqueue */
7861 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7862 guint curr_size_bytes = 0;
7863 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7864 "curr-size-bytes", &curr_size_bytes, NULL);
7865 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7866 buffered_total += curr_size_bytes;
7869 if (avg_byterate > 0)
7870 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7871 else if (player->total_maximum_bitrate > 0)
7872 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7873 else if (player->total_bitrate > 0)
7874 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7876 if (buffered_sec >= 0)
7877 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7881 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7882 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7884 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7885 buffered_total, buffered_sec, *start_pos, *stop_pos);
7887 return MM_ERROR_NONE;
7891 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7896 LOGW("set_message_callback is called with invalid player handle\n");
7897 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7900 player->msg_cb = callback;
7901 player->msg_cb_param = user_param;
7903 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7907 return MM_ERROR_NONE;
7910 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7912 int ret = MM_ERROR_PLAYER_INVALID_URI;
7917 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7918 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7919 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7921 memset(data, 0, sizeof(MMPlayerParseProfile));
7923 if ((path = strstr(uri, "es_buff://"))) {
7925 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7926 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7927 ret = MM_ERROR_NONE;
7929 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7931 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7932 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7933 ret = MM_ERROR_NONE;
7935 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7938 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7939 tmp = g_ascii_strdown(uri, strlen(uri));
7941 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7942 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7944 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7946 ret = MM_ERROR_NONE;
7949 } else if ((path = strstr(uri, "rtspu://"))) {
7951 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7952 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7953 ret = MM_ERROR_NONE;
7955 } else if ((path = strstr(uri, "rtspr://"))) {
7956 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7957 char *separater = strstr(path, "*");
7961 char *urgent = separater + strlen("*");
7963 if ((urgent_len = strlen(urgent))) {
7964 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7965 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7966 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7967 ret = MM_ERROR_NONE;
7970 } else if ((path = strstr(uri, "mms://"))) {
7972 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7973 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7974 ret = MM_ERROR_NONE;
7976 } else if ((path = strstr(uri, "mem://"))) {
7979 char *buffer = NULL;
7980 char *seperator = strchr(path, ',');
7981 char ext[100] = {0,}, size[100] = {0,};
7984 if ((buffer = strstr(path, "ext="))) {
7985 buffer += strlen("ext=");
7987 if (strlen(buffer)) {
7988 strncpy(ext, buffer, 99);
7990 if ((seperator = strchr(ext, ','))
7991 || (seperator = strchr(ext, ' '))
7992 || (seperator = strchr(ext, '\0'))) {
7993 seperator[0] = '\0';
7998 if ((buffer = strstr(path, "size="))) {
7999 buffer += strlen("size=");
8001 if (strlen(buffer) > 0) {
8002 strncpy(size, buffer, 99);
8004 if ((seperator = strchr(size, ','))
8005 || (seperator = strchr(size, ' '))
8006 || (seperator = strchr(size, '\0'))) {
8007 seperator[0] = '\0';
8010 mem_size = atoi(size);
8015 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8016 if (mem_size && param) {
8017 if (data->input_mem.buf)
8018 free(data->input_mem.buf);
8019 data->input_mem.buf = malloc(mem_size);
8021 if (data->input_mem.buf) {
8022 memcpy(data->input_mem.buf, param, mem_size);
8023 data->input_mem.len = mem_size;
8024 ret = MM_ERROR_NONE;
8026 LOGE("failed to alloc mem %d", mem_size);
8027 ret = MM_ERROR_PLAYER_INTERNAL;
8030 data->input_mem.offset = 0;
8031 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8035 gchar *location = NULL;
8038 if ((path = strstr(uri, "file://"))) {
8040 location = g_filename_from_uri(uri, NULL, &err);
8042 if (!location || (err != NULL)) {
8043 LOGE("Invalid URI '%s' for filesrc: %s", path,
8044 (err != NULL) ? err->message : "unknown error");
8046 if (err) g_error_free(err);
8047 if (location) g_free(location);
8049 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8053 LOGD("path from uri: %s", location);
8056 path = (location != NULL) ? (location) : ((char*)uri);
8057 int file_stat = MM_ERROR_NONE;
8059 file_stat = util_exist_file_path(path);
8061 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8062 if (file_stat == MM_ERROR_NONE) {
8063 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8065 if (util_is_sdp_file(path)) {
8066 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8067 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8069 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8071 ret = MM_ERROR_NONE;
8072 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8073 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8075 LOGE("invalid uri, could not play..\n");
8076 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8079 if (location) g_free(location);
8083 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8084 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8085 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8086 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8088 /* dump parse result */
8089 SECURE_LOGW("incomming uri : %s\n", uri);
8090 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8091 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8099 __mmplayer_can_do_interrupt(mm_player_t *player)
8101 if (!player || !player->pipeline || !player->attrs) {
8102 LOGW("not initialized");
8106 if (player->set_mode.pcm_extraction) {
8107 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8111 /* check if seeking */
8112 if (player->doing_seek) {
8113 MMMessageParamType msg_param;
8114 memset(&msg_param, 0, sizeof(MMMessageParamType));
8115 msg_param.code = MM_ERROR_PLAYER_SEEK;
8116 player->doing_seek = FALSE;
8117 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8121 /* check other thread */
8122 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8123 LOGW("locked already, cmd state : %d", player->cmd);
8125 /* check application command */
8126 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8127 LOGW("playing.. should wait cmd lock then, will be interrupted");
8129 /* lock will be released at mrp_resource_release_cb() */
8130 MMPLAYER_CMD_LOCK(player);
8133 LOGW("nothing to do");
8136 LOGW("can interrupt immediately");
8140 FAILED: /* with CMD UNLOCKED */
8143 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8148 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8151 mm_player_t *player = NULL;
8155 if (user_data == NULL) {
8156 LOGE("- user_data is null\n");
8159 player = (mm_player_t *)user_data;
8161 /* do something to release resource here.
8162 * player stop and interrupt forwarding */
8163 if (!__mmplayer_can_do_interrupt(player)) {
8164 LOGW("no need to interrupt, so leave");
8166 MMMessageParamType msg = {0, };
8167 unsigned long pos = 0;
8169 player->interrupted_by_resource = TRUE;
8171 /* get last play position */
8172 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8173 LOGW("failed to get play position.");
8175 msg.union_type = MM_MSG_UNION_TIME;
8176 msg.time.elapsed = (unsigned int)pos;
8177 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8179 LOGD("video resource conflict so, resource will be freed by unrealizing");
8180 if (_mmplayer_unrealize((MMHandleType)player))
8181 LOGW("failed to unrealize");
8183 /* lock is called in __mmplayer_can_do_interrupt() */
8184 MMPLAYER_CMD_UNLOCK(player);
8187 if (res == player->video_overlay_resource)
8188 player->video_overlay_resource = FALSE;
8190 player->video_decoder_resource = FALSE;
8198 _mmplayer_create_player(MMHandleType handle)
8200 int ret = MM_ERROR_PLAYER_INTERNAL;
8201 bool enabled = false;
8203 mm_player_t* player = MM_PLAYER_CAST(handle);
8207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8209 /* initialize player state */
8210 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8211 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8212 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8213 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8215 /* check current state */
8216 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8218 /* construct attributes */
8219 player->attrs = _mmplayer_construct_attribute(handle);
8221 if (!player->attrs) {
8222 LOGE("Failed to construct attributes\n");
8226 /* initialize gstreamer with configured parameter */
8227 if (!__mmplayer_init_gstreamer(player)) {
8228 LOGE("Initializing gstreamer failed\n");
8229 _mmplayer_deconstruct_attribute(handle);
8233 /* create lock. note that g_tread_init() has already called in gst_init() */
8234 g_mutex_init(&player->fsink_lock);
8236 /* create update tag lock */
8237 g_mutex_init(&player->update_tag_lock);
8239 /* create next play mutex */
8240 g_mutex_init(&player->next_play_thread_mutex);
8242 /* create next play cond */
8243 g_cond_init(&player->next_play_thread_cond);
8245 /* create next play thread */
8246 player->next_play_thread =
8247 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8248 if (!player->next_play_thread) {
8249 LOGE("failed to create next play thread");
8250 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8251 g_mutex_clear(&player->next_play_thread_mutex);
8252 g_cond_clear(&player->next_play_thread_cond);
8256 player->bus_msg_q = g_queue_new();
8257 if (!player->bus_msg_q) {
8258 LOGE("failed to create queue for bus_msg");
8259 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8263 ret = _mmplayer_initialize_video_capture(player);
8264 if (ret != MM_ERROR_NONE) {
8265 LOGE("failed to initialize video capture\n");
8269 /* initialize resource manager */
8270 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8271 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8272 &player->resource_manager)) {
8273 LOGE("failed to initialize resource manager\n");
8277 if (MMPLAYER_IS_HTTP_PD(player)) {
8278 player->pd_downloader = NULL;
8279 player->pd_file_save_path = NULL;
8282 /* create video bo lock and cond */
8283 g_mutex_init(&player->video_bo_mutex);
8284 g_cond_init(&player->video_bo_cond);
8286 /* create media stream callback mutex */
8287 g_mutex_init(&player->media_stream_cb_lock);
8289 /* create subtitle info lock and cond */
8290 g_mutex_init(&player->subtitle_info_mutex);
8291 g_cond_init(&player->subtitle_info_cond);
8293 player->streaming_type = STREAMING_SERVICE_NONE;
8295 /* give default value of audio effect setting */
8296 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8297 player->sound.rg_enable = false;
8298 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8300 player->play_subtitle = FALSE;
8301 player->use_deinterleave = FALSE;
8302 player->max_audio_channels = 0;
8303 player->video_share_api_delta = 0;
8304 player->video_share_clock_delta = 0;
8305 player->has_closed_caption = FALSE;
8306 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8307 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8308 player->pending_resume = FALSE;
8309 if (player->ini.dump_element_keyword[0][0] == '\0')
8310 player->ini.set_dump_element_flag = FALSE;
8312 player->ini.set_dump_element_flag = TRUE;
8314 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8315 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8316 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8318 /* Set video360 settings to their defaults for just-created player.
8321 player->is_360_feature_enabled = FALSE;
8322 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8323 LOGI("spherical feature info: %d", enabled);
8325 player->is_360_feature_enabled = TRUE;
8327 LOGE("failed to get spherical feature info");
8330 player->is_content_spherical = FALSE;
8331 player->is_video360_enabled = TRUE;
8332 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8333 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8334 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8335 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8336 player->video360_zoom = 1.0f;
8337 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8338 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8340 /* set player state to null */
8341 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8342 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8344 return MM_ERROR_NONE;
8348 g_mutex_clear(&player->fsink_lock);
8350 /* free update tag lock */
8351 g_mutex_clear(&player->update_tag_lock);
8353 g_queue_free(player->bus_msg_q);
8355 /* free next play thread */
8356 if (player->next_play_thread) {
8357 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8358 player->next_play_thread_exit = TRUE;
8359 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8360 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8362 g_thread_join(player->next_play_thread);
8363 player->next_play_thread = NULL;
8365 g_mutex_clear(&player->next_play_thread_mutex);
8366 g_cond_clear(&player->next_play_thread_cond);
8369 /* release attributes */
8370 _mmplayer_deconstruct_attribute(handle);
8378 __mmplayer_init_gstreamer(mm_player_t* player)
8380 static gboolean initialized = FALSE;
8381 static const int max_argc = 50;
8383 gchar** argv = NULL;
8384 gchar** argv2 = NULL;
8390 LOGD("gstreamer already initialized.\n");
8395 argc = malloc(sizeof(int));
8396 argv = malloc(sizeof(gchar*) * max_argc);
8397 argv2 = malloc(sizeof(gchar*) * max_argc);
8399 if (!argc || !argv || !argv2)
8402 memset(argv, 0, sizeof(gchar*) * max_argc);
8403 memset(argv2, 0, sizeof(gchar*) * max_argc);
8407 argv[0] = g_strdup("mmplayer");
8410 for (i = 0; i < 5; i++) {
8411 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8412 if (strlen(player->ini.gst_param[i]) > 0) {
8413 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8418 /* we would not do fork for scanning plugins */
8419 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8422 /* check disable registry scan */
8423 if (player->ini.skip_rescan) {
8424 argv[*argc] = g_strdup("--gst-disable-registry-update");
8428 /* check disable segtrap */
8429 if (player->ini.disable_segtrap) {
8430 argv[*argc] = g_strdup("--gst-disable-segtrap");
8434 LOGD("initializing gstreamer with following parameter\n");
8435 LOGD("argc : %d\n", *argc);
8438 for (i = 0; i < arg_count; i++) {
8440 LOGD("argv[%d] : %s\n", i, argv2[i]);
8443 /* initializing gstreamer */
8444 if (!gst_init_check(argc, &argv, &err)) {
8445 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8452 for (i = 0; i < arg_count; i++) {
8453 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8454 MMPLAYER_FREEIF(argv2[i]);
8457 MMPLAYER_FREEIF(argv);
8458 MMPLAYER_FREEIF(argv2);
8459 MMPLAYER_FREEIF(argc);
8469 for (i = 0; i < arg_count; i++) {
8470 LOGD("free[%d] : %s\n", i, argv2[i]);
8471 MMPLAYER_FREEIF(argv2[i]);
8474 MMPLAYER_FREEIF(argv);
8475 MMPLAYER_FREEIF(argv2);
8476 MMPLAYER_FREEIF(argc);
8482 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8487 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8488 MMPLAYER_FREEIF(player->pd_file_save_path);
8491 return MM_ERROR_NONE;
8495 __mmplayer_check_async_state_transition(mm_player_t* player)
8497 GstState element_state = GST_STATE_VOID_PENDING;
8498 GstState element_pending_state = GST_STATE_VOID_PENDING;
8499 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8500 GstElement * element = NULL;
8501 gboolean async = FALSE;
8503 /* check player handle */
8504 MMPLAYER_RETURN_IF_FAIL(player &&
8506 player->pipeline->mainbin &&
8507 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8510 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8512 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8513 LOGD("don't need to check the pipeline state");
8517 MMPLAYER_PRINT_STATE(player);
8519 /* wait for state transition */
8520 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8521 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8523 if (ret == GST_STATE_CHANGE_FAILURE) {
8524 LOGE(" [%s] state : %s pending : %s \n",
8525 GST_ELEMENT_NAME(element),
8526 gst_element_state_get_name(element_state),
8527 gst_element_state_get_name(element_pending_state));
8529 /* dump state of all element */
8530 __mmplayer_dump_pipeline_state(player);
8535 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8540 _mmplayer_destroy(MMHandleType handle)
8542 mm_player_t* player = MM_PLAYER_CAST(handle);
8546 /* check player handle */
8547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8549 /* destroy can called at anytime */
8550 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8552 /* check async state transition */
8553 __mmplayer_check_async_state_transition(player);
8555 __mmplayer_destroy_streaming_ext(player);
8557 /* release next play thread */
8558 if (player->next_play_thread) {
8559 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8560 player->next_play_thread_exit = TRUE;
8561 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8562 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8564 LOGD("waitting for next play thread exit\n");
8565 g_thread_join(player->next_play_thread);
8566 g_mutex_clear(&player->next_play_thread_mutex);
8567 g_cond_clear(&player->next_play_thread_cond);
8568 LOGD("next play thread released\n");
8571 _mmplayer_release_video_capture(player);
8573 /* de-initialize resource manager */
8574 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8575 player->resource_manager))
8576 LOGE("failed to deinitialize resource manager\n");
8578 /* release pipeline */
8579 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8580 LOGE("failed to destory pipeline\n");
8581 return MM_ERROR_PLAYER_INTERNAL;
8584 g_queue_free(player->bus_msg_q);
8586 /* release subtitle info lock and cond */
8587 g_mutex_clear(&player->subtitle_info_mutex);
8588 g_cond_clear(&player->subtitle_info_cond);
8590 __mmplayer_release_dump_list(player->dump_list);
8592 /* release miscellaneous information */
8593 __mmplayer_release_misc(player);
8595 /* release miscellaneous information.
8596 these info needs to be released after pipeline is destroyed. */
8597 __mmplayer_release_misc_post(player);
8599 /* release attributes */
8600 _mmplayer_deconstruct_attribute(handle);
8603 g_mutex_clear(&player->fsink_lock);
8606 g_mutex_clear(&player->update_tag_lock);
8608 /* release video bo lock and cond */
8609 g_mutex_clear(&player->video_bo_mutex);
8610 g_cond_clear(&player->video_bo_cond);
8612 /* release media stream callback lock */
8613 g_mutex_clear(&player->media_stream_cb_lock);
8617 return MM_ERROR_NONE;
8621 __mmplayer_realize_streaming_ext(mm_player_t* player)
8623 int ret = MM_ERROR_NONE;
8626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8628 if (MMPLAYER_IS_HTTP_PD(player)) {
8629 gboolean bret = FALSE;
8631 player->pd_downloader = _mmplayer_create_pd_downloader();
8632 if (!player->pd_downloader) {
8633 LOGE("Unable to create PD Downloader...");
8634 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8637 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8639 if (FALSE == bret) {
8640 LOGE("Unable to create PD Downloader...");
8641 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8650 _mmplayer_realize(MMHandleType hplayer)
8652 mm_player_t* player = (mm_player_t*)hplayer;
8655 MMHandleType attrs = 0;
8656 int ret = MM_ERROR_NONE;
8660 /* check player handle */
8661 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8663 /* check current state */
8664 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8666 attrs = MMPLAYER_GET_ATTRS(player);
8668 LOGE("fail to get attributes.\n");
8669 return MM_ERROR_PLAYER_INTERNAL;
8671 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8672 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8674 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8675 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8677 if (ret != MM_ERROR_NONE) {
8678 LOGE("failed to parse profile\n");
8683 if (uri && (strstr(uri, "es_buff://"))) {
8684 if (strstr(uri, "es_buff://push_mode"))
8685 player->es_player_push_mode = TRUE;
8687 player->es_player_push_mode = FALSE;
8690 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8691 LOGW("mms protocol is not supported format.\n");
8692 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8695 if (MMPLAYER_IS_STREAMING(player))
8696 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8698 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8700 player->smooth_streaming = FALSE;
8701 player->videodec_linked = 0;
8702 player->videosink_linked = 0;
8703 player->audiodec_linked = 0;
8704 player->audiosink_linked = 0;
8705 player->textsink_linked = 0;
8706 player->is_external_subtitle_present = FALSE;
8707 player->is_external_subtitle_added_now = FALSE;
8708 /* set the subtitle ON default */
8709 player->is_subtitle_off = FALSE;
8711 /* realize pipeline */
8712 ret = __gst_realize(player);
8713 if (ret != MM_ERROR_NONE)
8714 LOGE("fail to realize the player.\n");
8716 ret = __mmplayer_realize_streaming_ext(player);
8718 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8719 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8727 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8732 /* destroy can called at anytime */
8733 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8734 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8737 return MM_ERROR_NONE;
8741 _mmplayer_unrealize(MMHandleType hplayer)
8743 mm_player_t* player = (mm_player_t*)hplayer;
8744 int ret = MM_ERROR_NONE;
8748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8750 MMPLAYER_CMD_UNLOCK(player);
8751 /* destroy the gst bus msg thread which is created during realize.
8752 this funct have to be called before getting cmd lock. */
8753 _mmplayer_bus_msg_thread_destroy(player);
8754 MMPLAYER_CMD_LOCK(player);
8756 /* check current state */
8757 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8759 /* check async state transition */
8760 __mmplayer_check_async_state_transition(player);
8762 __mmplayer_unrealize_streaming_ext(player);
8764 /* unrealize pipeline */
8765 ret = __gst_unrealize(player);
8767 /* set asm stop if success */
8768 if (MM_ERROR_NONE == ret) {
8769 if (!player->interrupted_by_resource) {
8770 if (player->video_decoder_resource != NULL) {
8771 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8772 player->video_decoder_resource);
8773 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8774 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8776 player->video_decoder_resource = NULL;
8779 if (player->video_overlay_resource != NULL) {
8780 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8781 player->video_overlay_resource);
8782 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8783 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8785 player->video_overlay_resource = NULL;
8788 ret = mm_resource_manager_commit(player->resource_manager);
8789 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8790 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8793 LOGE("failed and don't change asm state to stop");
8801 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8803 mm_player_t* player = (mm_player_t*)hplayer;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8807 return __gst_set_message_callback(player, callback, user_param);
8811 _mmplayer_get_state(MMHandleType hplayer, int* state)
8813 mm_player_t *player = (mm_player_t*)hplayer;
8815 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8817 *state = MMPLAYER_CURRENT_STATE(player);
8819 return MM_ERROR_NONE;
8824 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8826 mm_player_t* player = (mm_player_t*) hplayer;
8827 GstElement* vol_element = NULL;
8832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834 LOGD("volume [L]=%f:[R]=%f\n",
8835 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8837 /* invalid factor range or not */
8838 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8839 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8840 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8841 return MM_ERROR_INVALID_ARGUMENT;
8845 /* not support to set other value into each channel */
8846 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8847 return MM_ERROR_INVALID_ARGUMENT;
8849 /* Save volume to handle. Currently the first array element will be saved. */
8850 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8852 /* check pipeline handle */
8853 if (!player->pipeline || !player->pipeline->audiobin) {
8854 LOGD("audiobin is not created yet\n");
8855 LOGD("but, current stored volume will be set when it's created.\n");
8857 /* NOTE : stored volume will be used in create_audiobin
8858 * returning MM_ERROR_NONE here makes application to able to
8859 * set volume at anytime.
8861 return MM_ERROR_NONE;
8864 /* setting volume to volume element */
8865 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8868 LOGD("volume is set [%f]\n", player->sound.volume);
8869 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8874 return MM_ERROR_NONE;
8879 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8881 mm_player_t* player = (mm_player_t*) hplayer;
8886 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8887 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8889 /* returning stored volume */
8890 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8891 volume->level[i] = player->sound.volume;
8895 return MM_ERROR_NONE;
8899 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8901 mm_player_t* player = (mm_player_t*) hplayer;
8902 GstElement* vol_element = NULL;
8906 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8908 /* mute value shoud 0 or 1 */
8909 if (mute != 0 && mute != 1) {
8910 LOGE("bad mute value\n");
8912 /* FIXIT : definitly, we need _BAD_PARAM error code */
8913 return MM_ERROR_INVALID_ARGUMENT;
8916 player->sound.mute = mute;
8918 /* just hold mute value if pipeline is not ready */
8919 if (!player->pipeline || !player->pipeline->audiobin) {
8920 LOGD("pipeline is not ready. holding mute value\n");
8921 return MM_ERROR_NONE;
8924 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8926 /* NOTE : volume will only created when the bt is enabled */
8928 LOGD("mute : %d\n", mute);
8929 g_object_set(vol_element, "mute", mute, NULL);
8931 LOGD("volume elemnet is not created. using volume in audiosink\n");
8935 return MM_ERROR_NONE;
8939 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8941 mm_player_t* player = (mm_player_t*) hplayer;
8945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8946 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8948 /* just hold mute value if pipeline is not ready */
8949 if (!player->pipeline || !player->pipeline->audiobin) {
8950 LOGD("pipeline is not ready. returning stored value\n");
8951 *pmute = player->sound.mute;
8952 return MM_ERROR_NONE;
8955 *pmute = player->sound.mute;
8959 return MM_ERROR_NONE;
8963 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_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 player->video_stream_changed_cb = callback;
8972 player->video_stream_changed_cb_user_param = user_param;
8973 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8977 return MM_ERROR_NONE;
8981 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8983 mm_player_t* player = (mm_player_t*) hplayer;
8987 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8989 player->audio_stream_changed_cb = callback;
8990 player->audio_stream_changed_cb_user_param = user_param;
8991 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8995 return MM_ERROR_NONE;
8999 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9001 mm_player_t* player = (mm_player_t*) hplayer;
9005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9007 player->audio_stream_render_cb_ex = callback;
9008 player->audio_stream_cb_user_param = user_param;
9009 player->audio_stream_sink_sync = sync;
9010 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);
9014 return MM_ERROR_NONE;
9018 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9020 mm_player_t* player = (mm_player_t*) hplayer;
9024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9026 if (callback && !player->bufmgr)
9027 player->bufmgr = tbm_bufmgr_init(-1);
9029 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9030 player->video_stream_cb = callback;
9031 player->video_stream_cb_user_param = user_param;
9033 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9037 return MM_ERROR_NONE;
9041 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9043 mm_player_t* player = (mm_player_t*) hplayer;
9047 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9049 player->audio_stream_cb = callback;
9050 player->audio_stream_cb_user_param = user_param;
9051 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9055 return MM_ERROR_NONE;
9059 __mmplayer_start_streaming_ext(mm_player_t *player)
9061 gint ret = MM_ERROR_NONE;
9064 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9066 if (MMPLAYER_IS_HTTP_PD(player)) {
9067 if (!player->pd_downloader) {
9068 ret = __mmplayer_realize_streaming_ext(player);
9070 if (ret != MM_ERROR_NONE) {
9071 LOGE("failed to realize streaming ext\n");
9076 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9077 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9079 LOGE("ERROR while starting PD...\n");
9080 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9082 ret = MM_ERROR_NONE;
9091 _mmplayer_start(MMHandleType hplayer)
9093 mm_player_t* player = (mm_player_t*) hplayer;
9094 gint ret = MM_ERROR_NONE;
9098 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9100 /* check current state */
9101 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9103 /* NOTE : we should check and create pipeline again if not created as we destroy
9104 * whole pipeline when stopping in streamming playback
9106 if (!player->pipeline) {
9107 ret = __gst_realize(player);
9108 if (MM_ERROR_NONE != ret) {
9109 LOGE("failed to realize before starting. only in streamming\n");
9115 ret = __mmplayer_start_streaming_ext(player);
9116 if (ret != MM_ERROR_NONE) {
9117 LOGE("failed to start streaming ext 0x%X", ret);
9121 /* start pipeline */
9122 ret = __gst_start(player);
9123 if (ret != MM_ERROR_NONE)
9124 LOGE("failed to start player.\n");
9131 /* NOTE: post "not supported codec message" to application
9132 * when one codec is not found during AUTOPLUGGING in MSL.
9133 * So, it's separated with error of __mmplayer_gst_callback().
9134 * And, if any codec is not found, don't send message here.
9135 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9138 __mmplayer_handle_missed_plugin(mm_player_t* player)
9140 MMMessageParamType msg_param;
9141 memset(&msg_param, 0, sizeof(MMMessageParamType));
9142 gboolean post_msg_direct = FALSE;
9146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9148 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9149 player->not_supported_codec, player->can_support_codec);
9151 if (player->not_found_demuxer) {
9152 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9153 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9155 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9156 MMPLAYER_FREEIF(msg_param.data);
9158 return MM_ERROR_NONE;
9161 if (player->not_supported_codec) {
9162 if (player->can_support_codec) {
9163 // There is one codec to play
9164 post_msg_direct = TRUE;
9166 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9167 post_msg_direct = TRUE;
9170 if (post_msg_direct) {
9171 MMMessageParamType msg_param;
9172 memset(&msg_param, 0, sizeof(MMMessageParamType));
9174 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9175 LOGW("not found AUDIO codec, posting error code to application.\n");
9177 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9178 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9179 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9180 LOGW("not found VIDEO codec, posting error code to application.\n");
9182 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9183 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9186 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9188 MMPLAYER_FREEIF(msg_param.data);
9190 return MM_ERROR_NONE;
9192 // no any supported codec case
9193 LOGW("not found any codec, posting error code to application.\n");
9195 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9196 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9197 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9199 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9200 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9203 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9205 MMPLAYER_FREEIF(msg_param.data);
9211 return MM_ERROR_NONE;
9214 static void __mmplayer_check_pipeline(mm_player_t* player)
9216 GstState element_state = GST_STATE_VOID_PENDING;
9217 GstState element_pending_state = GST_STATE_VOID_PENDING;
9219 int ret = MM_ERROR_NONE;
9221 if (player->gapless.reconfigure) {
9222 LOGW("pipeline is under construction.\n");
9224 MMPLAYER_PLAYBACK_LOCK(player);
9225 MMPLAYER_PLAYBACK_UNLOCK(player);
9227 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9229 /* wait for state transition */
9230 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9232 if (ret == GST_STATE_CHANGE_FAILURE)
9233 LOGE("failed to change pipeline state within %d sec\n", timeout);
9237 /* NOTE : it should be able to call 'stop' anytime*/
9239 _mmplayer_stop(MMHandleType hplayer)
9241 mm_player_t* player = (mm_player_t*)hplayer;
9242 int ret = MM_ERROR_NONE;
9246 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9248 /* check current state */
9249 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9251 /* check pipline building state */
9252 __mmplayer_check_pipeline(player);
9253 __mmplayer_reset_gapless_state(player);
9255 /* NOTE : application should not wait for EOS after calling STOP */
9256 __mmplayer_cancel_eos_timer(player);
9258 __mmplayer_unrealize_streaming_ext(player);
9261 player->doing_seek = FALSE;
9264 ret = __gst_stop(player);
9266 if (ret != MM_ERROR_NONE)
9267 LOGE("failed to stop player.\n");
9275 _mmplayer_pause(MMHandleType hplayer)
9277 mm_player_t* player = (mm_player_t*)hplayer;
9278 gint64 pos_msec = 0;
9279 gboolean async = FALSE;
9280 gint ret = MM_ERROR_NONE;
9284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9286 /* check current state */
9287 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9289 /* check pipline building state */
9290 __mmplayer_check_pipeline(player);
9292 switch (MMPLAYER_CURRENT_STATE(player)) {
9293 case MM_PLAYER_STATE_READY:
9295 /* check prepare async or not.
9296 * In the case of streaming playback, it's recommned to avoid blocking wait.
9298 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9299 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9301 /* Changing back sync of rtspsrc to async */
9302 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9303 LOGD("async prepare working mode for rtsp");
9309 case MM_PLAYER_STATE_PLAYING:
9311 /* NOTE : store current point to overcome some bad operation
9312 *(returning zero when getting current position in paused state) of some
9315 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9316 LOGW("getting current position failed in paused\n");
9318 player->last_position = pos_msec;
9320 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9321 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9322 This causes problem is position calculation during normal pause resume scenarios also.
9323 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9324 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9325 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9326 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9332 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9333 LOGD("doing async pause in case of ms buff src");
9337 /* pause pipeline */
9338 ret = __gst_pause(player, async);
9340 if (ret != MM_ERROR_NONE)
9341 LOGE("failed to pause player. ret : 0x%x\n", ret);
9343 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9344 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9345 LOGE("failed to update display_rotation");
9354 _mmplayer_resume(MMHandleType hplayer)
9356 mm_player_t* player = (mm_player_t*)hplayer;
9357 int ret = MM_ERROR_NONE;
9358 gboolean async = FALSE;
9362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9364 /* Changing back sync mode rtspsrc to async */
9365 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9366 LOGD("async resume for rtsp case");
9370 /* check current state */
9371 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9373 ret = __gst_resume(player, async);
9375 if (ret != MM_ERROR_NONE)
9376 LOGE("failed to resume player.\n");
9384 __mmplayer_set_pcm_extraction(mm_player_t* player)
9386 gint64 start_nsec = 0;
9387 gint64 end_nsec = 0;
9388 gint64 dur_nsec = 0;
9389 gint64 dur_msec = 0;
9390 int required_start = 0;
9391 int required_end = 0;
9396 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9398 mm_attrs_multiple_get(player->attrs,
9400 "pcm_extraction_start_msec", &required_start,
9401 "pcm_extraction_end_msec", &required_end,
9404 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9406 if (required_start == 0 && required_end == 0) {
9407 LOGD("extracting entire stream");
9408 return MM_ERROR_NONE;
9409 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9410 LOGD("invalid range for pcm extraction");
9411 return MM_ERROR_INVALID_ARGUMENT;
9415 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9417 LOGE("failed to get duration");
9418 return MM_ERROR_PLAYER_INTERNAL;
9420 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9422 if (dur_msec < required_end) {
9424 LOGD("invalid end pos for pcm extraction");
9425 return MM_ERROR_INVALID_ARGUMENT;
9428 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9429 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9431 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9434 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9435 GST_SEEK_TYPE_SET, start_nsec,
9436 GST_SEEK_TYPE_SET, end_nsec))) {
9437 LOGE("failed to seek for pcm extraction\n");
9439 return MM_ERROR_PLAYER_SEEK;
9442 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9446 return MM_ERROR_NONE;
9450 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9452 mm_player_t* player = (mm_player_t*)hplayer;
9453 gint64 pos_msec = 0;
9454 int ret = MM_ERROR_NONE;
9456 signed long long start = 0, stop = 0;
9457 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9460 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9461 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9463 /* The sound of video is not supported under 0.0 and over 2.0. */
9464 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9465 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9468 _mmplayer_set_mute(hplayer, mute);
9470 if (player->playback_rate == rate)
9471 return MM_ERROR_NONE;
9473 /* If the position is reached at start potion during fast backward, EOS is posted.
9474 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9476 player->playback_rate = rate;
9478 current_state = MMPLAYER_CURRENT_STATE(player);
9480 if (current_state != MM_PLAYER_STATE_PAUSED)
9481 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9483 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9485 if ((current_state == MM_PLAYER_STATE_PAUSED)
9486 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9487 LOGW("returning last point : %lld\n", player->last_position);
9488 pos_msec = player->last_position;
9493 stop = GST_CLOCK_TIME_NONE;
9495 start = GST_CLOCK_TIME_NONE;
9499 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9500 player->playback_rate,
9502 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9503 GST_SEEK_TYPE_SET, start,
9504 GST_SEEK_TYPE_SET, stop)) {
9505 LOGE("failed to set speed playback\n");
9506 return MM_ERROR_PLAYER_SEEK;
9509 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9513 return MM_ERROR_NONE;;
9517 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9519 mm_player_t* player = (mm_player_t*)hplayer;
9520 int ret = MM_ERROR_NONE;
9524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9526 /* check pipline building state */
9527 __mmplayer_check_pipeline(player);
9529 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9537 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9539 mm_player_t* player = (mm_player_t*)hplayer;
9540 int ret = MM_ERROR_NONE;
9542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9544 ret = __gst_get_position(player, format, position);
9550 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9552 mm_player_t* player = (mm_player_t*)hplayer;
9553 int ret = MM_ERROR_NONE;
9555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9557 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9563 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9565 mm_player_t* player = (mm_player_t*)hplayer;
9566 int ret = MM_ERROR_NONE;
9570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9572 ret = __gst_adjust_subtitle_position(player, format, position);
9579 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9581 mm_player_t* player = (mm_player_t*)hplayer;
9582 int ret = MM_ERROR_NONE;
9586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9588 ret = __gst_adjust_video_position(player, offset);
9596 __mmplayer_is_midi_type(gchar* str_caps)
9598 if ((g_strrstr(str_caps, "audio/midi")) ||
9599 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9600 (g_strrstr(str_caps, "application/x-smaf")) ||
9601 (g_strrstr(str_caps, "audio/x-imelody")) ||
9602 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9603 (g_strrstr(str_caps, "audio/xmf")) ||
9604 (g_strrstr(str_caps, "audio/mxmf"))) {
9613 __mmplayer_is_only_mp3_type(gchar *str_caps)
9615 if (g_strrstr(str_caps, "application/x-id3") ||
9616 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9622 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9624 GstStructure* caps_structure = NULL;
9625 gint samplerate = 0;
9629 MMPLAYER_RETURN_IF_FAIL(player && caps);
9631 caps_structure = gst_caps_get_structure(caps, 0);
9633 /* set stream information */
9634 gst_structure_get_int(caps_structure, "rate", &samplerate);
9635 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9637 gst_structure_get_int(caps_structure, "channels", &channels);
9638 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9640 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9644 __mmplayer_update_content_type_info(mm_player_t* player)
9647 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9649 if (__mmplayer_is_midi_type(player->type)) {
9650 player->bypass_audio_effect = TRUE;
9651 } else if (g_strrstr(player->type, "application/x-hls")) {
9652 /* If it can't know exact type when it parses uri because of redirection case,
9653 * it will be fixed by typefinder or when doing autoplugging.
9655 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9656 if (player->streamer) {
9657 player->streamer->is_adaptive_streaming = TRUE;
9658 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9659 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9661 } else if (g_strrstr(player->type, "application/dash+xml")) {
9662 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9669 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9670 GstCaps *caps, gpointer data)
9672 mm_player_t* player = (mm_player_t*)data;
9677 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9679 /* store type string */
9680 MMPLAYER_FREEIF(player->type);
9681 player->type = gst_caps_to_string(caps);
9683 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9684 player, player->type, probability, gst_caps_get_size(caps));
9687 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9688 (g_strrstr(player->type, "audio/x-raw-int"))) {
9689 LOGE("not support media format\n");
9691 if (player->msg_posted == FALSE) {
9692 MMMessageParamType msg_param;
9693 memset(&msg_param, 0, sizeof(MMMessageParamType));
9695 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9696 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9698 /* don't post more if one was sent already */
9699 player->msg_posted = TRUE;
9704 __mmplayer_update_content_type_info(player);
9706 pad = gst_element_get_static_pad(tf, "src");
9708 LOGE("fail to get typefind src pad.\n");
9712 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9713 gboolean async = FALSE;
9714 LOGE("failed to autoplug %s\n", player->type);
9716 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9718 if (async && player->msg_posted == FALSE)
9719 __mmplayer_handle_missed_plugin(player);
9725 gst_object_unref(GST_OBJECT(pad));
9733 __mmplayer_create_decodebin(mm_player_t* player)
9735 GstElement *decodebin = NULL;
9739 /* create decodebin */
9740 decodebin = gst_element_factory_make("decodebin", NULL);
9743 LOGE("fail to create decodebin\n");
9747 /* raw pad handling signal */
9748 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9749 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9751 /* no-more-pad pad handling signal */
9752 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9753 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9755 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9756 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9758 /* This signal is emitted when a pad for which there is no further possible
9759 decoding is added to the decodebin.*/
9760 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9761 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9763 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9764 before looking for any elements that can handle that stream.*/
9765 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9766 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9768 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9769 before looking for any elements that can handle that stream.*/
9770 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9771 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9773 /* This signal is emitted once decodebin has finished decoding all the data.*/
9774 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9775 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9777 /* This signal is emitted when a element is added to the bin.*/
9778 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9779 G_CALLBACK(__mmplayer_gst_element_added), player);
9786 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9788 MMPlayerGstElement* mainbin = NULL;
9789 GstElement* decodebin = NULL;
9790 GstElement* queue2 = NULL;
9791 GstPad* sinkpad = NULL;
9792 GstPad* qsrcpad = NULL;
9793 gint64 dur_bytes = 0L;
9795 guint max_buffer_size_bytes = 0;
9796 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9799 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9801 mainbin = player->pipeline->mainbin;
9803 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9804 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9805 LOGD("creating http streaming buffering queue(queue2)\n");
9807 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9808 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9810 queue2 = gst_element_factory_make("queue2", "queue2");
9812 LOGE("failed to create buffering queue element\n");
9816 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9817 LOGE("failed to add buffering queue\n");
9821 sinkpad = gst_element_get_static_pad(queue2, "sink");
9822 qsrcpad = gst_element_get_static_pad(queue2, "src");
9824 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9825 LOGE("failed to link buffering queue\n");
9829 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9830 LOGE("fail to get duration.\n");
9832 LOGD("dur_bytes = %lld\n", dur_bytes);
9834 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9836 if (dur_bytes > 0) {
9837 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9838 type = MUXED_BUFFER_TYPE_FILE;
9840 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9841 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9847 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9848 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9849 if (!g_strrstr(player->type, "video/mpegts")) {
9850 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9851 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9853 // FIXME : pass ini setting directly. is this ok?
9854 __mm_player_streaming_set_queue2(player->streamer,
9857 max_buffer_size_bytes,
9858 player->ini.http_buffering_time,
9860 player->ini.http_buffering_limit, // no meaning
9862 player->http_file_buffering_path,
9863 (guint64)dur_bytes);
9866 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9867 LOGE("failed to sync queue2 state with parent\n");
9873 gst_object_unref(GST_OBJECT(sinkpad));
9875 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9876 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9880 /* create decodebin */
9881 decodebin = __mmplayer_create_decodebin(player);
9884 LOGE("can not create autoplug element\n");
9888 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9889 LOGE("failed to add decodebin\n");
9893 /* to force caps on the decodebin element and avoid reparsing stuff by
9894 * typefind. It also avoids a deadlock in the way typefind activates pads in
9895 * the state change */
9896 g_object_set(decodebin, "sink-caps", caps, NULL);
9898 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9900 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9901 LOGE("failed to link decodebin\n");
9905 gst_object_unref(GST_OBJECT(sinkpad));
9907 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9908 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9910 /* set decodebin property about buffer in streaming playback. *
9911 * in case of HLS/DASH, it does not need to have big buffer *
9912 * because it is kind of adaptive streaming. */
9913 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9914 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9915 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9916 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9918 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9919 || MMPLAYER_IS_DASH_STREAMING(player)) {
9920 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9921 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9924 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9925 "high-percent", (gint)player->ini.http_buffering_limit,
9926 "low-percent", 1, // 1%
9927 "max-size-bytes", max_size_bytes,
9928 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9929 "max-size-buffers", 0, NULL); // disable or automatic
9932 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9933 LOGE("failed to sync decodebin state with parent\n");
9944 gst_object_unref(GST_OBJECT(sinkpad));
9947 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9948 * You need to explicitly set elements to the NULL state before
9949 * dropping the final reference, to allow them to clean up.
9951 gst_element_set_state(queue2, GST_STATE_NULL);
9953 /* And, it still has a parent "player".
9954 * You need to let the parent manage the object instead of unreffing the object directly.
9956 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9957 gst_object_unref(queue2);
9962 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9963 * You need to explicitly set elements to the NULL state before
9964 * dropping the final reference, to allow them to clean up.
9966 gst_element_set_state(decodebin, GST_STATE_NULL);
9968 /* And, it still has a parent "player".
9969 * You need to let the parent manage the object instead of unreffing the object directly.
9972 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9973 gst_object_unref(decodebin);
9981 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9985 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9986 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9988 LOGD("class : %s, mime : %s \n", factory_class, mime);
9990 /* add missing plugin */
9991 /* NOTE : msl should check missing plugin for image mime type.
9992 * Some motion jpeg clips can have playable audio track.
9993 * So, msl have to play audio after displaying popup written video format not supported.
9995 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9996 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9997 LOGD("not found demuxer\n");
9998 player->not_found_demuxer = TRUE;
9999 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10005 if (!g_strrstr(factory_class, "Demuxer")) {
10006 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10007 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10008 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10010 /* check that clip have multi tracks or not */
10011 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10012 LOGD("video plugin is already linked\n");
10014 LOGW("add VIDEO to missing plugin\n");
10015 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10016 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10018 } else if (g_str_has_prefix(mime, "audio")) {
10019 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10020 LOGD("audio plugin is already linked\n");
10022 LOGW("add AUDIO to missing plugin\n");
10023 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10024 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10032 return MM_ERROR_NONE;
10037 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10039 mm_player_t* player = (mm_player_t*)data;
10043 MMPLAYER_RETURN_IF_FAIL(player);
10045 /* remove fakesink. */
10046 if (!__mmplayer_gst_remove_fakesink(player,
10047 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10048 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10049 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10050 * source element are not same. To overcome this situation, this function will called
10051 * several places and several times. Therefore, this is not an error case.
10056 LOGD("[handle: %p] pipeline has completely constructed", player);
10058 if ((player->ini.async_start) &&
10059 (player->msg_posted == FALSE) &&
10060 (player->cmd >= MMPLAYER_COMMAND_START))
10061 __mmplayer_handle_missed_plugin(player);
10063 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10067 __mmplayer_verify_next_play_path(mm_player_t *player)
10069 MMHandleType attrs = 0;
10070 MMPlayerParseProfile profile;
10071 gint uri_idx = 0, check_cnt = 0;
10073 gint mode = MM_PLAYER_PD_MODE_NONE;
10077 guint num_of_list = 0;
10078 static int profile_tv = -1;
10082 LOGD("checking for gapless play");
10084 if (player->pipeline->textbin) {
10085 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10089 attrs = MMPLAYER_GET_ATTRS(player);
10091 LOGE("fail to get attributes.\n");
10095 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10097 if (__builtin_expect(profile_tv == -1, 0)) {
10099 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10100 switch (*profileName) {
10110 /* gapless playback is not supported in case of video at TV profile. */
10111 if (profile_tv && video) {
10112 LOGW("not support video gapless playback");
10116 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10117 if (mode == TRUE) {
10123 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10124 LOGE("can not get play count\n");
10126 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10127 LOGE("can not get gapless mode\n");
10129 if (video && !gapless) {
10130 LOGW("not enabled video gapless playback");
10134 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10138 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10142 num_of_list = g_list_length(player->uri_info.uri_list);
10144 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10146 if (num_of_list == 0) {
10147 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10148 LOGE("can not get profile_uri\n");
10153 LOGE("uri list is empty.\n");
10157 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10158 LOGD("add original path : %s ", uri);
10164 uri_idx = player->uri_info.uri_idx;
10169 if (check_cnt > num_of_list) {
10170 LOGE("there is no valid uri.");
10174 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10176 if (uri_idx < num_of_list-1) {
10179 if ((count <= 1) && (count != -1)) {
10180 LOGD("no repeat.");
10182 } else if (count > 1) {
10183 /* decrease play count */
10184 /* we succeeded to rewind. update play count and then wait for next EOS */
10187 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10189 /* commit attribute */
10190 if (mmf_attrs_commit(attrs))
10191 LOGE("failed to commit attribute\n");
10194 /* count < 0 : repeat continually */
10198 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10199 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10202 LOGW("next uri does not exist\n");
10206 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10207 LOGE("failed to parse profile\n");
10211 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10212 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10213 LOGW("uri type is not supported(%d).", profile.uri_type);
10220 player->uri_info.uri_idx = uri_idx;
10221 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10223 if (mmf_attrs_commit(player->attrs)) {
10224 LOGE("failed to commit.\n");
10228 LOGD("next uri %s(%d)\n", uri, uri_idx);
10234 LOGE("unable to play next path. EOS will be posted soon.\n");
10239 __mmplayer_initialize_next_play(mm_player_t *player)
10245 player->smooth_streaming = FALSE;
10246 player->videodec_linked = 0;
10247 player->audiodec_linked = 0;
10248 player->videosink_linked = 0;
10249 player->audiosink_linked = 0;
10250 player->textsink_linked = 0;
10251 player->is_external_subtitle_present = FALSE;
10252 player->is_external_subtitle_added_now = FALSE;
10253 player->not_supported_codec = MISSING_PLUGIN_NONE;
10254 player->can_support_codec = FOUND_PLUGIN_NONE;
10255 player->pending_seek.is_pending = FALSE;
10256 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10257 player->pending_seek.pos = 0;
10258 player->msg_posted = FALSE;
10259 player->has_many_types = FALSE;
10260 player->no_more_pad = FALSE;
10261 player->not_found_demuxer = 0;
10262 player->doing_seek = FALSE;
10263 player->max_audio_channels = 0;
10264 player->is_subtitle_force_drop = FALSE;
10265 player->play_subtitle = FALSE;
10266 player->adjust_subtitle_pos = 0;
10268 player->total_bitrate = 0;
10269 player->total_maximum_bitrate = 0;
10271 _mmplayer_track_initialize(player);
10272 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10274 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10275 player->bitrate[i] = 0;
10276 player->maximum_bitrate[i] = 0;
10279 if (player->v_stream_caps) {
10280 gst_caps_unref(player->v_stream_caps);
10281 player->v_stream_caps = NULL;
10284 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10286 /* clean found parsers */
10287 if (player->parsers) {
10288 GList *parsers = player->parsers;
10289 for (; parsers; parsers = g_list_next(parsers)) {
10290 gchar *name = parsers->data;
10291 MMPLAYER_FREEIF(name);
10293 g_list_free(player->parsers);
10294 player->parsers = NULL;
10297 /* clean found audio decoders */
10298 if (player->audio_decoders) {
10299 GList *a_dec = player->audio_decoders;
10300 for (; a_dec; a_dec = g_list_next(a_dec)) {
10301 gchar *name = a_dec->data;
10302 MMPLAYER_FREEIF(name);
10304 g_list_free(player->audio_decoders);
10305 player->audio_decoders = NULL;
10312 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10314 MMPlayerGstElement *mainbin = NULL;
10315 MMMessageParamType msg_param = {0,};
10316 GstElement *element = NULL;
10317 MMHandleType attrs = 0;
10319 enum MainElementID elemId = MMPLAYER_M_NUM;
10323 if ((player == NULL) ||
10324 (player->pipeline == NULL) ||
10325 (player->pipeline->mainbin == NULL)) {
10326 LOGE("player is null.\n");
10330 mainbin = player->pipeline->mainbin;
10331 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10333 attrs = MMPLAYER_GET_ATTRS(player);
10335 LOGE("fail to get attributes.\n");
10339 /* Initialize Player values */
10340 __mmplayer_initialize_next_play(player);
10342 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10344 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10345 LOGE("failed to parse profile\n");
10346 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10350 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10351 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10352 LOGE("it's dash or hls. not support.");
10353 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10358 switch (player->profile.uri_type) {
10360 case MM_PLAYER_URI_TYPE_FILE:
10362 LOGD("using filesrc for 'file://' handler.\n");
10363 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10364 LOGE("failed to get storage info");
10368 element = gst_element_factory_make("filesrc", "source");
10371 LOGE("failed to create filesrc\n");
10375 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10378 case MM_PLAYER_URI_TYPE_URL_HTTP:
10380 gchar *user_agent, *cookies, **cookie_list;
10381 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10382 user_agent = cookies = NULL;
10383 cookie_list = NULL;
10385 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10387 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10390 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10392 /* get attribute */
10393 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10394 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10396 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10397 LOGD("get timeout from ini\n");
10398 http_timeout = player->ini.http_timeout;
10401 /* get attribute */
10402 SECURE_LOGD("location : %s\n", player->profile.uri);
10403 SECURE_LOGD("cookies : %s\n", cookies);
10404 SECURE_LOGD("user_agent : %s\n", user_agent);
10405 LOGD("timeout : %d\n", http_timeout);
10407 /* setting property to streaming source */
10408 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10409 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10410 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10412 /* parsing cookies */
10413 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10414 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10416 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10420 LOGE("not support uri type %d\n", player->profile.uri_type);
10425 LOGE("no source element was created.\n");
10429 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10430 LOGE("failed to add source element to pipeline\n");
10431 gst_object_unref(GST_OBJECT(element));
10436 /* take source element */
10437 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10438 mainbin[MMPLAYER_M_SRC].gst = element;
10442 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10443 if (player->streamer == NULL) {
10444 player->streamer = __mm_player_streaming_create();
10445 __mm_player_streaming_initialize(player->streamer);
10448 elemId = MMPLAYER_M_TYPEFIND;
10449 element = gst_element_factory_make("typefind", "typefinder");
10450 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10451 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10453 elemId = MMPLAYER_M_AUTOPLUG;
10454 element = __mmplayer_create_decodebin(player);
10457 /* check autoplug element is OK */
10459 LOGE("can not create element(%d)\n", elemId);
10463 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10464 LOGE("failed to add sinkbin to pipeline\n");
10465 gst_object_unref(GST_OBJECT(element));
10470 mainbin[elemId].id = elemId;
10471 mainbin[elemId].gst = element;
10473 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10474 LOGE("Failed to link src - autoplug(or typefind)\n");
10478 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10479 LOGE("Failed to change state of src element\n");
10483 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10484 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10485 LOGE("Failed to change state of decodebin\n");
10489 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10490 LOGE("Failed to change state of src element\n");
10495 player->gapless.stream_changed = TRUE;
10496 player->gapless.running = TRUE;
10502 MMPLAYER_PLAYBACK_UNLOCK(player);
10504 if (!player->msg_posted) {
10505 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10506 player->msg_posted = TRUE;
10513 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10515 mm_player_selector_t *selector = &player->selector[type];
10516 MMPlayerGstElement *sinkbin = NULL;
10517 enum MainElementID selectorId = MMPLAYER_M_NUM;
10518 enum MainElementID sinkId = MMPLAYER_M_NUM;
10519 GstPad *srcpad = NULL;
10520 GstPad *sinkpad = NULL;
10521 gboolean send_notice = FALSE;
10524 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10526 LOGD("type %d", type);
10529 case MM_PLAYER_TRACK_TYPE_AUDIO:
10530 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10531 sinkId = MMPLAYER_A_BIN;
10532 sinkbin = player->pipeline->audiobin;
10534 case MM_PLAYER_TRACK_TYPE_VIDEO:
10535 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10536 sinkId = MMPLAYER_V_BIN;
10537 sinkbin = player->pipeline->videobin;
10538 send_notice = TRUE;
10540 case MM_PLAYER_TRACK_TYPE_TEXT:
10541 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10542 sinkId = MMPLAYER_T_BIN;
10543 sinkbin = player->pipeline->textbin;
10546 LOGE("requested type is not supportable");
10551 if (player->pipeline->mainbin[selectorId].gst) {
10554 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10556 if (selector->event_probe_id != 0)
10557 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10558 selector->event_probe_id = 0;
10560 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10561 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10563 if (srcpad && sinkpad) {
10564 /* after getting drained signal there is no data flows, so no need to do pad_block */
10565 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10566 gst_pad_unlink(srcpad, sinkpad);
10568 /* send custom event to sink pad to handle it at video sink */
10570 LOGD("send custom event to sinkpad");
10571 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10572 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10573 gst_pad_send_event(sinkpad, event);
10577 gst_object_unref(sinkpad);
10580 gst_object_unref(srcpad);
10583 LOGD("selector release");
10585 /* release and unref requests pad from the selector */
10586 for (n = 0; n < selector->channels->len; n++) {
10587 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10588 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10590 g_ptr_array_set_size(selector->channels, 0);
10592 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10593 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10595 player->pipeline->mainbin[selectorId].gst = NULL;
10603 __mmplayer_deactivate_old_path(mm_player_t *player)
10606 MMPLAYER_RETURN_IF_FAIL(player);
10608 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10609 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10610 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10611 LOGE("deactivate selector error");
10615 _mmplayer_track_destroy(player);
10616 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10618 if (player->streamer) {
10619 __mm_player_streaming_deinitialize(player->streamer);
10620 __mm_player_streaming_destroy(player->streamer);
10621 player->streamer = NULL;
10624 MMPLAYER_PLAYBACK_LOCK(player);
10625 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10632 if (!player->msg_posted) {
10633 MMMessageParamType msg = {0,};
10636 msg.code = MM_ERROR_PLAYER_INTERNAL;
10637 LOGE("next_uri_play> deactivate error");
10639 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10640 player->msg_posted = TRUE;
10645 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10647 int result = MM_ERROR_NONE;
10648 mm_player_t* player = (mm_player_t*) hplayer;
10651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10654 player->http_file_buffering_path = (gchar*)file_path;
10655 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10661 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10663 int result = MM_ERROR_NONE;
10664 mm_player_t* player = (mm_player_t*) hplayer;
10667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10669 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10670 if (mmf_attrs_commit(player->attrs)) {
10671 LOGE("failed to commit the original uri.\n");
10672 result = MM_ERROR_PLAYER_INTERNAL;
10674 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10675 LOGE("failed to add the original uri in the uri list.\n");
10682 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10684 mm_player_t* player = (mm_player_t*) hplayer;
10685 guint num_of_list = 0;
10689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10690 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10692 if (player->pipeline && player->pipeline->textbin) {
10693 LOGE("subtitle path is enabled.\n");
10694 return MM_ERROR_PLAYER_INVALID_STATE;
10697 num_of_list = g_list_length(player->uri_info.uri_list);
10699 if (is_first_path == TRUE) {
10700 if (num_of_list == 0) {
10701 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10702 LOGD("add original path : %s", uri);
10704 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10705 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10707 LOGD("change original path : %s", uri);
10710 MMHandleType attrs = 0;
10711 attrs = MMPLAYER_GET_ATTRS(player);
10713 if (num_of_list == 0) {
10714 char *original_uri = NULL;
10717 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10719 if (!original_uri) {
10720 LOGE("there is no original uri.");
10721 return MM_ERROR_PLAYER_INVALID_STATE;
10724 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10725 player->uri_info.uri_idx = 0;
10727 LOGD("add original path at first : %s(%d)", original_uri);
10731 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10732 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10736 return MM_ERROR_NONE;
10739 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10741 mm_player_t* player = (mm_player_t*) hplayer;
10742 char *next_uri = NULL;
10743 guint num_of_list = 0;
10746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10748 num_of_list = g_list_length(player->uri_info.uri_list);
10750 if (num_of_list > 0) {
10751 gint uri_idx = player->uri_info.uri_idx;
10753 if (uri_idx < num_of_list-1)
10758 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10759 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10761 *uri = g_strdup(next_uri);
10765 return MM_ERROR_NONE;
10769 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10770 GstCaps *caps, gpointer data)
10772 mm_player_t* player = (mm_player_t*)data;
10773 const gchar* klass = NULL;
10774 const gchar* mime = NULL;
10775 gchar* caps_str = NULL;
10777 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10778 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10779 caps_str = gst_caps_to_string(caps);
10781 LOGW("unknown type of caps : %s from %s",
10782 caps_str, GST_ELEMENT_NAME(elem));
10784 MMPLAYER_FREEIF(caps_str);
10786 /* There is no available codec. */
10787 __mmplayer_check_not_supported_codec(player, klass, mime);
10791 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10792 GstCaps * caps, gpointer data)
10794 mm_player_t* player = (mm_player_t*)data;
10795 const char* mime = NULL;
10796 gboolean ret = TRUE;
10798 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10799 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10801 if (g_str_has_prefix(mime, "audio")) {
10802 GstStructure* caps_structure = NULL;
10803 gint samplerate = 0;
10805 gchar *caps_str = NULL;
10807 caps_structure = gst_caps_get_structure(caps, 0);
10808 gst_structure_get_int(caps_structure, "rate", &samplerate);
10809 gst_structure_get_int(caps_structure, "channels", &channels);
10811 if ((channels > 0 && samplerate == 0)) {
10812 LOGD("exclude audio...");
10816 caps_str = gst_caps_to_string(caps);
10817 /* set it directly because not sent by TAG */
10818 if (g_strrstr(caps_str, "mobile-xmf"))
10819 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10820 MMPLAYER_FREEIF(caps_str);
10821 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10822 MMMessageParamType msg_param;
10823 memset(&msg_param, 0, sizeof(MMMessageParamType));
10824 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10825 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10826 LOGD("video file is not supported on this device");
10828 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10829 LOGD("already video linked");
10832 LOGD("found new stream");
10839 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10841 int ret = MM_ERROR_NONE;
10843 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10845 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10846 GstStructure* str = NULL;
10848 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10850 LOGD("audio codec type: %d", codec_type);
10851 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10852 /* sw codec will be skipped */
10853 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10854 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10855 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10856 ret = MM_ERROR_PLAYER_INTERNAL;
10860 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10861 /* hw codec will be skipped */
10862 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10863 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10864 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10865 ret = MM_ERROR_PLAYER_INTERNAL;
10870 str = gst_caps_get_structure(caps, 0);
10872 gst_structure_get_int(str, "channels", &channels);
10874 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10875 if (player->max_audio_channels < channels)
10876 player->max_audio_channels = channels;
10878 /* set stream information */
10879 if (!player->audiodec_linked)
10880 __mmplayer_set_audio_attrs(player, caps);
10882 /* update codec info */
10883 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10884 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10885 player->audiodec_linked = 1;
10887 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10889 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10891 LOGD("video codec type: %d", codec_type);
10892 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10893 /* sw codec is skipped */
10894 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10895 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10896 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10897 ret = MM_ERROR_PLAYER_INTERNAL;
10901 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10902 /* hw codec is skipped */
10903 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10904 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10905 ret = MM_ERROR_PLAYER_INTERNAL;
10910 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10911 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10913 /* mark video decoder for acquire */
10914 if (player->video_decoder_resource == NULL) {
10915 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10916 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10917 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10918 &player->video_decoder_resource)
10919 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10920 LOGE("could not mark video_decoder resource for acquire");
10921 ret = MM_ERROR_PLAYER_INTERNAL;
10925 LOGW("video decoder resource is already acquired, skip it.");
10926 ret = MM_ERROR_PLAYER_INTERNAL;
10930 player->interrupted_by_resource = FALSE;
10931 /* acquire resources for video playing */
10932 if (mm_resource_manager_commit(player->resource_manager)
10933 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10934 LOGE("could not acquire resources for video decoding\n");
10935 ret = MM_ERROR_PLAYER_INTERNAL;
10940 /* update codec info */
10941 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10942 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10943 player->videodec_linked = 1;
10951 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10952 GstCaps* caps, GstElementFactory* factory, gpointer data)
10954 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10955 We are defining our own and will be removed when it actually exposed */
10957 GST_AUTOPLUG_SELECT_TRY,
10958 GST_AUTOPLUG_SELECT_EXPOSE,
10959 GST_AUTOPLUG_SELECT_SKIP
10960 } GstAutoplugSelectResult;
10962 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10963 mm_player_t* player = (mm_player_t*)data;
10965 gchar* factory_name = NULL;
10966 gchar* caps_str = NULL;
10967 const gchar* klass = NULL;
10970 factory_name = GST_OBJECT_NAME(factory);
10971 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10972 caps_str = gst_caps_to_string(caps);
10974 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10976 /* store type string */
10977 if (player->type == NULL) {
10978 player->type = gst_caps_to_string(caps);
10979 __mmplayer_update_content_type_info(player);
10982 /* filtering exclude keyword */
10983 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10984 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10985 LOGW("skipping [%s] by exculde keyword [%s]\n",
10986 factory_name, player->ini.exclude_element_keyword[idx]);
10988 result = GST_AUTOPLUG_SELECT_SKIP;
10993 /* exclude webm format */
10994 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10995 * because webm format is not supportable.
10996 * If webm is disabled in "autoplug-continue", there is no state change
10997 * failure or error because the decodebin will expose the pad directly.
10998 * It make MSL invoke _prepare_async_callback.
10999 * So, we need to disable webm format in "autoplug-select" */
11000 if (caps_str && strstr(caps_str, "webm")) {
11001 LOGW("webm is not supported");
11002 result = GST_AUTOPLUG_SELECT_SKIP;
11006 /* check factory class for filtering */
11007 /* NOTE : msl don't need to use image plugins.
11008 * So, those plugins should be skipped for error handling.
11010 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11011 LOGD("skipping [%s] by not required\n", factory_name);
11012 result = GST_AUTOPLUG_SELECT_SKIP;
11016 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11017 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11018 // TO CHECK : subtitle if needed, add subparse exception.
11019 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11020 result = GST_AUTOPLUG_SELECT_SKIP;
11024 if (g_strrstr(factory_name, "mpegpsdemux")) {
11025 LOGD("skipping PS container - not support\n");
11026 result = GST_AUTOPLUG_SELECT_SKIP;
11030 if (g_strrstr(factory_name, "mssdemux"))
11031 player->smooth_streaming = TRUE;
11033 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11034 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11037 GstStructure *str = NULL;
11038 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11040 /* don't make video because of not required */
11041 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11042 (player->set_mode.media_packet_video_stream == FALSE)) {
11043 LOGD("no video because it's not required. -> return expose");
11044 result = GST_AUTOPLUG_SELECT_EXPOSE;
11048 /* get w/h for omx state-tune */
11049 /* FIXME: deprecated? */
11050 str = gst_caps_get_structure(caps, 0);
11051 gst_structure_get_int(str, "width", &width);
11054 if (player->v_stream_caps) {
11055 gst_caps_unref(player->v_stream_caps);
11056 player->v_stream_caps = NULL;
11059 player->v_stream_caps = gst_caps_copy(caps);
11060 LOGD("take caps for video state tune");
11061 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11065 if (g_strrstr(klass, "Codec/Decoder")) {
11066 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11067 LOGD("skipping %s codec", factory_name);
11068 result = GST_AUTOPLUG_SELECT_SKIP;
11074 MMPLAYER_FREEIF(caps_str);
11080 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11083 //mm_player_t* player = (mm_player_t*)data;
11084 GstCaps* caps = NULL;
11086 LOGD("[Decodebin2] pad-removed signal\n");
11088 caps = gst_pad_query_caps(new_pad, NULL);
11090 gchar* caps_str = NULL;
11091 caps_str = gst_caps_to_string(caps);
11093 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11095 MMPLAYER_FREEIF(caps_str);
11096 gst_caps_unref(caps);
11101 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11103 mm_player_t* player = (mm_player_t*)data;
11104 GstIterator *iter = NULL;
11105 GValue item = { 0, };
11106 GstPad *pad = NULL;
11107 gboolean done = FALSE;
11108 gboolean is_all_drained = TRUE;
11111 MMPLAYER_RETURN_IF_FAIL(player);
11113 LOGD("__mmplayer_gst_decode_drained");
11115 if (player->use_deinterleave == TRUE) {
11116 LOGD("group playing mode.");
11120 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11121 LOGW("Fail to get cmd lock");
11125 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11126 !__mmplayer_verify_next_play_path(player)) {
11127 LOGD("decoding is finished.");
11128 __mmplayer_reset_gapless_state(player);
11129 MMPLAYER_CMD_UNLOCK(player);
11133 player->gapless.reconfigure = TRUE;
11135 /* check decodebin src pads whether they received EOS or not */
11136 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11139 switch (gst_iterator_next(iter, &item)) {
11140 case GST_ITERATOR_OK:
11141 pad = g_value_get_object(&item);
11142 if (pad && !GST_PAD_IS_EOS(pad)) {
11143 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11144 is_all_drained = FALSE;
11147 g_value_reset(&item);
11149 case GST_ITERATOR_RESYNC:
11150 gst_iterator_resync(iter);
11152 case GST_ITERATOR_ERROR:
11153 case GST_ITERATOR_DONE:
11158 g_value_unset(&item);
11159 gst_iterator_free(iter);
11161 if (!is_all_drained) {
11162 LOGD("Wait util the all pads get EOS.");
11163 MMPLAYER_CMD_UNLOCK(player);
11168 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11169 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11171 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11172 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11173 __mmplayer_deactivate_old_path(player);
11174 MMPLAYER_CMD_UNLOCK(player);
11180 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11182 mm_player_t* player = (mm_player_t*)data;
11183 const gchar* klass = NULL;
11184 gchar* factory_name = NULL;
11186 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11187 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11189 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11191 if (__mmplayer_add_dump_buffer_probe(player, element))
11192 LOGD("add buffer probe");
11195 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11196 gchar* selected = NULL;
11197 selected = g_strdup(GST_ELEMENT_NAME(element));
11198 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11202 if (g_strrstr(klass, "Parser")) {
11203 gchar* selected = NULL;
11205 selected = g_strdup(factory_name);
11206 player->parsers = g_list_append(player->parsers, selected);
11209 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11210 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11211 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11213 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11214 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11216 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11217 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11218 "max-video-width", player->adaptive_info.limit.width,
11219 "max-video-height", player->adaptive_info.limit.height, NULL);
11221 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11222 /* FIXIT : first value will be overwritten if there's more
11223 * than 1 demuxer/parser
11226 //LOGD("plugged element is demuxer. take it\n");
11227 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11228 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11230 /*Added for multi audio support */ // Q. del?
11231 if (g_strrstr(klass, "Demux")) {
11232 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11233 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11237 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11238 int surface_type = 0;
11240 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11243 // to support trust-zone only
11244 if (g_strrstr(factory_name, "asfdemux")) {
11245 LOGD("set file-location %s\n", player->profile.uri);
11246 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11248 if (player->video_hub_download_mode == TRUE)
11249 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11250 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11251 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11252 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11253 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11254 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11255 (__mmplayer_is_only_mp3_type(player->type))) {
11256 LOGD("[mpegaudioparse] set streaming pull mode.");
11257 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11259 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11260 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11263 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11264 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11265 LOGD("plugged element is multiqueue. take it\n");
11267 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11268 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11270 if (!MMPLAYER_IS_HTTP_PD(player) &&
11271 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11272 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11273 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11274 __mm_player_streaming_set_multiqueue(player->streamer,
11277 player->ini.http_buffering_time,
11279 player->ini.http_buffering_limit);
11281 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11288 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11291 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11293 if (MMPLAYER_IS_STREAMING(player))
11296 /* This callback can be set to music player only. */
11297 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11298 LOGW("audio callback is not supported for video");
11302 if (player->audio_stream_cb) {
11303 GstPad *pad = NULL;
11305 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11308 LOGE("failed to get sink pad from audiosink to probe data\n");
11311 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11312 __mmplayer_audio_stream_probe, player, NULL);
11314 gst_object_unref(pad);
11318 LOGE("There is no audio callback to configure.\n");
11328 __mmplayer_release_misc(mm_player_t* player)
11331 bool cur_mode = player->set_mode.rich_audio;
11334 MMPLAYER_RETURN_IF_FAIL(player);
11336 player->video_stream_cb = NULL;
11337 player->video_stream_cb_user_param = NULL;
11338 player->video_stream_prerolled = FALSE;
11340 player->audio_stream_cb = NULL;
11341 player->audio_stream_render_cb_ex = NULL;
11342 player->audio_stream_cb_user_param = NULL;
11343 player->audio_stream_sink_sync = false;
11345 player->video_stream_changed_cb = NULL;
11346 player->video_stream_changed_cb_user_param = NULL;
11348 player->audio_stream_changed_cb = NULL;
11349 player->audio_stream_changed_cb_user_param = NULL;
11351 player->sent_bos = FALSE;
11352 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11354 player->doing_seek = FALSE;
11356 player->total_bitrate = 0;
11357 player->total_maximum_bitrate = 0;
11359 player->not_found_demuxer = 0;
11361 player->last_position = 0;
11362 player->duration = 0;
11363 player->http_content_size = 0;
11364 player->not_supported_codec = MISSING_PLUGIN_NONE;
11365 player->can_support_codec = FOUND_PLUGIN_NONE;
11366 player->pending_seek.is_pending = FALSE;
11367 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11368 player->pending_seek.pos = 0;
11369 player->msg_posted = FALSE;
11370 player->has_many_types = FALSE;
11371 player->max_audio_channels = 0;
11372 player->video_share_api_delta = 0;
11373 player->video_share_clock_delta = 0;
11374 player->is_subtitle_force_drop = FALSE;
11375 player->play_subtitle = FALSE;
11376 player->adjust_subtitle_pos = 0;
11377 player->last_multiwin_status = FALSE;
11378 player->has_closed_caption = FALSE;
11379 player->set_mode.media_packet_video_stream = FALSE;
11380 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11381 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11383 player->set_mode.rich_audio = cur_mode;
11385 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11386 player->bitrate[i] = 0;
11387 player->maximum_bitrate[i] = 0;
11390 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11392 /* remove media stream cb(appsrc cb) */
11393 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11394 player->media_stream_buffer_status_cb[i] = NULL;
11395 player->media_stream_seek_data_cb[i] = NULL;
11396 player->buffer_cb_user_param[i] = NULL;
11397 player->seek_cb_user_param[i] = NULL;
11399 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11401 /* free memory related to audio effect */
11402 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11404 if (player->adaptive_info.var_list) {
11405 g_list_free_full(player->adaptive_info.var_list, g_free);
11406 player->adaptive_info.var_list = NULL;
11409 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11410 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11411 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11413 /* Reset video360 settings to their defaults in case if the pipeline is to be
11416 player->video360_metadata.is_spherical = -1;
11417 player->is_openal_plugin_used = FALSE;
11419 player->is_content_spherical = FALSE;
11420 player->is_video360_enabled = TRUE;
11421 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11422 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11423 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11424 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11425 player->video360_zoom = 1.0f;
11426 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11427 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11429 player->sound.rg_enable = false;
11435 __mmplayer_release_misc_post(mm_player_t* player)
11437 char *original_uri = NULL;
11440 /* player->pipeline is already released before. */
11442 MMPLAYER_RETURN_IF_FAIL(player);
11444 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11446 /* clean found parsers */
11447 if (player->parsers) {
11448 GList *parsers = player->parsers;
11449 for (; parsers; parsers = g_list_next(parsers)) {
11450 gchar *name = parsers->data;
11451 MMPLAYER_FREEIF(name);
11453 g_list_free(player->parsers);
11454 player->parsers = NULL;
11457 /* clean found audio decoders */
11458 if (player->audio_decoders) {
11459 GList *a_dec = player->audio_decoders;
11460 for (; a_dec; a_dec = g_list_next(a_dec)) {
11461 gchar *name = a_dec->data;
11462 MMPLAYER_FREEIF(name);
11464 g_list_free(player->audio_decoders);
11465 player->audio_decoders = NULL;
11468 /* clean the uri list except original uri */
11469 if (player->uri_info.uri_list) {
11470 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11472 if (player->attrs) {
11473 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11474 LOGD("restore original uri = %s\n", original_uri);
11476 if (mmf_attrs_commit(player->attrs))
11477 LOGE("failed to commit the original uri.\n");
11480 GList *uri_list = player->uri_info.uri_list;
11481 for (; uri_list; uri_list = g_list_next(uri_list)) {
11482 gchar *uri = uri_list->data;
11483 MMPLAYER_FREEIF(uri);
11485 g_list_free(player->uri_info.uri_list);
11486 player->uri_info.uri_list = NULL;
11489 /* clear the audio stream buffer list */
11490 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11492 /* clear the video stream bo list */
11493 __mmplayer_video_stream_destroy_bo_list(player);
11494 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11496 if (player->profile.input_mem.buf) {
11497 free(player->profile.input_mem.buf);
11498 player->profile.input_mem.buf = NULL;
11500 player->profile.input_mem.len = 0;
11501 player->profile.input_mem.offset = 0;
11503 player->uri_info.uri_idx = 0;
11507 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11509 GstElement *element = NULL;
11512 LOGD("creating %s to plug\n", name);
11514 element = gst_element_factory_make(name, NULL);
11516 LOGE("failed to create queue\n");
11520 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11521 LOGE("failed to set state READY to %s\n", name);
11522 gst_object_unref(element);
11526 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11527 LOGE("failed to add %s\n", name);
11528 gst_object_unref(element);
11532 sinkpad = gst_element_get_static_pad(element, "sink");
11534 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11535 LOGE("failed to link %s\n", name);
11536 gst_object_unref(sinkpad);
11537 gst_object_unref(element);
11541 LOGD("linked %s to pipeline successfully\n", name);
11543 gst_object_unref(sinkpad);
11549 __mmplayer_check_subtitle(mm_player_t* player)
11551 MMHandleType attrs = 0;
11552 char *subtitle_uri = NULL;
11556 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11558 /* get subtitle attribute */
11559 attrs = MMPLAYER_GET_ATTRS(player);
11563 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11564 if (!subtitle_uri || !strlen(subtitle_uri))
11567 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11568 player->is_external_subtitle_present = TRUE;
11576 __mmplayer_can_extract_pcm(mm_player_t* player)
11578 MMHandleType attrs = 0;
11579 gboolean sound_extraction = FALSE;
11581 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11583 attrs = MMPLAYER_GET_ATTRS(player);
11585 LOGE("fail to get attributes.");
11589 /* get sound_extraction property */
11590 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11592 if (!sound_extraction) {
11593 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11601 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11604 MMMessageParamType msg_param;
11605 gchar *msg_src_element = NULL;
11606 GstStructure *s = NULL;
11607 guint error_id = 0;
11608 gchar *error_string = NULL;
11612 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11613 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11615 s = gst_structure_copy(gst_message_get_structure(message));
11618 if (!gst_structure_get_uint(s, "error_id", &error_id))
11619 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11621 switch (error_id) {
11622 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11623 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11625 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11626 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11628 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11629 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11631 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11632 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11634 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11635 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11637 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11638 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11640 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11641 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11643 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11644 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11646 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11647 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11649 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11650 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11652 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11653 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11655 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11656 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11658 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11659 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11661 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11662 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11664 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11665 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11667 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11668 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11670 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11671 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11673 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11674 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11676 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11677 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11679 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11680 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11682 case MMPLAYER_STREAMING_ERROR_GONE:
11683 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11685 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11686 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11688 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11689 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11691 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11692 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11694 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11695 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11697 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11698 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11700 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11701 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11703 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11704 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11706 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11707 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11709 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11710 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11712 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11713 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11715 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11716 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11718 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11719 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11721 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11722 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11724 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11725 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11727 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11728 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11730 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11731 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11733 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11734 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11736 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11737 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11739 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11740 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11742 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11743 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11745 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11746 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11748 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11749 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11751 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11752 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11754 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11755 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11759 gst_structure_free(s);
11760 return MM_ERROR_PLAYER_STREAMING_FAIL;
11764 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11766 msg_param.data = (void *) error_string;
11768 if (message->src) {
11769 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11771 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11772 msg_src_element, msg_param.code, (char*)msg_param.data);
11775 /* post error to application */
11776 if (!player->msg_posted) {
11777 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11779 /* don't post more if one was sent already */
11780 player->msg_posted = TRUE;
11782 LOGD("skip error post because it's sent already.\n");
11784 gst_structure_free(s);
11786 g_free(error_string);
11793 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11795 MMPLAYER_RETURN_IF_FAIL(player);
11797 /* post now if delay is zero */
11798 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11799 LOGD("eos delay is zero. posting EOS now\n");
11800 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11802 if (player->set_mode.pcm_extraction)
11803 __mmplayer_cancel_eos_timer(player);
11808 /* cancel if existing */
11809 __mmplayer_cancel_eos_timer(player);
11811 /* init new timeout */
11812 /* NOTE : consider give high priority to this timer */
11813 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11815 player->eos_timer = g_timeout_add(delay_in_ms,
11816 __mmplayer_eos_timer_cb, player);
11818 player->context.global_default = g_main_context_default();
11819 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11821 /* check timer is valid. if not, send EOS now */
11822 if (player->eos_timer == 0) {
11823 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11824 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11829 __mmplayer_cancel_eos_timer(mm_player_t* player)
11831 MMPLAYER_RETURN_IF_FAIL(player);
11833 if (player->eos_timer) {
11834 LOGD("cancel eos timer");
11835 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11836 player->eos_timer = 0;
11843 __mmplayer_eos_timer_cb(gpointer u_data)
11845 mm_player_t* player = NULL;
11846 MMHandleType attrs = 0;
11849 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11851 player = (mm_player_t*) u_data;
11852 attrs = MMPLAYER_GET_ATTRS(player);
11854 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11857 gint ret_value = 0;
11858 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11859 if (ret_value != MM_ERROR_NONE)
11860 LOGE("seeking to 0 failed in repeat play");
11863 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11866 /* we are returning FALSE as we need only one posting */
11870 /* sending event to one of sinkelements */
11872 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11874 GstEvent * event2 = NULL;
11875 GList *sinks = NULL;
11876 gboolean res = FALSE;
11879 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11880 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11882 /* While adding subtitles in live feeds seek is getting called.
11883 Adding defensive check in framework layer.*/
11884 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11885 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11886 LOGE("Should not send seek event during live playback");
11891 if (player->play_subtitle)
11892 event2 = gst_event_copy((const GstEvent *)event);
11894 sinks = player->sink_elements;
11896 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11898 if (GST_IS_ELEMENT(sink)) {
11899 /* keep ref to the event */
11900 gst_event_ref(event);
11902 if ((res = gst_element_send_event(sink, event))) {
11903 LOGD("sending event[%s] to sink element [%s] success!\n",
11904 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11906 /* rtsp case, asyn_done is not called after seek during pause state */
11907 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11908 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11909 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11910 LOGD("RTSP seek completed, after pause state..\n");
11911 player->doing_seek = FALSE;
11912 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11918 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11919 sinks = g_list_next(sinks);
11926 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11927 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11930 sinks = g_list_next(sinks);
11933 /* Note : Textbin is not linked to the video or audio bin.
11934 * It needs to send the event to the text sink seperatelly.
11936 if (player->play_subtitle && player->pipeline) {
11937 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11939 if (GST_IS_ELEMENT(text_sink)) {
11940 /* keep ref to the event */
11941 gst_event_ref(event2);
11943 if ((res = gst_element_send_event(text_sink, event2)))
11944 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11945 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11947 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11948 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11950 gst_event_unref(event2);
11954 gst_event_unref(event);
11962 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11966 MMPLAYER_RETURN_IF_FAIL(player);
11967 MMPLAYER_RETURN_IF_FAIL(sink);
11969 player->sink_elements =
11970 g_list_append(player->sink_elements, sink);
11976 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11980 MMPLAYER_RETURN_IF_FAIL(player);
11981 MMPLAYER_RETURN_IF_FAIL(sink);
11983 player->sink_elements =
11984 g_list_remove(player->sink_elements, sink);
11990 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11991 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11992 gint64 cur, GstSeekType stop_type, gint64 stop)
11994 GstEvent* event = NULL;
11995 gboolean result = FALSE;
11999 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12001 if (player->pipeline && player->pipeline->textbin)
12002 __mmplayer_drop_subtitle(player, FALSE);
12004 event = gst_event_new_seek(rate, format, flags, cur_type,
12005 cur, stop_type, stop);
12007 result = __gst_send_event_to_sink(player, event);
12014 /* NOTE : be careful with calling this api. please refer to below glib comment
12015 * glib comment : Note that there is a bug in GObject that makes this function much
12016 * less useful than it might seem otherwise. Once gobject is disposed, the callback
12017 * will no longer be called, but, the signal handler is not currently disconnected.
12018 * If the instance is itself being freed at the same time than this doesn't matter,
12019 * since the signal will automatically be removed, but if instance persists,
12020 * then the signal handler will leak. You should not remove the signal yourself
12021 * because in a future versions of GObject, the handler will automatically be
12024 * It's possible to work around this problem in a way that will continue to work
12025 * with future versions of GObject by checking that the signal handler is still
12026 * connected before disconnected it:
12028 * if (g_signal_handler_is_connected(instance, id))
12029 * g_signal_handler_disconnect(instance, id);
12032 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12034 GList* sig_list = NULL;
12035 MMPlayerSignalItem* item = NULL;
12039 MMPLAYER_RETURN_IF_FAIL(player);
12041 LOGD("release signals type : %d", type);
12043 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12044 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12045 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12046 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12047 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12048 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12052 sig_list = player->signals[type];
12054 for (; sig_list; sig_list = sig_list->next) {
12055 item = sig_list->data;
12057 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12058 if (g_signal_handler_is_connected(item->obj, item->sig))
12059 g_signal_handler_disconnect(item->obj, item->sig);
12062 MMPLAYER_FREEIF(item);
12065 g_list_free(player->signals[type]);
12066 player->signals[type] = NULL;
12073 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12075 mm_player_t* player = 0;
12076 int prev_display_surface_type = 0;
12077 void *prev_display_overlay = NULL;
12078 const gchar *klass = NULL;
12079 gchar *cur_videosink_name = NULL;
12082 int num_of_dec = 2; /* DEC1, DEC2 */
12086 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12087 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12089 player = MM_PLAYER_CAST(handle);
12091 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12092 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12094 return MM_ERROR_INVALID_ARGUMENT;
12097 /* load previous attributes */
12098 if (player->attrs) {
12099 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12100 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12101 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12102 if (prev_display_surface_type == surface_type) {
12103 LOGD("incoming display surface type is same as previous one, do nothing..");
12105 return MM_ERROR_NONE;
12108 LOGE("failed to load attributes");
12110 return MM_ERROR_PLAYER_INTERNAL;
12113 /* check videosink element is created */
12114 if (!player->pipeline || !player->pipeline->videobin ||
12115 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12116 LOGD("videosink element is not yet ready");
12118 /* videobin is not created yet, so we just set attributes related to display surface */
12119 LOGD("store display attribute for given surface type(%d)", surface_type);
12120 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12121 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12122 if (mmf_attrs_commit(player->attrs)) {
12123 LOGE("failed to commit attribute");
12125 return MM_ERROR_PLAYER_INTERNAL;
12128 return MM_ERROR_NONE;
12130 /* get player command status */
12131 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12132 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12134 return MM_ERROR_PLAYER_INVALID_STATE;
12137 /* surface change */
12138 for (i = 0 ; i < num_of_dec ; i++) {
12139 if (player->pipeline->mainbin &&
12140 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12141 GstElementFactory *decfactory;
12142 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12144 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12145 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12146 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12147 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12151 LOGW("success to changing display surface(%d)", surface_type);
12153 return MM_ERROR_NONE;
12155 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12156 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12160 LOGW("success to changing display surface(%d)", surface_type);
12162 return MM_ERROR_NONE;
12165 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12166 ret = MM_ERROR_PLAYER_INTERNAL;
12175 /* rollback to previous attributes */
12176 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12177 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12178 if (mmf_attrs_commit(player->attrs)) {
12179 LOGE("failed to commit attributes to rollback");
12181 return MM_ERROR_PLAYER_INTERNAL;
12187 /* NOTE : It does not support some use cases, eg using colorspace converter */
12189 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12191 GstPad *src_pad_dec = NULL;
12192 GstPad *sink_pad_videosink = NULL;
12193 GstPad *sink_pad_videobin = NULL;
12194 GstClock *clock = NULL;
12195 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12196 int ret = MM_ERROR_NONE;
12197 gboolean is_audiobin_created = TRUE;
12201 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12202 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12203 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12205 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12206 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12208 /* get information whether if audiobin is created */
12209 if (!player->pipeline->audiobin ||
12210 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12211 LOGW("audiobin is null, this video content may not have audio data");
12212 is_audiobin_created = FALSE;
12215 /* get current state of player */
12216 previous_state = MMPLAYER_CURRENT_STATE(player);
12217 LOGD("previous state(%d)", previous_state);
12220 /* get src pad of decoder and block it */
12221 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12222 if (!src_pad_dec) {
12223 LOGE("failed to get src pad from decode in mainbin");
12224 return MM_ERROR_PLAYER_INTERNAL;
12227 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12228 LOGW("trying to block pad(video)");
12229 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12230 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12233 LOGE("failed to set block pad(video)");
12234 return MM_ERROR_PLAYER_INTERNAL;
12236 LOGW("pad is blocked(video)");
12238 /* no data flows, so no need to do pad_block */
12239 if (player->doing_seek)
12240 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12242 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12246 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12247 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12248 LOGE("failed to remove previous ghost_pad for videobin");
12249 return MM_ERROR_PLAYER_INTERNAL;
12252 /* change state of videobin to NULL */
12253 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12254 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12255 if (ret != GST_STATE_CHANGE_SUCCESS) {
12256 LOGE("failed to change state of videobin to NULL");
12257 return MM_ERROR_PLAYER_INTERNAL;
12260 /* unlink between decoder and videobin and remove previous videosink from videobin */
12261 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12262 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12263 LOGE("failed to remove former videosink from videobin");
12264 return MM_ERROR_PLAYER_INTERNAL;
12267 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12269 /* create a new videosink and add it to videobin */
12270 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12271 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12272 LOGE("failed to create videosink element\n");
12274 return MM_ERROR_PLAYER_INTERNAL;
12276 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12277 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12278 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12280 /* save attributes */
12281 if (player->attrs) {
12282 /* set a new display surface type */
12283 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12284 /* set a new diplay overlay */
12285 switch (surface_type) {
12286 case MM_DISPLAY_SURFACE_OVERLAY:
12287 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12288 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12291 LOGE("invalid type(%d) for changing display surface", surface_type);
12293 return MM_ERROR_INVALID_ARGUMENT;
12295 if (mmf_attrs_commit(player->attrs)) {
12296 LOGE("failed to commit");
12298 return MM_ERROR_PLAYER_INTERNAL;
12301 LOGE("player->attrs is null, failed to save attributes");
12303 return MM_ERROR_PLAYER_INTERNAL;
12306 /* update video param */
12307 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12308 LOGE("failed to update video param");
12309 return MM_ERROR_PLAYER_INTERNAL;
12312 /* change state of videobin to READY */
12313 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12314 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12315 if (ret != GST_STATE_CHANGE_SUCCESS) {
12316 LOGE("failed to change state of videobin to READY");
12317 return MM_ERROR_PLAYER_INTERNAL;
12320 /* change ghostpad */
12321 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12322 if (!sink_pad_videosink) {
12323 LOGE("failed to get sink pad from videosink element");
12324 return MM_ERROR_PLAYER_INTERNAL;
12326 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12327 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12328 LOGE("failed to set active to ghost_pad");
12329 return MM_ERROR_PLAYER_INTERNAL;
12331 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12332 LOGE("failed to change ghostpad for videobin");
12333 return MM_ERROR_PLAYER_INTERNAL;
12335 gst_object_unref(sink_pad_videosink);
12337 /* link decoder with videobin */
12338 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12339 if (!sink_pad_videobin) {
12340 LOGE("failed to get sink pad from videobin");
12341 return MM_ERROR_PLAYER_INTERNAL;
12343 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12344 LOGE("failed to link");
12345 return MM_ERROR_PLAYER_INTERNAL;
12347 gst_object_unref(sink_pad_videobin);
12349 /* clock setting for a new videosink plugin */
12350 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12351 so we set it from audiosink plugin or pipeline(system clock) */
12352 if (!is_audiobin_created) {
12353 LOGW("audiobin is not created, get clock from pipeline..");
12354 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12356 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12360 GstClockTime base_time;
12361 LOGD("set the clock to videosink");
12362 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12363 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12365 LOGD("got clock of videosink");
12366 now = gst_clock_get_time(clock);
12367 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12368 LOGD("at time %" GST_TIME_FORMAT ", base %"
12369 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12371 LOGE("failed to get clock of videosink after setting clock");
12372 return MM_ERROR_PLAYER_INTERNAL;
12375 LOGW("failed to get clock, maybe it is the time before first playing");
12377 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12378 /* change state of videobin to PAUSED */
12379 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12380 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12381 if (ret != GST_STATE_CHANGE_FAILURE) {
12382 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12384 LOGE("failed to change state of videobin to PLAYING");
12385 return MM_ERROR_PLAYER_INTERNAL;
12388 /* release blocked and unref src pad of video decoder */
12390 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12391 LOGE("failed to set pad blocked FALSE(video)");
12392 return MM_ERROR_PLAYER_INTERNAL;
12395 LOGW("pad is unblocked(video)");
12397 if (player->doing_seek)
12398 LOGW("not completed seek(%d)", player->doing_seek);
12399 /* change state of videobin to PAUSED */
12400 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12401 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12402 if (ret != GST_STATE_CHANGE_FAILURE) {
12403 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12405 LOGE("failed to change state of videobin to PLAYING");
12406 return MM_ERROR_PLAYER_INTERNAL;
12409 /* already skipped pad block */
12410 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12413 /* do get/set position for new videosink plugin */
12415 unsigned long position = 0;
12416 gint64 pos_msec = 0;
12418 LOGD("do get/set position for new videosink plugin");
12419 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12420 LOGE("failed to get position");
12421 return MM_ERROR_PLAYER_INTERNAL;
12423 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12424 /* accurate seek */
12425 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12426 LOGE("failed to set position");
12427 return MM_ERROR_PLAYER_INTERNAL;
12430 /* key unit seek */
12431 pos_msec = position * G_GINT64_CONSTANT(1000000);
12432 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12433 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12434 GST_SEEK_TYPE_SET, pos_msec,
12435 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12437 LOGE("failed to set position");
12438 return MM_ERROR_PLAYER_INTERNAL;
12444 gst_object_unref(src_pad_dec);
12445 LOGD("success to change sink");
12449 return MM_ERROR_NONE;
12453 /* Note : if silent is true, then subtitle would not be displayed. :*/
12454 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12456 mm_player_t* player = (mm_player_t*) hplayer;
12460 /* check player handle */
12461 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12463 player->set_mode.subtitle_off = silent;
12465 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12469 return MM_ERROR_NONE;
12472 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12474 MMPlayerGstElement* mainbin = NULL;
12475 MMPlayerGstElement* textbin = NULL;
12476 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12477 GstState current_state = GST_STATE_VOID_PENDING;
12478 GstState element_state = GST_STATE_VOID_PENDING;
12479 GstState element_pending_state = GST_STATE_VOID_PENDING;
12481 GstEvent *event = NULL;
12482 int result = MM_ERROR_NONE;
12484 GstClock *curr_clock = NULL;
12485 GstClockTime base_time, start_time, curr_time;
12490 /* check player handle */
12491 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12492 player->pipeline &&
12493 player->pipeline->mainbin &&
12494 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12496 mainbin = player->pipeline->mainbin;
12497 textbin = player->pipeline->textbin;
12499 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12501 // sync clock with current pipeline
12502 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12503 curr_time = gst_clock_get_time(curr_clock);
12505 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12506 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12508 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12509 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12511 if (current_state > GST_STATE_READY) {
12512 // sync state with current pipeline
12513 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12514 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12515 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12517 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12518 if (GST_STATE_CHANGE_FAILURE == ret) {
12519 LOGE("fail to state change.\n");
12520 result = MM_ERROR_PLAYER_INTERNAL;
12525 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12526 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12529 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12530 gst_object_unref(curr_clock);
12533 // seek to current position
12534 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12535 result = MM_ERROR_PLAYER_INVALID_STATE;
12536 LOGE("gst_element_query_position failed, invalid state\n");
12540 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12541 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);
12543 __gst_send_event_to_sink(player, event);
12545 result = MM_ERROR_PLAYER_INTERNAL;
12546 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12550 /* sync state with current pipeline */
12551 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12552 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12553 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12555 return MM_ERROR_NONE;
12558 /* release text pipeline resource */
12559 player->textsink_linked = 0;
12561 /* release signal */
12562 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12564 /* release textbin with it's childs */
12565 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12566 MMPLAYER_FREEIF(player->pipeline->textbin);
12567 player->pipeline->textbin = NULL;
12569 /* release subtitle elem */
12570 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12571 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12577 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12579 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12580 GstState current_state = GST_STATE_VOID_PENDING;
12582 MMHandleType attrs = 0;
12583 MMPlayerGstElement* mainbin = NULL;
12584 MMPlayerGstElement* textbin = NULL;
12586 gchar* subtitle_uri = NULL;
12587 int result = MM_ERROR_NONE;
12588 const gchar *charset = NULL;
12592 /* check player handle */
12593 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12594 player->pipeline &&
12595 player->pipeline->mainbin &&
12596 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12597 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12599 mainbin = player->pipeline->mainbin;
12600 textbin = player->pipeline->textbin;
12602 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12603 if (current_state < GST_STATE_READY) {
12604 result = MM_ERROR_PLAYER_INVALID_STATE;
12605 LOGE("Pipeline is not in proper state\n");
12609 attrs = MMPLAYER_GET_ATTRS(player);
12611 LOGE("cannot get content attribute\n");
12612 result = MM_ERROR_PLAYER_INTERNAL;
12616 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12617 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12618 LOGE("subtitle uri is not proper filepath\n");
12619 result = MM_ERROR_PLAYER_INVALID_URI;
12623 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12624 LOGE("failed to get storage info of subtitle path");
12625 result = MM_ERROR_PLAYER_INVALID_URI;
12629 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12630 LOGD("new subtitle file path is [%s]\n", filepath);
12632 if (!strcmp(filepath, subtitle_uri)) {
12633 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12636 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12637 if (mmf_attrs_commit(player->attrs)) {
12638 LOGE("failed to commit.\n");
12643 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12644 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12645 player->subtitle_language_list = NULL;
12646 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12648 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12649 if (ret != GST_STATE_CHANGE_SUCCESS) {
12650 LOGE("failed to change state of textbin to READY");
12651 result = MM_ERROR_PLAYER_INTERNAL;
12655 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12656 if (ret != GST_STATE_CHANGE_SUCCESS) {
12657 LOGE("failed to change state of subparse to READY");
12658 result = MM_ERROR_PLAYER_INTERNAL;
12662 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12663 if (ret != GST_STATE_CHANGE_SUCCESS) {
12664 LOGE("failed to change state of filesrc to READY");
12665 result = MM_ERROR_PLAYER_INTERNAL;
12669 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12671 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12673 charset = util_get_charset(filepath);
12675 LOGD("detected charset is %s\n", charset);
12676 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12679 result = _mmplayer_sync_subtitle_pipeline(player);
12686 /* API to switch between external subtitles */
12687 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12689 int result = MM_ERROR_NONE;
12690 mm_player_t* player = (mm_player_t*)hplayer;
12695 /* check player handle */
12696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12698 /* filepath can be null in idle state */
12700 /* check file path */
12701 if ((path = strstr(filepath, "file://")))
12702 result = util_exist_file_path(path + 7);
12704 result = util_exist_file_path(filepath);
12706 if (result != MM_ERROR_NONE) {
12707 LOGE("invalid subtitle path 0x%X", result);
12708 return result; /* file not found or permission denied */
12712 if (!player->pipeline) {
12714 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12715 if (mmf_attrs_commit(player->attrs)) {
12716 LOGE("failed to commit"); /* subtitle path will not be created */
12717 return MM_ERROR_PLAYER_INTERNAL;
12720 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12721 /* check filepath */
12722 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12724 if (!__mmplayer_check_subtitle(player)) {
12725 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12726 if (mmf_attrs_commit(player->attrs)) {
12727 LOGE("failed to commit");
12728 return MM_ERROR_PLAYER_INTERNAL;
12731 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12732 LOGE("fail to create text pipeline");
12733 return MM_ERROR_PLAYER_INTERNAL;
12736 result = _mmplayer_sync_subtitle_pipeline(player);
12738 result = __mmplayer_change_external_subtitle_language(player, filepath);
12741 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12742 player->is_external_subtitle_added_now = TRUE;
12744 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12745 if (!player->subtitle_language_list) {
12746 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12747 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12748 LOGW("subtitle language list is not updated yet");
12750 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12758 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12760 int result = MM_ERROR_NONE;
12761 gchar* change_pad_name = NULL;
12762 GstPad* sinkpad = NULL;
12763 MMPlayerGstElement* mainbin = NULL;
12764 enum MainElementID elemId = MMPLAYER_M_NUM;
12765 GstCaps* caps = NULL;
12766 gint total_track_num = 0;
12770 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12771 MM_ERROR_PLAYER_NOT_INITIALIZED);
12773 LOGD("Change Track(%d) to %d\n", type, index);
12775 mainbin = player->pipeline->mainbin;
12777 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12778 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12779 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12780 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12782 /* Changing Video Track is not supported. */
12783 LOGE("Track Type Error\n");
12787 if (mainbin[elemId].gst == NULL) {
12788 result = MM_ERROR_PLAYER_NO_OP;
12789 LOGD("Req track doesn't exist\n");
12793 total_track_num = player->selector[type].total_track_num;
12794 if (total_track_num <= 0) {
12795 result = MM_ERROR_PLAYER_NO_OP;
12796 LOGD("Language list is not available \n");
12800 if ((index < 0) || (index >= total_track_num)) {
12801 result = MM_ERROR_INVALID_ARGUMENT;
12802 LOGD("Not a proper index : %d \n", index);
12806 /*To get the new pad from the selector*/
12807 change_pad_name = g_strdup_printf("sink_%u", index);
12808 if (change_pad_name == NULL) {
12809 result = MM_ERROR_PLAYER_INTERNAL;
12810 LOGD("Pad does not exists\n");
12814 LOGD("new active pad name: %s\n", change_pad_name);
12816 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12817 if (sinkpad == NULL) {
12818 LOGD("sinkpad is NULL");
12819 result = MM_ERROR_PLAYER_INTERNAL;
12823 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12824 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12826 caps = gst_pad_get_current_caps(sinkpad);
12827 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12830 gst_object_unref(sinkpad);
12832 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12833 __mmplayer_set_audio_attrs(player, caps);
12837 MMPLAYER_FREEIF(change_pad_name);
12841 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12843 int result = MM_ERROR_NONE;
12844 mm_player_t* player = NULL;
12845 MMPlayerGstElement* mainbin = NULL;
12847 gint current_active_index = 0;
12849 GstState current_state = GST_STATE_VOID_PENDING;
12850 GstEvent* event = NULL;
12855 player = (mm_player_t*)hplayer;
12856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12858 if (!player->pipeline) {
12859 LOGE("Track %d pre setting -> %d\n", type, index);
12861 player->selector[type].active_pad_index = index;
12865 mainbin = player->pipeline->mainbin;
12867 current_active_index = player->selector[type].active_pad_index;
12869 /*If index is same as running index no need to change the pad*/
12870 if (current_active_index == index)
12873 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12874 result = MM_ERROR_PLAYER_INVALID_STATE;
12878 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12879 if (current_state < GST_STATE_PAUSED) {
12880 result = MM_ERROR_PLAYER_INVALID_STATE;
12881 LOGW("Pipeline not in porper state\n");
12885 result = __mmplayer_change_selector_pad(player, type, index);
12886 if (result != MM_ERROR_NONE) {
12887 LOGE("change selector pad error\n");
12891 player->selector[type].active_pad_index = index;
12893 if (current_state == GST_STATE_PLAYING) {
12894 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);
12896 __gst_send_event_to_sink(player, event);
12898 result = MM_ERROR_PLAYER_INTERNAL;
12907 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12909 mm_player_t* player = (mm_player_t*) hplayer;
12913 /* check player handle */
12914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12916 *silent = player->set_mode.subtitle_off;
12918 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12922 return MM_ERROR_NONE;
12926 __is_ms_buff_src(mm_player_t* player)
12928 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12930 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12934 __has_suffix(mm_player_t* player, const gchar* suffix)
12936 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12937 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12939 gboolean ret = FALSE;
12940 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12941 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12943 if (g_str_has_suffix(player->profile.uri, suffix))
12946 MMPLAYER_FREEIF(t_url);
12947 MMPLAYER_FREEIF(t_suffix);
12953 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12955 mm_player_t* player = (mm_player_t*) hplayer;
12957 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12959 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12960 MMPLAYER_PRINT_STATE(player);
12961 LOGE("wrong-state : can't set the download mode to parse");
12962 return MM_ERROR_PLAYER_INVALID_STATE;
12965 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12966 player->video_hub_download_mode = mode;
12968 return MM_ERROR_NONE;
12972 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12974 mm_player_t* player = (mm_player_t*) hplayer;
12976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12978 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12979 player->sync_handler = enable;
12981 return MM_ERROR_NONE;
12985 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12987 long long clock_delta,
12988 long long video_time,
12989 long long media_clock,
12990 long long audio_time)
12992 mm_player_t* player = (mm_player_t*) hplayer;
12993 MMPlayerGstElement* mainbin = NULL;
12994 GstClockTime start_time_audio = 0, start_time_video = 0;
12995 GstClockTimeDiff base_time = 0, new_base_time = 0;
12996 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12997 gint64 api_delta = 0;
12998 gint64 position = 0, position_delta = 0;
12999 gint64 adj_base_time = 0;
13000 GstClock *curr_clock = NULL;
13001 GstClockTime curr_time = 0;
13002 gboolean query_ret = TRUE;
13003 int result = MM_ERROR_NONE;
13007 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13008 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13009 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13011 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13013 if ((video_time < 0) || (player->doing_seek)) {
13014 LOGD("skip setting master clock. %lld", video_time);
13018 mainbin = player->pipeline->mainbin;
13020 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13021 curr_time = gst_clock_get_time(curr_clock);
13023 current_state = MMPLAYER_CURRENT_STATE(player);
13025 if (current_state == MM_PLAYER_STATE_PLAYING)
13026 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13028 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13030 position = player->last_position;
13031 LOGD("query fail. %lld", position);
13034 clock *= GST_USECOND;
13035 clock_delta *= GST_USECOND;
13037 api_delta = clock - curr_time;
13038 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13039 player->video_share_api_delta = api_delta;
13041 clock_delta += (api_delta - player->video_share_api_delta);
13043 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13044 player->video_share_clock_delta = (gint64)clock_delta;
13046 position_delta = (position/GST_USECOND) - video_time;
13047 position_delta *= GST_USECOND;
13049 adj_base_time = position_delta;
13050 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13053 gint64 new_play_time = 0;
13054 gint64 network_delay = 0;
13056 video_time *= GST_USECOND;
13058 network_delay = clock_delta - player->video_share_clock_delta;
13059 new_play_time = video_time + network_delay;
13061 adj_base_time = position - new_play_time;
13063 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13064 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13067 /* Adjust Current Stream Time with base_time of sink
13068 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13069 * 2. Set new base time
13070 * if adj_base_time is positive value, the stream time will be decreased.
13071 * 3. If seek event is occurred, the start time will be reset. */
13072 if ((player->pipeline->audiobin) &&
13073 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13074 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13076 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13077 LOGD("audio sink : gst_element_set_start_time -> NONE");
13078 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13081 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13084 if ((player->pipeline->videobin) &&
13085 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13086 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13088 if (start_time_video != GST_CLOCK_TIME_NONE) {
13089 LOGD("video sink : gst_element_set_start_time -> NONE");
13090 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13093 // if videobin exist, get base_time from videobin.
13094 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13097 new_base_time = base_time + adj_base_time;
13099 if ((player->pipeline->audiobin) &&
13100 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13101 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13103 if ((player->pipeline->videobin) &&
13104 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13105 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13114 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13115 long long *video_time,
13116 long long *media_clock,
13117 long long *audio_time)
13119 mm_player_t* player = (mm_player_t*) hplayer;
13120 MMPlayerGstElement* mainbin = NULL;
13121 GstClock *curr_clock = NULL;
13122 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13123 gint64 position = 0;
13124 gboolean query_ret = TRUE;
13128 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13129 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13130 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13132 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13133 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13134 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13136 mainbin = player->pipeline->mainbin;
13138 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13140 current_state = MMPLAYER_CURRENT_STATE(player);
13142 if (current_state != MM_PLAYER_STATE_PAUSED)
13143 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13145 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13147 position = player->last_position;
13149 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13151 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13154 gst_object_unref(curr_clock);
13158 return MM_ERROR_NONE;
13162 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13164 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13165 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13167 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13168 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13172 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13173 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13174 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13175 mm_player_dump_t *dump_s;
13176 dump_s = g_malloc(sizeof(mm_player_dump_t));
13178 if (dump_s == NULL) {
13179 LOGE("malloc fail");
13183 dump_s->dump_element_file = NULL;
13184 dump_s->dump_pad = NULL;
13185 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13187 if (dump_s->dump_pad) {
13188 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13189 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]);
13190 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13191 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);
13192 /* add list for removed buffer probe and close FILE */
13193 player->dump_list = g_list_append(player->dump_list, dump_s);
13194 LOGD("%s sink pad added buffer probe for dump", factory_name);
13199 LOGE("failed to get %s sink pad added", factory_name);
13208 static GstPadProbeReturn
13209 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13211 FILE *dump_data = (FILE *) u_data;
13212 // int written = 0;
13213 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13214 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13216 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13218 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13220 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13222 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13224 return GST_PAD_PROBE_OK;
13228 __mmplayer_release_dump_list(GList *dump_list)
13231 GList *d_list = dump_list;
13232 for (; d_list; d_list = g_list_next(d_list)) {
13233 mm_player_dump_t *dump_s = d_list->data;
13234 if (dump_s->dump_pad) {
13235 if (dump_s->probe_handle_id)
13236 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13238 if (dump_s->dump_element_file) {
13239 fclose(dump_s->dump_element_file);
13240 dump_s->dump_element_file = NULL;
13242 MMPLAYER_FREEIF(dump_s);
13244 g_list_free(dump_list);
13250 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13252 mm_player_t* player = (mm_player_t*) hplayer;
13256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13257 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13259 *exist = player->has_closed_caption;
13263 return MM_ERROR_NONE;
13266 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13270 // LOGD("unref internal gst buffer %p", buffer);
13271 gst_buffer_unref((GstBuffer *)buffer);
13278 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13280 mm_player_t *player = (mm_player_t*)user_data;
13281 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13282 guint64 current_level_bytes = 0;
13284 MMPLAYER_RETURN_IF_FAIL(player);
13286 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13288 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13289 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13291 if (player->media_stream_buffer_status_cb[type])
13292 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13293 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13298 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13300 mm_player_t *player = (mm_player_t*)user_data;
13301 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13302 guint64 current_level_bytes = 0;
13304 MMPLAYER_RETURN_IF_FAIL(player);
13306 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13308 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13310 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13311 if (player->media_stream_buffer_status_cb[type])
13312 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13313 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13317 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13319 mm_player_t *player = (mm_player_t*)user_data;
13320 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13321 guint64 current_level_bytes = 0;
13323 MMPLAYER_RETURN_IF_FAIL(player);
13325 LOGI("app-src: feed subtitle\n");
13327 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13329 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13330 if (player->media_stream_buffer_status_cb[type])
13331 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13333 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13337 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13339 mm_player_t *player = (mm_player_t*)user_data;
13340 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13341 guint64 current_level_bytes = 0;
13343 MMPLAYER_RETURN_IF_FAIL(player);
13345 LOGI("app-src: audio buffer is full.\n");
13347 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13349 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13351 if (player->media_stream_buffer_status_cb[type])
13352 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13354 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13358 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13360 mm_player_t *player = (mm_player_t*)user_data;
13361 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13362 guint64 current_level_bytes = 0;
13364 MMPLAYER_RETURN_IF_FAIL(player);
13366 LOGI("app-src: video buffer is full.\n");
13368 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13370 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13371 if (player->media_stream_buffer_status_cb[type])
13372 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13374 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13378 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13380 mm_player_t *player = (mm_player_t*)user_data;
13381 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13383 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13385 LOGD("app-src: seek audio data %llu\n", position);
13386 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13388 if (player->media_stream_seek_data_cb[type])
13389 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13390 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13396 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13398 mm_player_t *player = (mm_player_t*)user_data;
13399 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13401 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13403 LOGD("app-src: seek video data %llu\n", position);
13404 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13405 if (player->media_stream_seek_data_cb[type])
13406 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13407 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13413 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13415 mm_player_t *player = (mm_player_t*)user_data;
13416 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13418 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13420 LOGD("app-src: seek subtitle data\n");
13421 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13423 if (player->media_stream_seek_data_cb[type])
13424 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13425 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13431 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13433 mm_player_t* player = (mm_player_t*) hplayer;
13437 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13439 player->pcm_samplerate = samplerate;
13440 player->pcm_channel = channel;
13443 return MM_ERROR_NONE;
13446 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13448 mm_player_t* player = (mm_player_t*) hplayer;
13452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13453 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13455 if (MMPLAYER_IS_STREAMING(player))
13456 *timeout = player->ini.live_state_change_timeout;
13458 *timeout = player->ini.localplayback_state_change_timeout;
13460 LOGD("timeout = %d\n", *timeout);
13463 return MM_ERROR_NONE;
13466 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13468 mm_player_t* player = (mm_player_t*) hplayer;
13472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13473 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13475 *num = player->video_num_buffers;
13476 *extra_num = player->video_extra_num_buffers;
13478 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13481 return MM_ERROR_NONE;
13485 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13489 MMPLAYER_RETURN_IF_FAIL(player);
13491 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13493 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13494 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13495 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13496 player->storage_info[i].id = -1;
13497 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13499 if (path_type != MMPLAYER_PATH_MAX)
13507 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13509 int ret = MM_ERROR_NONE;
13510 mm_player_t* player = (mm_player_t*)hplayer;
13511 MMMessageParamType msg_param = {0, };
13514 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13516 LOGW("state changed storage %d:%d", id, state);
13518 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13519 return MM_ERROR_NONE;
13521 /* FIXME: text path should be handled seperately. */
13522 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13523 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13524 LOGW("external storage is removed");
13526 if (player->msg_posted == FALSE) {
13527 memset(&msg_param, 0, sizeof(MMMessageParamType));
13528 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13529 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13530 player->msg_posted = TRUE;
13533 /* unrealize the player */
13534 ret = _mmplayer_unrealize(hplayer);
13535 if (ret != MM_ERROR_NONE)
13536 LOGE("failed to unrealize");
13543 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13545 int ret = MM_ERROR_NONE;
13546 mm_player_t* player = (mm_player_t*) hplayer;
13547 int idx = 0, total = 0;
13548 gchar *result = NULL, *tmp = NULL;
13551 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13552 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13554 total = *num = g_list_length(player->adaptive_info.var_list);
13556 LOGW("There is no stream variant info.");
13560 result = g_strdup("");
13561 for (idx = 0 ; idx < total ; idx++) {
13562 VariantData *v_data = NULL;
13563 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13566 gchar data[64] = {0};
13567 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13569 tmp = g_strconcat(result, data, NULL);
13573 LOGW("There is no variant data in %d", idx);
13578 *var_info = (char *)result;
13580 LOGD("variant info %d:%s", *num, *var_info);
13585 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13587 int ret = MM_ERROR_NONE;
13588 mm_player_t* player = (mm_player_t*) hplayer;
13591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13593 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13595 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13596 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13597 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13599 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13600 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13601 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13602 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13604 /* FIXME: seek to current position for applying new variant limitation */
13612 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13614 int ret = MM_ERROR_NONE;
13615 mm_player_t* player = (mm_player_t*) hplayer;
13618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13619 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13621 *bandwidth = player->adaptive_info.limit.bandwidth;
13622 *width = player->adaptive_info.limit.width;
13623 *height = player->adaptive_info.limit.height;
13625 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13631 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13633 int ret = MM_ERROR_NONE;
13634 mm_player_t* player = (mm_player_t*) hplayer;
13637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13639 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13640 LOGW("buffer_ms will not be applied.");
13643 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13645 if (player->streamer == NULL) {
13646 player->streamer = __mm_player_streaming_create();
13647 __mm_player_streaming_initialize(player->streamer);
13650 if (buffer_ms >= 0)
13651 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13653 if (rebuffer_ms >= 0)
13654 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13661 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13663 int ret = MM_ERROR_NONE;
13664 mm_player_t* player = (mm_player_t*) hplayer;
13667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13668 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13670 if (player->streamer == NULL) {
13671 player->streamer = __mm_player_streaming_create();
13672 __mm_player_streaming_initialize(player->streamer);
13675 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13676 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13678 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13684 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13686 #define IDX_FIRST_SW_CODEC 0
13687 mm_player_t* player = (mm_player_t*) hplayer;
13688 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13689 MMHandleType attrs = 0;
13692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13694 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13695 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13696 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13698 switch (stream_type) {
13699 case MM_PLAYER_STREAM_TYPE_AUDIO:
13700 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13701 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13702 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13703 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13704 LOGE("There is no a codec for codec_type %d", codec_type);
13705 return MM_ERROR_PLAYER_NO_OP;
13708 case MM_PLAYER_STREAM_TYPE_VIDEO:
13709 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13710 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13711 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13712 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13713 LOGE("There is no v codec for codec_type %d", codec_type);
13714 return MM_ERROR_PLAYER_NO_OP;
13719 LOGE("Invalid stream type %d", stream_type);
13720 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13724 LOGD("update %s codec_type to %d", attr_name, codec_type);
13726 attrs = MMPLAYER_GET_ATTRS(player);
13727 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13729 if (mmf_attrs_commit(player->attrs)) {
13730 LOGE("failed to commit codec_type attributes");
13731 return MM_ERROR_PLAYER_INTERNAL;
13735 return MM_ERROR_NONE;
13739 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13741 mm_player_t* player = (mm_player_t*) hplayer;
13742 GstElement* rg_vol_element = NULL;
13746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13748 player->sound.rg_enable = enabled;
13750 /* just hold rgvolume enable value if pipeline is not ready */
13751 if (!player->pipeline || !player->pipeline->audiobin) {
13752 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13753 return MM_ERROR_NONE;
13756 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13758 if (!rg_vol_element) {
13759 LOGD("rgvolume element is not created");
13760 return MM_ERROR_PLAYER_INTERNAL;
13764 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13766 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13770 return MM_ERROR_NONE;
13774 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13776 mm_player_t* player = (mm_player_t*) hplayer;
13777 GstElement* rg_vol_element = NULL;
13778 gboolean enable = FALSE;
13782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13783 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13785 /* just hold enable_rg value if pipeline is not ready */
13786 if (!player->pipeline || !player->pipeline->audiobin) {
13787 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13788 *enabled = player->sound.rg_enable;
13789 return MM_ERROR_NONE;
13792 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13794 if (!rg_vol_element) {
13795 LOGD("rgvolume element is not created");
13796 return MM_ERROR_PLAYER_INTERNAL;
13799 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13804 return MM_ERROR_NONE;