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/wayland/wayland.h>
33 #include <gst/audio/gstaudiobasesink.h>
43 #include <mm_attrs_private.h>
45 #include <mm_sound_focus.h>
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
54 #include <system_info.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
86 #define MM_PLAYER_MPEG_VNAME "mpegversion"
87 #define MM_PLAYER_DIVX_VNAME "divxversion"
88 #define MM_PLAYER_WMV_VNAME "wmvversion"
89 #define MM_PLAYER_WMA_VNAME "wmaversion"
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
93 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
94 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
95 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
96 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
98 #define GST_QUEUE_DEFAULT_TIME 4
99 #define GST_QUEUE_HLS_TIME 8
101 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
102 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
103 (player->ini.http_use_file_buffer) && \
104 (player->http_file_buffering_path) && \
105 (strlen(player->http_file_buffering_path) > 0))
106 #define MM_PLAYER_NAME "mmplayer"
108 #define PLAYER_DISPLAY_MODE_DST_ROI 5
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | GLOBAL VARIABLE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
122 /*---------------------------------------------------------------------------
123 | LOCAL VARIABLE DEFINITIONS: |
124 ---------------------------------------------------------------------------*/
126 /*---------------------------------------------------------------------------
127 | LOCAL FUNCTION PROTOTYPES: |
128 ---------------------------------------------------------------------------*/
129 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
131 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
132 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
133 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
137 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
138 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
139 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
140 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
141 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
142 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
143 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
144 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
148 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
149 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
151 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
152 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
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);
157 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
159 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
160 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
161 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
163 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
164 //static void __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
165 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
166 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
167 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
170 static void __mmplayer_init_factories(mm_player_t* player);
171 static void __mmplayer_release_factories(mm_player_t* player);
172 static void __mmplayer_release_misc(mm_player_t* player);
173 static void __mmplayer_release_misc_post(mm_player_t* player);
174 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
175 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
176 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
178 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
179 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
181 int __mmplayer_switch_audio_sink(mm_player_t* player);
182 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
183 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
184 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
185 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
186 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
187 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
189 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
190 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
191 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
192 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
193 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
194 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
195 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
196 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
197 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
198 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
199 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
200 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
201 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
202 static gpointer __mmplayer_next_play_thread(gpointer data);
203 static gpointer __mmplayer_repeat_thread(gpointer data);
204 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
207 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
208 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
209 static void __mmplayer_release_dump_list(GList *dump_list);
211 static int __gst_realize(mm_player_t* player);
212 static int __gst_unrealize(mm_player_t* player);
213 static int __gst_start(mm_player_t* player);
214 static int __gst_stop(mm_player_t* player);
215 static int __gst_pause(mm_player_t* player, gboolean async);
216 static int __gst_resume(mm_player_t* player, gboolean async);
217 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
218 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
219 gint64 cur, GstSeekType stop_type, gint64 stop);
220 static int __gst_pending_seek(mm_player_t* player);
222 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
223 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
224 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
225 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
226 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
228 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
230 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
231 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
234 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
235 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
237 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
238 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
241 static gboolean __is_ms_buff_src(mm_player_t* player);
242 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
244 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
245 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
246 static int __mmplayer_start_streaming_ext(mm_player_t *player);
247 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
248 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
250 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
251 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
252 static void __mmplayer_check_pipeline(mm_player_t* player);
253 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
254 static void __mmplayer_deactivate_old_path(mm_player_t *player);
255 #if 0 // We'll need this in future.
256 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
259 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
260 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
262 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
263 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
264 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
265 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
266 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
267 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
268 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
269 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
270 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
271 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
272 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
273 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
274 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
276 /*===========================================================================================
278 | FUNCTION DEFINITIONS |
280 ========================================================================================== */
284 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
288 count = gst_tag_list_get_tag_size(list, tag);
290 LOGD("count = %d", count);
292 for (i = 0; i < count; i++) {
295 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
296 if (!gst_tag_list_get_string_index(list, tag, i, &str))
297 g_assert_not_reached();
299 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
302 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
304 g_print(" : %s\n", str);
311 /* This function should be called after the pipeline goes PAUSED or higher
314 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
316 static gboolean has_duration = FALSE;
317 static gboolean has_video_attrs = FALSE;
318 static gboolean has_audio_attrs = FALSE;
319 static gboolean has_bitrate = FALSE;
320 gboolean missing_only = FALSE;
321 gboolean all = FALSE;
323 GstStructure* p = NULL;
324 MMHandleType attrs = 0;
326 gint stream_service_type = STREAMING_SERVICE_NONE;
331 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
333 /* check player state here */
334 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
335 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
336 /* give warning now only */
337 LOGW("be careful. content attributes may not available in this state ");
340 /* get content attribute first */
341 attrs = MMPLAYER_GET_ATTRS(player);
343 LOGE("cannot get content attribute");
347 /* get update flag */
349 if (flag & ATTR_MISSING_ONLY) {
351 LOGD("updating missed attr only");
354 if (flag & ATTR_ALL) {
356 has_duration = FALSE;
357 has_video_attrs = FALSE;
358 has_audio_attrs = FALSE;
361 LOGD("updating all attrs");
364 if (missing_only && all) {
365 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
366 missing_only = FALSE;
369 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
370 LOGD("try to update duration");
371 has_duration = FALSE;
373 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
374 player->duration = dur_nsec;
375 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
378 if (player->duration < 0) {
379 LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
380 player->duration = 0;
383 /* try to get streaming service type */
384 stream_service_type = __mmplayer_get_stream_service_type(player);
385 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
387 /* check duration is OK */
388 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
389 /* FIXIT : find another way to get duration here. */
390 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
393 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
398 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
399 /* update audio params
400 NOTE : We need original audio params and it can be only obtained from src pad of audio
401 decoder. Below code only valid when we are not using 'resampler' just before
404 LOGD("try to update audio attrs");
405 has_audio_attrs = FALSE;
407 if (player->pipeline->audiobin &&
408 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
409 GstCaps *caps_a = NULL;
411 gint samplerate = 0, channels = 0;
413 pad = gst_element_get_static_pad(
414 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
417 caps_a = gst_pad_get_current_caps(pad);
420 p = gst_caps_get_structure(caps_a, 0);
422 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
424 gst_structure_get_int(p, "rate", &samplerate);
425 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
427 gst_structure_get_int(p, "channels", &channels);
428 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
430 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
432 gst_caps_unref(caps_a);
435 has_audio_attrs = TRUE;
437 LOGW("not ready to get audio caps");
439 gst_object_unref(pad);
441 LOGW("failed to get pad from audiosink");
445 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
446 LOGD("try to update video attrs");
447 has_video_attrs = FALSE;
449 if (player->pipeline->videobin &&
450 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
451 GstCaps *caps_v = NULL;
456 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
458 caps_v = gst_pad_get_current_caps(pad);
460 /* Use v_stream_caps, if fail to get video_sink sink pad*/
461 if (!caps_v && player->v_stream_caps) {
462 caps_v = player->v_stream_caps;
463 gst_caps_ref(caps_v);
467 p = gst_caps_get_structure(caps_v, 0);
468 gst_structure_get_int(p, "width", &width);
469 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
471 gst_structure_get_int(p, "height", &height);
472 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
474 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
476 SECURE_LOGD("width : %d height : %d", width, height);
478 gst_caps_unref(caps_v);
482 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
483 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
486 has_video_attrs = TRUE;
488 LOGD("no negitiated caps from videosink");
489 gst_object_unref(pad);
492 LOGD("no videosink sink pad");
497 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
500 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
501 if (player->duration) {
502 guint64 data_size = 0;
504 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
505 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
507 if (stat(path, &sb) == 0)
508 data_size = (guint64)sb.st_size;
509 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
510 data_size = player->http_content_size;
511 LOGD("try to update bitrate : data_size = %lld", data_size);
515 guint64 msec_dur = 0;
517 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
518 bitrate = data_size * 8 * 1000 / msec_dur;
519 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
520 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
525 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
526 if (player->total_bitrate) {
527 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
535 if (mmf_attrs_commit(attrs)) {
536 LOGE("failed to update attributes\n");
545 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
547 gint streaming_type = STREAMING_SERVICE_NONE;
551 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
553 player->pipeline->mainbin &&
554 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
557 /* streaming service type if streaming */
558 if (!MMPLAYER_IS_STREAMING(player))
559 return STREAMING_SERVICE_NONE;
561 if (MMPLAYER_IS_HTTP_STREAMING(player))
562 streaming_type = (player->duration == 0) ?
563 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
565 switch (streaming_type) {
566 case STREAMING_SERVICE_LIVE:
567 LOGD("it's live streaming");
569 case STREAMING_SERVICE_VOD:
570 LOGD("it's vod streaming");
573 LOGE("should not get here");
576 player->streaming_type = streaming_type;
579 return streaming_type;
583 /* this function sets the player state and also report
584 * it to applicaton by calling callback function
587 __mmplayer_set_state(mm_player_t* player, int state) // @
589 MMMessageParamType msg = {0, };
590 int sound_result = MM_ERROR_NONE;
591 gboolean post_bos = FALSE;
592 gboolean interrupted_by_focus = FALSE;
593 gboolean interrupted_by_resource = FALSE;
594 int ret = MM_ERROR_NONE;
596 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
598 if (MMPLAYER_CURRENT_STATE(player) == state) {
599 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
600 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
604 /* update player states */
605 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
606 MMPLAYER_CURRENT_STATE(player) = state;
608 /* FIXIT : it's better to do like below code
609 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
610 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
611 and add more code to handling PENDING_STATE.
613 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
614 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
617 MMPLAYER_PRINT_STATE(player);
619 /* do some FSM stuffs before posting new state to application */
620 interrupted_by_focus = player->sound_focus.by_asm_cb;
621 interrupted_by_resource = player->resource_manager.by_rm_cb;
623 switch (MMPLAYER_CURRENT_STATE(player)) {
624 case MM_PLAYER_STATE_NULL:
625 case MM_PLAYER_STATE_READY:
627 if (player->cmd == MMPLAYER_COMMAND_STOP) {
628 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
629 if (sound_result != MM_ERROR_NONE) {
630 LOGE("failed to release sound focus\n");
631 return MM_ERROR_POLICY_INTERNAL;
637 case MM_PLAYER_STATE_PAUSED:
639 if (!player->sent_bos) {
641 #define MMPLAYER_MAX_SOUND_PRIORITY 3
643 /* rtsp case, get content attrs by GstMessage */
644 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
645 /* it's first time to update all content attrs. */
646 _mmplayer_update_content_attrs( player, ATTR_ALL );
649 /* set max sound priority to keep own sound and not to mute other's one */
650 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
652 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
654 LOGD("set max audio priority");
655 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
661 /* add audio callback probe if condition is satisfied */
662 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
663 __mmplayer_configure_audio_callback(player);
664 /* FIXIT : handle return value */
666 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
667 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
668 if (sound_result != MM_ERROR_NONE) {
669 LOGE("failed to release sound focus\n");
670 return MM_ERROR_POLICY_INTERNAL;
676 case MM_PLAYER_STATE_PLAYING:
678 /* try to get content metadata */
679 if (!player->sent_bos) {
680 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
681 * c-api since c-api doesn't use _start() anymore. It may not work propery with
682 * legacy mmfw-player api */
683 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
686 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
687 if (!player->sent_bos)
688 __mmplayer_handle_missed_plugin(player);
689 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
690 if (sound_result != MM_ERROR_NONE) {
691 // FIXME : need to check history
692 if (player->pipeline->videobin) {
693 MMMessageParamType msg = {0, };
695 LOGE("failed to go ahead because of video conflict\n");
697 msg.union_type = MM_MSG_UNION_CODE;
698 msg.code = MM_ERROR_POLICY_INTERRUPTED;
699 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
701 _mmplayer_unrealize((MMHandleType)player);
703 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
704 _mmplayer_pause((MMHandleType)player);
708 return MM_ERROR_POLICY_INTERNAL;
712 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
713 /* initialize because auto resume is done well. */
714 player->resumed_by_rewind = FALSE;
715 player->playback_rate = 1.0;
718 if (!player->sent_bos) {
719 /* check audio codec field is set or not
720 * we can get it from typefinder or codec's caps.
722 gchar *audio_codec = NULL;
723 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
725 /* The codec format can't be sent for audio only case like amr, mid etc.
726 * Because, parser don't make related TAG.
727 * So, if it's not set yet, fill it with found data.
730 if (g_strrstr(player->type, "audio/midi"))
731 audio_codec = g_strdup("MIDI");
732 else if (g_strrstr(player->type, "audio/x-amr"))
733 audio_codec = g_strdup("AMR");
734 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
735 audio_codec = g_strdup("AAC");
737 audio_codec = g_strdup("unknown");
738 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
740 MMPLAYER_FREEIF(audio_codec);
741 mmf_attrs_commit(player->attrs);
742 LOGD("set audio codec type with caps\n");
750 case MM_PLAYER_STATE_NONE:
752 LOGW("invalid target state, there is nothing to do.\n");
757 /* post message to application */
758 if (MMPLAYER_TARGET_STATE(player) == state) {
759 /* fill the message with state of player */
760 msg.state.previous = MMPLAYER_PREV_STATE(player);
761 msg.state.current = MMPLAYER_CURRENT_STATE(player);
763 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
765 /* state changed by focus or resource callback */
766 if (interrupted_by_focus || interrupted_by_resource) {
767 msg.union_type = MM_MSG_UNION_CODE;
768 if (interrupted_by_focus)
769 msg.code = player->sound_focus.focus_changed_msg;
770 else if (interrupted_by_resource)
771 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
772 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
773 } else /* state changed by usecase */
774 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
776 LOGD("intermediate state, do nothing.\n");
777 MMPLAYER_PRINT_STATE(player);
782 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
783 player->sent_bos = TRUE;
789 static gpointer __mmplayer_next_play_thread(gpointer data)
791 mm_player_t* player = (mm_player_t*) data;
792 MMPlayerGstElement *mainbin = NULL;
794 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
796 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
797 while (!player->next_play_thread_exit) {
798 LOGD("next play thread started. waiting for signal.\n");
799 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
801 LOGD("reconfigure pipeline for gapless play.\n");
803 if (player->next_play_thread_exit) {
804 if (player->gapless.reconfigure) {
805 player->gapless.reconfigure = false;
806 MMPLAYER_PLAYBACK_UNLOCK(player);
808 LOGD("exiting gapless play thread\n");
812 mainbin = player->pipeline->mainbin;
814 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
815 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
816 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
817 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
818 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
820 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
822 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
827 static gpointer __mmplayer_repeat_thread(gpointer data)
829 mm_player_t* player = (mm_player_t*) data;
830 gboolean ret_value = FALSE;
831 MMHandleType attrs = 0;
834 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
836 MMPLAYER_REPEAT_THREAD_LOCK(player);
837 while (!player->repeat_thread_exit) {
838 LOGD("repeat thread started. waiting for signal.\n");
839 MMPLAYER_REPEAT_THREAD_WAIT(player);
841 if (player->repeat_thread_exit) {
842 LOGD("exiting repeat thread\n");
848 MMPLAYER_CMD_LOCK(player);
850 attrs = MMPLAYER_GET_ATTRS(player);
852 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
853 LOGE("can not get play count\n");
854 MMPLAYER_CMD_UNLOCK(player);
858 if (player->section_repeat) {
859 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
861 if (player->playback_rate < 0.0) {
862 player->resumed_by_rewind = TRUE;
863 _mmplayer_set_mute((MMHandleType)player, 0);
864 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
867 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
868 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
869 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
872 player->sent_bos = FALSE;
876 LOGE("failed to set position to zero for rewind\n");
877 MMPLAYER_CMD_UNLOCK(player);
881 /* decrease play count */
883 /* we successeded to rewind. update play count and then wait for next EOS */
886 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
888 /* commit attribute */
889 if (mmf_attrs_commit(attrs))
890 LOGE("failed to commit attribute\n");
894 MMPLAYER_CMD_UNLOCK(player);
897 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
902 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
904 MMHandleType attrs = 0;
905 guint64 data_size = 0;
907 unsigned long pos_msec = 0;
910 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
912 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
914 attrs = MMPLAYER_GET_ATTRS(player);
916 LOGE("fail to get attributes.\n");
920 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
921 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
923 if (stat(path, &sb) == 0)
924 data_size = (guint64)sb.st_size;
925 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
926 data_size = player->http_content_size;
928 __mm_player_streaming_buffering(player->streamer,
931 player->last_position,
934 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
940 __mmplayer_handle_buffering_message(mm_player_t* player)
942 int ret = MM_ERROR_NONE;
943 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
944 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
945 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
946 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
948 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
949 LOGW("do nothing for buffering msg\n");
950 ret = MM_ERROR_PLAYER_INVALID_STATE;
954 prev_state = MMPLAYER_PREV_STATE(player);
955 current_state = MMPLAYER_CURRENT_STATE(player);
956 target_state = MMPLAYER_TARGET_STATE(player);
957 pending_state = MMPLAYER_PENDING_STATE(player);
959 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
960 MMPLAYER_STATE_GET_NAME(prev_state),
961 MMPLAYER_STATE_GET_NAME(current_state),
962 MMPLAYER_STATE_GET_NAME(pending_state),
963 MMPLAYER_STATE_GET_NAME(target_state),
964 player->streamer->is_buffering);
966 if (!player->streamer->is_buffering) {
967 /* NOTE : if buffering has done, player has to go to target state. */
968 switch (target_state) {
969 case MM_PLAYER_STATE_PAUSED:
971 switch (pending_state) {
972 case MM_PLAYER_STATE_PLAYING:
973 __gst_pause(player, TRUE);
976 case MM_PLAYER_STATE_PAUSED:
977 LOGD("player is already going to paused state, there is nothing to do.\n");
980 case MM_PLAYER_STATE_NONE:
981 case MM_PLAYER_STATE_NULL:
982 case MM_PLAYER_STATE_READY:
984 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
990 case MM_PLAYER_STATE_PLAYING:
992 switch (pending_state) {
993 case MM_PLAYER_STATE_NONE:
995 if (current_state != MM_PLAYER_STATE_PLAYING)
996 __gst_resume(player, TRUE);
1000 case MM_PLAYER_STATE_PAUSED:
1001 /* NOTE: It should be worked as asynchronously.
1002 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1004 __gst_resume(player, TRUE);
1007 case MM_PLAYER_STATE_PLAYING:
1008 LOGD("player is already going to playing state, there is nothing to do.\n");
1011 case MM_PLAYER_STATE_NULL:
1012 case MM_PLAYER_STATE_READY:
1014 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1020 case MM_PLAYER_STATE_NULL:
1021 case MM_PLAYER_STATE_READY:
1022 case MM_PLAYER_STATE_NONE:
1024 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1028 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1029 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1031 switch (pending_state) {
1032 case MM_PLAYER_STATE_NONE:
1034 if (current_state != MM_PLAYER_STATE_PAUSED) {
1035 /* rtsp streaming pause makes rtsp server stop sending data. */
1036 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1037 LOGD("set pause state during buffering\n");
1038 __gst_pause( player, TRUE );
1044 case MM_PLAYER_STATE_PLAYING:
1045 /* rtsp streaming pause makes rtsp server stop sending data. */
1046 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1047 __gst_pause ( player, TRUE );
1051 case MM_PLAYER_STATE_PAUSED:
1054 case MM_PLAYER_STATE_NULL:
1055 case MM_PLAYER_STATE_READY:
1057 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1067 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1069 MMPlayerGstElement *textbin;
1072 MMPLAYER_RETURN_IF_FAIL(player &&
1074 player->pipeline->textbin);
1076 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1078 textbin = player->pipeline->textbin;
1081 LOGD("Drop subtitle text after getting EOS\n");
1083 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1084 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1086 player->is_subtitle_force_drop = TRUE;
1088 if (player->is_subtitle_force_drop == TRUE) {
1089 LOGD("Enable subtitle data path without drop\n");
1091 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1092 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1094 LOGD("non-connected with external display");
1096 player->is_subtitle_force_drop = FALSE;
1102 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1104 mm_player_t* player = (mm_player_t*) data;
1105 gboolean ret = TRUE;
1106 static gboolean async_done = FALSE;
1108 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1109 MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1111 switch (GST_MESSAGE_TYPE(msg)) {
1112 case GST_MESSAGE_UNKNOWN:
1113 LOGD("unknown message received\n");
1116 case GST_MESSAGE_EOS:
1118 MMHandleType attrs = 0;
1121 LOGD("GST_MESSAGE_EOS received\n");
1123 /* NOTE : EOS event is comming multiple time. watch out it */
1124 /* check state. we only process EOS when pipeline state goes to PLAYING */
1125 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1126 LOGD("EOS received on non-playing state. ignoring it\n");
1130 if (player->pipeline) {
1131 if (player->pipeline->textbin)
1132 __mmplayer_drop_subtitle(player, TRUE);
1134 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1137 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1139 LOGD("release audio callback\n");
1141 /* release audio callback */
1142 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1143 player->audio_cb_probe_id = 0;
1144 /* audio callback should be free because it can be called even though probe remove.*/
1145 player->audio_stream_cb = NULL;
1146 player->audio_stream_cb_user_param = NULL;
1150 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1151 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1153 /* rewind if repeat count is greater then zero */
1154 /* get play count */
1155 attrs = MMPLAYER_GET_ATTRS(player);
1158 gboolean smooth_repeat = FALSE;
1160 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1161 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1163 player->play_count = count;
1165 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1167 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1168 if (smooth_repeat) {
1169 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1171 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1177 if (player->section_repeat) {
1178 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1180 if (player->playback_rate < 0.0) {
1181 player->resumed_by_rewind = TRUE;
1182 _mmplayer_set_mute((MMHandleType)player, 0);
1183 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1186 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1189 player->sent_bos = FALSE;
1192 if (MM_ERROR_NONE != ret_value)
1193 LOGE("failed to set position to zero for rewind\n");
1195 /* not posting eos when repeating */
1201 if (player->pipeline)
1202 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1204 /* post eos message to application */
1205 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1207 /* reset last position */
1208 player->last_position = 0;
1212 case GST_MESSAGE_ERROR:
1214 GError *error = NULL;
1215 gchar* debug = NULL;
1217 /* generating debug info before returning error */
1218 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1220 /* get error code */
1221 gst_message_parse_error(msg, &error, &debug);
1223 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1224 /* Note : the streaming error from the streaming source is handled
1225 * using __mmplayer_handle_streaming_error.
1227 __mmplayer_handle_streaming_error(player, msg);
1229 /* dump state of all element */
1230 __mmplayer_dump_pipeline_state(player);
1232 /* traslate gst error code to msl error code. then post it
1233 * to application if needed
1235 __mmplayer_handle_gst_error(player, msg, error);
1238 LOGE("error debug : %s", debug);
1241 if (MMPLAYER_IS_HTTP_PD(player))
1242 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1244 MMPLAYER_FREEIF(debug);
1245 g_error_free(error);
1249 case GST_MESSAGE_WARNING:
1252 GError* error = NULL;
1254 gst_message_parse_warning(msg, &error, &debug);
1256 LOGD("warning : %s\n", error->message);
1257 LOGD("debug : %s\n", debug);
1259 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1261 MMPLAYER_FREEIF(debug);
1262 g_error_free(error);
1266 case GST_MESSAGE_TAG:
1268 LOGD("GST_MESSAGE_TAG\n");
1269 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1270 LOGW("failed to extract tags from gstmessage\n");
1274 case GST_MESSAGE_BUFFERING:
1276 MMMessageParamType msg_param = {0, };
1277 int bRet = MM_ERROR_NONE;
1279 if (!MMPLAYER_IS_STREAMING(player))
1282 /* ignore the prev buffering message */
1283 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1284 gint buffer_percent = 0;
1286 gst_message_parse_buffering(msg, &buffer_percent);
1288 if (buffer_percent == MAX_BUFFER_PERCENT) {
1289 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1290 player->streamer->is_buffering_done = FALSE;
1296 MMPLAYER_CMD_LOCK(player);
1297 __mmplayer_update_buffer_setting(player, msg);
1299 bRet = __mmplayer_handle_buffering_message(player);
1301 if (bRet == MM_ERROR_NONE) {
1302 msg_param.connection.buffering = player->streamer->buffering_percent;
1303 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1305 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1306 player->pending_resume &&
1307 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1309 player->is_external_subtitle_added_now = FALSE;
1310 player->pending_resume = FALSE;
1311 _mmplayer_resume((MMHandleType)player);
1314 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1315 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1317 if (player->doing_seek) {
1318 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1319 player->doing_seek = FALSE;
1320 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1321 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1326 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1327 if (!player->streamer) {
1328 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1329 MMPLAYER_CMD_UNLOCK(player);
1333 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1335 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1336 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1338 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1339 msg_param.connection.buffering = player->streamer->buffering_percent;
1340 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1342 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1345 msg_param.connection.buffering = player->streamer->buffering_percent;
1346 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1349 MMPLAYER_CMD_UNLOCK(player);
1353 case GST_MESSAGE_STATE_CHANGED:
1355 MMPlayerGstElement *mainbin;
1356 const GValue *voldstate, *vnewstate, *vpending;
1357 GstState oldstate = GST_STATE_NULL;
1358 GstState newstate = GST_STATE_NULL;
1359 GstState pending = GST_STATE_NULL;
1361 if (!(player->pipeline && player->pipeline->mainbin)) {
1362 LOGE("player pipeline handle is null");
1366 mainbin = player->pipeline->mainbin;
1368 /* we only handle messages from pipeline */
1369 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1372 /* get state info from msg */
1373 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1374 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1375 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1377 if (!voldstate || !vnewstate) {
1378 LOGE("received msg has wrong format.");
1382 oldstate = (GstState)voldstate->data[0].v_int;
1383 newstate = (GstState)vnewstate->data[0].v_int;
1385 pending = (GstState)vpending->data[0].v_int;
1387 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1388 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1389 gst_element_state_get_name((GstState)oldstate),
1390 gst_element_state_get_name((GstState)newstate),
1391 gst_element_state_get_name((GstState)pending));
1393 if (newstate == GST_STATE_PLAYING) {
1394 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1396 int retVal = MM_ERROR_NONE;
1397 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1399 retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1401 if (MM_ERROR_NONE != retVal)
1402 LOGE("failed to seek pending postion. just keep staying current position.\n");
1404 player->pending_seek.is_pending = FALSE;
1408 if (oldstate == newstate) {
1409 LOGD("pipeline reports state transition to old state");
1414 case GST_STATE_VOID_PENDING:
1417 case GST_STATE_NULL:
1420 case GST_STATE_READY:
1423 case GST_STATE_PAUSED:
1425 gboolean prepare_async = FALSE;
1427 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1428 __mmplayer_configure_audio_callback(player);
1430 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1431 // managed prepare async case
1432 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1433 LOGD("checking prepare mode for async transition - %d", prepare_async);
1436 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1437 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1439 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1440 __mm_player_streaming_set_content_bitrate(player->streamer,
1441 player->total_maximum_bitrate, player->total_bitrate);
1446 case GST_STATE_PLAYING:
1448 if (MMPLAYER_IS_STREAMING(player)) {
1449 // managed prepare async case when buffering is completed
1450 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1451 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1452 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1453 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1455 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1457 LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1458 if (player->streamer->buffering_percent < 100) {
1460 MMMessageParamType msg_param = {0, };
1461 LOGW("Posting Buffering Completed Message to Application !!!");
1463 msg_param.connection.buffering = 100;
1464 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1469 if (player->gapless.stream_changed) {
1470 _mmplayer_update_content_attrs(player, ATTR_ALL);
1471 player->gapless.stream_changed = FALSE;
1474 if (player->doing_seek && async_done) {
1475 player->doing_seek = FALSE;
1477 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1488 case GST_MESSAGE_CLOCK_LOST:
1490 GstClock *clock = NULL;
1491 gboolean need_new_clock = FALSE;
1493 gst_message_parse_clock_lost(msg, &clock);
1494 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1496 if (!player->videodec_linked)
1497 need_new_clock = TRUE;
1498 else if (!player->ini.use_system_clock)
1499 need_new_clock = TRUE;
1501 if (need_new_clock) {
1502 LOGD("Provide clock is TRUE, do pause->resume\n");
1503 __gst_pause(player, FALSE);
1504 __gst_resume(player, FALSE);
1509 case GST_MESSAGE_NEW_CLOCK:
1511 GstClock *clock = NULL;
1512 gst_message_parse_new_clock(msg, &clock);
1513 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1517 case GST_MESSAGE_ELEMENT:
1519 const gchar *structure_name;
1521 MMHandleType attrs = 0;
1523 attrs = MMPLAYER_GET_ATTRS(player);
1525 LOGE("cannot get content attribute");
1530 if (gst_message_get_structure(msg) == NULL)
1533 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1534 if (!structure_name)
1537 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1538 gint num_buffers = 0;
1539 gint extra_num_buffers = 0;
1541 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1542 player->video_num_buffers = num_buffers;
1543 LOGD("video_num_buffers : %d", player->video_num_buffers);
1546 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1547 player->video_extra_num_buffers = extra_num_buffers;
1548 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1553 if (!strcmp(structure_name, "Language_list")) {
1554 const GValue *lang_list = NULL;
1555 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1556 if (lang_list != NULL) {
1557 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1559 LOGD("Total audio tracks(from parser) = %d \n", count);
1563 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1564 const GValue *lang_list = NULL;
1565 MMPlayerLangStruct *temp = NULL;
1567 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1568 if (lang_list != NULL) {
1569 count = g_list_length((GList *)g_value_get_pointer(lang_list));
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);
1587 /* custom message */
1588 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1589 MMMessageParamType msg_param = {0,};
1590 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1591 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1594 /* custom message for RTSP attribute :
1595 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1596 sdp which has contents info is received when rtsp connection is opened.
1597 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1598 if (!strcmp(structure_name, "rtspsrc_properties")) {
1600 gchar *audio_codec = NULL;
1601 gchar *video_codec = NULL;
1602 gchar *video_frame_size = NULL;
1604 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1605 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1606 __mmplayer_get_stream_service_type(player);
1607 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1609 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1610 LOGD("rtsp_audio_codec : %s", audio_codec);
1612 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1614 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1615 LOGD("rtsp_video_codec : %s", video_codec);
1617 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1619 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1620 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1621 if (video_frame_size) {
1623 char *seperator = strchr(video_frame_size, '-');
1626 char video_width[10]={0,};
1627 int frame_size_len = strlen(video_frame_size);
1628 int separtor_len = strlen(seperator);
1630 strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1631 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1634 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1638 if (mmf_attrs_commit(attrs))
1639 LOGE("failed to commit.\n");
1644 case GST_MESSAGE_DURATION_CHANGED:
1646 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1647 ret = __mmplayer_gst_handle_duration(player, msg);
1649 LOGW("failed to update duration");
1654 case GST_MESSAGE_ASYNC_START:
1655 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1658 case GST_MESSAGE_ASYNC_DONE:
1660 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1662 /* we only handle messages from pipeline */
1663 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1666 if (player->doing_seek) {
1667 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1668 player->doing_seek = FALSE;
1669 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1670 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1671 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1672 (player->streamer) &&
1673 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1674 (player->streamer->is_buffering == FALSE)) {
1675 GstQuery *query = NULL;
1676 gboolean busy = FALSE;
1679 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1680 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1681 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1682 gst_query_parse_buffering_percent(query, &busy, &percent);
1683 gst_query_unref(query);
1685 LOGD("buffered percent(%s): %d\n",
1686 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1689 if (percent >= 100) {
1690 player->streamer->is_buffering = FALSE;
1691 __mmplayer_handle_buffering_message(player);
1701 #if 0 /* delete unnecessary logs */
1702 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1703 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1704 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1705 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1706 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1707 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1708 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1709 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1710 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1711 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1712 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1713 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1714 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1715 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1716 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1723 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1724 * gst_element_post_message api takes ownership of the message.
1726 //gst_message_unref(msg);
1732 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1738 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1739 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1741 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1742 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1743 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1745 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1746 LOGD("data total size of http content: %lld", bytes);
1747 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1750 /* handling audio clip which has vbr. means duration is keep changing */
1751 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1760 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1763 /* macro for better code readability */
1764 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1765 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1766 if (string != NULL) {\
1767 SECURE_LOGD("update tag string : %s\n", string); \
1768 mm_attrs_set_string_by_name(attribute, playertag, string); \
1774 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1775 GstSample *sample = NULL;\
1776 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1777 GstMapInfo info = GST_MAP_INFO_INIT;\
1778 buffer = gst_sample_get_buffer(sample);\
1779 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1780 LOGD("failed to get image data from tag");\
1783 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1784 MMPLAYER_FREEIF(player->album_art);\
1785 player->album_art = (gchar *)g_malloc(info.size);\
1786 if (player->album_art) {\
1787 memcpy(player->album_art, info.data, info.size);\
1788 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1789 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1790 msg_param.data = (void *)player->album_art;\
1791 msg_param.size = info.size;\
1792 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1793 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1796 gst_buffer_unmap(buffer, &info);\
1799 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1800 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1802 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1803 if (player->updated_bitrate_count == 0) \
1804 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1805 if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1806 player->bitrate[player->updated_bitrate_count] = v_uint;\
1807 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1808 player->updated_bitrate_count++; \
1809 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1810 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1813 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1814 if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1815 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1816 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1817 player->updated_maximum_bitrate_count++; \
1818 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1819 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1822 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1827 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1828 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1829 if (date != NULL) {\
1830 string = g_strdup_printf("%d", g_date_get_year(date));\
1831 mm_attrs_set_string_by_name(attribute, playertag, string);\
1832 SECURE_LOGD("metainfo year : %s\n", string);\
1833 MMPLAYER_FREEIF(string);\
1838 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1839 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1840 if (datetime != NULL) {\
1841 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1842 mm_attrs_set_string_by_name(attribute, playertag, string);\
1843 SECURE_LOGD("metainfo year : %s\n", string);\
1844 MMPLAYER_FREEIF(string);\
1845 gst_date_time_unref(datetime);\
1849 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1850 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1852 /* FIXIT : don't know how to store date */\
1858 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1859 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1861 /* FIXIT : don't know how to store date */\
1867 /* function start */
1868 GstTagList* tag_list = NULL;
1870 MMHandleType attrs = 0;
1872 char *string = NULL;
1875 GstDateTime *datetime = NULL;
1877 GstBuffer *buffer = NULL;
1879 MMMessageParamType msg_param = {0, };
1881 /* currently not used. but those are needed for above macro */
1882 //guint64 v_uint64 = 0;
1883 //gdouble v_double = 0;
1885 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1887 attrs = MMPLAYER_GET_ATTRS(player);
1889 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1891 /* get tag list from gst message */
1892 gst_message_parse_tag(msg, &tag_list);
1894 /* store tags to player attributes */
1895 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1896 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1897 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1898 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1899 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1900 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1901 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1902 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1903 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1904 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1905 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1907 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1908 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1909 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1910 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1911 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1912 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1913 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1915 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1916 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1917 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1918 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1920 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1923 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1924 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1925 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1926 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1927 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1928 MMPLAYER_UPDATE_TAG_LOCK(player);
1929 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1930 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1931 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1932 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1933 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1940 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1941 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1942 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1943 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1945 if (mmf_attrs_commit(attrs))
1946 LOGE("failed to commit.\n");
1948 gst_tag_list_free(tag_list);
1954 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) // @
1956 mm_player_t* player = (mm_player_t*) data;
1960 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1961 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1962 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1963 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1965 * [1] audio and video will be dumped with filesink.
1966 * [2] autoplugging is done by just using pad caps.
1967 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1968 * and the video will be dumped via filesink.
1970 if (player->num_dynamic_pad == 0) {
1971 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1973 if (!__mmplayer_gst_remove_fakesink(player,
1974 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1975 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1976 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1977 * source element are not same. To overcome this situation, this function will called
1978 * several places and several times. Therefore, this is not an error case.
1983 /* create dot before error-return. for debugging */
1984 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1986 player->no_more_pad = TRUE;
1992 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1994 GstElement* parent = NULL;
1996 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1998 /* if we have no fakesink. this meas we are using decodebin which doesn'
1999 t need to add extra fakesink */
2000 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2003 MMPLAYER_FSINK_LOCK(player);
2008 /* get parent of fakesink */
2009 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2011 LOGD("fakesink already removed\n");
2015 gst_element_set_locked_state(fakesink->gst, TRUE);
2017 /* setting the state to NULL never returns async
2018 * so no need to wait for completion of state transiton
2020 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2021 LOGE("fakesink state change failure!\n");
2022 /* FIXIT : should I return here? or try to proceed to next? */
2025 /* remove fakesink from it's parent */
2026 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2027 LOGE("failed to remove fakesink\n");
2029 gst_object_unref(parent);
2034 gst_object_unref(parent);
2036 LOGD("state-holder removed\n");
2038 gst_element_set_locked_state(fakesink->gst, FALSE);
2040 MMPLAYER_FSINK_UNLOCK(player);
2045 gst_element_set_locked_state(fakesink->gst, FALSE);
2047 MMPLAYER_FSINK_UNLOCK(player);
2053 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2055 GstPad *sinkpad = NULL;
2056 GstCaps* caps = NULL;
2057 GstElement* new_element = NULL;
2058 GstStructure* str = NULL;
2059 const gchar* name = NULL;
2061 mm_player_t* player = (mm_player_t*) data;
2065 MMPLAYER_RETURN_IF_FAIL(element && pad);
2066 MMPLAYER_RETURN_IF_FAIL(player &&
2068 player->pipeline->mainbin);
2071 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2072 * num_dynamic_pad will decreased after creating a sinkbin.
2074 player->num_dynamic_pad++;
2075 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2077 caps = gst_pad_query_caps(pad, NULL);
2079 MMPLAYER_CHECK_NULL(caps);
2081 /* clear previous result*/
2082 player->have_dynamic_pad = FALSE;
2084 str = gst_caps_get_structure(caps, 0);
2087 LOGE("cannot get structure from caps.\n");
2091 name = gst_structure_get_name(str);
2093 LOGE("cannot get mimetype from structure.\n");
2097 if (strstr(name, "video")) {
2099 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2101 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2102 if (player->v_stream_caps) {
2103 gst_caps_unref(player->v_stream_caps);
2104 player->v_stream_caps = NULL;
2107 new_element = gst_element_factory_make("fakesink", NULL);
2108 player->num_dynamic_pad--;
2113 /* clear previous result*/
2114 player->have_dynamic_pad = FALSE;
2116 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2117 LOGE("failed to autoplug for caps");
2121 /* check if there's dynamic pad*/
2122 if (player->have_dynamic_pad) {
2123 LOGE("using pad caps assums there's no dynamic pad !\n");
2127 gst_caps_unref(caps);
2132 /* excute new_element if created*/
2134 LOGD("adding new element to pipeline\n");
2136 /* set state to READY before add to bin */
2137 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2139 /* add new element to the pipeline */
2140 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2141 LOGE("failed to add autoplug element to bin\n");
2145 /* get pad from element */
2146 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2148 LOGE("failed to get sinkpad from autoplug element\n");
2153 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2154 LOGE("failed to link autoplug element\n");
2158 gst_object_unref(sinkpad);
2161 /* run. setting PLAYING here since streamming source is live source */
2162 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2169 STATE_CHANGE_FAILED:
2171 /* FIXIT : take care if new_element has already added to pipeline */
2173 gst_object_unref(GST_OBJECT(new_element));
2176 gst_object_unref(GST_OBJECT(sinkpad));
2179 gst_object_unref(GST_OBJECT(caps));
2181 /* FIXIT : how to inform this error to MSL ????? */
2182 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2183 * then post an error to application
2189 /* FIXIT : check indent */
2192 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2194 GstPad *sinkpad = NULL;
2195 GstCaps* caps = NULL;
2196 GstElement* new_element = NULL;
2197 enum MainElementID element_id = MMPLAYER_M_NUM;
2199 mm_player_t* player = (mm_player_t*) data;
2203 MMPLAYER_RETURN_IF_FAIL(element && pad);
2204 MMPLAYER_RETURN_IF_FAIL(player &&
2206 player->pipeline->mainbin);
2208 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2211 LOGD("using pad caps to autopluging instead of doing typefind\n");
2212 caps = gst_pad_query_caps(pad);
2213 MMPLAYER_CHECK_NULL(caps);
2214 /* clear previous result*/
2215 player->have_dynamic_pad = FALSE;
2216 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2218 LOGE("failed to create wfd rtp depay element\n");
2221 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2222 /* add new element to the pipeline */
2223 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2224 LOGD("failed to add autoplug element to bin\n");
2227 /* get pad from element */
2228 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2230 LOGD("failed to get sinkpad from autoplug element\n");
2234 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2235 LOGD("failed to link autoplug element\n");
2238 gst_object_unref(sinkpad);
2240 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2241 caps = gst_pad_query_caps(pad);
2242 MMPLAYER_CHECK_NULL(caps);
2243 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2244 /* create typefind */
2245 new_element = gst_element_factory_make("typefind", NULL);
2247 LOGD("failed to create typefind\n");
2251 MMPLAYER_SIGNAL_CONNECT(player,
2252 G_OBJECT(new_element),
2253 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2255 G_CALLBACK(__mmplayer_typefind_have_type),
2258 player->have_dynamic_pad = FALSE;
2261 /* excute new_element if created*/
2263 LOGD("adding new element to pipeline\n");
2265 /* set state to READY before add to bin */
2266 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2268 /* add new element to the pipeline */
2269 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2270 LOGD("failed to add autoplug element to bin\n");
2274 /* get pad from element */
2275 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2277 LOGD("failed to get sinkpad from autoplug element\n");
2282 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2283 LOGD("failed to link autoplug element\n");
2287 gst_object_unref(sinkpad);
2290 /* run. setting PLAYING here since streamming source is live source */
2291 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2294 /* store handle to futher manipulation */
2295 player->pipeline->mainbin[element_id].id = element_id;
2296 player->pipeline->mainbin[element_id].gst = new_element;
2302 STATE_CHANGE_FAILED:
2304 /* FIXIT : take care if new_element has already added to pipeline */
2306 gst_object_unref(GST_OBJECT(new_element));
2309 gst_object_unref(GST_OBJECT(sinkpad));
2312 gst_object_unref(GST_OBJECT(caps));
2314 /* FIXIT : how to inform this error to MSL ????? */
2315 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2316 * then post an error to application
2321 static GstPadProbeReturn
2322 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2324 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2325 return GST_PAD_PROBE_OK;
2328 static GstPadProbeReturn
2329 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2331 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2332 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2333 mm_player_t* player = (mm_player_t*)data;
2334 GstCaps* caps = NULL;
2335 GstStructure* str = NULL;
2336 const gchar* name = NULL;
2337 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2340 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2341 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2342 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2343 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2344 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2346 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2347 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2351 caps = gst_pad_query_caps(pad, NULL);
2353 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2357 str = gst_caps_get_structure(caps, 0);
2359 LOGE("failed to get structure from caps");
2363 name = gst_structure_get_name(str);
2365 LOGE("failed to get name from str");
2369 if (strstr(name, "audio")) {
2370 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2371 } else if (strstr(name, "video")) {
2372 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2374 /* text track is not supportable */
2375 LOGE("invalid name %s", name);
2379 switch (GST_EVENT_TYPE(event)) {
2382 /* in case of gapless, drop eos event not to send it to sink */
2383 if (player->gapless.reconfigure && !player->msg_posted) {
2384 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2385 ret = GST_PAD_PROBE_DROP;
2389 case GST_EVENT_STREAM_START:
2391 gint64 stop_running_time = 0;
2392 gint64 position_running_time = 0;
2393 gint64 position = 0;
2396 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2397 if ((player->gapless.update_segment[idx] == TRUE) ||
2398 !(player->selector[idx].event_probe_id)) {
2399 /* LOGW("[%d] skip", idx); */
2403 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2405 gst_segment_to_running_time(&player->gapless.segment[idx],
2406 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2407 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2409 gst_segment_to_running_time(&player->gapless.segment[idx],
2410 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2412 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2414 gst_segment_to_running_time(&player->gapless.segment[idx],
2415 GST_FORMAT_TIME, player->duration);
2418 position_running_time =
2419 gst_segment_to_running_time(&player->gapless.segment[idx],
2420 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2422 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2423 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2425 GST_TIME_ARGS(stop_running_time),
2426 GST_TIME_ARGS(position_running_time),
2427 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2428 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2430 position_running_time = MAX(position_running_time, stop_running_time);
2431 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2432 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2433 position_running_time = MAX(0, position_running_time);
2434 position = MAX(position, position_running_time);
2437 if (position != 0) {
2438 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2439 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2440 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2442 player->gapless.start_time[stream_type] += position;
2446 case GST_EVENT_FLUSH_STOP:
2448 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2449 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2450 player->gapless.start_time[stream_type] = 0;
2453 case GST_EVENT_SEGMENT:
2458 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2459 gst_event_copy_segment(event, &segment);
2461 if (segment.format == GST_FORMAT_TIME) {
2462 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2463 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2464 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2465 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2466 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2467 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2469 /* keep the all the segment ev to cover the seeking */
2470 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2471 player->gapless.update_segment[stream_type] = TRUE;
2473 if (!player->gapless.running)
2476 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2478 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2480 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2481 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2482 gst_event_unref(event);
2483 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2489 gdouble proportion = 0.0;
2490 GstClockTimeDiff diff = 0;
2491 GstClockTime timestamp = 0;
2492 gint64 running_time_diff = -1;
2493 GstQOSType type = 0;
2494 GstEvent *tmpev = NULL;
2496 running_time_diff = player->gapless.segment[stream_type].base;
2498 if (running_time_diff <= 0) /* don't need to adjust */
2501 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2502 gst_event_unref(event);
2504 if (timestamp < running_time_diff) {
2505 LOGW("QOS event from previous group");
2506 ret = GST_PAD_PROBE_DROP;
2510 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2511 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2512 stream_type, GST_TIME_ARGS(timestamp),
2513 GST_TIME_ARGS(running_time_diff),
2514 GST_TIME_ARGS(timestamp - running_time_diff));
2516 timestamp -= running_time_diff;
2518 /* That case is invalid for QoS events */
2519 if (diff < 0 && -diff > timestamp) {
2520 LOGW("QOS event from previous group");
2521 ret = GST_PAD_PROBE_DROP;
2525 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2526 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2536 gst_caps_unref(caps);
2541 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2543 mm_player_t* player = NULL;
2544 GstElement* pipeline = NULL;
2545 GstElement* selector = NULL;
2546 GstElement* fakesink = NULL;
2547 GstCaps* caps = NULL;
2548 GstStructure* str = NULL;
2549 const gchar* name = NULL;
2550 GstPad* sinkpad = NULL;
2551 GstPad* srcpad = NULL;
2552 gboolean first_track = FALSE;
2554 enum MainElementID elemId = MMPLAYER_M_NUM;
2555 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2558 player = (mm_player_t*)data;
2560 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2561 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2563 //LOGD("pad-added signal handling\n");
2565 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2567 /* get mimetype from caps */
2568 caps = gst_pad_query_caps(pad, NULL);
2570 LOGE("cannot get caps from pad.\n");
2574 str = gst_caps_get_structure(caps, 0);
2576 LOGE("cannot get structure from caps.\n");
2580 name = gst_structure_get_name(str);
2582 LOGE("cannot get mimetype from structure.\n");
2586 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2587 //LOGD("detected mimetype : %s\n", name);
2589 if (strstr(name, "video")) {
2591 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2593 /* don't make video because of not required, and not support multiple track */
2594 if (stype == MM_DISPLAY_SURFACE_NULL) {
2595 LOGD("no video sink by null surface");
2596 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2597 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2599 /* acquire resources for video playing */
2600 if (resource_state == RESOURCE_STATE_PREPARED) {
2601 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2603 LOGE("could not acquire resources for video playing\n");
2604 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2610 gchar *caps_str = gst_caps_to_string(caps);
2611 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2612 player->set_mode.video_zc = TRUE;
2614 MMPLAYER_FREEIF(caps_str);
2616 if (player->v_stream_caps) {
2617 gst_caps_unref(player->v_stream_caps);
2618 player->v_stream_caps = NULL;
2621 LOGD("create fakesink instead of videobin");
2624 fakesink = gst_element_factory_make("fakesink", NULL);
2625 if (fakesink == NULL) {
2626 LOGE("ERROR : fakesink create error\n");
2630 if (player->ini.set_dump_element_flag)
2631 __mmplayer_add_dump_buffer_probe(player, fakesink);
2633 player->video_fakesink = fakesink;
2635 /* store it as it's sink element */
2636 __mmplayer_add_sink(player, player->video_fakesink);
2638 gst_bin_add(GST_BIN(pipeline), fakesink);
2641 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2643 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2644 LOGW("failed to link fakesink\n");
2645 gst_object_unref(GST_OBJECT(fakesink));
2649 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2650 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2651 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2654 if (player->set_mode.media_packet_video_stream) {
2655 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2657 MMPLAYER_SIGNAL_CONNECT(player,
2659 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2661 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2664 MMPLAYER_SIGNAL_CONNECT(player,
2666 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2668 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2672 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2673 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2677 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2678 __mmplayer_gst_decode_callback(elem, pad, player);
2682 LOGD("video selector \n");
2683 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2684 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2686 if (strstr(name, "audio")) {
2687 gint samplerate = 0;
2690 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2691 __mmplayer_gst_decode_callback(elem, pad, player);
2695 LOGD("audio selector \n");
2696 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2697 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2699 gst_structure_get_int(str, "rate", &samplerate);
2700 gst_structure_get_int(str, "channels", &channels);
2702 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2704 fakesink = gst_element_factory_make("fakesink", NULL);
2705 if (fakesink == NULL) {
2706 LOGE("ERROR : fakesink create error\n");
2710 gst_bin_add(GST_BIN(pipeline), fakesink);
2713 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2715 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2716 LOGW("failed to link fakesink\n");
2717 gst_object_unref(GST_OBJECT(fakesink));
2721 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2722 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2723 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2727 } else if (strstr(name, "text")) {
2728 LOGD("text selector \n");
2729 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2730 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2732 LOGE("wrong elem id \n");
2737 selector = player->pipeline->mainbin[elemId].gst;
2738 if (selector == NULL) {
2739 selector = gst_element_factory_make("input-selector", NULL);
2740 LOGD("Creating input-selector\n");
2741 if (selector == NULL) {
2742 LOGE("ERROR : input-selector create error\n");
2745 g_object_set(selector, "sync-streams", TRUE, NULL);
2747 player->pipeline->mainbin[elemId].id = elemId;
2748 player->pipeline->mainbin[elemId].gst = selector;
2751 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2753 srcpad = gst_element_get_static_pad(selector, "src");
2755 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2756 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2757 __mmplayer_gst_selector_blocked, NULL, NULL);
2758 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2759 __mmplayer_gst_selector_event_probe, player, NULL);
2761 gst_element_set_state(selector, GST_STATE_PAUSED);
2762 gst_bin_add(GST_BIN(pipeline), selector);
2764 LOGD("input-selector is already created.\n");
2767 LOGD("Calling request pad with selector %p \n", selector);
2768 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2770 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2772 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2773 LOGW("failed to link selector\n");
2774 gst_object_unref(GST_OBJECT(selector));
2779 LOGD("this is first track --> active track \n");
2780 g_object_set(selector, "active-pad", sinkpad, NULL);
2783 _mmplayer_track_update_info(player, stream_type, sinkpad);
2790 gst_caps_unref(caps);
2793 gst_object_unref(GST_OBJECT(sinkpad));
2798 gst_object_unref(GST_OBJECT(srcpad));
2805 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2807 GstPad* srcpad = NULL;
2808 MMHandleType attrs = 0;
2809 gint active_index = 0;
2811 // [link] input-selector :: textbin
2812 srcpad = gst_element_get_static_pad(text_selector, "src");
2814 LOGE("failed to get srcpad from selector\n");
2818 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2820 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2821 if ((active_index != DEFAULT_TRACK) &&
2822 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2823 LOGW("failed to change text track\n");
2824 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2827 player->no_more_pad = TRUE;
2828 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2830 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2831 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2832 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2833 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2836 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2838 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2839 player->has_closed_caption = TRUE;
2841 attrs = MMPLAYER_GET_ATTRS(player);
2843 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2844 if (mmf_attrs_commit(attrs))
2845 LOGE("failed to commit.\n");
2847 LOGE("cannot get content attribute");
2850 gst_object_unref(GST_OBJECT(srcpad));
2855 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2857 int result = MM_ERROR_NONE;
2859 mm_player_t* player = (mm_player_t*)hplayer;
2860 MMPlayerGstElement* mainbin = NULL;
2861 gchar* change_pad_name = NULL;
2862 GstPad* sinkpad = NULL;
2863 GstCaps* caps = NULL;
2867 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2869 LOGD("Change Audio mode to %d\n", ch_idx);
2870 player->use_deinterleave = TRUE;
2872 if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2873 LOGD("pre setting : %d\n", ch_idx);
2875 player->audio_mode.active_pad_index = ch_idx;
2879 mainbin = player->pipeline->mainbin;
2881 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2882 if (player->max_audio_channels < 2) {
2883 LOGD("mono channel track only\n");
2887 LOGW("selector doesn't exist\n");
2888 return result; /* keep playing */
2891 LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2893 if (player->audio_mode.total_track_num < 2) {
2894 LOGW("there is no another audio path\n");
2895 return result; /* keep playing */
2898 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2899 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2900 return result; /* keep playing */
2903 /*To get the new pad from the selector*/
2904 change_pad_name = g_strdup_printf("sink%d", ch_idx);
2905 if (change_pad_name == NULL) {
2906 LOGW("Pad does not exists\n");
2907 goto ERROR; /* keep playing */
2910 LOGD("new active pad name: %s\n", change_pad_name);
2912 sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2913 if (sinkpad == NULL)
2914 //result = MM_ERROR_PLAYER_INTERNAL;
2915 goto ERROR; /* keep playing */
2917 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2918 g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2920 caps = gst_pad_get_current_caps(sinkpad);
2921 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2923 __mmplayer_set_audio_attrs(player, caps);
2924 player->audio_mode.active_pad_index = ch_idx;
2929 gst_object_unref(sinkpad);
2931 MMPLAYER_FREEIF(change_pad_name);
2940 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2942 mm_player_t* player = (mm_player_t*)data;
2943 GstElement* selector = NULL;
2944 GstElement* queue = NULL;
2946 GstPad* srcpad = NULL;
2947 GstPad* sinkpad = NULL;
2948 gchar* caps_str = NULL;
2951 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2953 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2954 LOGD("deinterleave new caps : %s\n", caps_str);
2955 MMPLAYER_FREEIF(caps_str);
2957 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2958 LOGE("ERROR : queue create error\n");
2962 g_object_set(G_OBJECT(queue),
2963 "max-size-buffers", 10,
2964 "max-size-bytes", 0,
2965 "max-size-time", (guint64)0,
2968 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2971 LOGE("there is no audio channel selector.\n");
2975 srcpad = gst_element_get_static_pad(queue, "src");
2976 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2978 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2980 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2981 LOGW("failed to link deinterleave - selector\n");
2985 gst_element_set_state(queue, GST_STATE_PAUSED);
2986 player->audio_mode.total_track_num++;
2991 gst_object_unref(GST_OBJECT(srcpad));
2996 gst_object_unref(GST_OBJECT(sinkpad));
3005 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
3007 mm_player_t* player = NULL;
3008 GstElement* selector = NULL;
3009 GstPad* sinkpad = NULL;
3010 gint active_index = 0;
3011 gchar* change_pad_name = NULL;
3012 GstCaps* caps = NULL; // no need to unref
3013 gint default_audio_ch = 0;
3016 player = (mm_player_t*) data;
3018 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3021 LOGE("there is no audio channel selector.\n");
3025 active_index = player->audio_mode.active_pad_index;
3027 if (active_index != default_audio_ch) {
3028 gint audio_ch = default_audio_ch;
3030 /*To get the new pad from the selector*/
3031 change_pad_name = g_strdup_printf("sink%d", active_index);
3032 if (change_pad_name != NULL) {
3033 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3034 if (sinkpad != NULL) {
3035 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3036 g_object_set(selector, "active-pad", sinkpad, NULL);
3038 audio_ch = active_index;
3040 caps = gst_pad_get_current_caps(sinkpad);
3041 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3043 __mmplayer_set_audio_attrs(player, caps);
3045 MMPLAYER_FREEIF(change_pad_name);
3048 player->audio_mode.active_pad_index = audio_ch;
3049 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3055 gst_object_unref(sinkpad);
3062 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3064 mm_player_t* player = NULL;
3065 MMPlayerGstElement *mainbin = NULL;
3067 GstElement* tee = NULL;
3068 GstElement* stereo_queue = NULL;
3069 GstElement* mono_queue = NULL;
3070 GstElement* conv = NULL;
3071 GstElement* filter = NULL;
3072 GstElement* deinterleave = NULL;
3073 GstElement* selector = NULL;
3075 GstPad* srcpad = NULL;
3076 GstPad* selector_srcpad = NULL;
3077 GstPad* sinkpad = NULL;
3078 GstCaps* caps = NULL;
3079 gulong block_id = 0;
3084 player = (mm_player_t*) data;
3086 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3087 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3089 mainbin = player->pipeline->mainbin;
3092 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3093 LOGE("ERROR : tee create error\n");
3097 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3098 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3100 gst_element_set_state(tee, GST_STATE_PAUSED);
3103 srcpad = gst_element_get_request_pad(tee, "src_%u");
3104 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3105 LOGE("ERROR : stereo queue create error\n");
3109 g_object_set(G_OBJECT(stereo_queue),
3110 "max-size-buffers", 10,
3111 "max-size-bytes", 0,
3112 "max-size-time", (guint64)0,
3115 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3116 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3119 gst_object_unref(GST_OBJECT(srcpad));
3123 srcpad = gst_element_get_request_pad(tee, "src_%u");
3125 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3126 LOGE("ERROR : mono queue create error\n");
3130 g_object_set(G_OBJECT(mono_queue),
3131 "max-size-buffers", 10,
3132 "max-size-bytes", 0,
3133 "max-size-time", (guint64)0,
3136 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3137 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3139 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3140 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3143 srcpad = gst_element_get_static_pad(mono_queue, "src");
3144 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3145 LOGE("ERROR : audioconvert create error\n");
3149 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3150 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3154 gst_object_unref(GST_OBJECT(srcpad));
3157 srcpad = gst_element_get_static_pad(conv, "src");
3159 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3160 LOGE("ERROR : capsfilter create error\n");
3164 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3165 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3167 caps = gst_caps_from_string("audio/x-raw-int, "
3168 "width = (int) 16, "
3169 "depth = (int) 16, "
3170 "channels = (int) 2");
3172 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3173 gst_caps_unref(caps);
3175 gst_element_set_state(conv, GST_STATE_PAUSED);
3176 gst_element_set_state(filter, GST_STATE_PAUSED);
3180 gst_object_unref(GST_OBJECT(srcpad));
3183 srcpad = gst_element_get_static_pad(filter, "src");
3185 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3186 LOGE("ERROR : deinterleave create error\n");
3190 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3192 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3193 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3195 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3196 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3198 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3199 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3202 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3203 if (selector == NULL) {
3204 LOGE("ERROR : audio-selector create error\n");
3208 g_object_set(selector, "sync-streams", TRUE, NULL);
3209 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3211 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3212 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3214 selector_srcpad = gst_element_get_static_pad(selector, "src");
3216 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3218 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3219 __mmplayer_gst_selector_blocked, NULL, NULL);
3222 gst_object_unref(GST_OBJECT(srcpad));
3226 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3227 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3229 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3230 LOGW("failed to link queue_stereo - selector\n");
3234 player->audio_mode.total_track_num++;
3236 g_object_set(selector, "active-pad", sinkpad, NULL);
3237 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3238 gst_element_set_state(selector, GST_STATE_PAUSED);
3240 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3244 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3245 if (block_id != 0) {
3246 gst_pad_remove_probe(selector_srcpad, block_id);
3251 gst_object_unref(GST_OBJECT(sinkpad));
3256 gst_object_unref(GST_OBJECT(srcpad));
3260 if (selector_srcpad) {
3261 gst_object_unref(GST_OBJECT(selector_srcpad));
3262 selector_srcpad = NULL;
3270 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3272 mm_player_t* player = NULL;
3273 GstPad* srcpad = NULL;
3274 GstElement* video_selector = NULL;
3275 GstElement* audio_selector = NULL;
3276 GstElement* text_selector = NULL;
3277 MMHandleType attrs = 0;
3278 gint active_index = 0;
3279 gint64 dur_bytes = 0L;
3281 player = (mm_player_t*) data;
3283 LOGD("no-more-pad signal handling\n");
3285 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3286 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3287 LOGW("no need to go more");
3289 if (player->gapless.reconfigure) {
3290 player->gapless.reconfigure = FALSE;
3291 MMPLAYER_PLAYBACK_UNLOCK(player);
3297 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3298 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3299 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3300 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3301 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3303 if (NULL == player->streamer) {
3304 LOGW("invalid state for buffering");
3308 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3309 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3311 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3312 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3314 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3316 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3317 LOGE("fail to get duration.\n");
3319 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3320 // use file information was already set on Q2 when it was created.
3321 __mm_player_streaming_set_queue2(player->streamer,
3322 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3323 TRUE, // use_buffering
3325 init_buffering_time,
3327 player->ini.http_buffering_limit, // high percent
3328 MUXED_BUFFER_TYPE_MEM_QUEUE,
3330 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3333 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3334 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3335 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3336 if (video_selector) {
3337 // [link] input-selector :: videobin
3338 srcpad = gst_element_get_static_pad(video_selector, "src");
3340 LOGE("failed to get srcpad from video selector\n");
3344 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3345 if (!text_selector && !audio_selector)
3346 player->no_more_pad = TRUE;
3348 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3350 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3351 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3352 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3353 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3357 if (audio_selector) {
3358 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3359 if ((active_index != DEFAULT_TRACK) &&
3360 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3361 LOGW("failed to change audio track\n");
3362 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3365 // [link] input-selector :: audiobin
3366 srcpad = gst_element_get_static_pad(audio_selector, "src");
3368 LOGE("failed to get srcpad from selector\n");
3372 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3374 player->no_more_pad = TRUE;
3376 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3377 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3378 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3379 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3380 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3383 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3385 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3387 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3388 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3389 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3390 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3394 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3396 attrs = MMPLAYER_GET_ATTRS(player);
3398 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3399 if (mmf_attrs_commit(attrs))
3400 LOGE("failed to commit.\n");
3402 LOGE("cannot get content attribute");
3404 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3405 LOGD("There is no audio track : remove audiobin");
3407 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3408 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3410 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3411 MMPLAYER_FREEIF(player->pipeline->audiobin)
3414 if (player->num_dynamic_pad == 0)
3415 __mmplayer_pipeline_complete(NULL, player);
3418 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3420 __mmplayer_handle_text_decode_path(player, text_selector);
3427 gst_object_unref(GST_OBJECT(srcpad));
3431 if (player->gapless.reconfigure) {
3432 player->gapless.reconfigure = FALSE;
3433 MMPLAYER_PLAYBACK_UNLOCK(player);
3438 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3440 mm_player_t* player = NULL;
3441 MMHandleType attrs = 0;
3442 GstElement* pipeline = NULL;
3443 GstCaps* caps = NULL;
3444 gchar* caps_str = NULL;
3445 GstStructure* str = NULL;
3446 const gchar* name = NULL;
3447 GstPad* sinkpad = NULL;
3448 GstElement* sinkbin = NULL;
3449 gboolean reusing = FALSE;
3450 GstElement *text_selector = NULL;
3451 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3454 player = (mm_player_t*) data;
3456 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3457 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3459 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3461 attrs = MMPLAYER_GET_ATTRS(player);
3463 LOGE("cannot get content attribute\n");
3467 /* get mimetype from caps */
3468 caps = gst_pad_query_caps(pad, NULL);
3470 LOGE("cannot get caps from pad.\n");
3473 caps_str = gst_caps_to_string(caps);
3475 str = gst_caps_get_structure(caps, 0);
3477 LOGE("cannot get structure from caps.\n");
3481 name = gst_structure_get_name(str);
3483 LOGE("cannot get mimetype from structure.\n");
3487 //LOGD("detected mimetype : %s\n", name);
3489 if (strstr(name, "audio")) {
3490 if (player->pipeline->audiobin == NULL) {
3491 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3492 LOGE("failed to create audiobin. continuing without audio\n");
3496 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3497 LOGD("creating audiosink bin success\n");
3500 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3501 LOGD("reusing audiobin\n");
3502 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3505 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3506 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3508 player->audiosink_linked = 1;
3510 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3512 LOGE("failed to get pad from sinkbin\n");
3515 } else if (strstr(name, "video")) {
3516 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3517 player->set_mode.video_zc = TRUE;
3519 if (player->pipeline->videobin == NULL) {
3520 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3521 /* get video surface type */
3522 int surface_type = 0;
3523 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3524 LOGD("display_surface_type(%d)\n", surface_type);
3526 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3527 LOGD("not make videobin because it dose not want\n");
3531 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3532 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3533 /* prepare resource manager for video overlay */
3534 if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3535 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3537 LOGE("could not prepare for video_overlay resource\n");
3544 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3546 /* acquire resources for video playing */
3547 if (resource_state == RESOURCE_STATE_PREPARED) {
3548 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3550 LOGE("could not acquire resources for video playing\n");
3551 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3557 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3558 LOGE("failed to create videobin. continuing without video\n");
3562 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3563 LOGD("creating videosink bin success\n");
3566 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3567 LOGD("re-using videobin\n");
3568 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3571 /* FIXIT : track number shouldn't be hardcoded */
3572 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3573 player->videosink_linked = 1;
3575 /* NOTE : intermediate code before doing H/W subtitle compositon */
3576 if (player->use_textoverlay && player->play_subtitle) {
3577 LOGD("using textoverlay for external subtitle");
3578 /* check text bin has created well */
3579 if (player->pipeline && player->pipeline->textbin) {
3580 /* get sinkpad from textoverlay */
3581 sinkpad = gst_element_get_static_pad(
3582 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3585 LOGE("failed to get sink pad from textoverlay");
3589 /* link new pad with textoverlay first */
3590 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3591 LOGE("failed to get pad from sinkbin\n");
3595 gst_object_unref(sinkpad);
3598 /* alright, override pad to textbin.src for futher link */
3599 pad = gst_element_get_static_pad(
3600 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3603 LOGE("failed to get sink pad from textoverlay");
3607 LOGE("should not reach here.");
3612 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3614 LOGE("failed to get pad from sinkbin\n");
3617 } else if (strstr(name, "text")) {
3618 if (player->pipeline->textbin == NULL) {
3619 MMPlayerGstElement* mainbin = NULL;
3621 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
3622 LOGE("failed to create textbin. continuing without text\n");
3626 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3627 LOGD("creating textsink bin success\n");
3629 /* FIXIT : track number shouldn't be hardcoded */
3630 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3632 player->textsink_linked = 1;
3633 LOGI("player->textsink_linked set to 1\n");
3635 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3637 LOGE("failed to get pad from sinkbin\n");
3641 mainbin = player->pipeline->mainbin;
3643 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3644 /* input selector */
3645 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3646 if (!text_selector) {
3647 LOGE("failed to create subtitle input selector element\n");
3650 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3652 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3653 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3656 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3657 LOGE("failed to set state(READY) to sinkbin\n");
3661 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3662 LOGW("failed to add subtitle input selector\n");
3666 LOGD("created element input-selector");
3669 LOGD("already having subtitle input selector");
3670 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3673 if (!player->textsink_linked) {
3674 LOGD("re-using textbin\n");
3677 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3679 player->textsink_linked = 1;
3680 LOGI("player->textsink_linked set to 1\n");
3682 LOGD("ignoring internal subtutle since external subtitle is available");
3685 LOGW("unknown type of elementary stream!ignoring it...\n");
3692 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3693 LOGE("failed to set state(READY) to sinkbin\n");
3697 /* Added for multi audio support to avoid adding audio bin again*/
3699 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3700 LOGE("failed to add sinkbin to pipeline\n");
3706 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3707 LOGE("failed to get pad from sinkbin\n");
3713 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3714 LOGE("failed to set state(PAUSED) to sinkbin\n");
3718 if (text_selector) {
3719 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3720 LOGE("failed to set state(PAUSED) to sinkbin\n");
3726 gst_object_unref(sinkpad);
3730 LOGD("linking sink bin success\n");
3732 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3733 * streaming task. if the task blocked, then buffer will not flow to the next element
3734 *(autoplugging element). so this is special hack for streaming. please try to remove it
3736 /* dec stream count. we can remove fakesink if it's zero */
3737 if (player->num_dynamic_pad)
3738 player->num_dynamic_pad--;
3740 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3742 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3743 __mmplayer_pipeline_complete(NULL, player);
3745 /* FIXIT : please leave a note why this code is needed */
3746 if (MMPLAYER_IS_WFD_STREAMING(player))
3747 player->no_more_pad = TRUE;
3751 MMPLAYER_FREEIF(caps_str);
3754 gst_caps_unref(caps);
3757 gst_object_unref(GST_OBJECT(sinkpad));
3759 /* flusing out new attributes */
3760 if (mmf_attrs_commit(attrs))
3761 LOGE("failed to comit attributes\n");
3767 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3769 int pro_value = 0; // in the case of expection, default will be returned.
3770 int dest_angle = rotation_angle;
3771 int rotation_type = -1;
3773 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3774 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3775 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3777 if (rotation_angle >= 360)
3778 dest_angle = rotation_angle - 360;
3780 /* chech if supported or not */
3781 if (dest_angle % 90) {
3782 LOGD("not supported rotation angle = %d", rotation_angle);
3788 * custom_convert - none (B)
3789 * videoflip - none (C)
3791 if (player->set_mode.video_zc) {
3792 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3793 rotation_type = ROTATION_USING_CUSTOM;
3795 rotation_type = ROTATION_USING_SINK;
3797 int surface_type = 0;
3798 rotation_type = ROTATION_USING_FLIP;
3800 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3801 LOGD("check display surface type attribute: %d", surface_type);
3803 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3804 rotation_type = ROTATION_USING_SINK;
3806 rotation_type = ROTATION_USING_FLIP; //C
3808 LOGD("using %d type for rotation", rotation_type);
3811 /* get property value for setting */
3812 switch (rotation_type) {
3813 case ROTATION_USING_SINK: // waylandsink
3815 switch (dest_angle) {
3819 pro_value = 3; // clockwise 90
3825 pro_value = 1; // counter-clockwise 90
3830 case ROTATION_USING_CUSTOM:
3832 gchar *ename = NULL;
3833 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3835 if (g_strrstr(ename, "fimcconvert")) {
3836 switch (dest_angle) {
3840 pro_value = 90; // clockwise 90
3846 pro_value = 270; // counter-clockwise 90
3852 case ROTATION_USING_FLIP: // videoflip
3854 switch (dest_angle) {
3858 pro_value = 1; // clockwise 90
3864 pro_value = 3; // counter-clockwise 90
3871 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3879 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3881 /* check video sinkbin is created */
3882 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3884 player->pipeline->videobin &&
3885 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3886 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3887 MM_ERROR_PLAYER_NOT_INITIALIZED);
3889 return MM_ERROR_NONE;
3893 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3895 int rotation_value = 0;
3896 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3900 /* check video sinkbin is created */
3901 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3904 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3906 /* get rotation value to set */
3907 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3908 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3909 LOGD("set video param : rotate %d", rotation_value);
3913 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3915 MMHandleType attrs = 0;
3919 /* check video sinkbin is created */
3920 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3923 attrs = MMPLAYER_GET_ATTRS(player);
3924 MMPLAYER_RETURN_IF_FAIL(attrs);
3926 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3927 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3928 LOGD("set video param : visible %d", visible);
3932 __mmplayer_video_param_set_display_method(mm_player_t* player)
3934 MMHandleType attrs = 0;
3935 int display_method = 0;
3938 /* check video sinkbin is created */
3939 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3942 attrs = MMPLAYER_GET_ATTRS(player);
3943 MMPLAYER_RETURN_IF_FAIL(attrs);
3945 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3946 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3947 LOGD("set video param : method %d", display_method);
3951 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3953 MMHandleType attrs = 0;
3954 int display_method = 0;
3955 void *handle = NULL;
3957 int wl_window_x = 0;
3958 int wl_window_y = 0;
3959 int wl_window_width = 0;
3960 int wl_window_height = 0;
3963 /* check video sinkbin is created */
3964 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3967 attrs = MMPLAYER_GET_ATTRS(player);
3968 MMPLAYER_RETURN_IF_FAIL(attrs);
3970 /* check roi mode is set */
3971 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3972 if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3973 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3976 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3979 /*It should be set after setting window*/
3980 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3981 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3982 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3983 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3985 /* After setting window handle, set render rectangle */
3986 gst_video_overlay_set_render_rectangle(
3987 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3988 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3989 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3990 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3995 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3997 MMHandleType attrs = 0;
3998 void *handle = NULL;
4000 gboolean use_wl_surface = 0;
4001 void * wl_display = NULL;
4002 GstContext *context = NULL;
4004 /* check video sinkbin is created */
4005 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4008 attrs = MMPLAYER_GET_ATTRS(player);
4009 MMPLAYER_RETURN_IF_FAIL(attrs);
4011 /* common case if using overlay surface */
4012 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
4013 mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
4015 if (handle && !use_wl_surface) {
4016 /* default is using wl_surface_id */
4017 unsigned int wl_surface_id = 0;
4018 wl_surface_id = *(int*)handle;
4019 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
4020 gst_video_overlay_set_wl_window_wl_surface_id(
4021 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4023 } else if (handle && use_wl_surface) {
4024 /* use wl_surface for legacy_player_test */
4025 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
4027 context = gst_wayland_display_handle_context_new(wl_display);
4029 gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
4031 guintptr wl_surface = (guintptr)handle;
4032 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
4033 gst_video_overlay_set_window_handle(
4034 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4037 /* FIXIT : is it error case? */
4038 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
4043 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
4045 bool update_all_param = FALSE;
4048 /* check video sinkbin is created */
4049 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4050 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4052 if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
4053 LOGE("can not find waylandsink");
4054 return MM_ERROR_PLAYER_INTERNAL;
4057 LOGD("param_name : %s", param_name);
4058 if (!g_strcmp0(param_name, "update_all_param"))
4059 update_all_param = TRUE;
4061 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
4062 __mmplayer_video_param_set_display_overlay(player);
4063 if (update_all_param || !g_strcmp0(param_name, "display_method"))
4064 __mmplayer_video_param_set_display_method(player);
4065 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
4066 __mmplayer_video_param_set_render_rectangle(player);
4067 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
4068 __mmplayer_video_param_set_display_visible(player);
4069 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4070 __mmplayer_video_param_set_display_rotation(player);
4072 return MM_ERROR_NONE;
4076 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
4078 MMHandleType attrs = 0;
4079 int surface_type = 0;
4080 int ret = MM_ERROR_NONE;
4084 /* check video sinkbin is created */
4085 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4086 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4088 attrs = MMPLAYER_GET_ATTRS(player);
4090 LOGE("cannot get content attribute");
4091 return MM_ERROR_PLAYER_INTERNAL;
4093 LOGD("param_name : %s", param_name);
4095 /* update display surface */
4096 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4097 LOGD("check display surface type attribute: %d", surface_type);
4099 /* configuring display */
4100 switch (surface_type) {
4101 case MM_DISPLAY_SURFACE_OVERLAY:
4103 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4104 if (ret != MM_ERROR_NONE)
4112 return MM_ERROR_NONE;
4116 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4118 GList* bucket = element_bucket;
4119 MMPlayerGstElement* element = NULL;
4120 MMPlayerGstElement* prv_element = NULL;
4121 gint successful_link_count = 0;
4125 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4127 prv_element = (MMPlayerGstElement*)bucket->data;
4128 bucket = bucket->next;
4130 for (; bucket; bucket = bucket->next) {
4131 element = (MMPlayerGstElement*)bucket->data;
4133 if (element && element->gst) {
4134 /* If next element is audio appsrc then make a separate audio pipeline */
4135 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4136 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4137 prv_element = element;
4141 if (prv_element && prv_element->gst) {
4142 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4143 LOGD("linking [%s] to [%s] success\n",
4144 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4145 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4146 successful_link_count++;
4148 LOGD("linking [%s] to [%s] failed\n",
4149 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4150 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4156 prv_element = element;
4161 return successful_link_count;
4165 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4167 GList* bucket = element_bucket;
4168 MMPlayerGstElement* element = NULL;
4169 int successful_add_count = 0;
4173 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4174 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4176 for (; bucket; bucket = bucket->next) {
4177 element = (MMPlayerGstElement*)bucket->data;
4179 if (element && element->gst) {
4180 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4181 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4182 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4183 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4186 successful_add_count++;
4192 return successful_add_count;
4195 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4197 mm_player_t* player = (mm_player_t*) data;
4198 GstCaps *caps = NULL;
4199 GstStructure *str = NULL;
4204 MMPLAYER_RETURN_IF_FAIL(pad)
4205 MMPLAYER_RETURN_IF_FAIL(unused)
4206 MMPLAYER_RETURN_IF_FAIL(data)
4208 caps = gst_pad_get_current_caps(pad);
4212 str = gst_caps_get_structure(caps, 0);
4216 name = gst_structure_get_name(str);
4220 LOGD("name = %s\n", name);
4222 if (strstr(name, "audio")) {
4223 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4225 if (player->audio_stream_changed_cb) {
4226 LOGE("call the audio stream changed cb\n");
4227 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4229 } else if (strstr(name, "video")) {
4230 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4232 if (player->video_stream_changed_cb) {
4233 LOGE("call the video stream changed cb\n");
4234 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4241 gst_caps_unref(caps);
4251 * This function is to create audio pipeline for playing.
4253 * @param player [in] handle of player
4255 * @return This function returns zero on success.
4257 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4259 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4260 x_bin[x_id].id = x_id;\
4261 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4262 if (!x_bin[x_id].gst) {\
4263 LOGE("failed to create %s \n", x_factory);\
4267 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4268 x_bin[x_id].id = x_id;\
4269 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4270 if (!x_bin[x_id].gst) {\
4271 LOGE("failed to create %s \n", x_factory);\
4274 if (x_player->ini.set_dump_element_flag)\
4275 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4277 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4278 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
4279 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4280 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4284 /* macro for code readability. just for sinkbin-creation functions */
4285 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4287 x_bin[x_id].id = x_id;\
4288 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4289 if (!x_bin[x_id].gst) {\
4290 LOGE("failed to create %s \n", x_factory);\
4293 if (x_player->ini.set_dump_element_flag)\
4294 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4297 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4301 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4306 MMPLAYER_RETURN_IF_FAIL(player);
4308 if (player->audio_stream_buff_list) {
4309 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4310 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4313 LOGD("[%lld] send remained data.", tmp->channel_mask);
4314 __mmplayer_audio_stream_send_data(player, tmp);
4317 g_free(tmp->pcm_data);
4321 g_list_free(player->audio_stream_buff_list);
4322 player->audio_stream_buff_list = NULL;
4329 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4331 MMPlayerAudioStreamDataType audio_stream = { 0, };
4334 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4336 audio_stream.bitrate = a_buffer->bitrate;
4337 audio_stream.channel = a_buffer->channel;
4338 audio_stream.depth = a_buffer->depth;
4339 audio_stream.is_little_endian = a_buffer->is_little_endian;
4340 audio_stream.channel_mask = a_buffer->channel_mask;
4341 audio_stream.data_size = a_buffer->data_size;
4342 audio_stream.data = a_buffer->pcm_data;
4344 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4345 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4351 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4353 mm_player_t* player = (mm_player_t*) data;
4358 gint endianness = 0;
4359 guint64 channel_mask = 0;
4360 void *a_data = NULL;
4362 mm_player_audio_stream_buff_t *a_buffer = NULL;
4363 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4367 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4369 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4370 a_data = mapinfo.data;
4371 a_size = mapinfo.size;
4373 GstCaps *caps = gst_pad_get_current_caps(pad);
4374 GstStructure *structure = gst_caps_get_structure(caps, 0);
4376 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4377 gst_structure_get_int(structure, "rate", &rate);
4378 gst_structure_get_int(structure, "channels", &channel);
4379 gst_structure_get_int(structure, "depth", &depth);
4380 gst_structure_get_int(structure, "endianness", &endianness);
4381 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4382 gst_caps_unref(GST_CAPS(caps));
4384 /* In case of the sync is false, use buffer list. *
4385 * The num of buffer list depends on the num of audio channels */
4386 if (player->audio_stream_buff_list) {
4387 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4388 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4390 if (channel_mask == tmp->channel_mask) {
4391 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4392 if (tmp->data_size + a_size < tmp->buff_size) {
4393 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4394 tmp->data_size += a_size;
4396 /* send data to client */
4397 __mmplayer_audio_stream_send_data(player, tmp);
4399 if (a_size > tmp->buff_size) {
4400 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4401 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4402 if (tmp->pcm_data == NULL) {
4403 LOGE("failed to realloc data.");
4406 tmp->buff_size = a_size;
4408 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4409 memcpy(tmp->pcm_data, a_data, a_size);
4410 tmp->data_size = a_size;
4415 LOGE("data is empty in list.");
4421 /* create new audio stream data */
4422 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4423 if (a_buffer == NULL) {
4424 LOGE("failed to alloc data.");
4427 a_buffer->bitrate = rate;
4428 a_buffer->channel = channel;
4429 a_buffer->depth = depth;
4430 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4431 a_buffer->channel_mask = channel_mask;
4432 a_buffer->data_size = a_size;
4434 if (!player->audio_stream_sink_sync) {
4435 /* If sync is FALSE, use buffer list to reduce the IPC. */
4436 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4437 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4438 if (a_buffer->pcm_data == NULL) {
4439 LOGE("failed to alloc data.");
4443 memcpy(a_buffer->pcm_data, a_data, a_size);
4444 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4445 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4447 /* If sync is TRUE, send data directly. */
4448 a_buffer->pcm_data = a_data;
4449 __mmplayer_audio_stream_send_data(player, a_buffer);
4454 gst_buffer_unmap(buffer, &mapinfo);
4459 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4461 mm_player_t* player = (mm_player_t*)data;
4462 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4463 GstPad* sinkpad = NULL;
4464 GstElement *queue = NULL, *sink = NULL;
4467 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4469 queue = gst_element_factory_make("queue", NULL);
4470 if (queue == NULL) {
4471 LOGD("fail make queue\n");
4475 sink = gst_element_factory_make("fakesink", NULL);
4477 LOGD("fail make fakesink\n");
4481 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4483 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4484 LOGW("failed to link queue & sink\n");
4488 sinkpad = gst_element_get_static_pad(queue, "sink");
4490 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4491 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4495 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4497 gst_object_unref(sinkpad);
4498 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4499 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4501 gst_element_set_state(sink, GST_STATE_PAUSED);
4502 gst_element_set_state(queue, GST_STATE_PAUSED);
4504 MMPLAYER_SIGNAL_CONNECT(player,
4506 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4508 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4515 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4517 gst_object_unref(GST_OBJECT(queue));
4521 gst_object_unref(GST_OBJECT(sink));
4525 gst_object_unref(GST_OBJECT(sinkpad));
4532 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4534 #define MAX_PROPS_LEN 64
4535 gint latency_mode = 0;
4536 gchar *stream_type = NULL;
4537 gchar *latency = NULL;
4539 gchar stream_props[MAX_PROPS_LEN] = {0,};
4540 GstStructure *props = NULL;
4543 * It should be set after player creation through attribute.
4544 * But, it can not be changed during playing.
4547 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4548 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4551 LOGE("stream_type is null.\n");
4553 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4554 props = gst_structure_from_string(stream_props, NULL);
4555 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4556 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4559 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4561 switch (latency_mode) {
4562 case AUDIO_LATENCY_MODE_LOW:
4563 latency = g_strndup("low", 3);
4565 case AUDIO_LATENCY_MODE_MID:
4566 latency = g_strndup("mid", 3);
4568 case AUDIO_LATENCY_MODE_HIGH:
4569 latency = g_strndup("high", 4);
4573 #if 0 //need to check
4574 if (player->sound_focus.user_route_policy != 0)
4575 route_path = player->sound_focus.user_route_policy;
4577 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4578 "latency", latency_mode,
4581 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4582 volume_type, route_path, latency_mode);
4587 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4591 LOGD("audiosink property - latency=%s \n", latency);
4599 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4601 MMPlayerGstElement* first_element = NULL;
4602 MMPlayerGstElement* audiobin = NULL;
4603 MMHandleType attrs = 0;
4605 GstPad *ghostpad = NULL;
4606 GList* element_bucket = NULL;
4607 gboolean link_audio_sink_now = TRUE;
4612 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4615 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4617 LOGE("failed to allocate memory for audiobin\n");
4618 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4621 attrs = MMPLAYER_GET_ATTRS(player);
4624 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4625 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4626 if (!audiobin[MMPLAYER_A_BIN].gst) {
4627 LOGE("failed to create audiobin\n");
4632 player->pipeline->audiobin = audiobin;
4634 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4636 /* Adding audiotp plugin for reverse trickplay feature */
4637 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4645 if (player->set_mode.pcm_extraction) {
4646 // pcm extraction only and no sound output
4647 if (player->audio_stream_render_cb_ex) {
4648 char *caps_str = NULL;
4649 GstCaps* caps = NULL;
4650 gchar *format = NULL;
4653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4655 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4657 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4659 caps = gst_caps_new_simple("audio/x-raw",
4660 "format", G_TYPE_STRING, format,
4661 "rate", G_TYPE_INT, player->pcm_samplerate,
4662 "channels", G_TYPE_INT, player->pcm_channel,
4664 caps_str = gst_caps_to_string(caps);
4665 LOGD("new caps : %s\n", caps_str);
4667 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4670 gst_caps_unref(caps);
4671 MMPLAYER_FREEIF(caps_str);
4673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4676 /* raw pad handling signal */
4677 MMPLAYER_SIGNAL_CONNECT(player,
4678 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4679 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4680 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4682 int dst_samplerate = 0;
4683 int dst_channels = 0;
4685 char *caps_str = NULL;
4686 GstCaps* caps = NULL;
4688 /* get conf. values */
4689 mm_attrs_multiple_get(player->attrs,
4691 "pcm_extraction_samplerate", &dst_samplerate,
4692 "pcm_extraction_channels", &dst_channels,
4693 "pcm_extraction_depth", &dst_depth,
4697 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4698 caps = gst_caps_new_simple("audio/x-raw",
4699 "rate", G_TYPE_INT, dst_samplerate,
4700 "channels", G_TYPE_INT, dst_channels,
4701 "depth", G_TYPE_INT, dst_depth,
4703 caps_str = gst_caps_to_string(caps);
4704 LOGD("new caps : %s\n", caps_str);
4706 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4709 gst_caps_unref(caps);
4710 MMPLAYER_FREEIF(caps_str);
4713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4720 //GstCaps* caps = NULL;
4723 /* for logical volume control */
4724 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4727 if (player->sound.mute) {
4728 LOGD("mute enabled\n");
4729 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4734 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4735 caps = gst_caps_from_string("audio/x-raw-int, "
4736 "endianness = (int) LITTLE_ENDIAN, "
4737 "signed = (boolean) true, "
4738 "width = (int) 16, "
4739 "depth = (int) 16");
4740 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4741 gst_caps_unref(caps);
4744 /* chech if multi-chennels */
4745 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4746 GstPad *srcpad = NULL;
4747 GstCaps *caps = NULL;
4749 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4750 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4751 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4752 GstStructure *str = gst_caps_get_structure(caps, 0);
4754 gst_structure_get_int(str, "channels", &channels);
4755 gst_caps_unref(caps);
4757 gst_object_unref(srcpad);
4761 /* audio effect element. if audio effect is enabled */
4762 if ((strcmp(player->ini.audioeffect_element, ""))
4764 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4765 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4767 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4769 if ((!player->bypass_audio_effect)
4770 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4771 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4772 if (!_mmplayer_audio_effect_custom_apply(player))
4773 LOGI("apply audio effect(custom) setting success\n");
4777 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4778 && (player->set_mode.rich_audio))
4779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4781 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4782 if (player->set_mode.rich_audio && channels <= 2)
4783 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4786 /* create audio sink */
4787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4790 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4791 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4794 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4795 (player->videodec_linked && player->ini.use_system_clock)) {
4796 LOGD("system clock will be used.\n");
4797 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4800 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4801 __mmplayer_gst_set_audiosink_property(player, attrs);
4804 if (audiobin[MMPLAYER_A_SINK].gst) {
4805 GstPad *sink_pad = NULL;
4806 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4807 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4808 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4809 gst_object_unref(GST_OBJECT(sink_pad));
4812 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4814 /* adding created elements to bin */
4815 LOGD("adding created elements to bin\n");
4816 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4817 LOGE("failed to add elements\n");
4821 /* linking elements in the bucket by added order. */
4822 LOGD("Linking elements in the bucket by added order.\n");
4823 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4824 LOGE("failed to link elements\n");
4828 /* get first element's sinkpad for creating ghostpad */
4829 first_element = (MMPlayerGstElement *)element_bucket->data;
4830 if (!first_element) {
4831 LOGE("failed to get first elem\n");
4835 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4837 LOGE("failed to get pad from first element of audiobin\n");
4841 ghostpad = gst_ghost_pad_new("sink", pad);
4843 LOGE("failed to create ghostpad\n");
4847 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4848 LOGE("failed to add ghostpad to audiobin\n");
4852 gst_object_unref(pad);
4854 g_list_free(element_bucket);
4856 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4860 return MM_ERROR_NONE;
4864 LOGD("ERROR : releasing audiobin\n");
4867 gst_object_unref(GST_OBJECT(pad));
4870 gst_object_unref(GST_OBJECT(ghostpad));
4873 g_list_free(element_bucket);
4875 /* release element which are not added to bin */
4876 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4877 /* NOTE : skip bin */
4878 if (audiobin[i].gst) {
4879 GstObject* parent = NULL;
4880 parent = gst_element_get_parent(audiobin[i].gst);
4883 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4884 audiobin[i].gst = NULL;
4886 gst_object_unref(GST_OBJECT(parent));
4890 /* release audiobin with it's childs */
4891 if (audiobin[MMPLAYER_A_BIN].gst)
4892 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4894 MMPLAYER_FREEIF(audiobin);
4896 player->pipeline->audiobin = NULL;
4898 return MM_ERROR_PLAYER_INTERNAL;
4901 static GstPadProbeReturn
4902 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4904 mm_player_t* player = (mm_player_t*) u_data;
4905 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4906 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4908 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4910 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4911 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4913 return GST_PAD_PROBE_OK;
4916 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4918 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4921 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4923 int ret = MM_ERROR_NONE;
4925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4926 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4928 MMPLAYER_VIDEO_BO_LOCK(player);
4930 if (player->video_bo_list) {
4931 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4932 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4933 if (tmp && tmp->bo == bo) {
4935 LOGD("release bo %p", bo);
4936 MMPLAYER_VIDEO_BO_UNLOCK(player);
4937 MMPLAYER_VIDEO_BO_SIGNAL(player);
4942 /* hw codec is running or the list was reset for DRC. */
4943 LOGW("there is no bo list.");
4945 MMPLAYER_VIDEO_BO_UNLOCK(player);
4947 LOGW("failed to find bo %p", bo);
4952 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4957 MMPLAYER_RETURN_IF_FAIL(player);
4959 MMPLAYER_VIDEO_BO_LOCK(player);
4960 if (player->video_bo_list) {
4961 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4962 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4963 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4966 tbm_bo_unref(tmp->bo);
4970 g_list_free(player->video_bo_list);
4971 player->video_bo_list = NULL;
4973 player->video_bo_size = 0;
4974 MMPLAYER_VIDEO_BO_UNLOCK(player);
4981 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4984 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4985 gboolean ret = TRUE;
4987 /* check DRC, if it is, destroy the prev bo list to create again */
4988 if (player->video_bo_size != size) {
4989 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4990 __mmplayer_video_stream_destroy_bo_list(player);
4991 player->video_bo_size = size;
4994 MMPLAYER_VIDEO_BO_LOCK(player);
4996 if ((!player->video_bo_list) ||
4997 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4999 /* create bo list */
5001 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5003 if (player->video_bo_list) {
5004 /* if bo list did not created all, try it again. */
5005 idx = g_list_length(player->video_bo_list);
5006 LOGD("bo list exist(len: %d)", idx);
5009 for (; idx < player->ini.num_of_video_bo; idx++) {
5010 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5012 LOGE("Fail to alloc bo_info.");
5015 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5017 LOGE("Fail to tbm_bo_alloc.");
5021 bo_info->using = FALSE;
5022 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5025 /* update video num buffers */
5026 player->video_num_buffers = idx;
5027 if (idx == player->ini.num_of_video_bo)
5028 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5031 MMPLAYER_VIDEO_BO_UNLOCK(player);
5035 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5039 /* get bo from list*/
5040 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5041 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5042 if (tmp && (tmp->using == FALSE)) {
5043 LOGD("found bo %p to use", tmp->bo);
5045 MMPLAYER_VIDEO_BO_UNLOCK(player);
5050 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5051 MMPLAYER_VIDEO_BO_UNLOCK(player);
5055 if (player->ini.video_bo_timeout <= 0) {
5056 MMPLAYER_VIDEO_BO_WAIT(player);
5058 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5059 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5066 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5068 mm_player_t* player = (mm_player_t*)data;
5070 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5072 /* send prerolled pkt */
5073 player->video_stream_prerolled = FALSE;
5075 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5077 /* not to send prerolled pkt again */
5078 player->video_stream_prerolled = TRUE;
5082 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5084 mm_player_t* player = (mm_player_t*)data;
5085 GstCaps *caps = NULL;
5086 MMPlayerVideoStreamDataType stream;
5087 MMVideoBuffer *video_buffer = NULL;
5088 GstMemory *dataBlock = NULL;
5089 GstMemory *metaBlock = NULL;
5090 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5091 GstStructure *structure = NULL;
5092 const gchar *string_format = NULL;
5093 unsigned int fourcc = 0;
5096 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5098 if (player->video_stream_prerolled) {
5099 player->video_stream_prerolled = FALSE;
5100 LOGD("skip the prerolled pkt not to send it again");
5104 caps = gst_pad_get_current_caps(pad);
5106 LOGE("Caps is NULL.");
5110 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5112 /* clear stream data structure */
5113 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5115 structure = gst_caps_get_structure(caps, 0);
5116 gst_structure_get_int(structure, "width", & (stream.width));
5117 gst_structure_get_int(structure, "height", & (stream.height));
5118 string_format = gst_structure_get_string(structure, "format");
5120 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5121 stream.format = util_get_pixtype(fourcc);
5122 gst_caps_unref(caps);
5126 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5127 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5130 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5131 LOGE("Wrong condition!!");
5135 /* set size and timestamp */
5136 dataBlock = gst_buffer_peek_memory(buffer, 0);
5137 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5138 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5140 /* check zero-copy */
5141 if (player->set_mode.video_zc &&
5142 player->set_mode.media_packet_video_stream &&
5143 gst_buffer_n_memory(buffer) > 1) {
5144 metaBlock = gst_buffer_peek_memory(buffer, 1);
5145 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5146 video_buffer = (MMVideoBuffer *)mapinfo.data;
5149 if (video_buffer) { /* hw codec */
5151 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5152 /* copy pointer of tbm bo, stride, elevation */
5153 memcpy(stream.bo, video_buffer->handle.bo,
5154 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5155 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5156 /* FIXME: need to check this path */
5157 memcpy(stream.data, video_buffer->data,
5158 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5160 memcpy(stream.stride, video_buffer->stride_width,
5161 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5162 memcpy(stream.elevation, video_buffer->stride_height,
5163 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5164 /* set gst buffer */
5165 stream.internal_buffer = buffer;
5166 } else { /* sw codec */
5167 tbm_bo_handle thandle;
5168 int stride = GST_ROUND_UP_4(stream.width);
5169 int elevation = stream.height;
5173 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5175 LOGE("fail to gst_memory_map");
5179 stream.stride[0] = stride;
5180 stream.elevation[0] = elevation;
5181 if (stream.format == MM_PIXEL_FORMAT_I420) {
5182 stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5183 stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5184 size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5185 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5186 stream.stride[0] = stream.width * 4;
5187 size = stream.stride[0] * stream.height;
5189 LOGE("Not support format %d", stream.format);
5190 gst_memory_unmap(dataBlock, &mapinfo);
5193 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5194 if (!stream.bo[0]) {
5195 LOGE("Fail to tbm_bo_alloc!!");
5196 gst_memory_unmap(dataBlock, &mapinfo);
5199 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5200 if (thandle.ptr && mapinfo.data)
5201 memcpy(thandle.ptr, mapinfo.data, size);
5203 LOGE("data pointer is wrong. dest : %p, src : %p",
5204 thandle.ptr, mapinfo.data);
5205 tbm_bo_unmap(stream.bo[0]);
5208 if (player->video_stream_cb)
5209 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5212 gst_memory_unmap(metaBlock, &mapinfo);
5214 gst_memory_unmap(dataBlock, &mapinfo);
5220 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5222 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5223 gchar* video_csc = "videoconvert"; // default colorspace converter
5224 GList* element_bucket = *bucket;
5226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5230 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5232 if (player->set_mode.video_zc) {
5233 video_csc = ""; /* videosinks don't use videoconvert normally */
5235 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5236 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5237 video_csc = "videoconvert";
5239 if (video_csc && (strcmp(video_csc, ""))) {
5240 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5241 LOGD("using video converter: %s", video_csc);
5244 /* set video rotator */
5245 if (!player->set_mode.video_zc)
5246 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5248 *bucket = element_bucket;
5250 return MM_ERROR_NONE;
5255 return MM_ERROR_PLAYER_INTERNAL;
5259 * This function is to create video pipeline.
5261 * @param player [in] handle of player
5262 * caps [in] src caps of decoder
5263 * surface_type [in] surface type for video rendering
5265 * @return This function returns zero on success.
5267 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5271 * - video overlay surface(arm/x86) : waylandsink
5274 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5278 GList*element_bucket = NULL;
5279 MMPlayerGstElement* first_element = NULL;
5280 MMPlayerGstElement* videobin = NULL;
5281 gchar *videosink_element = NULL;
5285 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5290 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5292 player->pipeline->videobin = videobin;
5294 attrs = MMPLAYER_GET_ATTRS(player);
5296 LOGE("cannot get content attribute");
5297 return MM_ERROR_PLAYER_INTERNAL;
5301 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5302 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5303 if (!videobin[MMPLAYER_V_BIN].gst) {
5304 LOGE("failed to create videobin");
5308 int enable_video_decoded_cb = 0;
5309 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5311 /* set video sink */
5312 switch (surface_type) {
5313 case MM_DISPLAY_SURFACE_OVERLAY:
5314 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5316 if (strlen(player->ini.videosink_element_overlay) > 0)
5317 videosink_element = player->ini.videosink_element_overlay;
5321 case MM_DISPLAY_SURFACE_NULL:
5322 if (strlen(player->ini.videosink_element_fake) > 0)
5323 videosink_element = player->ini.videosink_element_fake;
5327 case MM_DISPLAY_SURFACE_REMOTE:
5328 if (strlen(player->ini.videosink_element_fake) > 0)
5329 videosink_element = player->ini.videosink_element_fake;
5334 LOGE("unidentified surface type");
5337 LOGD("selected videosink name: %s", videosink_element);
5339 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5341 /* additional setting for sink plug-in */
5342 switch (surface_type) {
5343 case MM_DISPLAY_SURFACE_OVERLAY:
5345 bool use_tbm = player->set_mode.video_zc;
5347 LOGD("selected videosink name: %s", videosink_element);
5349 /* support shard memory with S/W codec on HawkP */
5350 if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5351 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5352 "use-tbm", use_tbm, NULL);
5358 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5361 LOGD("disable last-sample");
5362 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5366 if (player->set_mode.media_packet_video_stream) {
5368 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5370 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5372 MMPLAYER_SIGNAL_CONNECT(player,
5373 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5374 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5376 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5379 MMPLAYER_SIGNAL_CONNECT(player,
5380 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5381 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5383 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5388 case MM_DISPLAY_SURFACE_REMOTE:
5390 if (player->set_mode.media_packet_video_stream) {
5391 LOGE("add data probe at videosink");
5392 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5393 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5395 MMPLAYER_SIGNAL_CONNECT(player,
5396 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5397 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5399 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5402 MMPLAYER_SIGNAL_CONNECT(player,
5403 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5404 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5406 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5411 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5414 LOGD("disable last-sample");
5415 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5425 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5428 if (videobin[MMPLAYER_V_SINK].gst) {
5429 GstPad *sink_pad = NULL;
5430 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5432 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5433 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5434 gst_object_unref(GST_OBJECT(sink_pad));
5436 LOGW("failed to get sink pad from videosink\n");
5439 /* store it as it's sink element */
5440 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5442 /* adding created elements to bin */
5443 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5444 LOGE("failed to add elements\n");
5448 /* Linking elements in the bucket by added order */
5449 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5450 LOGE("failed to link elements\n");
5454 /* get first element's sinkpad for creating ghostpad */
5456 first_element = (MMPlayerGstElement *)element_bucket->data;
5457 if (!first_element) {
5458 LOGE("failed to get first element from bucket\n");
5462 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5464 LOGE("failed to get pad from first element\n");
5468 /* create ghostpad */
5469 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5470 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5471 LOGE("failed to add ghostpad to videobin\n");
5474 gst_object_unref(pad);
5476 /* done. free allocated variables */
5478 g_list_free(element_bucket);
5480 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5484 return MM_ERROR_NONE;
5487 LOGE("ERROR : releasing videobin\n");
5489 g_list_free(element_bucket);
5492 gst_object_unref(GST_OBJECT(pad));
5494 /* release videobin with it's childs */
5495 if (videobin[MMPLAYER_V_BIN].gst)
5496 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5499 MMPLAYER_FREEIF(videobin);
5501 player->pipeline->videobin = NULL;
5503 return MM_ERROR_PLAYER_INTERNAL;
5506 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5508 GList *element_bucket = NULL;
5509 MMPlayerGstElement *textbin = player->pipeline->textbin;
5511 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5512 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5513 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5514 "signal-handoffs", FALSE,
5517 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5518 MMPLAYER_SIGNAL_CONNECT(player,
5519 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5520 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5522 G_CALLBACK(__mmplayer_update_subtitle),
5525 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5526 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5527 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5529 if (!player->play_subtitle) {
5530 LOGD("add textbin sink as sink element of whole pipeline.\n");
5531 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5534 /* adding created elements to bin */
5535 LOGD("adding created elements to bin\n");
5536 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5537 LOGE("failed to add elements\n");
5541 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5542 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5543 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5545 /* linking elements in the bucket by added order. */
5546 LOGD("Linking elements in the bucket by added order.\n");
5547 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5548 LOGE("failed to link elements\n");
5552 /* done. free allocated variables */
5553 g_list_free(element_bucket);
5555 if (textbin[MMPLAYER_T_QUEUE].gst) {
5557 GstPad *ghostpad = NULL;
5559 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5561 LOGE("failed to get video pad of textbin\n");
5562 return MM_ERROR_PLAYER_INTERNAL;
5565 ghostpad = gst_ghost_pad_new("text_sink", pad);
5566 gst_object_unref(pad);
5569 LOGE("failed to create ghostpad of textbin\n");
5573 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5574 LOGE("failed to add ghostpad to textbin\n");
5579 return MM_ERROR_NONE;
5582 g_list_free(element_bucket);
5584 return MM_ERROR_PLAYER_INTERNAL;
5587 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5589 MMPlayerGstElement *textbin = NULL;
5590 GList *element_bucket = NULL;
5595 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5598 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5600 LOGE("failed to allocate memory for textbin\n");
5601 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5605 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5606 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5607 if (!textbin[MMPLAYER_T_BIN].gst) {
5608 LOGE("failed to create textbin\n");
5613 player->pipeline->textbin = textbin;
5616 if (player->use_textoverlay) {
5617 LOGD("use textoverlay for displaying \n");
5619 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5621 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5623 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5625 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5627 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5628 LOGE("failed to link queue and converter\n");
5632 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5633 LOGE("failed to link queue and textoverlay\n");
5637 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5638 LOGE("failed to link queue and textoverlay\n");
5642 int surface_type = 0;
5644 LOGD("use subtitle message for displaying \n");
5646 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5648 switch (surface_type) {
5649 case MM_DISPLAY_SURFACE_OVERLAY:
5650 case MM_DISPLAY_SURFACE_NULL:
5651 case MM_DISPLAY_SURFACE_REMOTE:
5652 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5653 LOGE("failed to make plain text elements\n");
5665 return MM_ERROR_NONE;
5669 LOGD("ERROR : releasing textbin\n");
5671 g_list_free(element_bucket);
5673 /* release element which are not added to bin */
5674 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5675 /* NOTE : skip bin */
5676 if (textbin[i].gst) {
5677 GstObject* parent = NULL;
5678 parent = gst_element_get_parent(textbin[i].gst);
5681 gst_object_unref(GST_OBJECT(textbin[i].gst));
5682 textbin[i].gst = NULL;
5684 gst_object_unref(GST_OBJECT(parent));
5688 /* release textbin with it's childs */
5689 if (textbin[MMPLAYER_T_BIN].gst)
5690 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5692 MMPLAYER_FREEIF(textbin);
5694 player->pipeline->textbin = NULL;
5696 return MM_ERROR_PLAYER_INTERNAL;
5701 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5703 MMPlayerGstElement* mainbin = NULL;
5704 MMHandleType attrs = 0;
5705 GstElement *subsrc = NULL;
5706 GstElement *subparse = NULL;
5707 gchar *subtitle_uri = NULL;
5708 const gchar *charset = NULL;
5714 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716 mainbin = player->pipeline->mainbin;
5718 attrs = MMPLAYER_GET_ATTRS(player);
5720 LOGE("cannot get content attribute\n");
5721 return MM_ERROR_PLAYER_INTERNAL;
5724 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5725 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5726 LOGE("subtitle uri is not proper filepath.\n");
5727 return MM_ERROR_PLAYER_INVALID_URI;
5729 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5732 /* create the subtitle source */
5733 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5735 LOGE("failed to create filesrc element\n");
5738 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5740 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5741 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5743 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5744 LOGW("failed to add queue\n");
5749 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5751 LOGE("failed to create subparse element\n");
5755 charset = util_get_charset(subtitle_uri);
5757 LOGD("detected charset is %s\n", charset);
5758 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5761 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5762 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5764 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5765 LOGW("failed to add subparse\n");
5769 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5770 LOGW("failed to link subsrc and subparse\n");
5774 player->play_subtitle = TRUE;
5775 player->adjust_subtitle_pos = 0;
5777 LOGD("play subtitle using subtitle file\n");
5779 if (player->pipeline->textbin == NULL) {
5780 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
5781 LOGE("failed to create textbin. continuing without text\n");
5785 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5786 LOGW("failed to add textbin\n");
5790 LOGD("link text input selector and textbin ghost pad");
5792 player->textsink_linked = 1;
5793 player->external_text_idx = 0;
5794 LOGI("player->textsink_linked set to 1\n");
5796 LOGD("text bin has been created. reuse it.");
5797 player->external_text_idx = 1;
5800 if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5801 LOGW("failed to link subparse and textbin\n");
5805 pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5808 LOGE("failed to get sink pad from textsink to probe data");
5809 return MM_ERROR_PLAYER_INTERNAL;
5812 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5813 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5815 gst_object_unref(pad);
5818 /* create dot. for debugging */
5819 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5822 return MM_ERROR_NONE;
5825 player->textsink_linked = 0;
5826 return MM_ERROR_PLAYER_INTERNAL;
5830 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5832 mm_player_t* player = (mm_player_t*) data;
5833 MMMessageParamType msg = {0, };
5834 GstClockTime duration = 0;
5835 gpointer text = NULL;
5836 guint text_size = 0;
5837 gboolean ret = TRUE;
5838 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5842 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5843 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5845 if (player->is_subtitle_force_drop)
5847 LOGW("subtitle is dropped forcedly.");
5851 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5852 text = mapinfo.data;
5853 text_size = mapinfo.size;
5854 duration = GST_BUFFER_DURATION(buffer);
5856 if (player->set_mode.subtitle_off) {
5857 LOGD("subtitle is OFF.\n");
5861 if (!text || (text_size == 0)) {
5862 LOGD("There is no subtitle to be displayed.\n");
5866 msg.data = (void *) text;
5867 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5869 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5871 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5872 gst_buffer_unmap(buffer, &mapinfo);
5879 static GstPadProbeReturn
5880 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5883 mm_player_t *player = (mm_player_t *) u_data;
5884 GstClockTime cur_timestamp = 0;
5885 gint64 adjusted_timestamp = 0;
5886 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5888 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5890 if (player->set_mode.subtitle_off) {
5891 LOGD("subtitle is OFF.\n");
5895 if (player->adjust_subtitle_pos == 0) {
5896 LOGD("nothing to do");
5900 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5901 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5903 if (adjusted_timestamp < 0) {
5904 LOGD("adjusted_timestamp under zero");
5909 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5910 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5911 GST_TIME_ARGS(cur_timestamp),
5912 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5914 return GST_PAD_PROBE_OK;
5916 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5920 /* check player and subtitlebin are created */
5921 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5922 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5924 if (position == 0) {
5925 LOGD("nothing to do\n");
5927 return MM_ERROR_NONE;
5931 case MM_PLAYER_POS_FORMAT_TIME:
5933 /* check current postion */
5934 player->adjust_subtitle_pos = position;
5936 LOGD("save adjust_subtitle_pos in player") ;
5942 LOGW("invalid format.\n");
5944 return MM_ERROR_INVALID_ARGUMENT;
5950 return MM_ERROR_NONE;
5952 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5955 LOGD("adjusting video_pos in player") ;
5956 int current_pos = 0;
5957 /* check player and videobin are created */
5958 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5959 if (!player->pipeline->videobin ||
5960 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5961 LOGD("no video pipeline or sink is there");
5962 return MM_ERROR_PLAYER_INVALID_STATE ;
5965 LOGD("nothing to do\n");
5967 return MM_ERROR_NONE;
5969 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
5970 LOGD("failed to get current position");
5971 return MM_ERROR_PLAYER_INTERNAL;
5973 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5974 LOGD("enter video delay is valid");
5976 LOGD("enter video delay is crossing content boundary");
5977 return MM_ERROR_INVALID_ARGUMENT ;
5979 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5980 LOGD("video delay has been done");
5983 return MM_ERROR_NONE;
5987 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5989 GstElement *appsrc = element;
5990 tBuffer *buf = (tBuffer *)user_data;
5991 GstBuffer *buffer = NULL;
5992 GstFlowReturn ret = GST_FLOW_OK;
5995 MMPLAYER_RETURN_IF_FAIL(element);
5996 MMPLAYER_RETURN_IF_FAIL(buf);
5998 buffer = gst_buffer_new();
6000 if (buf->offset >= buf->len) {
6001 LOGD("call eos appsrc\n");
6002 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6006 if (buf->len - buf->offset < size)
6007 len = buf->len - buf->offset + buf->offset;
6009 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, (guint8*)(buf->buf + buf->offset), g_free));
6010 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6011 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6013 //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6014 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6020 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6022 tBuffer *buf = (tBuffer *)user_data;
6024 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6026 buf->offset = (int)size;
6031 static GstBusSyncReply
6032 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6034 mm_player_t *player = (mm_player_t *)data;
6035 GstBusSyncReply reply = GST_BUS_DROP;
6037 if (!(player->pipeline && player->pipeline->mainbin)) {
6038 LOGE("player pipeline handle is null");
6039 return GST_BUS_PASS;
6042 if (!__mmplayer_check_useful_message(player, message)) {
6043 gst_message_unref(message);
6044 return GST_BUS_DROP;
6047 switch (GST_MESSAGE_TYPE(message)) {
6048 case GST_MESSAGE_STATE_CHANGED:
6049 /* post directly for fast launch */
6050 if (player->sync_handler) {
6051 __mmplayer_gst_callback(NULL, message, player);
6052 reply = GST_BUS_DROP;
6054 reply = GST_BUS_PASS;
6056 case GST_MESSAGE_TAG:
6057 __mmplayer_gst_extract_tag_from_msg(player, message);
6061 GstTagList *tags = NULL;
6063 gst_message_parse_tag(message, &tags);
6065 LOGE("TAGS received from element \"%s\".\n",
6066 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6068 gst_tag_list_foreach(tags, print_tag, NULL);
6069 gst_tag_list_free(tags);
6077 case GST_MESSAGE_DURATION_CHANGED:
6078 __mmplayer_gst_handle_duration(player, message);
6080 case GST_MESSAGE_ASYNC_DONE:
6081 /* NOTE:Don't call gst_callback directly
6082 * because previous frame can be showed even though this message is received for seek.
6085 reply = GST_BUS_PASS;
6089 if (reply == GST_BUS_DROP)
6090 gst_message_unref(message);
6096 __mmplayer_gst_create_decoder(mm_player_t *player,
6097 MMPlayerTrackType track,
6099 enum MainElementID elemId,
6102 gboolean ret = TRUE;
6103 GstPad *sinkpad = NULL;
6107 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6109 player->pipeline->mainbin, FALSE);
6110 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6111 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6112 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6114 GstElement *decodebin = NULL;
6115 GstCaps *dec_caps = NULL;
6117 /* create decodebin */
6118 decodebin = gst_element_factory_make("decodebin", name);
6121 LOGE("error : fail to create decodebin for %d decoder\n", track);
6126 /* raw pad handling signal */
6127 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6128 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6130 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6131 before looking for any elements that can handle that stream.*/
6132 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6133 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6135 /* This signal is emitted when a element is added to the bin.*/
6136 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6137 G_CALLBACK(__mmplayer_gst_element_added), player);
6139 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6140 LOGE("failed to add new decodebin\n");
6145 dec_caps = gst_pad_query_caps(srcpad, NULL);
6147 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6148 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6149 gst_caps_unref(dec_caps);
6152 player->pipeline->mainbin[elemId].id = elemId;
6153 player->pipeline->mainbin[elemId].gst = decodebin;
6155 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6157 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6158 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6159 gst_object_unref(GST_OBJECT(decodebin));
6162 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6163 LOGE("failed to sync second level decodebin state with parent\n");
6165 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6169 gst_object_unref(GST_OBJECT(sinkpad));
6178 * This function is to create audio or video pipeline for playing.
6180 * @param player [in] handle of player
6182 * @return This function returns zero on success.
6187 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6190 MMPlayerGstElement *mainbin = NULL;
6191 MMHandleType attrs = 0;
6192 GstElement* element = NULL;
6193 GstElement* elem_src_audio = NULL;
6194 GstElement* elem_src_subtitle = NULL;
6195 GstElement* es_video_queue = NULL;
6196 GstElement* es_audio_queue = NULL;
6197 GstElement* es_subtitle_queue = NULL;
6198 GList* element_bucket = NULL;
6199 gboolean need_state_holder = TRUE;
6201 #ifdef SW_CODEC_ONLY
6202 int surface_type = 0;
6206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6208 /* get profile attribute */
6209 attrs = MMPLAYER_GET_ATTRS(player);
6211 LOGE("cannot get content attribute\n");
6215 /* create pipeline handles */
6216 if (player->pipeline) {
6217 LOGW("pipeline should be released before create new one\n");
6221 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6222 if (player->pipeline == NULL)
6225 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6228 /* create mainbin */
6229 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6230 if (mainbin == NULL)
6233 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6235 /* create pipeline */
6236 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6237 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6238 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6239 LOGE("failed to create pipeline\n");
6242 player->demux_pad_index = 0;
6243 player->subtitle_language_list = NULL;
6245 player->is_subtitle_force_drop = FALSE;
6246 player->last_multiwin_status = FALSE;
6248 _mmplayer_track_initialize(player);
6250 /* create source element */
6251 switch (player->profile.uri_type) {
6252 /* rtsp streamming */
6253 case MM_PLAYER_URI_TYPE_URL_RTSP:
6255 gint network_bandwidth;
6256 gchar *user_agent, *wap_profile;
6258 element = gst_element_factory_make("rtspsrc", "rtsp source");
6261 LOGE("failed to create streaming source element\n");
6266 network_bandwidth = 0;
6267 user_agent = wap_profile = NULL;
6270 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6271 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6272 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6274 SECURE_LOGD("user_agent : %s\n", user_agent);
6275 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6277 /* setting property to streaming source */
6278 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6280 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6282 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6284 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6285 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6286 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6287 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6289 player->use_decodebin = FALSE;
6294 case MM_PLAYER_URI_TYPE_URL_HTTP:
6296 gchar *user_agent, *proxy, *cookies, **cookie_list;
6297 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6298 user_agent = proxy = cookies = NULL;
6300 gint mode = MM_PLAYER_PD_MODE_NONE;
6302 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6304 player->pd_mode = mode;
6306 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6308 if (!MMPLAYER_IS_HTTP_PD(player)) {
6309 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6311 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6314 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6317 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6318 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6319 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6320 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6322 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6323 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6324 LOGD("get timeout from ini\n");
6325 http_timeout = player->ini.http_timeout;
6329 SECURE_LOGD("location : %s\n", player->profile.uri);
6330 SECURE_LOGD("cookies : %s\n", cookies);
6331 SECURE_LOGD("proxy : %s\n", proxy);
6332 SECURE_LOGD("user_agent : %s\n", user_agent);
6333 LOGD("timeout : %d\n", http_timeout);
6335 /* setting property to streaming source */
6336 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6337 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6338 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6340 /* check if prosy is vailid or not */
6341 if (util_check_valid_url(proxy))
6342 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6343 /* parsing cookies */
6344 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6345 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6347 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6349 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6350 LOGW("it's dash. and it's still experimental feature.");
6352 // progressive download
6353 gchar* location = NULL;
6355 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6358 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6360 MMPLAYER_FREEIF(player->pd_file_save_path);
6362 LOGD("PD Location : %s\n", path);
6365 player->pd_file_save_path = g_strdup(path);
6367 LOGE("can't find pd location so, it should be set \n");
6372 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6374 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6378 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6379 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6381 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6383 g_object_get(element, "location", &location, NULL);
6384 LOGD("PD_LOCATION [%s].\n", location);
6392 case MM_PLAYER_URI_TYPE_FILE:
6395 LOGD("using filesrc for 'file://' handler.\n");
6397 element = gst_element_factory_make("filesrc", "source");
6400 LOGE("failed to create filesrc\n");
6404 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6405 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6409 case MM_PLAYER_URI_TYPE_SS:
6411 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6412 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6414 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6418 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6420 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6421 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6422 LOGD("get timeout from ini\n");
6423 http_timeout = player->ini.http_timeout;
6426 /* setting property to streaming source */
6427 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6428 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6431 case MM_PLAYER_URI_TYPE_MS_BUFF:
6433 LOGD("MS buff src is selected\n");
6435 if (player->v_stream_caps) {
6436 element = gst_element_factory_make("appsrc", "video_appsrc");
6438 LOGF("failed to create video app source element[appsrc].\n");
6442 if (player->a_stream_caps) {
6443 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6444 if (!elem_src_audio) {
6445 LOGF("failed to create audio app source element[appsrc].\n");
6449 } else if (player->a_stream_caps) {
6450 /* no video, only audio pipeline*/
6451 element = gst_element_factory_make("appsrc", "audio_appsrc");
6453 LOGF("failed to create audio app source element[appsrc].\n");
6458 if (player->s_stream_caps) {
6459 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6460 if (!elem_src_subtitle) {
6461 LOGF("failed to create subtitle app source element[appsrc].\n");
6466 LOGD("setting app sources properties.\n");
6467 LOGD("location : %s\n", player->profile.uri);
6469 if (player->v_stream_caps && element) {
6470 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6471 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6472 "caps", player->v_stream_caps, NULL);
6474 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6475 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6476 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6477 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6479 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6480 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6481 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6482 G_CALLBACK(__gst_seek_video_data), player);
6484 if (player->a_stream_caps && elem_src_audio) {
6485 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6486 "caps", player->a_stream_caps, NULL);
6488 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6489 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6490 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6491 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6493 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6494 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6495 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6496 G_CALLBACK(__gst_seek_audio_data), player);
6498 } else if (player->a_stream_caps && element) {
6499 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6500 "caps", player->a_stream_caps, NULL);
6502 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6503 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6504 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6505 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6507 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6508 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6509 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6510 G_CALLBACK(__gst_seek_audio_data), player);
6513 if (player->s_stream_caps && elem_src_subtitle) {
6514 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6515 "caps", player->s_stream_caps, NULL);
6517 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6518 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6519 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6520 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6522 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6524 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6525 G_CALLBACK(__gst_seek_subtitle_data), player);
6528 if (player->v_stream_caps && element) {
6529 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6530 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6531 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6532 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6534 if (player->a_stream_caps && elem_src_audio) {
6535 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6536 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6537 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6538 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6540 } else if (player->a_stream_caps && element) {
6541 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6542 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6543 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6544 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6547 if (player->s_stream_caps && elem_src_subtitle)
6548 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6549 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6551 need_state_holder = FALSE;
6553 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6554 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6555 LOGE("failed to commit\n");
6559 case MM_PLAYER_URI_TYPE_MEM:
6561 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6563 LOGD("mem src is selected\n");
6565 element = gst_element_factory_make("appsrc", "mem-source");
6567 LOGE("failed to create appsrc element\n");
6571 g_object_set(element, "stream-type", stream_type, NULL);
6572 g_object_set(element, "size", player->mem_buf.len, NULL);
6573 g_object_set(element, "blocksize", (guint64)20480, NULL);
6575 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6576 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6577 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6578 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6581 case MM_PLAYER_URI_TYPE_URL:
6584 case MM_PLAYER_URI_TYPE_TEMP:
6587 case MM_PLAYER_URI_TYPE_NONE:
6592 /* check source element is OK */
6594 LOGE("no source element was created.\n");
6598 /* take source element */
6599 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6600 mainbin[MMPLAYER_M_SRC].gst = element;
6601 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6603 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6604 player->streamer = __mm_player_streaming_create();
6605 __mm_player_streaming_initialize(player->streamer);
6608 if (MMPLAYER_IS_HTTP_PD(player)) {
6609 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6611 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6612 element = gst_element_factory_make("queue2", "queue2");
6614 LOGE("failed to create http streaming buffer element\n");
6619 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6620 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6621 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6623 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6625 __mm_player_streaming_set_queue2(player->streamer,
6628 player->ini.http_max_size_bytes,
6631 player->ini.http_buffering_limit,
6632 MUXED_BUFFER_TYPE_MEM_QUEUE,
6636 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6637 if (player->v_stream_caps) {
6638 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6639 if (!es_video_queue) {
6640 LOGE("create es_video_queue for es player failed\n");
6643 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6644 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6645 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6646 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6648 /* Adding audio appsrc to bucket */
6649 if (player->a_stream_caps && elem_src_audio) {
6650 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6651 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6652 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6654 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6655 if (!es_audio_queue) {
6656 LOGE("create es_audio_queue for es player failed\n");
6659 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6661 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6662 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6663 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6665 } else if (player->a_stream_caps) {
6666 /* Only audio stream, no video */
6667 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6668 if (!es_audio_queue) {
6669 LOGE("create es_audio_queue for es player failed\n");
6672 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6673 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6674 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6677 if (player->s_stream_caps && elem_src_subtitle) {
6678 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6679 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6680 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6682 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6683 if (!es_subtitle_queue) {
6684 LOGE("create es_subtitle_queue for es player failed\n");
6687 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6688 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6689 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6693 /* create autoplugging element if src element is not a rtsp src */
6694 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6695 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6696 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6698 enum MainElementID elemId = MMPLAYER_M_NUM;
6700 if ((player->use_decodebin) &&
6701 ((MMPLAYER_IS_HTTP_PD(player)) ||
6702 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6703 elemId = MMPLAYER_M_AUTOPLUG;
6704 element = __mmplayer_create_decodebin(player);
6706 /* default size of mq in decodebin is 2M
6707 * but it can cause blocking issue during seeking depends on content. */
6708 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6710 need_state_holder = FALSE;
6712 elemId = MMPLAYER_M_TYPEFIND;
6713 element = gst_element_factory_make("typefind", "typefinder");
6714 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6715 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6719 /* check autoplug element is OK */
6721 LOGE("can not create element(%d)\n", elemId);
6725 mainbin[elemId].id = elemId;
6726 mainbin[elemId].gst = element;
6728 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6731 /* add elements to pipeline */
6732 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6733 LOGE("Failed to add elements to pipeline\n");
6738 /* linking elements in the bucket by added order. */
6739 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6740 LOGE("Failed to link some elements\n");
6745 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6746 if (need_state_holder) {
6748 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6749 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6751 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6752 LOGE("fakesink element could not be created\n");
6755 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6757 /* take ownership of fakesink. we are reusing it */
6758 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6761 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6762 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6763 LOGE("failed to add fakesink to bin\n");
6768 /* now we have completed mainbin. take it */
6769 player->pipeline->mainbin = mainbin;
6771 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6772 GstPad *srcpad = NULL;
6774 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6775 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6777 __mmplayer_gst_create_decoder(player,
6778 MM_PLAYER_TRACK_TYPE_VIDEO,
6780 MMPLAYER_M_AUTOPLUG_V_DEC,
6783 gst_object_unref(GST_OBJECT(srcpad));
6788 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6789 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6791 __mmplayer_gst_create_decoder(player,
6792 MM_PLAYER_TRACK_TYPE_AUDIO,
6794 MMPLAYER_M_AUTOPLUG_A_DEC,
6797 gst_object_unref(GST_OBJECT(srcpad));
6802 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6803 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6806 /* connect bus callback */
6807 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6809 LOGE("cannot get bus from pipeline.\n");
6813 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6815 player->context.thread_default = g_main_context_get_thread_default();
6817 if (NULL == player->context.thread_default) {
6818 player->context.thread_default = g_main_context_default();
6819 LOGD("thread-default context is the global default context");
6821 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6823 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6824 if (__mmplayer_check_subtitle(player)) {
6825 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6826 LOGE("fail to create subtitle src\n");
6829 /* set sync handler to get tag synchronously */
6830 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6833 gst_object_unref(GST_OBJECT(bus));
6834 g_list_free(element_bucket);
6838 return MM_ERROR_NONE;
6842 __mmplayer_gst_destroy_pipeline(player);
6843 g_list_free(element_bucket);
6846 /* release element which are not added to bin */
6847 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6848 /* NOTE : skip pipeline */
6849 if (mainbin[i].gst) {
6850 GstObject* parent = NULL;
6851 parent = gst_element_get_parent(mainbin[i].gst);
6854 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6855 mainbin[i].gst = NULL;
6857 gst_object_unref(GST_OBJECT(parent));
6861 /* release pipeline with it's childs */
6862 if (mainbin[MMPLAYER_M_PIPE].gst)
6863 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6865 MMPLAYER_FREEIF(mainbin);
6868 MMPLAYER_FREEIF(player->pipeline);
6869 return MM_ERROR_PLAYER_INTERNAL;
6873 __mmplayer_reset_gapless_state(mm_player_t* player)
6876 MMPLAYER_RETURN_IF_FAIL(player
6878 && player->pipeline->audiobin
6879 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6881 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6888 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6891 int ret = MM_ERROR_NONE;
6895 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6897 /* cleanup stuffs */
6898 MMPLAYER_FREEIF(player->type);
6899 player->have_dynamic_pad = FALSE;
6900 player->no_more_pad = FALSE;
6901 player->num_dynamic_pad = 0;
6902 player->demux_pad_index = 0;
6903 player->subtitle_language_list = NULL;
6904 player->use_deinterleave = FALSE;
6905 player->max_audio_channels = 0;
6906 player->video_share_api_delta = 0;
6907 player->video_share_clock_delta = 0;
6908 player->video_hub_download_mode = 0;
6909 __mmplayer_reset_gapless_state(player);
6911 if (player->streamer) {
6912 __mm_player_streaming_deinitialize(player->streamer);
6913 __mm_player_streaming_destroy(player->streamer);
6914 player->streamer = NULL;
6917 /* cleanup unlinked mime type */
6918 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6919 MMPLAYER_FREEIF(player->unlinked_video_mime);
6920 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6922 /* cleanup running stuffs */
6923 __mmplayer_cancel_eos_timer(player);
6925 /* cleanup gst stuffs */
6926 if (player->pipeline) {
6927 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6928 GstTagList* tag_list = player->pipeline->tag_list;
6930 /* first we need to disconnect all signal hander */
6931 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6933 /* disconnecting bus watch */
6934 if (player->bus_watcher)
6935 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6936 player->bus_watcher = 0;
6939 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6940 MMPlayerGstElement* videobin = player->pipeline->videobin;
6941 MMPlayerGstElement* textbin = player->pipeline->textbin;
6942 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6943 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6944 gst_object_unref(bus);
6946 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6947 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6948 if (ret != MM_ERROR_NONE) {
6949 LOGE("fail to change state to NULL\n");
6950 return MM_ERROR_PLAYER_INTERNAL;
6953 LOGW("succeeded in chaning state to NULL\n");
6955 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6958 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6959 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6961 /* free avsysaudiosink
6962 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6963 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6965 MMPLAYER_FREEIF(audiobin);
6966 MMPLAYER_FREEIF(videobin);
6967 MMPLAYER_FREEIF(textbin);
6968 MMPLAYER_FREEIF(mainbin);
6972 gst_tag_list_free(tag_list);
6974 MMPLAYER_FREEIF(player->pipeline);
6976 MMPLAYER_FREEIF(player->album_art);
6978 if (player->v_stream_caps) {
6979 gst_caps_unref(player->v_stream_caps);
6980 player->v_stream_caps = NULL;
6982 if (player->a_stream_caps) {
6983 gst_caps_unref(player->a_stream_caps);
6984 player->a_stream_caps = NULL;
6987 if (player->s_stream_caps) {
6988 gst_caps_unref(player->s_stream_caps);
6989 player->s_stream_caps = NULL;
6991 _mmplayer_track_destroy(player);
6993 if (player->sink_elements)
6994 g_list_free(player->sink_elements);
6995 player->sink_elements = NULL;
6997 if (player->bufmgr) {
6998 tbm_bufmgr_deinit(player->bufmgr);
6999 player->bufmgr = NULL;
7002 LOGW("finished destroy pipeline\n");
7009 static int __gst_realize(mm_player_t* player) // @
7012 int ret = MM_ERROR_NONE;
7016 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7018 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7020 ret = __mmplayer_gst_create_pipeline(player);
7022 LOGE("failed to create pipeline\n");
7026 /* set pipeline state to READY */
7027 /* NOTE : state change to READY must be performed sync. */
7028 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7029 ret = __mmplayer_gst_set_state(player,
7030 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7032 if (ret != MM_ERROR_NONE) {
7033 /* return error if failed to set state */
7034 LOGE("failed to set READY state");
7037 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7039 /* create dot before error-return. for debugging */
7040 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7047 static int __gst_unrealize(mm_player_t* player) // @
7049 int ret = MM_ERROR_NONE;
7053 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7055 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7056 MMPLAYER_PRINT_STATE(player);
7058 /* release miscellaneous information */
7059 __mmplayer_release_misc(player);
7061 /* destroy pipeline */
7062 ret = __mmplayer_gst_destroy_pipeline(player);
7063 if (ret != MM_ERROR_NONE) {
7064 LOGE("failed to destory pipeline\n");
7068 /* release miscellaneous information.
7069 these info needs to be released after pipeline is destroyed. */
7070 __mmplayer_release_misc_post(player);
7072 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7079 static int __gst_pending_seek(mm_player_t* player)
7081 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7082 int ret = MM_ERROR_NONE;
7086 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7088 if (!player->pending_seek.is_pending) {
7089 LOGD("pending seek is not reserved. nothing to do.\n");
7093 /* check player state if player could pending seek or not. */
7094 current_state = MMPLAYER_CURRENT_STATE(player);
7096 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7097 LOGW("try to pending seek in %s state, try next time. \n",
7098 MMPLAYER_STATE_GET_NAME(current_state));
7102 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7104 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7106 if (MM_ERROR_NONE != ret)
7107 LOGE("failed to seek pending postion. just keep staying current position.\n");
7109 player->pending_seek.is_pending = FALSE;
7116 static int __gst_start(mm_player_t* player) // @
7118 gboolean sound_extraction = 0;
7119 int ret = MM_ERROR_NONE;
7120 gboolean async = FALSE;
7124 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7126 /* get sound_extraction property */
7127 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7129 /* NOTE : if SetPosition was called before Start. do it now */
7130 /* streaming doesn't support it. so it should be always sync */
7131 /* !!create one more api to check if there is pending seek rather than checking variables */
7132 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7133 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7134 ret = __gst_pause(player, FALSE);
7135 if (ret != MM_ERROR_NONE) {
7136 LOGE("failed to set state to PAUSED for pending seek\n");
7140 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7142 if (sound_extraction) {
7143 LOGD("setting pcm extraction\n");
7145 ret = __mmplayer_set_pcm_extraction(player);
7146 if (MM_ERROR_NONE != ret) {
7147 LOGW("failed to set pcm extraction\n");
7151 if (MM_ERROR_NONE != __gst_pending_seek(player))
7152 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7156 LOGD("current state before doing transition");
7157 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7158 MMPLAYER_PRINT_STATE(player);
7160 /* set pipeline state to PLAYING */
7161 if (player->es_player_push_mode)
7163 /* set pipeline state to PLAYING */
7164 ret = __mmplayer_gst_set_state(player,
7165 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7167 if (ret == MM_ERROR_NONE) {
7168 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7170 LOGE("failed to set state to PLAYING");
7174 /* generating debug info before returning error */
7175 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7182 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7186 MMPLAYER_RETURN_IF_FAIL(player
7188 && player->pipeline->audiobin
7189 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7191 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7198 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7202 MMPLAYER_RETURN_IF_FAIL(player
7204 && player->pipeline->audiobin
7205 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7207 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
7212 static int __gst_stop(mm_player_t* player) // @
7214 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7215 MMHandleType attrs = 0;
7216 gboolean fadedown = FALSE;
7217 gboolean rewind = FALSE;
7219 int ret = MM_ERROR_NONE;
7220 gboolean async = FALSE;
7224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7225 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7227 LOGD("current state before doing transition");
7228 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7229 MMPLAYER_PRINT_STATE(player);
7231 attrs = MMPLAYER_GET_ATTRS(player);
7233 LOGE("cannot get content attribute\n");
7234 return MM_ERROR_PLAYER_INTERNAL;
7237 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7239 /* enable fadedown */
7240 if (fadedown || player->sound_focus.by_asm_cb)
7241 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7243 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7244 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7246 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7247 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7250 if (player->es_player_push_mode)
7253 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7255 /* disable fadeout */
7256 if (fadedown || player->sound_focus.by_asm_cb)
7257 __mmplayer_undo_sound_fadedown(player);
7259 /* return if set_state has failed */
7260 if (ret != MM_ERROR_NONE) {
7261 LOGE("failed to set state.\n");
7267 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7268 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7269 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7270 LOGW("failed to rewind\n");
7271 ret = MM_ERROR_PLAYER_SEEK;
7276 player->sent_bos = FALSE;
7278 if (player->es_player_push_mode) //for cloudgame
7281 /* wait for seek to complete */
7282 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7283 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7284 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7286 LOGE("fail to stop player.\n");
7287 ret = MM_ERROR_PLAYER_INTERNAL;
7288 __mmplayer_dump_pipeline_state(player);
7291 /* generate dot file if enabled */
7292 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7299 int __gst_pause(mm_player_t* player, gboolean async) // @
7301 int ret = MM_ERROR_NONE;
7305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7306 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7308 LOGD("current state before doing transition");
7309 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7310 MMPLAYER_PRINT_STATE(player);
7312 /* set pipeline status to PAUSED */
7313 player->ignore_asyncdone = TRUE;
7315 ret = __mmplayer_gst_set_state(player,
7316 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7318 player->ignore_asyncdone = FALSE;
7320 if (FALSE == async) {
7321 if (ret != MM_ERROR_NONE) {
7322 GstMessage *msg = NULL;
7323 GTimer *timer = NULL;
7324 gdouble MAX_TIMEOUT_SEC = 3;
7326 LOGE("failed to set state to PAUSED");
7328 if (player->msg_posted) {
7329 LOGE("error msg is already posted.");
7333 timer = g_timer_new();
7334 g_timer_start(timer);
7336 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7339 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7341 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7342 GError *error = NULL;
7344 /* parse error code */
7345 gst_message_parse_error(msg, &error, NULL);
7347 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7348 /* Note : the streaming error from the streaming source is handled
7349 * using __mmplayer_handle_streaming_error.
7351 __mmplayer_handle_streaming_error(player, msg);
7354 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7356 if (error->domain == GST_STREAM_ERROR)
7357 ret = __gst_handle_stream_error(player, error, msg);
7358 else if (error->domain == GST_RESOURCE_ERROR)
7359 ret = __gst_handle_resource_error(player, error->code);
7360 else if (error->domain == GST_LIBRARY_ERROR)
7361 ret = __gst_handle_library_error(player, error->code);
7362 else if (error->domain == GST_CORE_ERROR)
7363 ret = __gst_handle_core_error(player, error->code);
7365 player->msg_posted = TRUE;
7367 gst_message_unref(msg);
7369 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7371 gst_object_unref(bus);
7372 g_timer_stop(timer);
7373 g_timer_destroy(timer);
7377 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7378 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7380 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7382 } else if (ret == MM_ERROR_NONE) {
7384 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7388 /* generate dot file before returning error */
7389 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7396 int __gst_resume(mm_player_t* player, gboolean async) // @
7398 int ret = MM_ERROR_NONE;
7403 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7404 MM_ERROR_PLAYER_NOT_INITIALIZED);
7406 LOGD("current state before doing transition");
7407 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7408 MMPLAYER_PRINT_STATE(player);
7410 /* generate dot file before returning error */
7411 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7414 LOGD("do async state transition to PLAYING.\n");
7416 /* set pipeline state to PLAYING */
7417 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7419 ret = __mmplayer_gst_set_state(player,
7420 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7421 if (ret != MM_ERROR_NONE) {
7422 LOGE("failed to set state to PLAYING\n");
7425 if (async == FALSE) {
7426 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7427 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7428 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7432 /* generate dot file before returning error */
7433 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7441 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7443 unsigned long dur_msec = 0;
7444 gint64 dur_nsec = 0;
7445 gint64 pos_nsec = 0;
7446 gboolean ret = TRUE;
7447 gboolean accurated = FALSE;
7448 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7451 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7452 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7454 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7455 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7458 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7459 /* check duration */
7460 /* NOTE : duration cannot be zero except live streaming.
7461 * Since some element could have some timing problemn with quering duration, try again.
7463 if (!player->duration) {
7464 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7466 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7467 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7468 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7469 player->pending_seek.is_pending = TRUE;
7470 player->pending_seek.format = format;
7471 player->pending_seek.pos = position;
7472 player->doing_seek = FALSE;
7473 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7474 return MM_ERROR_NONE;
7478 player->duration = dur_nsec;
7481 if (player->duration) {
7482 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7484 LOGE("could not get the duration. fail to seek.\n");
7488 LOGD("playback rate: %f\n", player->playback_rate);
7490 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7492 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7494 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7498 case MM_PLAYER_POS_FORMAT_TIME:
7500 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7501 /* check position is valid or not */
7502 if (position > dur_msec)
7505 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7507 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7508 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7509 This causes problem is position calculation during normal pause resume scenarios also.
7510 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7511 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7512 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7513 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7514 LOGW("getting current position failed in seek\n");
7516 player->last_position = pos_nsec;
7517 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7520 if (player->doing_seek) {
7521 LOGD("not completed seek");
7522 return MM_ERROR_PLAYER_DOING_SEEK;
7526 if (!internal_called)
7527 player->doing_seek = TRUE;
7529 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7531 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7532 gint64 cur_time = 0;
7534 /* get current position */
7535 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7538 GstEvent *event = gst_event_new_seek(1.0,
7540 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7541 GST_SEEK_TYPE_SET, cur_time,
7542 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7544 __gst_send_event_to_sink(player, event);
7546 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7547 __gst_pause(player, FALSE);
7550 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7551 that's why set position through property. */
7552 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7553 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7554 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7555 (!player->videodec_linked) && (!player->audiodec_linked)) {
7557 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7558 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7559 gst_element_get_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7560 player->doing_seek = FALSE;
7561 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7563 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7564 GST_FORMAT_TIME, seek_flags,
7565 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7569 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7575 case MM_PLAYER_POS_FORMAT_PERCENT:
7577 LOGD("seeking to(%lu)%% \n", position);
7579 if (player->doing_seek) {
7580 LOGD("not completed seek");
7581 return MM_ERROR_PLAYER_DOING_SEEK;
7584 if (!internal_called)
7585 player->doing_seek = TRUE;
7587 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7588 pos_nsec = (gint64)((position * player->duration) / 100);
7589 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7590 GST_FORMAT_TIME, seek_flags,
7591 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7593 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7603 /* NOTE : store last seeking point to overcome some bad operation
7604 * (returning zero when getting current position) of some elements
7606 player->last_position = pos_nsec;
7608 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7609 if (player->playback_rate > 1.0)
7610 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7613 return MM_ERROR_NONE;
7616 player->pending_seek.is_pending = TRUE;
7617 player->pending_seek.format = format;
7618 player->pending_seek.pos = position;
7620 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7621 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7623 return MM_ERROR_NONE;
7626 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7627 return MM_ERROR_INVALID_ARGUMENT;
7630 player->doing_seek = FALSE;
7631 return MM_ERROR_PLAYER_SEEK;
7634 #define TRICKPLAY_OFFSET GST_MSECOND
7637 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7639 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7640 gint64 pos_msec = 0;
7641 gboolean ret = TRUE;
7643 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7644 MM_ERROR_PLAYER_NOT_INITIALIZED);
7646 current_state = MMPLAYER_CURRENT_STATE(player);
7648 /* NOTE : query position except paused state to overcome some bad operation
7649 * please refer to below comments in details
7651 if (current_state != MM_PLAYER_STATE_PAUSED)
7652 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7654 /* NOTE : get last point to overcome some bad operation of some elements
7655 *(returning zero when getting current position in paused state
7656 * and when failed to get postion during seeking
7658 if ((current_state == MM_PLAYER_STATE_PAUSED)
7660 //|| (player->last_position != 0 && pos_msec == 0))
7661 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7663 if (player->playback_rate < 0.0)
7664 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7666 pos_msec = player->last_position;
7669 pos_msec = player->last_position;
7671 player->last_position = pos_msec;
7673 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7676 if (player->duration > 0 && pos_msec > player->duration)
7677 pos_msec = player->duration;
7679 if (player->sound_focus.keep_last_pos) {
7680 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7681 pos_msec = player->last_position;
7683 player->last_position = pos_msec;
7687 case MM_PLAYER_POS_FORMAT_TIME:
7688 *position = GST_TIME_AS_MSECONDS(pos_msec);
7691 case MM_PLAYER_POS_FORMAT_PERCENT:
7693 if (player->duration <= 0) {
7694 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7697 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7698 *position = pos_msec * 100 / player->duration;
7703 return MM_ERROR_PLAYER_INTERNAL;
7706 return MM_ERROR_NONE;
7710 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7712 #define STREAMING_IS_FINISHED 0
7713 #define BUFFERING_MAX_PER 100
7714 #define DEFAULT_PER_VALUE -1
7715 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7717 MMPlayerGstElement *mainbin = NULL;
7718 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7719 gint64 buffered_total = 0;
7720 unsigned long position = 0;
7721 gint buffered_sec = -1;
7722 GstBufferingMode mode = GST_BUFFERING_STREAM;
7723 gint64 content_size_time = player->duration;
7724 guint64 content_size_bytes = player->http_content_size;
7726 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7728 player->pipeline->mainbin,
7729 MM_ERROR_PLAYER_NOT_INITIALIZED);
7731 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7736 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7737 /* and rtsp is not ready yet. */
7738 LOGW("it's only used for http streaming case.\n");
7739 return MM_ERROR_PLAYER_NO_OP;
7742 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7743 LOGW("Time format is not supported yet.\n");
7744 return MM_ERROR_INVALID_ARGUMENT;
7747 if (content_size_time <= 0 || content_size_bytes <= 0) {
7748 LOGW("there is no content size.");
7749 return MM_ERROR_NONE;
7752 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7753 LOGW("fail to get current position.");
7754 return MM_ERROR_NONE;
7757 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7758 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7760 mainbin = player->pipeline->mainbin;
7761 start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7763 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7764 GstQuery *query = NULL;
7765 gint byte_in_rate = 0, byte_out_rate = 0;
7766 gint64 estimated_total = 0;
7768 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7769 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7770 LOGW("fail to get buffering query from queue2");
7772 gst_query_unref(query);
7773 return MM_ERROR_NONE;
7776 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7777 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7779 if (mode == GST_BUFFERING_STREAM) {
7780 /* using only queue in case of push mode(ts / mp3) */
7781 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7782 GST_FORMAT_BYTES, &buffered_total)) {
7783 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7784 stop_per = 100 * buffered_total / content_size_bytes;
7787 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7789 guint num_of_ranges = 0;
7790 gint64 start_byte = 0, stop_byte = 0;
7792 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7793 if (estimated_total != STREAMING_IS_FINISHED) {
7794 /* buffered size info from queue2 */
7795 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7796 for (idx = 0; idx < num_of_ranges; idx++) {
7797 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7798 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7800 buffered_total += (stop_byte - start_byte);
7803 stop_per = BUFFERING_MAX_PER;
7805 gst_query_unref(query);
7808 if (stop_per == DEFAULT_PER_VALUE) {
7809 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7811 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7813 /* buffered size info from multiqueue */
7814 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7815 guint curr_size_bytes = 0;
7816 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7817 "curr-size-bytes", &curr_size_bytes, NULL);
7818 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7819 buffered_total += curr_size_bytes;
7822 if (avg_byterate > 0)
7823 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7824 else if (player->total_maximum_bitrate > 0)
7825 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7826 else if (player->total_bitrate > 0)
7827 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7829 if (buffered_sec >= 0)
7830 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7834 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7835 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7837 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7838 buffered_total, buffered_sec, *start_pos, *stop_pos);
7840 return MM_ERROR_NONE;
7844 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7849 LOGW("set_message_callback is called with invalid player handle\n");
7850 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7853 player->msg_cb = callback;
7854 player->msg_cb_param = user_param;
7856 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7860 return MM_ERROR_NONE;
7863 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7865 int ret = MM_ERROR_PLAYER_INVALID_URI;
7870 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7871 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7872 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7874 memset(data, 0, sizeof(MMPlayerParseProfile));
7876 if ((path = strstr(uri, "es_buff://"))) {
7878 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7879 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7880 ret = MM_ERROR_NONE;
7882 } else if ((path = strstr(uri, "rtsp://"))) {
7884 if ((path = strstr(uri, "/wfd1.0/"))) {
7885 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7886 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7887 ret = MM_ERROR_NONE;
7888 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7890 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7891 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7892 ret = MM_ERROR_NONE;
7895 } else if ((path = strstr(uri, "http://"))) {
7897 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7899 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7900 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7901 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7903 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7905 ret = MM_ERROR_NONE;
7907 } else if ((path = strstr(uri, "https://"))) {
7909 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7911 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7912 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7913 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7915 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7917 ret = MM_ERROR_NONE;
7919 } else if ((path = strstr(uri, "rtspu://"))) {
7921 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7922 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7923 ret = MM_ERROR_NONE;
7925 } else if ((path = strstr(uri, "rtspr://"))) {
7926 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7927 char *separater = strstr(path, "*");
7931 char *urgent = separater + strlen("*");
7933 if ((urgent_len = strlen(urgent))) {
7934 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7935 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7936 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7937 ret = MM_ERROR_NONE;
7940 } else if ((path = strstr(uri, "mms://"))) {
7942 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7943 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7944 ret = MM_ERROR_NONE;
7946 } else if ((path = strstr(uri, "mem://"))) {
7949 char *buffer = NULL;
7950 char *seperator = strchr(path, ',');
7951 char ext[100] = {0,}, size[100] = {0,};
7954 if ((buffer = strstr(path, "ext="))) {
7955 buffer += strlen("ext=");
7957 if (strlen(buffer)) {
7958 strncpy(ext, buffer, 99);
7960 if ((seperator = strchr(ext, ','))
7961 || (seperator = strchr(ext, ' '))
7962 || (seperator = strchr(ext, '\0'))) {
7963 seperator[0] = '\0';
7968 if ((buffer = strstr(path, "size="))) {
7969 buffer += strlen("size=");
7971 if (strlen(buffer) > 0) {
7972 strncpy(size, buffer, 99);
7974 if ((seperator = strchr(size, ','))
7975 || (seperator = strchr(size, ' '))
7976 || (seperator = strchr(size, '\0'))) {
7977 seperator[0] = '\0';
7980 mem_size = atoi(size);
7985 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7986 if (mem_size && param) {
7988 data->mem_size = mem_size;
7989 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7990 ret = MM_ERROR_NONE;
7994 gchar *location = NULL;
7997 if ((path = strstr(uri, "file://"))) {
7999 location = g_filename_from_uri(uri, NULL, &err);
8001 if (!location || (err != NULL)) {
8002 LOGE("Invalid URI '%s' for filesrc: %s", path,
8003 (err != NULL) ? err->message : "unknown error");
8005 if (err) g_error_free(err);
8006 if (location) g_free(location);
8008 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8012 LOGD("path from uri: %s", location);
8015 path = (location != NULL) ? (location) : ((char*)uri);
8016 int file_stat = MM_ERROR_NONE;
8018 file_stat = util_exist_file_path(path);
8020 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8021 if (file_stat == MM_ERROR_NONE) {
8022 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8024 if (util_is_sdp_file(path)) {
8025 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8026 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8028 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8030 ret = MM_ERROR_NONE;
8031 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8032 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8034 LOGE("invalid uri, could not play..\n");
8035 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8038 if (location) g_free(location);
8042 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8043 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8044 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8045 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8047 /* dump parse result */
8048 SECURE_LOGW("incomming uri : %s\n", uri);
8049 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8050 data->uri_type, data->mem, data->mem_size, data->urgent);
8057 gboolean _asm_postmsg(gpointer *data)
8059 mm_player_t* player = (mm_player_t*)data;
8060 MMMessageParamType msg = {0, };
8063 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8064 LOGW("get notified");
8066 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8067 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8073 msg.union_type = MM_MSG_UNION_CODE;
8074 msg.code = player->sound_focus.focus_changed_msg;
8076 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8077 player->resume_event_id = 0;
8083 gboolean _asm_lazy_pause(gpointer *data)
8085 mm_player_t* player = (mm_player_t*)data;
8086 int ret = MM_ERROR_NONE;
8090 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8092 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8093 LOGD("Ready to proceed lazy pause\n");
8094 ret = _mmplayer_pause((MMHandleType)player);
8095 if (MM_ERROR_NONE != ret)
8096 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8098 LOGD("Invalid state to proceed lazy pause\n");
8101 if (player->pipeline && player->pipeline->audiobin)
8102 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8104 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8112 __mmplayer_can_do_interrupt(mm_player_t *player)
8114 if (!player || !player->pipeline || !player->attrs) {
8115 LOGW("not initialized");
8119 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8120 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8124 /* check if seeking */
8125 if (player->doing_seek) {
8126 MMMessageParamType msg_param;
8127 memset(&msg_param, 0, sizeof(MMMessageParamType));
8128 msg_param.code = MM_ERROR_PLAYER_SEEK;
8129 player->doing_seek = FALSE;
8130 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8134 /* check other thread */
8135 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8136 LOGW("locked already, cmd state : %d", player->cmd);
8138 /* check application command */
8139 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8140 LOGW("playing.. should wait cmd lock then, will be interrupted");
8142 /* lock will be released at mrp_resource_release_cb() */
8143 MMPLAYER_CMD_LOCK(player);
8146 LOGW("nothing to do");
8149 LOGW("can interrupt immediately");
8153 FAILED: /* with CMD UNLOCKED */
8156 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8160 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8162 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8164 int ret = MM_ERROR_NONE;
8165 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8167 if (strstr(reason_for_change, "alarm")) {
8168 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8170 } else if (strstr(reason_for_change, "notification")) {
8171 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8173 } else if (strstr(reason_for_change, "emergency")) {
8174 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8176 } else if (strstr(reason_for_change, "call-voice") ||
8177 strstr(reason_for_change, "call-video") ||
8178 strstr(reason_for_change, "voip") ||
8179 strstr(reason_for_change, "ringtone-voip") ||
8180 strstr(reason_for_change, "ringtone-call")) {
8181 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8183 } else if (strstr(reason_for_change, "media") ||
8184 strstr(reason_for_change, "radio") ||
8185 strstr(reason_for_change, "loopback") ||
8186 strstr(reason_for_change, "system") ||
8187 strstr(reason_for_change, "voice-information") ||
8188 strstr(reason_for_change, "voice-recognition")) {
8189 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8192 ret = MM_ERROR_INVALID_ARGUMENT;
8193 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8197 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8199 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8201 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8208 /* FIXME: will be updated with new funct */
8209 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8210 const char *reason_for_change, const char *additional_info, void *user_data)
8212 mm_player_t* player = (mm_player_t*) user_data;
8213 int result = MM_ERROR_NONE;
8214 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8216 LOGW("focus watch notified");
8218 if (!__mmplayer_can_do_interrupt(player)) {
8219 LOGW("no need to interrupt, so leave");
8220 goto EXIT_WITHOUT_UNLOCK;
8223 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8224 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8228 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8229 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8231 player->sound_focus.cb_pending = TRUE;
8232 player->sound_focus.by_asm_cb = TRUE;
8234 if (focus_state == FOCUS_IS_ACQUIRED) {
8235 LOGW("watch: FOCUS_IS_ACQUIRED");
8236 player->sound_focus.acquired = TRUE;
8238 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8239 player->sound_focus.focus_changed_msg = (int)msg;
8241 if (strstr(reason_for_change, "call") ||
8242 strstr(reason_for_change, "voip") || /* FIXME: to check */
8243 strstr(reason_for_change, "alarm") ||
8244 strstr(reason_for_change, "media")) {
8245 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8246 // hold 0.7 second to excute "fadedown mute" effect
8247 LOGW("do fade down->pause->undo fade down");
8249 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8251 result = _mmplayer_pause((MMHandleType)player);
8252 if (result != MM_ERROR_NONE) {
8253 LOGW("fail to set Pause state by asm");
8256 __mmplayer_undo_sound_fadedown(player);
8258 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8259 _mmplayer_unrealize((MMHandleType)player);
8261 LOGW("pause immediately");
8262 result = _mmplayer_pause((MMHandleType)player);
8263 if (result != MM_ERROR_NONE) {
8264 LOGW("fail to set Pause state by asm");
8268 } else if (focus_state == FOCUS_IS_RELEASED) {
8269 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8270 player->sound_focus.acquired = FALSE;
8271 player->sound_focus.antishock = TRUE;
8272 player->sound_focus.by_asm_cb = FALSE;
8274 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8275 player->sound_focus.focus_changed_msg = (int)msg;
8277 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8278 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8281 LOGW("unknown focus state %d", focus_state);
8284 player->sound_focus.by_asm_cb = FALSE;
8285 player->sound_focus.cb_pending = FALSE;
8288 MMPLAYER_CMD_UNLOCK(player);
8292 EXIT_WITHOUT_UNLOCK:
8298 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8299 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8301 mm_player_t* player = (mm_player_t*) user_data;
8302 int result = MM_ERROR_NONE;
8303 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8305 LOGW("get focus notified");
8307 if (!__mmplayer_can_do_interrupt(player)) {
8308 LOGW("no need to interrupt, so leave");
8309 goto EXIT_WITHOUT_UNLOCK;
8312 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8313 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8317 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8318 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8320 player->sound_focus.cb_pending = TRUE;
8321 player->sound_focus.by_asm_cb = TRUE;
8322 // player->sound_focus.event_src = event_src;
8324 if (focus_state == FOCUS_IS_RELEASED) {
8325 LOGW("FOCUS_IS_RELEASED");
8326 player->sound_focus.acquired = FALSE;
8328 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8329 player->sound_focus.focus_changed_msg = (int)msg;
8331 if (strstr(reason_for_change, "call") ||
8332 strstr(reason_for_change, "voip") || /* FIXME: to check */
8333 strstr(reason_for_change, "alarm") ||
8334 strstr(reason_for_change, "media")) {
8335 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8336 //hold 0.7 second to excute "fadedown mute" effect
8337 LOGW("do fade down->pause->undo fade down");
8339 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8341 result = _mmplayer_pause((MMHandleType)player);
8342 if (result != MM_ERROR_NONE) {
8343 LOGW("fail to set Pause state by asm");
8346 __mmplayer_undo_sound_fadedown(player);
8348 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8349 _mmplayer_unrealize((MMHandleType)player);
8351 LOGW("pause immediately");
8352 result = _mmplayer_pause((MMHandleType)player);
8353 if (result != MM_ERROR_NONE) {
8354 LOGW("fail to set Pause state by asm");
8358 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8359 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8360 player->sound_focus.acquired = TRUE;
8361 player->sound_focus.antishock = TRUE;
8362 player->sound_focus.by_asm_cb = FALSE;
8364 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8365 player->sound_focus.focus_changed_msg = (int)msg;
8367 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8368 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8371 LOGW("unknown focus state %d", focus_state);
8374 player->sound_focus.by_asm_cb = FALSE;
8375 player->sound_focus.cb_pending = FALSE;
8378 MMPLAYER_CMD_UNLOCK(player);
8382 EXIT_WITHOUT_UNLOCK:
8389 _mmplayer_create_player(MMHandleType handle) // @
8391 int ret = MM_ERROR_PLAYER_INTERNAL;
8392 mm_player_t* player = MM_PLAYER_CAST(handle);
8396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8398 /* initialize player state */
8399 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8400 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8401 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8402 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8404 /* check current state */
8405 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8407 /* construct attributes */
8408 player->attrs = _mmplayer_construct_attribute(handle);
8410 if (!player->attrs) {
8411 LOGE("Failed to construct attributes\n");
8415 /* initialize gstreamer with configured parameter */
8416 if (!__mmplayer_init_gstreamer(player)) {
8417 LOGE("Initializing gstreamer failed\n");
8418 _mmplayer_deconstruct_attribute(handle);
8422 /* initialize factories if not using decodebin */
8423 if (player->factories == NULL)
8424 __mmplayer_init_factories(player);
8426 /* create lock. note that g_tread_init() has already called in gst_init() */
8427 g_mutex_init(&player->fsink_lock);
8429 /* create update tag lock */
8430 g_mutex_init(&player->update_tag_lock);
8432 /* create repeat mutex */
8433 g_mutex_init(&player->repeat_thread_mutex);
8435 /* create repeat cond */
8436 g_cond_init(&player->repeat_thread_cond);
8438 /* create repeat thread */
8439 player->repeat_thread =
8440 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8441 if (!player->repeat_thread) {
8442 LOGE("failed to create repeat_thread(%s)");
8443 g_mutex_clear(&player->repeat_thread_mutex);
8444 g_cond_clear(&player->repeat_thread_cond);
8445 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8449 /* create next play mutex */
8450 g_mutex_init(&player->next_play_thread_mutex);
8452 /* create next play cond */
8453 g_cond_init(&player->next_play_thread_cond);
8455 /* create next play thread */
8456 player->next_play_thread =
8457 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8458 if (!player->next_play_thread) {
8459 LOGE("failed to create next play thread");
8460 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8461 g_mutex_clear(&player->next_play_thread_mutex);
8462 g_cond_clear(&player->next_play_thread_cond);
8466 ret = _mmplayer_initialize_video_capture(player);
8467 if (ret != MM_ERROR_NONE) {
8468 LOGE("failed to initialize video capture\n");
8472 /* initialize resource manager */
8473 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8474 LOGE("failed to initialize resource manager\n");
8478 if (MMPLAYER_IS_HTTP_PD(player)) {
8479 player->pd_downloader = NULL;
8480 player->pd_file_save_path = NULL;
8483 /* create video bo lock and cond */
8484 g_mutex_init(&player->video_bo_mutex);
8485 g_cond_init(&player->video_bo_cond);
8487 /* create media stream callback mutex */
8488 g_mutex_init(&player->media_stream_cb_lock);
8490 player->streaming_type = STREAMING_SERVICE_NONE;
8492 /* give default value of audio effect setting */
8493 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8494 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8496 player->play_subtitle = FALSE;
8497 player->use_textoverlay = FALSE;
8498 player->play_count = 0;
8499 player->use_decodebin = TRUE;
8500 player->ignore_asyncdone = FALSE;
8501 player->use_deinterleave = FALSE;
8502 player->max_audio_channels = 0;
8503 player->video_share_api_delta = 0;
8504 player->video_share_clock_delta = 0;
8505 player->has_closed_caption = FALSE;
8506 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8507 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8508 player->pending_resume = FALSE;
8509 if (player->ini.dump_element_keyword[0][0] == '\0')
8510 player->ini.set_dump_element_flag = FALSE;
8512 player->ini.set_dump_element_flag = TRUE;
8514 /* set player state to null */
8515 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8516 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8518 return MM_ERROR_NONE;
8522 g_mutex_clear(&player->fsink_lock);
8524 /* free update tag lock */
8525 g_mutex_clear(&player->update_tag_lock);
8528 if (player->repeat_thread) {
8529 player->repeat_thread_exit = TRUE;
8530 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8532 g_thread_join(player->repeat_thread);
8533 player->repeat_thread = NULL;
8535 g_mutex_clear(&player->repeat_thread_mutex);
8536 g_cond_clear(&player->repeat_thread_cond);
8539 /* free next play thread */
8540 if (player->next_play_thread) {
8541 player->next_play_thread_exit = TRUE;
8542 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8544 g_thread_join(player->next_play_thread);
8545 player->next_play_thread = NULL;
8547 g_mutex_clear(&player->next_play_thread_mutex);
8548 g_cond_clear(&player->next_play_thread_cond);
8551 /* release attributes */
8552 _mmplayer_deconstruct_attribute(handle);
8560 __mmplayer_init_gstreamer(mm_player_t* player) // @
8562 static gboolean initialized = FALSE;
8563 static const int max_argc = 50;
8565 gchar** argv = NULL;
8566 gchar** argv2 = NULL;
8572 LOGD("gstreamer already initialized.\n");
8577 argc = malloc(sizeof(int));
8578 argv = malloc(sizeof(gchar*) * max_argc);
8579 argv2 = malloc(sizeof(gchar*) * max_argc);
8581 if (!argc || !argv || !argv2)
8584 memset(argv, 0, sizeof(gchar*) * max_argc);
8585 memset(argv2, 0, sizeof(gchar*) * max_argc);
8589 argv[0] = g_strdup("mmplayer");
8592 for (i = 0; i < 5; i++) {
8593 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8594 if (strlen(player->ini.gst_param[i]) > 0) {
8595 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8600 /* we would not do fork for scanning plugins */
8601 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8604 /* check disable registry scan */
8605 if (player->ini.skip_rescan) {
8606 argv[*argc] = g_strdup("--gst-disable-registry-update");
8610 /* check disable segtrap */
8611 if (player->ini.disable_segtrap) {
8612 argv[*argc] = g_strdup("--gst-disable-segtrap");
8616 LOGD("initializing gstreamer with following parameter\n");
8617 LOGD("argc : %d\n", *argc);
8620 for (i = 0; i < arg_count; i++) {
8622 LOGD("argv[%d] : %s\n", i, argv2[i]);
8626 /* initializing gstreamer */
8627 if (!gst_init_check(argc, &argv, &err)) {
8628 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8635 for (i = 0; i < arg_count; i++) {
8636 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8637 MMPLAYER_FREEIF(argv2[i]);
8640 MMPLAYER_FREEIF(argv);
8641 MMPLAYER_FREEIF(argv2);
8642 MMPLAYER_FREEIF(argc);
8652 for (i = 0; i < arg_count; i++) {
8653 LOGD("free[%d] : %s\n", i, argv2[i]);
8654 MMPLAYER_FREEIF(argv2[i]);
8657 MMPLAYER_FREEIF(argv);
8658 MMPLAYER_FREEIF(argv2);
8659 MMPLAYER_FREEIF(argc);
8665 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669 if (player->pd_downloader) {
8670 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8671 MMPLAYER_FREEIF(player->pd_downloader);
8674 if (MMPLAYER_IS_HTTP_PD(player)) {
8675 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8676 MMPLAYER_FREEIF(player->pd_file_save_path);
8679 return MM_ERROR_NONE;
8683 __mmplayer_check_async_state_transition(mm_player_t* player)
8685 GstState element_state = GST_STATE_VOID_PENDING;
8686 GstState element_pending_state = GST_STATE_VOID_PENDING;
8687 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8688 GstElement * element = NULL;
8689 gboolean async = FALSE;
8691 /* check player handle */
8692 MMPLAYER_RETURN_IF_FAIL(player &&
8694 player->pipeline->mainbin &&
8695 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8698 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8700 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8701 LOGD("don't need to check the pipeline state");
8705 MMPLAYER_PRINT_STATE(player);
8707 /* wait for state transition */
8708 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8709 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8711 if (ret == GST_STATE_CHANGE_FAILURE) {
8712 LOGE(" [%s] state : %s pending : %s \n",
8713 GST_ELEMENT_NAME(element),
8714 gst_element_state_get_name(element_state),
8715 gst_element_state_get_name(element_pending_state));
8717 /* dump state of all element */
8718 __mmplayer_dump_pipeline_state(player);
8723 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8728 _mmplayer_destroy(MMHandleType handle) // @
8730 mm_player_t* player = MM_PLAYER_CAST(handle);
8734 /* check player handle */
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8737 /* destroy can called at anytime */
8738 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8740 /* check async state transition */
8741 __mmplayer_check_async_state_transition(player);
8743 __mmplayer_destroy_streaming_ext(player);
8745 /* release repeat thread */
8746 if (player->repeat_thread) {
8747 player->repeat_thread_exit = TRUE;
8748 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8750 LOGD("waitting for repeat thread exit\n");
8751 g_thread_join(player->repeat_thread);
8752 g_mutex_clear(&player->repeat_thread_mutex);
8753 g_cond_clear(&player->repeat_thread_cond);
8754 LOGD("repeat thread released\n");
8757 /* release next play thread */
8758 if (player->next_play_thread) {
8759 player->next_play_thread_exit = TRUE;
8760 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8762 LOGD("waitting for next play thread exit\n");
8763 g_thread_join(player->next_play_thread);
8764 g_mutex_clear(&player->next_play_thread_mutex);
8765 g_cond_clear(&player->next_play_thread_cond);
8766 LOGD("next play thread released\n");
8769 _mmplayer_release_video_capture(player);
8771 /* flush any pending asm_cb */
8772 if (player->sound_focus.cb_pending) {
8773 /* set a flag for make sure asm_cb to be returned immediately */
8774 LOGW("asm cb has pending state");
8775 player->sound_focus.exit_cb = TRUE;
8777 /* make sure to release any pending asm_cb which locked by cmd_lock */
8778 MMPLAYER_CMD_UNLOCK(player);
8780 MMPLAYER_CMD_LOCK(player);
8784 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8785 LOGE("failed to deregister asm server\n");
8787 /* de-initialize resource manager */
8788 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8789 LOGE("failed to deinitialize resource manager\n");
8791 #ifdef USE_LAZY_PAUSE
8792 if (player->lazy_pause_event_id) {
8793 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8794 player->lazy_pause_event_id = 0;
8798 if (player->resume_event_id) {
8799 g_source_remove(player->resume_event_id);
8800 player->resume_event_id = 0;
8803 if (player->resumable_cancel_id) {
8804 g_source_remove(player->resumable_cancel_id);
8805 player->resumable_cancel_id = 0;
8808 /* release pipeline */
8809 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8810 LOGE("failed to destory pipeline\n");
8811 return MM_ERROR_PLAYER_INTERNAL;
8814 if (player->is_external_subtitle_present && player->subtitle_language_list) {
8815 g_list_free(player->subtitle_language_list);
8816 player->subtitle_language_list = NULL;
8819 __mmplayer_release_dump_list(player->dump_list);
8821 /* release miscellaneous information.
8822 these info needs to be released after pipeline is destroyed. */
8823 __mmplayer_release_misc_post(player);
8825 /* release attributes */
8826 _mmplayer_deconstruct_attribute(handle);
8828 /* release factories */
8829 __mmplayer_release_factories(player);
8832 g_mutex_clear(&player->fsink_lock);
8835 g_mutex_clear(&player->update_tag_lock);
8837 /* release video bo lock and cond */
8838 g_mutex_clear(&player->video_bo_mutex);
8839 g_cond_clear(&player->video_bo_cond);
8841 /* release media stream callback lock */
8842 g_mutex_clear(&player->media_stream_cb_lock);
8846 return MM_ERROR_NONE;
8850 __mmplayer_realize_streaming_ext(mm_player_t* player)
8852 int ret = MM_ERROR_NONE;
8855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8857 if (MMPLAYER_IS_HTTP_PD(player)) {
8858 gboolean bret = FALSE;
8860 player->pd_downloader = _mmplayer_create_pd_downloader();
8861 if (!player->pd_downloader) {
8862 LOGE("Unable to create PD Downloader...");
8863 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8866 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8868 if (FALSE == bret) {
8869 LOGE("Unable to create PD Downloader...");
8870 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8879 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8881 mm_player_t* player = (mm_player_t*)hplayer;
8882 MMHandleType attrs = 0;
8883 int ret = MM_ERROR_NONE;
8885 attrs = MMPLAYER_GET_ATTRS(player);
8887 LOGE("fail to get attributes.\n");
8888 return MM_ERROR_PLAYER_INTERNAL;
8891 player->sound_focus.pid = pid;
8893 /* register to asm */
8894 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8895 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8896 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8898 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8899 LOGE("failed to register asm server\n");
8900 return MM_ERROR_POLICY_INTERNAL;
8906 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8908 mm_player_t* player = (mm_player_t*) hplayer;
8912 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8914 *pid = player->sound_focus.pid;
8916 LOGD("registered pid[%d] %p", *pid, player);
8920 return MM_ERROR_NONE;
8924 _mmplayer_realize(MMHandleType hplayer) // @
8926 mm_player_t* player = (mm_player_t*)hplayer;
8929 gboolean update_registry = FALSE;
8930 MMHandleType attrs = 0;
8931 int ret = MM_ERROR_NONE;
8935 /* check player handle */
8936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8938 /* check current state */
8939 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8941 attrs = MMPLAYER_GET_ATTRS(player);
8943 LOGE("fail to get attributes.\n");
8944 return MM_ERROR_PLAYER_INTERNAL;
8946 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8947 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8949 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8950 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8952 if (ret != MM_ERROR_NONE) {
8953 LOGE("failed to parse profile\n");
8958 /* FIXIT : we can use thouse in player->profile directly */
8959 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8960 player->mem_buf.buf = (char *)player->profile.mem;
8961 player->mem_buf.len = player->profile.mem_size;
8962 player->mem_buf.offset = 0;
8965 if (uri && (strstr(uri, "es_buff://"))) {
8966 if (strstr(uri, "es_buff://push_mode"))
8967 player->es_player_push_mode = TRUE;
8969 player->es_player_push_mode = FALSE;
8972 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8973 LOGW("mms protocol is not supported format.\n");
8974 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8977 if (MMPLAYER_IS_STREAMING(player))
8978 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8980 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8982 player->smooth_streaming = FALSE;
8983 player->videodec_linked = 0;
8984 player->videosink_linked = 0;
8985 player->audiodec_linked = 0;
8986 player->audiosink_linked = 0;
8987 player->textsink_linked = 0;
8988 player->is_external_subtitle_present = FALSE;
8989 player->is_external_subtitle_added_now = FALSE;
8990 /* set the subtitle ON default */
8991 player->is_subtitle_off = FALSE;
8993 /* registry should be updated for downloadable codec */
8994 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8996 if (update_registry) {
8997 LOGD("updating registry...\n");
8998 gst_update_registry();
9000 /* then we have to rebuild factories */
9001 __mmplayer_release_factories(player);
9002 __mmplayer_init_factories(player);
9005 /* realize pipeline */
9006 ret = __gst_realize(player);
9007 if (ret != MM_ERROR_NONE)
9008 LOGE("fail to realize the player.\n");
9010 ret = __mmplayer_realize_streaming_ext(player);
9018 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9021 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9023 /* destroy can called at anytime */
9024 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9025 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9026 MMPLAYER_FREEIF(player->pd_downloader);
9030 return MM_ERROR_NONE;
9034 _mmplayer_unrealize(MMHandleType hplayer)
9036 mm_player_t* player = (mm_player_t*)hplayer;
9037 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9038 int ret = MM_ERROR_NONE;
9042 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9044 /* check current state */
9045 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9047 /* check async state transition */
9048 __mmplayer_check_async_state_transition(player);
9050 __mmplayer_unrealize_streaming_ext(player);
9052 /* unrealize pipeline */
9053 ret = __gst_unrealize(player);
9055 /* set asm stop if success */
9056 if (MM_ERROR_NONE == ret) {
9057 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9058 if (ret != MM_ERROR_NONE)
9059 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9061 if (!player->resource_manager.by_rm_cb &&
9062 _mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9063 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9064 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9065 if (ret != MM_ERROR_NONE)
9066 LOGE("failed to release resource, ret(0x%x)\n", ret);
9070 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9071 if (resource_state == RESOURCE_STATE_PREPARED) {
9072 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9073 if (ret != MM_ERROR_NONE)
9074 LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9078 LOGE("failed and don't change asm state to stop");
9086 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9088 mm_player_t* player = (mm_player_t*)hplayer;
9090 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9092 return __gst_set_message_callback(player, callback, user_param);
9096 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9098 mm_player_t *player = (mm_player_t*)hplayer;
9100 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9102 *state = MMPLAYER_CURRENT_STATE(player);
9104 return MM_ERROR_NONE;
9109 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9111 mm_player_t* player = (mm_player_t*) hplayer;
9112 GstElement* vol_element = NULL;
9117 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9119 LOGD("volume [L]=%f:[R]=%f\n",
9120 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9122 /* invalid factor range or not */
9123 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9124 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9125 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9126 return MM_ERROR_INVALID_ARGUMENT;
9130 /* not support to set other value into each channel */
9131 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9132 return MM_ERROR_INVALID_ARGUMENT;
9134 /* Save volume to handle. Currently the first array element will be saved. */
9135 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9137 /* check pipeline handle */
9138 if (!player->pipeline || !player->pipeline->audiobin) {
9139 LOGD("audiobin is not created yet\n");
9140 LOGD("but, current stored volume will be set when it's created.\n");
9142 /* NOTE : stored volume will be used in create_audiobin
9143 * returning MM_ERROR_NONE here makes application to able to
9144 * set volume at anytime.
9146 return MM_ERROR_NONE;
9149 /* setting volume to volume element */
9150 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9153 LOGD("volume is set [%f]\n", player->sound.volume);
9154 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9159 return MM_ERROR_NONE;
9164 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9166 mm_player_t* player = (mm_player_t*) hplayer;
9171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9172 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9174 /* returning stored volume */
9175 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9176 volume->level[i] = player->sound.volume;
9180 return MM_ERROR_NONE;
9186 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9188 mm_player_t* player = (mm_player_t*) hplayer;
9189 GstElement* vol_element = NULL;
9193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9195 /* mute value shoud 0 or 1 */
9196 if (mute != 0 && mute != 1) {
9197 LOGE("bad mute value\n");
9199 /* FIXIT : definitly, we need _BAD_PARAM error code */
9200 return MM_ERROR_INVALID_ARGUMENT;
9203 player->sound.mute = mute;
9205 /* just hold mute value if pipeline is not ready */
9206 if (!player->pipeline || !player->pipeline->audiobin) {
9207 LOGD("pipeline is not ready. holding mute value\n");
9208 return MM_ERROR_NONE;
9211 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9213 /* NOTE : volume will only created when the bt is enabled */
9215 LOGD("mute : %d\n", mute);
9216 g_object_set(vol_element, "mute", mute, NULL);
9218 LOGD("volume elemnet is not created. using volume in audiosink\n");
9222 return MM_ERROR_NONE;
9226 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9228 mm_player_t* player = (mm_player_t*) hplayer;
9232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9233 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9235 /* just hold mute value if pipeline is not ready */
9236 if (!player->pipeline || !player->pipeline->audiobin) {
9237 LOGD("pipeline is not ready. returning stored value\n");
9238 *pmute = player->sound.mute;
9239 return MM_ERROR_NONE;
9242 *pmute = player->sound.mute;
9246 return MM_ERROR_NONE;
9250 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9252 mm_player_t* player = (mm_player_t*) hplayer;
9256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9258 player->video_stream_changed_cb = callback;
9259 player->video_stream_changed_cb_user_param = user_param;
9260 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9264 return MM_ERROR_NONE;
9268 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9270 mm_player_t* player = (mm_player_t*) hplayer;
9274 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9276 player->audio_stream_changed_cb = callback;
9277 player->audio_stream_changed_cb_user_param = user_param;
9278 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9282 return MM_ERROR_NONE;
9286 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9288 mm_player_t* player = (mm_player_t*) hplayer;
9292 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9294 player->audio_stream_render_cb_ex = callback;
9295 player->audio_stream_cb_user_param = user_param;
9296 player->audio_stream_sink_sync = sync;
9297 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);
9301 return MM_ERROR_NONE;
9305 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9307 mm_player_t* player = (mm_player_t*) hplayer;
9311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9313 if (callback && !player->bufmgr)
9314 player->bufmgr = tbm_bufmgr_init(-1);
9316 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9317 player->video_stream_cb = callback;
9318 player->video_stream_cb_user_param = user_param;
9320 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9324 return MM_ERROR_NONE;
9328 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9330 mm_player_t* player = (mm_player_t*) hplayer;
9334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9336 player->audio_stream_cb = callback;
9337 player->audio_stream_cb_user_param = user_param;
9338 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9342 return MM_ERROR_NONE;
9347 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9349 mm_player_t* player = (mm_player_t*) hplayer;
9353 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9355 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9356 return MM_ERROR_PLAYER_INVALID_STATE;
9358 LOGD("pre buffer size : %d sec\n", second);
9361 LOGE("bad size value\n");
9362 return MM_ERROR_INVALID_ARGUMENT;
9365 if (player->streamer == NULL) {
9366 player->streamer = __mm_player_streaming_create();
9367 __mm_player_streaming_initialize(player->streamer);
9370 player->streamer->buffering_req.initial_second = second;
9374 return MM_ERROR_NONE;
9379 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9381 mm_player_t* player = (mm_player_t*) hplayer;
9385 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9387 LOGD("mode %d\n", mode);
9389 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9390 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9391 return MM_ERROR_INVALID_ARGUMENT;
9393 if (player->streamer == NULL) {
9394 player->streamer = __mm_player_streaming_create();
9395 __mm_player_streaming_initialize(player->streamer);
9398 player->streamer->buffering_req.mode = mode;
9401 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9402 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9403 player->streamer->buffering_req.runtime_second = second;
9407 return MM_ERROR_NONE;
9411 __mmplayer_start_streaming_ext(mm_player_t *player)
9413 gint ret = MM_ERROR_NONE;
9416 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9418 if (MMPLAYER_IS_HTTP_PD(player)) {
9419 if (!player->pd_downloader) {
9420 ret = __mmplayer_realize_streaming_ext(player);
9422 if (ret != MM_ERROR_NONE) {
9423 LOGE("failed to realize streaming ext\n");
9428 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9429 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9431 LOGE("ERROR while starting PD...\n");
9432 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9434 ret = MM_ERROR_NONE;
9443 _mmplayer_start(MMHandleType hplayer) // @
9445 mm_player_t* player = (mm_player_t*) hplayer;
9446 gint ret = MM_ERROR_NONE;
9450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9452 /* check current state */
9453 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9455 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9456 if (ret != MM_ERROR_NONE) {
9457 LOGE("failed to acquire sound focus.\n");
9461 /* NOTE : we should check and create pipeline again if not created as we destroy
9462 * whole pipeline when stopping in streamming playback
9464 if (!player->pipeline) {
9465 ret = __gst_realize(player);
9466 if (MM_ERROR_NONE != ret) {
9467 LOGE("failed to realize before starting. only in streamming\n");
9473 ret = __mmplayer_start_streaming_ext(player);
9474 if (ret != MM_ERROR_NONE)
9475 LOGE("failed to start streaming ext \n");
9477 /* start pipeline */
9478 ret = __gst_start(player);
9479 if (ret != MM_ERROR_NONE)
9480 LOGE("failed to start player.\n");
9487 /* NOTE: post "not supported codec message" to application
9488 * when one codec is not found during AUTOPLUGGING in MSL.
9489 * So, it's separated with error of __mmplayer_gst_callback().
9490 * And, if any codec is not found, don't send message here.
9491 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9494 __mmplayer_handle_missed_plugin(mm_player_t* player)
9496 MMMessageParamType msg_param;
9497 memset(&msg_param, 0, sizeof(MMMessageParamType));
9498 gboolean post_msg_direct = FALSE;
9502 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9504 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9505 player->not_supported_codec, player->can_support_codec);
9507 if (player->not_found_demuxer) {
9508 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9509 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9511 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9512 MMPLAYER_FREEIF(msg_param.data);
9514 return MM_ERROR_NONE;
9517 if (player->not_supported_codec) {
9518 if (player->can_support_codec) {
9519 // There is one codec to play
9520 post_msg_direct = TRUE;
9522 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9523 post_msg_direct = TRUE;
9526 if (post_msg_direct) {
9527 MMMessageParamType msg_param;
9528 memset(&msg_param, 0, sizeof(MMMessageParamType));
9530 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9531 LOGW("not found AUDIO codec, posting error code to application.\n");
9533 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9534 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9535 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9536 LOGW("not found VIDEO codec, posting error code to application.\n");
9538 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9539 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9542 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9544 MMPLAYER_FREEIF(msg_param.data);
9546 return MM_ERROR_NONE;
9548 // no any supported codec case
9549 LOGW("not found any codec, posting error code to application.\n");
9551 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9552 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9553 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9555 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9556 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9559 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9561 MMPLAYER_FREEIF(msg_param.data);
9567 return MM_ERROR_NONE;
9570 static void __mmplayer_check_pipeline(mm_player_t* player)
9572 GstState element_state = GST_STATE_VOID_PENDING;
9573 GstState element_pending_state = GST_STATE_VOID_PENDING;
9575 int ret = MM_ERROR_NONE;
9577 if (player->gapless.reconfigure) {
9578 LOGW("pipeline is under construction.\n");
9580 MMPLAYER_PLAYBACK_LOCK(player);
9581 MMPLAYER_PLAYBACK_UNLOCK(player);
9583 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9585 /* wait for state transition */
9586 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9588 if (ret == GST_STATE_CHANGE_FAILURE)
9589 LOGE("failed to change pipeline state within %d sec\n", timeout);
9593 /* NOTE : it should be able to call 'stop' anytime*/
9595 _mmplayer_stop(MMHandleType hplayer) // @
9597 mm_player_t* player = (mm_player_t*)hplayer;
9598 int ret = MM_ERROR_NONE;
9602 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9604 /* check current state */
9605 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9607 /* check pipline building state */
9608 __mmplayer_check_pipeline(player);
9609 __mmplayer_reset_gapless_state(player);
9611 /* NOTE : application should not wait for EOS after calling STOP */
9612 __mmplayer_cancel_eos_timer(player);
9614 __mmplayer_unrealize_streaming_ext(player);
9617 player->doing_seek = FALSE;
9620 ret = __gst_stop(player);
9622 if (ret != MM_ERROR_NONE)
9623 LOGE("failed to stop player.\n");
9631 _mmplayer_pause(MMHandleType hplayer) // @
9633 mm_player_t* player = (mm_player_t*)hplayer;
9634 gint64 pos_msec = 0;
9635 gboolean async = FALSE;
9636 gint ret = MM_ERROR_NONE;
9640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9642 /* check current state */
9643 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9645 /* check pipline building state */
9646 __mmplayer_check_pipeline(player);
9648 switch (MMPLAYER_CURRENT_STATE(player)) {
9649 case MM_PLAYER_STATE_READY:
9651 /* check prepare async or not.
9652 * In the case of streaming playback, it's recommned to avoid blocking wait.
9654 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9655 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9657 /* Changing back sync of rtspsrc to async */
9658 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9659 LOGD("async prepare working mode for rtsp");
9665 case MM_PLAYER_STATE_PLAYING:
9667 /* NOTE : store current point to overcome some bad operation
9668 *(returning zero when getting current position in paused state) of some
9671 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9672 LOGW("getting current position failed in paused\n");
9674 player->last_position = pos_msec;
9676 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9677 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9678 This causes problem is position calculation during normal pause resume scenarios also.
9679 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9680 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9681 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9682 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9688 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9689 LOGD("doing async pause in case of ms buff src");
9693 /* pause pipeline */
9694 ret = __gst_pause(player, async);
9696 if (ret != MM_ERROR_NONE)
9697 LOGE("failed to pause player. ret : 0x%x\n", ret);
9699 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9700 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9701 LOGE("failed to update display_rotation");
9710 _mmplayer_resume(MMHandleType hplayer)
9712 mm_player_t* player = (mm_player_t*)hplayer;
9713 int ret = MM_ERROR_NONE;
9714 gboolean async = FALSE;
9718 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9720 /* Changing back sync mode rtspsrc to async */
9721 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9722 LOGD("async resume for rtsp case");
9726 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9727 if (ret != MM_ERROR_NONE) {
9728 LOGE("failed to acquire sound focus.\n");
9732 /* check current state */
9733 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9735 ret = __gst_resume(player, async);
9737 if (ret != MM_ERROR_NONE)
9738 LOGE("failed to resume player.\n");
9746 __mmplayer_set_play_count(mm_player_t* player, gint count)
9748 MMHandleType attrs = 0;
9752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9754 attrs = MMPLAYER_GET_ATTRS(player);
9756 LOGE("fail to get attributes.\n");
9757 return MM_ERROR_PLAYER_INTERNAL;
9760 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9761 if (mmf_attrs_commit(attrs)) /* return -1 if error */
9762 LOGE("failed to commit\n");
9766 return MM_ERROR_NONE;
9770 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9772 mm_player_t* player = (mm_player_t*)hplayer;
9773 gint64 start_pos = 0;
9779 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9780 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9782 player->section_repeat = TRUE;
9783 player->section_repeat_start = start;
9784 player->section_repeat_end = end;
9786 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9787 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9789 __mmplayer_set_play_count(player, infinity);
9791 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9792 player->playback_rate,
9794 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9795 GST_SEEK_TYPE_SET, start_pos,
9796 GST_SEEK_TYPE_SET, end_pos))) {
9797 LOGE("failed to activate section repeat\n");
9799 return MM_ERROR_PLAYER_SEEK;
9802 LOGD("succeeded to set section repeat from %d to %d\n",
9803 player->section_repeat_start, player->section_repeat_end);
9807 return MM_ERROR_NONE;
9811 __mmplayer_set_pcm_extraction(mm_player_t* player)
9813 gint64 start_nsec = 0;
9814 gint64 end_nsec = 0;
9815 gint64 dur_nsec = 0;
9816 gint64 dur_msec = 0;
9817 int required_start = 0;
9818 int required_end = 0;
9823 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9825 mm_attrs_multiple_get(player->attrs,
9827 "pcm_extraction_start_msec", &required_start,
9828 "pcm_extraction_end_msec", &required_end,
9831 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9833 if (required_start == 0 && required_end == 0) {
9834 LOGD("extracting entire stream");
9835 return MM_ERROR_NONE;
9836 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9837 LOGD("invalid range for pcm extraction");
9838 return MM_ERROR_INVALID_ARGUMENT;
9842 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9844 LOGE("failed to get duration");
9845 return MM_ERROR_PLAYER_INTERNAL;
9847 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9849 if (dur_msec < required_end) {
9851 LOGD("invalid end pos for pcm extraction");
9852 return MM_ERROR_INVALID_ARGUMENT;
9855 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9856 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9858 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9861 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9862 GST_SEEK_TYPE_SET, start_nsec,
9863 GST_SEEK_TYPE_SET, end_nsec))) {
9864 LOGE("failed to seek for pcm extraction\n");
9866 return MM_ERROR_PLAYER_SEEK;
9869 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9873 return MM_ERROR_NONE;
9877 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9879 mm_player_t* player = (mm_player_t*)hplayer;
9885 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9887 player->section_repeat = FALSE;
9889 __mmplayer_set_play_count(player, onetime);
9891 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9893 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9896 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9897 GST_SEEK_TYPE_SET, cur_pos,
9898 GST_SEEK_TYPE_SET, player->duration))) {
9899 LOGE("failed to deactivate section repeat\n");
9901 return MM_ERROR_PLAYER_SEEK;
9906 return MM_ERROR_NONE;
9910 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9912 mm_player_t* player = (mm_player_t*)hplayer;
9913 gint64 pos_msec = 0;
9914 int ret = MM_ERROR_NONE;
9916 signed long long start = 0, stop = 0;
9917 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9920 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9921 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9923 /* The sound of video is not supported under 0.0 and over 2.0. */
9924 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9925 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9928 _mmplayer_set_mute(hplayer, mute);
9930 if (player->playback_rate == rate)
9931 return MM_ERROR_NONE;
9933 /* If the position is reached at start potion during fast backward, EOS is posted.
9934 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9936 player->playback_rate = rate;
9938 current_state = MMPLAYER_CURRENT_STATE(player);
9940 if (current_state != MM_PLAYER_STATE_PAUSED)
9941 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9943 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9945 if ((current_state == MM_PLAYER_STATE_PAUSED)
9946 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9947 LOGW("returning last point : %lld\n", player->last_position);
9948 pos_msec = player->last_position;
9954 stop = GST_CLOCK_TIME_NONE;
9956 start = GST_CLOCK_TIME_NONE;
9959 if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9962 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9963 GST_SEEK_TYPE_SET, start,
9964 GST_SEEK_TYPE_SET, stop))) {
9965 LOGE("failed to set speed playback\n");
9966 return MM_ERROR_PLAYER_SEEK;
9969 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9973 return MM_ERROR_NONE;;
9977 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9979 mm_player_t* player = (mm_player_t*)hplayer;
9980 int ret = MM_ERROR_NONE;
9984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9986 /* check pipline building state */
9987 __mmplayer_check_pipeline(player);
9989 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9997 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
9999 mm_player_t* player = (mm_player_t*)hplayer;
10000 int ret = MM_ERROR_NONE;
10002 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10004 ret = __gst_get_position(player, format, position);
10010 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10012 mm_player_t* player = (mm_player_t*)hplayer;
10013 int ret = MM_ERROR_NONE;
10015 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10017 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10023 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10025 mm_player_t* player = (mm_player_t*)hplayer;
10026 int ret = MM_ERROR_NONE;
10030 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10032 ret = __gst_adjust_subtitle_position(player, format, position);
10039 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10041 mm_player_t* player = (mm_player_t*)hplayer;
10042 int ret = MM_ERROR_NONE;
10046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10048 ret = __gst_adjust_video_position(player, offset);
10056 __mmplayer_is_midi_type(gchar* str_caps)
10058 if ((g_strrstr(str_caps, "audio/midi")) ||
10059 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10060 (g_strrstr(str_caps, "application/x-smaf")) ||
10061 (g_strrstr(str_caps, "audio/x-imelody")) ||
10062 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10063 (g_strrstr(str_caps, "audio/xmf")) ||
10064 (g_strrstr(str_caps, "audio/mxmf"))) {
10073 __mmplayer_is_only_mp3_type(gchar *str_caps)
10075 if (g_strrstr(str_caps, "application/x-id3") ||
10076 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10082 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10084 GstStructure* caps_structure = NULL;
10085 gint samplerate = 0;
10089 MMPLAYER_RETURN_IF_FAIL(player && caps);
10091 caps_structure = gst_caps_get_structure(caps, 0);
10093 /* set stream information */
10094 gst_structure_get_int(caps_structure, "rate", &samplerate);
10095 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10097 gst_structure_get_int(caps_structure, "channels", &channels);
10098 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10100 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10104 __mmplayer_update_content_type_info(mm_player_t* player)
10107 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10109 if (__mmplayer_is_midi_type(player->type)) {
10110 player->bypass_audio_effect = TRUE;
10111 } else if (g_strrstr(player->type, "application/x-hls")) {
10112 /* If it can't know exact type when it parses uri because of redirection case,
10113 * it will be fixed by typefinder or when doing autoplugging.
10115 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10116 if (player->streamer) {
10117 player->streamer->is_adaptive_streaming = TRUE;
10118 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10119 player->streamer->buffering_req.runtime_second = 5;
10121 } else if (g_strrstr(player->type, "application/dash+xml")) {
10122 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10129 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10130 GstCaps *caps, gpointer data)
10132 mm_player_t* player = (mm_player_t*)data;
10133 GstPad* pad = NULL;
10137 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10139 /* store type string */
10140 MMPLAYER_FREEIF(player->type);
10141 player->type = gst_caps_to_string(caps);
10143 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10145 if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10146 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10147 (g_strrstr(player->type, "audio/x-raw-int"))) {
10148 LOGE("not support media format\n");
10150 if (player->msg_posted == FALSE) {
10151 MMMessageParamType msg_param;
10152 memset(&msg_param, 0, sizeof(MMMessageParamType));
10154 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10155 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10157 /* don't post more if one was sent already */
10158 player->msg_posted = TRUE;
10163 __mmplayer_update_content_type_info(player);
10165 pad = gst_element_get_static_pad(tf, "src");
10167 LOGE("fail to get typefind src pad.\n");
10171 if (player->use_decodebin) {
10172 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10173 gboolean async = FALSE;
10174 LOGE("failed to autoplug %s\n", player->type);
10176 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10178 if (async && player->msg_posted == FALSE)
10179 __mmplayer_handle_missed_plugin(player);
10185 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10186 gboolean async = FALSE;
10187 LOGE("failed to autoplug %s\n", player->type);
10189 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10191 if (async && player->msg_posted == FALSE)
10192 __mmplayer_handle_missed_plugin(player);
10197 /* finish autopluging if no dynamic pad waiting */
10198 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10199 if (!MMPLAYER_IS_RTSP_STREAMING(player))
10200 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10205 gst_object_unref(GST_OBJECT(pad));
10212 static GstElement *
10213 __mmplayer_create_decodebin(mm_player_t* player)
10215 GstElement *decodebin = NULL;
10219 /* create decodebin */
10220 decodebin = gst_element_factory_make("decodebin", NULL);
10223 LOGE("fail to create decodebin\n");
10227 /* raw pad handling signal */
10228 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10229 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10231 /* no-more-pad pad handling signal */
10232 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10233 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10235 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10236 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10238 /* This signal is emitted when a pad for which there is no further possible
10239 decoding is added to the decodebin.*/
10240 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10241 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10243 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10244 before looking for any elements that can handle that stream.*/
10245 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10246 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10248 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10249 before looking for any elements that can handle that stream.*/
10250 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10251 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10253 /* This signal is emitted once decodebin has finished decoding all the data.*/
10254 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10255 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10257 /* This signal is emitted when a element is added to the bin.*/
10258 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10259 G_CALLBACK(__mmplayer_gst_element_added), player);
10266 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10268 MMPlayerGstElement* mainbin = NULL;
10269 GstElement* decodebin = NULL;
10270 GstElement* queue2 = NULL;
10271 GstPad* sinkpad = NULL;
10272 GstPad* qsrcpad = NULL;
10273 gchar *caps_str = NULL;
10274 gint64 dur_bytes = 0L;
10276 guint max_buffer_size_bytes = 0;
10277 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10280 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10282 mainbin = player->pipeline->mainbin;
10284 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10285 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10286 LOGD("creating http streaming buffering queue(queue2)\n");
10288 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10289 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10291 queue2 = gst_element_factory_make("queue2", "queue2");
10293 LOGE("failed to create buffering queue element\n");
10297 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10298 LOGE("failed to add buffering queue\n");
10302 sinkpad = gst_element_get_static_pad(queue2, "sink");
10303 qsrcpad = gst_element_get_static_pad(queue2, "src");
10305 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10306 LOGE("failed to link buffering queue\n");
10310 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10311 LOGE("fail to get duration.\n");
10313 LOGD("dur_bytes = %lld\n", dur_bytes);
10315 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10317 if (dur_bytes > 0) {
10318 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10319 type = MUXED_BUFFER_TYPE_FILE;
10321 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10322 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10328 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10329 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10330 if (!g_strrstr(player->type, "video/mpegts")) {
10331 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10332 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10334 __mm_player_streaming_set_queue2(player->streamer,
10337 max_buffer_size_bytes,
10338 player->ini.http_buffering_time,
10340 player->ini.http_buffering_limit, // no meaning
10342 player->http_file_buffering_path,
10343 (guint64)dur_bytes);
10346 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10347 LOGE("failed to sync queue2 state with parent\n");
10353 gst_object_unref(GST_OBJECT(sinkpad));
10355 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10356 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10360 /* create decodebin */
10361 decodebin = __mmplayer_create_decodebin(player);
10364 LOGE("can not create autoplug element\n");
10368 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10369 LOGE("failed to add decodebin\n");
10373 /* to force caps on the decodebin element and avoid reparsing stuff by
10374 * typefind. It also avoids a deadlock in the way typefind activates pads in
10375 * the state change */
10376 g_object_set(decodebin, "sink-caps", caps, NULL);
10378 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10380 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10381 LOGE("failed to link decodebin\n");
10385 gst_object_unref(GST_OBJECT(sinkpad));
10387 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10388 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10390 /* set decodebin property about buffer in streaming playback. *
10391 * in case of hls, it does not need to have big buffer *
10392 * because it is kind of adaptive streaming. */
10393 if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10394 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10395 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10396 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10397 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10399 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10400 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10401 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10404 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10405 "high-percent", (gint)player->ini.http_buffering_limit,
10406 "low-percent", 1, // 1%
10407 "max-size-bytes", max_size_bytes,
10408 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10409 "max-size-buffers", 0, NULL); // disable or automatic
10412 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10413 LOGE("failed to sync decodebin state with parent\n");
10423 MMPLAYER_FREEIF(caps_str);
10426 gst_object_unref(GST_OBJECT(sinkpad));
10429 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10430 * You need to explicitly set elements to the NULL state before
10431 * dropping the final reference, to allow them to clean up.
10433 gst_element_set_state(queue2, GST_STATE_NULL);
10435 /* And, it still has a parent "player".
10436 * You need to let the parent manage the object instead of unreffing the object directly.
10438 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10439 gst_object_unref(queue2);
10444 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10445 * You need to explicitly set elements to the NULL state before
10446 * dropping the final reference, to allow them to clean up.
10448 gst_element_set_state(decodebin, GST_STATE_NULL);
10450 /* And, it still has a parent "player".
10451 * You need to let the parent manage the object instead of unreffing the object directly.
10454 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10455 gst_object_unref(decodebin);
10462 /* it will return first created element */
10464 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10466 MMPlayerGstElement* mainbin = NULL;
10467 const char* mime = NULL;
10468 const GList* item = NULL;
10469 const gchar* klass = NULL;
10470 GstCaps* res = NULL;
10471 gboolean skip = FALSE;
10472 GstPad* queue_pad = NULL;
10473 GstElement* queue = NULL;
10474 GstElement *element = NULL;
10478 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10480 mainbin = player->pipeline->mainbin;
10482 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10484 /* return if we got raw output */
10485 if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10486 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10488 element = (GstElement*)gst_pad_get_parent(pad);
10489 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10490 * No queue will be added. I think it can caused breaking sound when playing raw audio
10491 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10492 * Anyway, currentely raw-queue seems not necessary.
10495 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10496 * has linked. if so, we need to add queue for quality of output. note that
10497 * decodebin also has same problem.
10499 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10501 /* add queue if needed */
10502 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10503 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) {
10504 LOGD("adding raw queue\n");
10506 queue = gst_element_factory_make("queue", NULL);
10508 LOGW("failed to create queue\n");
10513 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10514 LOGW("failed to set state READY to queue\n");
10518 /* add to pipeline */
10519 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10520 LOGW("failed to add queue\n");
10525 queue_pad = gst_element_get_static_pad(queue, "sink");
10527 if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10528 LOGW("failed to link queue\n");
10531 gst_object_unref(GST_OBJECT(queue_pad));
10535 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10536 LOGW("failed to set state PAUSED to queue\n");
10540 /* replace given pad to queue:src */
10541 pad = gst_element_get_static_pad(queue, "src");
10543 LOGW("failed to get pad from queue\n");
10548 /* check if player can do start continually */
10549 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10551 if (__mmplayer_link_sink(player, pad))
10552 __mmplayer_gst_decode_callback(element, pad, player);
10554 gst_object_unref(GST_OBJECT(element));
10560 item = player->factories;
10561 for (; item != NULL; item = item->next) {
10562 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10568 /* filtering exclude keyword */
10569 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10570 if (g_strrstr(GST_OBJECT_NAME(factory),
10571 player->ini.exclude_element_keyword[idx])) {
10572 LOGW("skipping [%s] by exculde keyword [%s]\n",
10573 GST_OBJECT_NAME(factory),
10574 player->ini.exclude_element_keyword[idx]);
10581 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10582 // omx decoder can not support mpeg4video data partitioned
10583 // rtsp streaming didn't know mpeg4video data partitioned format
10584 // so, if rtsp playback, player will skip omx_mpeg4dec.
10585 LOGW("skipping [%s] when rtsp streaming \n",
10586 GST_OBJECT_NAME(factory));
10591 if (skip) continue;
10593 /* check factory class for filtering */
10594 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10596 /*parsers are not required in case of external feeder*/
10597 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10600 /* NOTE : msl don't need to use image plugins.
10601 * So, those plugins should be skipped for error handling.
10603 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10604 LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10608 /* check pad compatability */
10609 for (pads = gst_element_factory_get_static_pad_templates(factory);
10610 pads != NULL; pads = pads->next) {
10611 GstStaticPadTemplate *temp1 = pads->data;
10612 GstCaps* static_caps = NULL;
10614 if (temp1->direction != GST_PAD_SINK
10615 || temp1->presence != GST_PAD_ALWAYS)
10618 /* using existing caps */
10619 if (GST_IS_CAPS(&temp1->static_caps.caps))
10620 static_caps = gst_caps_ref(temp1->static_caps.caps);
10623 static_caps = gst_caps_from_string(temp1->static_caps.string);
10625 res = gst_caps_intersect((GstCaps*)caps, static_caps);
10626 gst_caps_unref(static_caps);
10627 static_caps = NULL;
10629 if (res && !gst_caps_is_empty(res)) {
10630 GstElement *new_element;
10631 GList *elements = player->parsers;
10632 char *name_template = g_strdup(temp1->name_template);
10633 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10634 gst_caps_unref(res);
10636 /* check ALP Codec can be used or not */
10637 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10638 /* consider mp3 audio only */
10639 if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10640 /* try to use ALP decoder first instead of selected decoder */
10641 GstElement *element = NULL;
10642 GstElementFactory * element_facory;
10643 gchar *path = NULL;
10644 guint64 data_size = 0;
10645 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
10648 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10650 if (stat(path, &sb) == 0)
10651 data_size = (guint64)sb.st_size;
10652 LOGD("file size : %u", data_size);
10654 if (data_size > MIN_THRESHOLD_SIZE) {
10655 LOGD("checking if ALP can be used or not");
10656 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10658 /* check availability because multi-instance is not supported */
10659 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10661 if (ret != GST_STATE_CHANGE_SUCCESS) {
10662 // use just selected decoder
10663 gst_object_unref(element);
10664 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10665 // replace facotry to use omx
10667 gst_element_set_state(element, GST_STATE_NULL);
10668 gst_object_unref(element);
10670 element_facory = gst_element_factory_find("omx_mp3dec");
10671 /* replace, otherwise use selected thing instead */
10672 if (element_facory) {
10673 factory = element_facory;
10674 name_to_plug = GST_OBJECT_NAME(factory);
10680 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10681 if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10682 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10684 if (strncasecmp(env, "yes", 3) == 0) {
10685 LOGD("skipping [%s] by disabled\n", name_to_plug);
10686 MMPLAYER_FREEIF(name_template);
10693 LOGD("found %s to plug\n", name_to_plug);
10695 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10696 if (!new_element) {
10697 LOGE("failed to create element [%s]. continue with next.\n",
10698 GST_OBJECT_NAME(factory));
10700 MMPLAYER_FREEIF(name_template);
10705 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10706 * because parser can accept its own output as input.
10708 if (g_strrstr(klass, "Parser")) {
10709 gchar *selected = NULL;
10711 for (; elements; elements = g_list_next(elements)) {
10712 gchar *element_name = elements->data;
10714 if (g_strrstr(element_name, name_to_plug)) {
10715 LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10721 MMPLAYER_FREEIF(name_template);
10725 selected = g_strdup(name_to_plug);
10726 player->parsers = g_list_append(player->parsers, selected);
10729 /* store specific handles for futher control */
10730 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10731 /* FIXIT : first value will be overwritten if there's more
10732 * than 1 demuxer/parser
10734 LOGD("plugged element is demuxer. take it\n");
10735 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10736 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10738 /*Added for multi audio support */
10739 if (g_strrstr(klass, "Demux")) {
10740 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10741 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10743 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10744 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10745 this code should be removed after mpegtsdemux is fixed */
10746 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10747 LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10748 player->no_more_pad = TRUE;
10751 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10752 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10753 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10754 if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10755 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10756 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10757 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10758 } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10759 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10760 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10761 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10763 /* NOTE : IF one codec is found, add it to supported_codec and remove from
10764 * missing plugin. Both of them are used to check what's supported codec
10765 * before returning result of play start. And, missing plugin should be
10766 * updated here for multi track files.
10768 if (g_str_has_prefix(mime, "video")) {
10769 GstPad *src_pad = NULL;
10770 GstPadTemplate *pad_templ = NULL;
10771 GstCaps *caps = NULL;
10772 gchar *caps_str = NULL;
10774 LOGD("found VIDEO decoder\n");
10775 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10776 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10778 src_pad = gst_element_get_static_pad(new_element, "src");
10779 pad_templ = gst_pad_get_pad_template(src_pad);
10780 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10782 caps_str = gst_caps_to_string(caps);
10785 MMPLAYER_FREEIF(caps_str);
10786 gst_object_unref(src_pad);
10787 } else if (g_str_has_prefix(mime, "audio")) {
10788 LOGD("found AUDIO decoder\n");
10789 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10790 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10794 if (!__mmplayer_close_link(player, pad, new_element,
10795 name_template, gst_element_factory_get_static_pad_templates(factory))) {
10796 MMPLAYER_FREEIF(name_template);
10797 if (player->keep_detecting_vcodec)
10800 /* Link is failed even though a supportable codec is found. */
10801 __mmplayer_check_not_supported_codec(player, klass, mime);
10803 LOGE("failed to call _close_link\n");
10807 MMPLAYER_FREEIF(name_template);
10811 gst_caps_unref(res);
10816 /* There is no available codec. */
10817 __mmplayer_check_not_supported_codec(player, klass, mime);
10825 gst_object_unref(queue);
10828 gst_object_unref(queue_pad);
10831 gst_object_unref(element);
10838 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10842 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10843 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10845 LOGD("class : %s, mime : %s \n", factory_class, mime);
10847 /* add missing plugin */
10848 /* NOTE : msl should check missing plugin for image mime type.
10849 * Some motion jpeg clips can have playable audio track.
10850 * So, msl have to play audio after displaying popup written video format not supported.
10852 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10853 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10854 LOGD("not found demuxer\n");
10855 player->not_found_demuxer = TRUE;
10856 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10862 if (!g_strrstr(factory_class, "Demuxer")) {
10863 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10864 LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10865 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10867 /* check that clip have multi tracks or not */
10868 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10869 LOGD("video plugin is already linked\n");
10871 LOGW("add VIDEO to missing plugin\n");
10872 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10874 } else if (g_str_has_prefix(mime, "audio")) {
10875 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10876 LOGD("audio plugin is already linked\n");
10878 LOGW("add AUDIO to missing plugin\n");
10879 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10887 return MM_ERROR_NONE;
10892 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10894 mm_player_t* player = (mm_player_t*)data;
10898 MMPLAYER_RETURN_IF_FAIL(player);
10900 /* remove fakesink. */
10901 if (!__mmplayer_gst_remove_fakesink(player,
10902 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10903 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10904 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10905 * source element are not same. To overcome this situation, this function will called
10906 * several places and several times. Therefore, this is not an error case.
10911 LOGD("pipeline has completely constructed\n");
10913 if ((player->ini.async_start) &&
10914 (player->msg_posted == FALSE) &&
10915 (player->cmd >= MMPLAYER_COMMAND_START))
10916 __mmplayer_handle_missed_plugin(player);
10918 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10922 __mmplayer_verify_next_play_path(mm_player_t *player)
10924 MMHandleType attrs = 0;
10925 MMPlayerParseProfile profile;
10926 gint uri_idx = 0, check_cnt = 0;
10928 gint mode = MM_PLAYER_PD_MODE_NONE;
10932 guint num_of_list = 0;
10933 static int profile_tv = -1;
10937 LOGD("checking for gapless play");
10939 if (player->pipeline->textbin) {
10940 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10944 attrs = MMPLAYER_GET_ATTRS(player);
10946 LOGE("fail to get attributes.\n");
10950 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10952 if (__builtin_expect(profile_tv == -1, 0)) {
10954 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10955 switch (*profileName) {
10965 /* gapless playback is not supported in case of video at TV profile. */
10966 if (profile_tv && video) {
10967 LOGW("not support video gapless playback");
10971 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10972 if (mode == TRUE) {
10978 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10979 LOGE("can not get play count\n");
10981 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10982 LOGE("can not get gapless mode\n");
10984 if (video && !gapless) {
10985 LOGW("not enabled video gapless playback");
10989 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10993 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10997 num_of_list = g_list_length(player->uri_info.uri_list);
10999 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11001 if (num_of_list == 0) {
11002 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11003 LOGE("can not get profile_uri\n");
11008 LOGE("uri list is empty.\n");
11012 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11013 LOGD("add original path : %s ", uri);
11019 uri_idx = player->uri_info.uri_idx;
11024 if (check_cnt > num_of_list) {
11025 LOGE("there is no valid uri.");
11029 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11031 if (uri_idx < num_of_list-1) {
11034 if ((count <= 1) && (count != -1)) {
11035 LOGD("no repeat.");
11037 } else if (count > 1) {
11038 /* decrease play count */
11039 /* we succeeded to rewind. update play count and then wait for next EOS */
11042 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11044 /* commit attribute */
11045 if (mmf_attrs_commit(attrs))
11046 LOGE("failed to commit attribute\n");
11049 /* count < 0 : repeat continually */
11053 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11054 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11057 LOGW("next uri does not exist\n");
11061 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11062 LOGE("failed to parse profile\n");
11066 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11067 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11068 LOGW("uri type is not supported(%d).", profile.uri_type);
11075 player->uri_info.uri_idx = uri_idx;
11076 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11078 if (mmf_attrs_commit(player->attrs)) {
11079 LOGE("failed to commit.\n");
11083 LOGD("next uri %s(%d)\n", uri, uri_idx);
11089 LOGE("unable to play next path. EOS will be posted soon.\n");
11094 __mmplayer_initialize_next_play(mm_player_t *player)
11100 player->smooth_streaming = FALSE;
11101 player->videodec_linked = 0;
11102 player->audiodec_linked = 0;
11103 player->videosink_linked = 0;
11104 player->audiosink_linked = 0;
11105 player->textsink_linked = 0;
11106 player->is_external_subtitle_present = FALSE;
11107 player->is_external_subtitle_added_now = FALSE;
11108 player->not_supported_codec = MISSING_PLUGIN_NONE;
11109 player->can_support_codec = FOUND_PLUGIN_NONE;
11110 player->pending_seek.is_pending = FALSE;
11111 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11112 player->pending_seek.pos = 0;
11113 player->msg_posted = FALSE;
11114 player->has_many_types = FALSE;
11115 player->no_more_pad = FALSE;
11116 player->not_found_demuxer = 0;
11117 player->doing_seek = FALSE;
11118 player->max_audio_channels = 0;
11119 player->is_subtitle_force_drop = FALSE;
11120 player->play_subtitle = FALSE;
11121 player->use_textoverlay = FALSE;
11122 player->adjust_subtitle_pos = 0;
11124 player->updated_bitrate_count = 0;
11125 player->total_bitrate = 0;
11126 player->updated_maximum_bitrate_count = 0;
11127 player->total_maximum_bitrate = 0;
11129 _mmplayer_track_initialize(player);
11131 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11132 player->bitrate[i] = 0;
11133 player->maximum_bitrate[i] = 0;
11136 if (player->v_stream_caps) {
11137 gst_caps_unref(player->v_stream_caps);
11138 player->v_stream_caps = NULL;
11141 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11142 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11144 /* clean found parsers */
11145 if (player->parsers) {
11146 GList *parsers = player->parsers;
11147 for (; parsers; parsers = g_list_next(parsers)) {
11148 gchar *name = parsers->data;
11149 MMPLAYER_FREEIF(name);
11151 g_list_free(player->parsers);
11152 player->parsers = NULL;
11155 /* clean found audio decoders */
11156 if (player->audio_decoders) {
11157 GList *a_dec = player->audio_decoders;
11158 for (; a_dec; a_dec = g_list_next(a_dec)) {
11159 gchar *name = a_dec->data;
11160 MMPLAYER_FREEIF(name);
11162 g_list_free(player->audio_decoders);
11163 player->audio_decoders = NULL;
11170 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11172 MMPlayerGstElement *mainbin = NULL;
11173 MMMessageParamType msg_param = {0,};
11174 GstElement *element = NULL;
11175 MMHandleType attrs = 0;
11177 enum MainElementID elemId = MMPLAYER_M_NUM;
11181 if ((player == NULL) ||
11182 (player->pipeline == NULL) ||
11183 (player->pipeline->mainbin == NULL)) {
11184 LOGE("player is null.\n");
11188 mainbin = player->pipeline->mainbin;
11189 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11191 attrs = MMPLAYER_GET_ATTRS(player);
11193 LOGE("fail to get attributes.\n");
11197 /* Initialize Player values */
11198 __mmplayer_initialize_next_play(player);
11200 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11202 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11203 LOGE("failed to parse profile\n");
11204 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11208 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11209 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11210 LOGE("it's dash or hls. not support.");
11211 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11216 switch (player->profile.uri_type) {
11218 case MM_PLAYER_URI_TYPE_FILE:
11220 LOGD("using filesrc for 'file://' handler.\n");
11222 element = gst_element_factory_make("filesrc", "source");
11225 LOGE("failed to create filesrc\n");
11229 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11232 case MM_PLAYER_URI_TYPE_URL_HTTP:
11234 gchar *user_agent, *proxy, *cookies, **cookie_list;
11235 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11236 user_agent = proxy = cookies = NULL;
11237 cookie_list = NULL;
11239 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11241 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11244 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11246 /* get attribute */
11247 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11248 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11249 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11250 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11252 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11253 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11254 LOGD("get timeout from ini\n");
11255 http_timeout = player->ini.http_timeout;
11258 /* get attribute */
11259 SECURE_LOGD("location : %s\n", player->profile.uri);
11260 SECURE_LOGD("cookies : %s\n", cookies);
11261 SECURE_LOGD("proxy : %s\n", proxy);
11262 SECURE_LOGD("user_agent : %s\n", user_agent);
11263 LOGD("timeout : %d\n", http_timeout);
11265 /* setting property to streaming source */
11266 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11267 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11268 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11270 /* check if prosy is vailid or not */
11271 if (util_check_valid_url(proxy))
11272 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11273 /* parsing cookies */
11274 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11275 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11277 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11281 LOGE("not support uri type %d\n", player->profile.uri_type);
11286 LOGE("no source element was created.\n");
11290 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11291 LOGE("failed to add source element to pipeline\n");
11292 gst_object_unref(GST_OBJECT(element));
11297 /* take source element */
11298 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11299 mainbin[MMPLAYER_M_SRC].gst = element;
11303 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11304 if (player->streamer == NULL) {
11305 player->streamer = __mm_player_streaming_create();
11306 __mm_player_streaming_initialize(player->streamer);
11309 elemId = MMPLAYER_M_TYPEFIND;
11310 element = gst_element_factory_make("typefind", "typefinder");
11311 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11312 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11314 elemId = MMPLAYER_M_AUTOPLUG;
11315 element = __mmplayer_create_decodebin(player);
11318 /* check autoplug element is OK */
11320 LOGE("can not create element(%d)\n", elemId);
11324 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11325 LOGE("failed to add sinkbin to pipeline\n");
11326 gst_object_unref(GST_OBJECT(element));
11331 mainbin[elemId].id = elemId;
11332 mainbin[elemId].gst = element;
11334 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11335 LOGE("Failed to link src - autoplug(or typefind)\n");
11339 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11340 LOGE("Failed to change state of src element\n");
11344 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11345 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11346 LOGE("Failed to change state of decodebin\n");
11350 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11351 LOGE("Failed to change state of src element\n");
11356 player->gapless.stream_changed = TRUE;
11357 player->gapless.running = TRUE;
11363 MMPLAYER_PLAYBACK_UNLOCK(player);
11365 if (!player->msg_posted) {
11366 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11367 player->msg_posted = TRUE;
11374 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11376 mm_player_selector_t *selector = &player->selector[type];
11377 MMPlayerGstElement *sinkbin = NULL;
11378 enum MainElementID selectorId = MMPLAYER_M_NUM;
11379 enum MainElementID sinkId = MMPLAYER_M_NUM;
11380 GstPad *srcpad = NULL;
11381 GstPad *sinkpad = NULL;
11382 gboolean send_notice = FALSE;
11385 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11387 LOGD("type %d", type);
11390 case MM_PLAYER_TRACK_TYPE_AUDIO:
11391 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11392 sinkId = MMPLAYER_A_BIN;
11393 sinkbin = player->pipeline->audiobin;
11395 case MM_PLAYER_TRACK_TYPE_VIDEO:
11396 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11397 sinkId = MMPLAYER_V_BIN;
11398 sinkbin = player->pipeline->videobin;
11399 send_notice = TRUE;
11401 case MM_PLAYER_TRACK_TYPE_TEXT:
11402 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11403 sinkId = MMPLAYER_T_BIN;
11404 sinkbin = player->pipeline->textbin;
11407 LOGE("requested type is not supportable");
11412 if (player->pipeline->mainbin[selectorId].gst) {
11415 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11417 if (selector->event_probe_id != 0)
11418 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11419 selector->event_probe_id = 0;
11421 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11422 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11424 if (srcpad && sinkpad) {
11425 /* after getting drained signal there is no data flows, so no need to do pad_block */
11426 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11427 gst_pad_unlink(srcpad, sinkpad);
11429 /* send custom event to sink pad to handle it at video sink */
11431 LOGD("send custom event to sinkpad");
11432 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11433 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11434 gst_pad_send_event(sinkpad, event);
11438 gst_object_unref(sinkpad);
11441 gst_object_unref(srcpad);
11444 LOGD("selector release");
11446 /* release and unref requests pad from the selector */
11447 for (n = 0; n < selector->channels->len; n++) {
11448 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11449 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11451 g_ptr_array_set_size(selector->channels, 0);
11453 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11454 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11456 player->pipeline->mainbin[selectorId].gst = NULL;
11464 __mmplayer_deactivate_old_path(mm_player_t *player)
11467 MMPLAYER_RETURN_IF_FAIL(player);
11469 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11470 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11471 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11472 LOGE("deactivate selector error");
11476 _mmplayer_track_destroy(player);
11477 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11479 if (player->streamer) {
11480 __mm_player_streaming_deinitialize(player->streamer);
11481 __mm_player_streaming_destroy(player->streamer);
11482 player->streamer = NULL;
11485 MMPLAYER_PLAYBACK_LOCK(player);
11486 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11493 if (!player->msg_posted) {
11494 MMMessageParamType msg = {0,};
11497 msg.code = MM_ERROR_PLAYER_INTERNAL;
11498 LOGE("next_uri_play> deactivate error");
11500 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11501 player->msg_posted = TRUE;
11506 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11508 int result = MM_ERROR_NONE;
11509 mm_player_t* player = (mm_player_t*) hplayer;
11512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11515 player->http_file_buffering_path = (gchar*)file_path;
11516 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11522 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11524 int result = MM_ERROR_NONE;
11525 mm_player_t* player = (mm_player_t*) hplayer;
11528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11530 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11531 if (mmf_attrs_commit(player->attrs)) {
11532 LOGE("failed to commit the original uri.\n");
11533 result = MM_ERROR_PLAYER_INTERNAL;
11535 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11536 LOGE("failed to add the original uri in the uri list.\n");
11543 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11545 mm_player_t* player = (mm_player_t*) hplayer;
11546 guint num_of_list = 0;
11550 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11551 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11553 if (player->pipeline && player->pipeline->textbin) {
11554 LOGE("subtitle path is enabled.\n");
11555 return MM_ERROR_PLAYER_INVALID_STATE;
11558 num_of_list = g_list_length(player->uri_info.uri_list);
11560 if (is_first_path == TRUE) {
11561 if (num_of_list == 0) {
11562 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11563 LOGD("add original path : %s", uri);
11565 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11566 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11568 LOGD("change original path : %s", uri);
11571 MMHandleType attrs = 0;
11572 attrs = MMPLAYER_GET_ATTRS(player);
11574 if (num_of_list == 0) {
11575 char *original_uri = NULL;
11578 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11580 if (!original_uri) {
11581 LOGE("there is no original uri.");
11582 return MM_ERROR_PLAYER_INVALID_STATE;
11585 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11586 player->uri_info.uri_idx = 0;
11588 LOGD("add original path at first : %s(%d)", original_uri);
11592 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11593 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11597 return MM_ERROR_NONE;
11600 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11602 mm_player_t* player = (mm_player_t*) hplayer;
11603 char *next_uri = NULL;
11604 guint num_of_list = 0;
11607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11609 num_of_list = g_list_length(player->uri_info.uri_list);
11611 if (num_of_list > 0) {
11612 gint uri_idx = player->uri_info.uri_idx;
11614 if (uri_idx < num_of_list-1)
11619 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11620 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11622 *uri = g_strdup(next_uri);
11626 return MM_ERROR_NONE;
11630 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11631 GstCaps *caps, gpointer data)
11633 mm_player_t* player = (mm_player_t*)data;
11634 const gchar* klass = NULL;
11635 const gchar* mime = NULL;
11636 gchar* caps_str = NULL;
11638 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11639 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11640 caps_str = gst_caps_to_string(caps);
11642 LOGW("unknown type of caps : %s from %s",
11643 caps_str, GST_ELEMENT_NAME(elem));
11645 MMPLAYER_FREEIF(caps_str);
11647 /* There is no available codec. */
11648 __mmplayer_check_not_supported_codec(player, klass, mime);
11652 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11653 GstCaps * caps, gpointer data)
11655 mm_player_t* player = (mm_player_t*)data;
11656 const char* mime = NULL;
11657 gboolean ret = TRUE;
11659 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11660 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11662 if (g_str_has_prefix(mime, "audio")) {
11663 GstStructure* caps_structure = NULL;
11664 gint samplerate = 0;
11666 gchar *caps_str = NULL;
11668 caps_structure = gst_caps_get_structure(caps, 0);
11669 gst_structure_get_int(caps_structure, "rate", &samplerate);
11670 gst_structure_get_int(caps_structure, "channels", &channels);
11672 if ((channels > 0 && samplerate == 0)) {
11673 LOGD("exclude audio...");
11677 caps_str = gst_caps_to_string(caps);
11678 /* set it directly because not sent by TAG */
11679 if (g_strrstr(caps_str, "mobile-xmf"))
11680 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11681 MMPLAYER_FREEIF(caps_str);
11682 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11683 MMMessageParamType msg_param;
11684 memset(&msg_param, 0, sizeof(MMMessageParamType));
11685 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11686 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11687 LOGD("video file is not supported on this device");
11689 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11690 LOGD("already video linked");
11693 LOGD("found new stream");
11700 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11701 GstCaps* caps, GstElementFactory* factory, gpointer data)
11703 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11704 We are defining our own and will be removed when it actually exposed */
11706 GST_AUTOPLUG_SELECT_TRY,
11707 GST_AUTOPLUG_SELECT_EXPOSE,
11708 GST_AUTOPLUG_SELECT_SKIP
11709 } GstAutoplugSelectResult;
11711 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11712 mm_player_t* player = (mm_player_t*)data;
11714 gchar* factory_name = NULL;
11715 gchar* caps_str = NULL;
11716 const gchar* klass = NULL;
11718 int surface_type = 0;
11720 factory_name = GST_OBJECT_NAME(factory);
11721 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11722 caps_str = gst_caps_to_string(caps);
11724 LOGD("found new element [%s] to link", factory_name);
11726 /* store type string */
11727 if (player->type == NULL) {
11728 player->type = gst_caps_to_string(caps);
11729 __mmplayer_update_content_type_info(player);
11732 mm_attrs_get_int_by_name(player->attrs,
11733 "display_surface_type", &surface_type);
11734 LOGD("check display surface type attribute: %d", surface_type);
11736 /* filtering exclude keyword */
11737 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11738 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11739 LOGW("skipping [%s] by exculde keyword [%s]\n",
11740 factory_name, player->ini.exclude_element_keyword[idx]);
11742 // NOTE : does we need to check n_value against the number of item selected?
11743 result = GST_AUTOPLUG_SELECT_SKIP;
11748 /* exclude webm format */
11749 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11750 * because webm format is not supportable.
11751 * If webm is disabled in "autoplug-continue", there is no state change
11752 * failure or error because the decodebin will expose the pad directly.
11753 * It make MSL invoke _prepare_async_callback.
11754 * So, we need to disable webm format in "autoplug-select" */
11755 if (strstr(caps_str, "webm")) {
11756 LOGW("webm is not supported");
11757 result = GST_AUTOPLUG_SELECT_SKIP;
11761 /* check factory class for filtering */
11762 /* NOTE : msl don't need to use image plugins.
11763 * So, those plugins should be skipped for error handling.
11765 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11766 LOGD("skipping [%s] by not required\n", factory_name);
11767 result = GST_AUTOPLUG_SELECT_SKIP;
11771 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11772 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11773 // TO CHECK : subtitle if needed, add subparse exception.
11774 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11775 result = GST_AUTOPLUG_SELECT_SKIP;
11779 if (g_strrstr(factory_name, "mpegpsdemux")) {
11780 LOGD("skipping PS container - not support\n");
11781 result = GST_AUTOPLUG_SELECT_SKIP;
11785 if (g_strrstr(factory_name, "mssdemux"))
11786 player->smooth_streaming = TRUE;
11788 /* check ALP Codec can be used or not */
11789 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11790 GstStructure* str = NULL;
11793 str = gst_caps_get_structure(caps, 0);
11795 gst_structure_get_int(str, "channels", &channels);
11797 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11798 if (player->max_audio_channels < channels)
11799 player->max_audio_channels = channels;
11801 /* set stream information */
11802 if (!player->audiodec_linked)
11803 __mmplayer_set_audio_attrs(player, caps);
11804 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11805 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11806 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11807 /* prepare resource manager for video decoder */
11808 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11810 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11811 /* prepare resource manager for video decoder */
11812 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11813 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11814 != MM_ERROR_NONE) {
11815 LOGW("could not prepare for video_decoder resource, skip it.");
11816 result = GST_AUTOPLUG_SELECT_SKIP;
11824 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11825 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11828 GstStructure *str = NULL;
11829 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11831 /* don't make video because of not required */
11832 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11833 (player->set_mode.media_packet_video_stream == FALSE)) {
11834 LOGD("no video because it's not required. -> return expose");
11835 result = GST_AUTOPLUG_SELECT_EXPOSE;
11839 /* get w/h for omx state-tune */
11840 str = gst_caps_get_structure(caps, 0);
11841 gst_structure_get_int(str, "width", &width);
11844 if (player->v_stream_caps) {
11845 gst_caps_unref(player->v_stream_caps);
11846 player->v_stream_caps = NULL;
11849 player->v_stream_caps = gst_caps_copy(caps);
11850 LOGD("take caps for video state tune");
11851 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11855 if (g_strrstr(klass, "Decoder")) {
11856 const char* mime = NULL;
11857 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11859 if (g_str_has_prefix(mime, "video")) {
11860 // __mmplayer_check_video_zero_cpoy(player, factory);
11862 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11863 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11865 player->videodec_linked = 1;
11866 } else if (g_str_has_prefix(mime, "audio")) {
11867 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11868 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11870 player->audiodec_linked = 1;
11875 MMPLAYER_FREEIF(caps_str);
11882 static GValueArray*
11883 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
11884 GstCaps * caps, gpointer data)
11886 //mm_player_t* player = (mm_player_t*)data;
11888 LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11889 gst_caps_to_string(caps),
11890 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11897 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11898 gpointer data) // @
11900 //mm_player_t* player = (mm_player_t*)data;
11901 GstCaps* caps = NULL;
11903 LOGD("[Decodebin2] pad-removed signal\n");
11905 caps = gst_pad_query_caps(new_pad, NULL);
11907 gchar* caps_str = NULL;
11908 caps_str = gst_caps_to_string(caps);
11910 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11912 MMPLAYER_FREEIF(caps_str);
11917 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11919 mm_player_t* player = (mm_player_t*)data;
11920 GstIterator *iter = NULL;
11921 GValue item = { 0, };
11922 GstPad *pad = NULL;
11923 gboolean done = FALSE;
11924 gboolean is_all_drained = TRUE;
11927 MMPLAYER_RETURN_IF_FAIL(player);
11929 LOGD("__mmplayer_gst_decode_drained");
11931 if (player->use_deinterleave == TRUE) {
11932 LOGD("group playing mode.");
11936 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11937 LOGW("Fail to get cmd lock");
11941 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11942 !__mmplayer_verify_next_play_path(player)) {
11943 LOGD("decoding is finished.");
11944 __mmplayer_reset_gapless_state(player);
11945 MMPLAYER_CMD_UNLOCK(player);
11949 player->gapless.reconfigure = TRUE;
11951 /* check decodebin src pads whether they received EOS or not */
11952 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11955 switch (gst_iterator_next(iter, &item)) {
11956 case GST_ITERATOR_OK:
11957 pad = g_value_get_object(&item);
11958 if (!GST_PAD_IS_EOS(pad)) {
11959 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11960 is_all_drained = FALSE;
11963 g_value_reset(&item);
11965 case GST_ITERATOR_RESYNC:
11966 gst_iterator_resync(iter);
11968 case GST_ITERATOR_ERROR:
11969 case GST_ITERATOR_DONE:
11974 g_value_unset(&item);
11975 gst_iterator_free(iter);
11977 if (!is_all_drained) {
11978 LOGD("Wait util the all pads get EOS.");
11979 MMPLAYER_CMD_UNLOCK(player);
11984 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11985 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11987 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11988 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11989 __mmplayer_deactivate_old_path(player);
11990 MMPLAYER_CMD_UNLOCK(player);
11996 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11998 mm_player_t* player = (mm_player_t*)data;
11999 const gchar* klass = NULL;
12000 gchar* factory_name = NULL;
12002 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12003 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12005 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12007 if (__mmplayer_add_dump_buffer_probe(player, element))
12008 LOGD("add buffer probe");
12011 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12012 gchar* selected = NULL;
12013 selected = g_strdup(GST_ELEMENT_NAME(element));
12014 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12018 if (g_strrstr(klass, "Parser")) {
12019 gchar* selected = NULL;
12021 selected = g_strdup(factory_name);
12022 player->parsers = g_list_append(player->parsers, selected);
12025 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
12026 /* FIXIT : first value will be overwritten if there's more
12027 * than 1 demuxer/parser
12030 //LOGD("plugged element is demuxer. take it\n");
12031 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12032 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12034 /*Added for multi audio support */ // Q. del?
12035 if (g_strrstr(klass, "Demux")) {
12036 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12037 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12041 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12042 int surface_type = 0;
12044 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12047 // to support trust-zone only
12048 if (g_strrstr(factory_name, "asfdemux")) {
12049 LOGD("set file-location %s\n", player->profile.uri);
12050 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12052 if (player->video_hub_download_mode == TRUE)
12053 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12054 } else if (g_strrstr(factory_name, "legacyh264parse")) {
12055 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12056 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12057 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12058 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12059 (__mmplayer_is_only_mp3_type(player->type))) {
12060 LOGD("[mpegaudioparse] set streaming pull mode.");
12061 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12063 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12064 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12067 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12068 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12069 LOGD("plugged element is multiqueue. take it\n");
12071 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12072 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12074 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12075 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12076 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12077 __mm_player_streaming_set_multiqueue(player->streamer,
12080 player->ini.http_buffering_time,
12082 player->ini.http_buffering_limit);
12084 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12091 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12094 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12096 if (MMPLAYER_IS_STREAMING(player))
12099 /* This callback can be set to music player only. */
12100 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12101 LOGW("audio callback is not supported for video");
12105 if (player->audio_stream_cb) {
12106 GstPad *pad = NULL;
12108 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12111 LOGE("failed to get sink pad from audiosink to probe data\n");
12114 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12115 __mmplayer_audio_stream_probe, player, NULL);
12117 gst_object_unref(pad);
12121 LOGE("There is no audio callback to configure.\n");
12131 __mmplayer_init_factories(mm_player_t* player) // @
12133 MMPLAYER_RETURN_IF_FAIL(player);
12135 player->factories = gst_registry_feature_filter(gst_registry_get(),
12136 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12137 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12141 __mmplayer_release_factories(mm_player_t* player) // @
12144 MMPLAYER_RETURN_IF_FAIL(player);
12146 if (player->factories) {
12147 gst_plugin_feature_list_free(player->factories);
12148 player->factories = NULL;
12155 __mmplayer_release_misc(mm_player_t* player)
12158 gboolean cur_mode = player->set_mode.rich_audio;
12161 MMPLAYER_RETURN_IF_FAIL(player);
12163 player->video_stream_cb = NULL;
12164 player->video_stream_cb_user_param = NULL;
12165 player->video_stream_prerolled = FALSE;
12167 player->audio_stream_cb = NULL;
12168 player->audio_stream_render_cb_ex = NULL;
12169 player->audio_stream_cb_user_param = NULL;
12170 player->audio_stream_sink_sync = false;
12172 player->video_stream_changed_cb = NULL;
12173 player->video_stream_changed_cb_user_param = NULL;
12175 player->audio_stream_changed_cb = NULL;
12176 player->audio_stream_changed_cb_user_param = NULL;
12178 player->sent_bos = FALSE;
12179 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12181 player->doing_seek = FALSE;
12183 player->updated_bitrate_count = 0;
12184 player->total_bitrate = 0;
12185 player->updated_maximum_bitrate_count = 0;
12186 player->total_maximum_bitrate = 0;
12188 player->not_found_demuxer = 0;
12190 player->last_position = 0;
12191 player->duration = 0;
12192 player->http_content_size = 0;
12193 player->not_supported_codec = MISSING_PLUGIN_NONE;
12194 player->can_support_codec = FOUND_PLUGIN_NONE;
12195 player->pending_seek.is_pending = FALSE;
12196 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12197 player->pending_seek.pos = 0;
12198 player->msg_posted = FALSE;
12199 player->has_many_types = FALSE;
12200 player->max_audio_channels = 0;
12201 player->video_share_api_delta = 0;
12202 player->video_share_clock_delta = 0;
12203 player->sound_focus.keep_last_pos = FALSE;
12204 player->sound_focus.acquired = FALSE;
12205 player->is_subtitle_force_drop = FALSE;
12206 player->play_subtitle = FALSE;
12207 player->use_textoverlay = FALSE;
12208 player->adjust_subtitle_pos = 0;
12209 player->last_multiwin_status = FALSE;
12210 player->has_closed_caption = FALSE;
12211 player->set_mode.media_packet_video_stream = FALSE;
12212 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12213 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12215 player->set_mode.rich_audio = cur_mode;
12217 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12218 player->bitrate[i] = 0;
12219 player->maximum_bitrate[i] = 0;
12222 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12224 /* remove media stream cb(appsrc cb) */
12225 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12226 player->media_stream_buffer_status_cb[i] = NULL;
12227 player->media_stream_seek_data_cb[i] = NULL;
12229 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12231 /* free memory related to audio effect */
12232 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12234 if (player->state_tune_caps) {
12235 gst_caps_unref(player->state_tune_caps);
12236 player->state_tune_caps = NULL;
12243 __mmplayer_release_misc_post(mm_player_t* player)
12245 char *original_uri = NULL;
12248 /* player->pipeline is already released before. */
12250 MMPLAYER_RETURN_IF_FAIL(player);
12252 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12253 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12255 /* clean found parsers */
12256 if (player->parsers) {
12257 GList *parsers = player->parsers;
12258 for (; parsers; parsers = g_list_next(parsers)) {
12259 gchar *name = parsers->data;
12260 MMPLAYER_FREEIF(name);
12262 g_list_free(player->parsers);
12263 player->parsers = NULL;
12266 /* clean found audio decoders */
12267 if (player->audio_decoders) {
12268 GList *a_dec = player->audio_decoders;
12269 for (; a_dec; a_dec = g_list_next(a_dec)) {
12270 gchar *name = a_dec->data;
12271 MMPLAYER_FREEIF(name);
12273 g_list_free(player->audio_decoders);
12274 player->audio_decoders = NULL;
12277 /* clean the uri list except original uri */
12278 if (player->uri_info.uri_list) {
12279 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12281 if (player->attrs) {
12282 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12283 LOGD("restore original uri = %s\n", original_uri);
12285 if (mmf_attrs_commit(player->attrs))
12286 LOGE("failed to commit the original uri.\n");
12289 GList *uri_list = player->uri_info.uri_list;
12290 for (; uri_list; uri_list = g_list_next(uri_list)) {
12291 gchar *uri = uri_list->data;
12292 MMPLAYER_FREEIF(uri);
12294 g_list_free(player->uri_info.uri_list);
12295 player->uri_info.uri_list = NULL;
12298 /* clear the audio stream buffer list */
12299 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12301 /* clear the video stream bo list */
12302 __mmplayer_video_stream_destroy_bo_list(player);
12304 player->uri_info.uri_idx = 0;
12308 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12310 GstElement *element = NULL;
12313 LOGD("creating %s to plug\n", name);
12315 element = gst_element_factory_make(name, NULL);
12317 LOGE("failed to create queue\n");
12321 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12322 LOGE("failed to set state READY to %s\n", name);
12323 gst_object_unref(element);
12327 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12328 LOGE("failed to add %s\n", name);
12329 gst_object_unref(element);
12333 sinkpad = gst_element_get_static_pad(element, "sink");
12335 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12336 LOGE("failed to link %s\n", name);
12337 gst_object_unref(sinkpad);
12338 gst_object_unref(element);
12342 LOGD("linked %s to pipeline successfully\n", name);
12344 gst_object_unref(sinkpad);
12350 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12351 const char *padname, const GList *templlist)
12353 GstPad *pad = NULL;
12354 gboolean has_dynamic_pads = FALSE;
12355 gboolean has_many_types = FALSE;
12356 const char *klass = NULL;
12357 GstStaticPadTemplate *padtemplate = NULL;
12358 GstElementFactory *factory = NULL;
12359 GstElement* queue = NULL;
12360 GstElement* parser = NULL;
12361 GstPad *pssrcpad = NULL;
12362 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12363 MMPlayerGstElement *mainbin = NULL;
12364 GstStructure* str = NULL;
12365 GstCaps* srccaps = NULL;
12366 GstState target_state = GST_STATE_READY;
12367 gboolean isvideo_decoder = FALSE;
12368 guint q_max_size_time = 0;
12372 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12373 player->pipeline &&
12374 player->pipeline->mainbin,
12377 mainbin = player->pipeline->mainbin;
12379 LOGD("plugging pad %s:%s to newly create %s:%s\n",
12380 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12381 GST_PAD_NAME(srcpad),
12382 GST_ELEMENT_NAME(sinkelement),
12385 factory = gst_element_get_factory(sinkelement);
12386 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12388 /* check if player can do start continually */
12389 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12391 /* need it to warm up omx before linking to pipeline */
12392 if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12393 LOGD("get demux caps.\n");
12394 if (player->state_tune_caps) {
12395 gst_caps_unref(player->state_tune_caps);
12396 player->state_tune_caps = NULL;
12398 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12401 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12402 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12403 if (player->state_tune_caps != NULL) {
12404 LOGD("set demux's caps to omx codec if resource is available");
12405 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12406 target_state = GST_STATE_PAUSED;
12407 isvideo_decoder = TRUE;
12408 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12410 LOGW("failed to set caps for state tuning");
12412 gst_caps_unref(player->state_tune_caps);
12413 player->state_tune_caps = NULL;
12416 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12417 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12418 if (isvideo_decoder) {
12419 gst_element_set_state(sinkelement, GST_STATE_NULL);
12420 gst_object_unref(G_OBJECT(sinkelement));
12421 player->keep_detecting_vcodec = TRUE;
12426 /* add to pipeline */
12427 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12428 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12432 LOGD("element klass : %s\n", klass);
12434 /* added to support multi track files */
12435 /* only decoder case and any of the video/audio still need to link*/
12436 if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12437 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12439 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12440 gchar *src_demux_caps_str = NULL;
12441 gchar *needed_parser = NULL;
12442 GstCaps *src_demux_caps = NULL;
12443 gboolean smooth_streaming = FALSE;
12445 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12446 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12448 gst_caps_unref(src_demux_caps);
12450 if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12451 if (g_strrstr(name, "mssdemux")) {
12452 needed_parser = g_strdup("legacyh264parse");
12453 smooth_streaming = TRUE;
12455 needed_parser = g_strdup("h264parse");
12456 } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12457 needed_parser = g_strdup("mpeg4videoparse");
12459 MMPLAYER_FREEIF(src_demux_caps_str);
12461 if (needed_parser) {
12462 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12463 MMPLAYER_FREEIF(needed_parser);
12466 LOGE("failed to create parser\n");
12468 if (smooth_streaming)
12469 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12471 /* update srcpad if parser is created */
12472 pssrcpad = gst_element_get_static_pad(parser, "src");
12477 MMPLAYER_FREEIF(name);
12479 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12481 LOGE("failed to create queue\n");
12485 /* update srcpad to link with decoder */
12486 qsrcpad = gst_element_get_static_pad(queue, "src");
12489 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12491 /* assigning queue handle for futher manipulation purpose */
12492 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12493 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12494 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12495 mainbin[MMPLAYER_M_Q1].gst = queue;
12497 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12498 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12499 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12500 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12502 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12503 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12505 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12506 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12507 mainbin[MMPLAYER_M_Q2].gst = queue;
12509 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12510 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12511 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12512 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12514 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12515 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12518 LOGE("Not supporting more then two elementary stream\n");
12522 pad = gst_element_get_static_pad(sinkelement, padname);
12525 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12526 padname, GST_ELEMENT_NAME(sinkelement));
12528 pad = gst_element_get_static_pad(sinkelement, "sink");
12530 LOGE("failed to get pad(sink) from %s. \n",
12531 GST_ELEMENT_NAME(sinkelement));
12536 /* to check the video/audio type set the proper flag*/
12537 const gchar *mime_type = NULL;
12538 srccaps = gst_pad_query_caps(srcpad, NULL);
12541 str = gst_caps_get_structure(srccaps, 0);
12544 mime_type = gst_structure_get_name(str);
12548 /* link queue and decoder. so, it will be queue - decoder. */
12549 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12550 gst_object_unref(GST_OBJECT(pad));
12551 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12553 /* reconstitute supportable codec */
12554 if (strstr(mime_type, "video"))
12555 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12556 else if (strstr(mime_type, "audio"))
12557 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12561 if (strstr(mime_type, "video")) {
12562 player->videodec_linked = 1;
12563 LOGI("player->videodec_linked set to 1\n");
12565 } else if (strstr(mime_type, "audio")) {
12566 player->audiodec_linked = 1;
12567 LOGI("player->auddiodec_linked set to 1\n");
12570 gst_object_unref(GST_OBJECT(pad));
12571 gst_caps_unref(GST_CAPS(srccaps));
12575 if (!MMPLAYER_IS_HTTP_PD(player)) {
12576 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12577 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12578 gint64 dur_bytes = 0L;
12579 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12581 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12582 LOGD("creating http streaming buffering queue\n");
12584 queue = gst_element_factory_make("queue2", "queue2");
12586 LOGE("failed to create buffering queue element\n");
12590 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12591 LOGE("failed to set state READY to buffering queue\n");
12595 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12596 LOGE("failed to add buffering queue\n");
12600 qsinkpad = gst_element_get_static_pad(queue, "sink");
12601 qsrcpad = gst_element_get_static_pad(queue, "src");
12603 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12604 LOGE("failed to link buffering queue\n");
12610 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12611 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12613 if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12614 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12615 LOGE("fail to get duration.\n");
12617 if (dur_bytes > 0) {
12618 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12619 type = MUXED_BUFFER_TYPE_FILE;
12621 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12622 if (player->streamer)
12623 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12630 /* NOTE : we cannot get any duration info from ts container in case of streaming */
12631 if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12632 __mm_player_streaming_set_queue2(player->streamer,
12635 player->ini.http_max_size_bytes,
12636 player->ini.http_buffering_time,
12638 player->ini.http_buffering_limit,
12640 player->http_file_buffering_path,
12641 (guint64)dur_bytes);
12647 /* if it is not decoder or */
12648 /* in decoder case any of the video/audio still need to link*/
12649 if (!g_strrstr(klass, "Decoder")) {
12650 pad = gst_element_get_static_pad(sinkelement, padname);
12652 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12653 padname, GST_ELEMENT_NAME(sinkelement));
12655 pad = gst_element_get_static_pad(sinkelement, "sink");
12658 LOGE("failed to get pad(sink) from %s. \n",
12659 GST_ELEMENT_NAME(sinkelement));
12664 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12665 gst_object_unref(GST_OBJECT(pad));
12666 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12670 gst_object_unref(GST_OBJECT(pad));
12673 for (; templlist != NULL; templlist = templlist->next) {
12674 padtemplate = templlist->data;
12676 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12678 if (padtemplate->direction != GST_PAD_SRC ||
12679 padtemplate->presence == GST_PAD_REQUEST)
12682 switch (padtemplate->presence) {
12683 case GST_PAD_ALWAYS:
12685 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12686 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12688 /* Check whether caps has many types */
12689 if (!gst_caps_is_fixed(caps)) {
12690 LOGD("always pad but, caps has many types");
12691 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12692 has_many_types = TRUE;
12696 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12697 gst_object_unref(GST_OBJECT(srcpad));
12698 gst_caps_unref(GST_CAPS(caps));
12700 LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12704 gst_caps_unref(GST_CAPS(caps));
12705 gst_object_unref(GST_OBJECT(srcpad));
12711 case GST_PAD_SOMETIMES:
12712 has_dynamic_pads = TRUE;
12720 /* check if player can do start continually */
12721 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12723 if (has_dynamic_pads) {
12724 player->have_dynamic_pad = TRUE;
12725 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12726 G_CALLBACK(__mmplayer_add_new_pad), player);
12728 /* for streaming, more then one typefind will used for each elementary stream
12729 * so this doesn't mean the whole pipeline completion
12731 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12732 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12733 G_CALLBACK(__mmplayer_pipeline_complete), player);
12737 if (has_many_types) {
12738 GstPad *pad = NULL;
12740 player->has_many_types = has_many_types;
12742 pad = gst_element_get_static_pad(sinkelement, "src");
12743 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12744 gst_object_unref(GST_OBJECT(pad));
12748 /* check if player can do start continually */
12749 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12751 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12752 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12757 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12758 LOGE("failed to set state PAUSED to queue\n");
12764 gst_object_unref(GST_OBJECT(qsrcpad));
12769 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12770 LOGE("failed to set state PAUSED to queue\n");
12776 gst_object_unref(GST_OBJECT(pssrcpad));
12787 gst_object_unref(GST_OBJECT(qsrcpad));
12789 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12790 * You need to explicitly set elements to the NULL state before
12791 * dropping the final reference, to allow them to clean up.
12793 gst_element_set_state(queue, GST_STATE_NULL);
12794 /* And, it still has a parent "player".
12795 * You need to let the parent manage the object instead of unreffing the object directly.
12798 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12799 //gst_object_unref(queue);
12803 gst_caps_unref(GST_CAPS(srccaps));
12808 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12810 const gchar *klass;
12812 /* we only care about element factories */
12813 if (!GST_IS_ELEMENT_FACTORY(feature))
12816 /* only parsers, demuxers and decoders */
12817 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12819 if (g_strrstr(klass, "Demux") == NULL &&
12820 g_strrstr(klass, "Codec/Decoder") == NULL &&
12821 g_strrstr(klass, "Depayloader") == NULL &&
12822 g_strrstr(klass, "Parse") == NULL)
12828 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12830 mm_player_t* player = (mm_player_t*) data;
12831 GstCaps *caps = NULL;
12832 GstStructure *str = NULL;
12837 MMPLAYER_RETURN_IF_FAIL(pad)
12838 MMPLAYER_RETURN_IF_FAIL(unused)
12839 MMPLAYER_RETURN_IF_FAIL(data)
12841 caps = gst_pad_query_caps(pad, NULL);
12845 str = gst_caps_get_structure(caps, 0);
12849 name = gst_structure_get_name(str);
12852 LOGD("name=%s\n", name);
12854 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12855 LOGE("failed to autoplug for type(%s)\n", name);
12856 gst_caps_unref(caps);
12860 gst_caps_unref(caps);
12862 __mmplayer_pipeline_complete(NULL, (gpointer)player);
12869 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12873 const char *stream_type;
12874 gchar *version_field = NULL;
12878 MMPLAYER_RETURN_IF_FAIL(player);
12879 MMPLAYER_RETURN_IF_FAIL(caps);
12881 str = gst_caps_get_structure(caps, 0);
12885 stream_type = gst_structure_get_name(str);
12890 /* set unlinked mime type for downloadable codec */
12891 if (g_str_has_prefix(stream_type, "video/")) {
12892 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12893 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12894 version_field = MM_PLAYER_MPEG_VNAME;
12895 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12896 gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12897 version_field = MM_PLAYER_WMV_VNAME;
12899 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12900 gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12901 version_field = MM_PLAYER_DIVX_VNAME;
12905 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12907 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12908 } else if (g_str_has_prefix(stream_type, "audio/")) {
12909 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12911 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12912 version_field = MM_PLAYER_MPEG_VNAME;
12913 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12914 gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12915 version_field = MM_PLAYER_WMA_VNAME;
12919 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12921 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12927 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12929 mm_player_t* player = (mm_player_t*) data;
12930 GstCaps *caps = NULL;
12931 GstStructure *str = NULL;
12935 MMPLAYER_RETURN_IF_FAIL(player);
12936 MMPLAYER_RETURN_IF_FAIL(pad);
12938 GST_OBJECT_LOCK(pad);
12939 if ((caps = gst_pad_get_current_caps(pad)))
12940 gst_caps_ref(caps);
12941 GST_OBJECT_UNLOCK(pad);
12943 if (NULL == caps) {
12944 caps = gst_pad_query_caps(pad, NULL);
12948 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12950 str = gst_caps_get_structure(caps, 0);
12954 name = gst_structure_get_name(str);
12958 player->num_dynamic_pad++;
12959 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12961 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12962 * If want to play it, remove this code.
12964 if (g_strrstr(name, "application")) {
12965 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12966 /* If id3/ape tag comes, keep going */
12967 LOGD("application mime exception : id3/ape tag");
12969 /* Otherwise, we assume that this stream is subtile. */
12970 LOGD(" application mime type pad is closed.");
12973 } else if (g_strrstr(name, "audio")) {
12974 gint samplerate = 0, channels = 0;
12976 if (player->audiodec_linked) {
12977 gst_caps_unref(caps);
12978 LOGD("multi tracks. skip to plug");
12982 /* set stream information */
12983 /* if possible, set it here because the caps is not distrubed by resampler. */
12984 gst_structure_get_int(str, "rate", &samplerate);
12985 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12987 gst_structure_get_int(str, "channels", &channels);
12988 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12990 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
12991 } else if (g_strrstr(name, "video")) {
12993 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12995 /* don't make video because of not required */
12996 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
12997 LOGD("no video because it's not required");
13001 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13004 if (!__mmplayer_try_to_plug(player, pad, caps)) {
13005 LOGE("failed to autoplug for type(%s)", name);
13007 __mmplayer_set_unlinked_mime_type(player, caps);
13010 gst_caps_unref(caps);
13017 __mmplayer_check_subtitle(mm_player_t* player)
13019 MMHandleType attrs = 0;
13020 char *subtitle_uri = NULL;
13024 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13026 /* get subtitle attribute */
13027 attrs = MMPLAYER_GET_ATTRS(player);
13031 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13032 if (!subtitle_uri || !strlen(subtitle_uri))
13035 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13036 player->is_external_subtitle_present = TRUE;
13044 __mmplayer_can_extract_pcm(mm_player_t* player)
13046 MMHandleType attrs = 0;
13047 gboolean sound_extraction = FALSE;
13049 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13051 attrs = MMPLAYER_GET_ATTRS(player);
13053 LOGE("fail to get attributes.");
13057 /* get sound_extraction property */
13058 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13060 if (!sound_extraction) {
13061 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13069 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13072 MMMessageParamType msg_param;
13073 gchar *msg_src_element = NULL;
13074 GstStructure *s = NULL;
13075 guint error_id = 0;
13076 gchar *error_string = NULL;
13080 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13081 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13083 s = malloc(sizeof(GstStructure));
13084 memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13086 if (!gst_structure_get_uint(s, "error_id", &error_id))
13087 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13089 switch (error_id) {
13090 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13091 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13093 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13094 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13096 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13097 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13099 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13100 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13102 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13103 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13105 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13106 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13108 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13109 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13111 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13112 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13114 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13115 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13117 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13118 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13120 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13121 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13123 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13124 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13126 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13127 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13129 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13130 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13132 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13133 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13135 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13136 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13138 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13139 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13141 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13142 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13144 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13145 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13147 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13148 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13150 case MMPLAYER_STREAMING_ERROR_GONE:
13151 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13153 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13154 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13156 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13157 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13159 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13160 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13162 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13163 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13165 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13166 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13168 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13169 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13171 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13172 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13174 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13175 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13177 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13178 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13180 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13181 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13183 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13184 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13186 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13187 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13189 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13190 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13192 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13193 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13195 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13196 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13198 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13199 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13201 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13202 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13204 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13205 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13207 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13208 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13210 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13211 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13213 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13214 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13216 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13217 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13219 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13220 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13222 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13223 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13227 MMPLAYER_FREEIF(s);
13228 return MM_ERROR_PLAYER_STREAMING_FAIL;
13232 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13234 msg_param.data = (void *) error_string;
13236 if (message->src) {
13237 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13239 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13240 msg_src_element, msg_param.code, (char*)msg_param.data);
13243 /* post error to application */
13244 if (!player->msg_posted) {
13245 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13247 /* don't post more if one was sent already */
13248 player->msg_posted = TRUE;
13250 LOGD("skip error post because it's sent already.\n");
13252 MMPLAYER_FREEIF(s);
13254 g_free(error_string);
13261 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13263 MMPLAYER_RETURN_IF_FAIL(player);
13266 /* post now if delay is zero */
13267 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13268 LOGD("eos delay is zero. posting EOS now\n");
13269 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13271 if (player->set_mode.pcm_extraction)
13272 __mmplayer_cancel_eos_timer(player);
13277 /* cancel if existing */
13278 __mmplayer_cancel_eos_timer(player);
13280 /* init new timeout */
13281 /* NOTE : consider give high priority to this timer */
13282 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13284 player->eos_timer = g_timeout_add(delay_in_ms,
13285 __mmplayer_eos_timer_cb, player);
13287 player->context.global_default = g_main_context_default();
13288 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13290 /* check timer is valid. if not, send EOS now */
13291 if (player->eos_timer == 0) {
13292 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13293 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13298 __mmplayer_cancel_eos_timer(mm_player_t* player)
13300 MMPLAYER_RETURN_IF_FAIL(player);
13302 if (player->eos_timer) {
13303 LOGD("cancel eos timer");
13304 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13305 player->eos_timer = 0;
13312 __mmplayer_eos_timer_cb(gpointer u_data)
13314 mm_player_t* player = NULL;
13315 player = (mm_player_t*) u_data;
13317 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13319 if (player->play_count > 1) {
13320 gint ret_value = 0;
13321 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13322 if (ret_value == MM_ERROR_NONE) {
13323 MMHandleType attrs = 0;
13324 attrs = MMPLAYER_GET_ATTRS(player);
13326 /* we successeded to rewind. update play count and then wait for next EOS */
13327 player->play_count--;
13329 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13330 mmf_attrs_commit(attrs);
13332 LOGE("seeking to 0 failed in repeat play");
13335 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13337 /* we are returning FALSE as we need only one posting */
13342 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13344 const gchar* name = NULL;
13345 GstStructure* str = NULL;
13346 GstCaps* srccaps = NULL;
13350 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13351 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13353 /* to check any of the decoder(video/audio) need to be linked to parser*/
13354 srccaps = gst_pad_query_caps(srcpad, NULL);
13358 str = gst_caps_get_structure(srccaps, 0);
13362 name = gst_structure_get_name(str);
13366 if (strstr(name, "video")) {
13367 if (player->videodec_linked) {
13368 LOGI("Video decoder already linked\n");
13372 if (strstr(name, "audio")) {
13373 if (player->audiodec_linked) {
13374 LOGI("Audio decoder already linked\n");
13379 gst_caps_unref(srccaps);
13387 gst_caps_unref(srccaps);
13393 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13395 const gchar* name = NULL;
13396 GstStructure* str = NULL;
13397 GstCaps* srccaps = NULL;
13401 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13402 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13404 /* to check any of the decoder(video/audio) need to be linked to parser*/
13405 srccaps = gst_pad_query_caps(srcpad, NULL);
13409 str = gst_caps_get_structure(srccaps, 0);
13413 name = gst_structure_get_name(str);
13417 if (strstr(name, "video")) {
13418 if (player->videosink_linked) {
13419 LOGI("Video Sink already linked\n");
13423 if (strstr(name, "audio")) {
13424 if (player->audiosink_linked) {
13425 LOGI("Audio Sink already linked\n");
13429 if (strstr(name, "text")) {
13430 if (player->textsink_linked) {
13431 LOGI("Text Sink already linked\n");
13436 gst_caps_unref(srccaps);
13440 //return (!player->videosink_linked || !player->audiosink_linked);
13445 gst_caps_unref(srccaps);
13451 /* sending event to one of sinkelements */
13453 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13455 GstEvent * event2 = NULL;
13456 GList *sinks = NULL;
13457 gboolean res = FALSE;
13460 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13461 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13463 /* While adding subtitles in live feeds seek is getting called.
13464 Adding defensive check in framework layer.*/
13465 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13466 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13467 LOGE ("Should not send seek event during live playback");
13472 if (player->play_subtitle && !player->use_textoverlay)
13473 event2 = gst_event_copy((const GstEvent *)event);
13475 sinks = player->sink_elements;
13477 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13479 if (GST_IS_ELEMENT(sink)) {
13480 /* keep ref to the event */
13481 gst_event_ref(event);
13483 if ((res = gst_element_send_event(sink, event))) {
13484 LOGD("sending event[%s] to sink element [%s] success!\n",
13485 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13487 /* rtsp case, asyn_done is not called after seek during pause state */
13488 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13489 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13490 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13491 LOGD("RTSP seek completed, after pause state..\n");
13492 player->doing_seek = FALSE;
13493 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13499 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13500 sinks = g_list_next(sinks);
13506 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13507 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13510 sinks = g_list_next(sinks);
13515 request pad name = sink0;
13517 request pad name = sink1; // external
13520 /* Note : Textbin is not linked to the video or audio bin.
13521 * It needs to send the event to the text sink seperatelly.
13523 if (player->play_subtitle && !player->use_textoverlay) {
13524 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13526 if (GST_IS_ELEMENT(text_sink)) {
13527 /* keep ref to the event */
13528 gst_event_ref(event2);
13530 if ((res = gst_element_send_event(text_sink, event2)))
13531 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13532 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13534 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13535 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13537 gst_event_unref(event2);
13541 gst_event_unref(event);
13549 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13553 MMPLAYER_RETURN_IF_FAIL(player);
13554 MMPLAYER_RETURN_IF_FAIL(sink);
13556 player->sink_elements =
13557 g_list_append(player->sink_elements, sink);
13563 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13567 MMPLAYER_RETURN_IF_FAIL(player);
13568 MMPLAYER_RETURN_IF_FAIL(sink);
13570 player->sink_elements =
13571 g_list_remove(player->sink_elements, sink);
13577 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13578 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13579 gint64 cur, GstSeekType stop_type, gint64 stop)
13581 GstEvent* event = NULL;
13582 gboolean result = FALSE;
13586 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13588 if (player->pipeline && player->pipeline->textbin)
13589 __mmplayer_drop_subtitle(player, FALSE);
13591 event = gst_event_new_seek(rate, format, flags, cur_type,
13592 cur, stop_type, stop);
13594 result = __gst_send_event_to_sink(player, event);
13601 /* NOTE : be careful with calling this api. please refer to below glib comment
13602 * glib comment : Note that there is a bug in GObject that makes this function much
13603 * less useful than it might seem otherwise. Once gobject is disposed, the callback
13604 * will no longer be called, but, the signal handler is not currently disconnected.
13605 * If the instance is itself being freed at the same time than this doesn't matter,
13606 * since the signal will automatically be removed, but if instance persists,
13607 * then the signal handler will leak. You should not remove the signal yourself
13608 * because in a future versions of GObject, the handler will automatically be
13611 * It's possible to work around this problem in a way that will continue to work
13612 * with future versions of GObject by checking that the signal handler is still
13613 * connected before disconnected it:
13615 * if (g_signal_handler_is_connected(instance, id))
13616 * g_signal_handler_disconnect(instance, id);
13619 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13621 GList* sig_list = NULL;
13622 MMPlayerSignalItem* item = NULL;
13626 MMPLAYER_RETURN_IF_FAIL(player);
13628 LOGD("release signals type : %d", type);
13630 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13631 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13632 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13633 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13634 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13635 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13639 sig_list = player->signals[type];
13641 for (; sig_list; sig_list = sig_list->next) {
13642 item = sig_list->data;
13644 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13645 if (g_signal_handler_is_connected(item->obj, item->sig))
13646 g_signal_handler_disconnect(item->obj, item->sig);
13649 MMPLAYER_FREEIF(item);
13652 g_list_free(player->signals[type]);
13653 player->signals[type] = NULL;
13660 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13662 mm_player_t* player = 0;
13663 int prev_display_surface_type = 0;
13664 void *prev_display_overlay = NULL;
13665 const gchar *klass = NULL;
13666 gchar *cur_videosink_name = NULL;
13669 int num_of_dec = 2; /* DEC1, DEC2 */
13673 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13674 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13676 player = MM_PLAYER_CAST(handle);
13678 if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13679 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13681 return MM_ERROR_INVALID_ARGUMENT;
13684 /* load previous attributes */
13685 if (player->attrs) {
13686 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13687 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13688 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13689 if (prev_display_surface_type == surface_type) {
13690 LOGD("incoming display surface type is same as previous one, do nothing..");
13692 return MM_ERROR_NONE;
13695 LOGE("failed to load attributes");
13697 return MM_ERROR_PLAYER_INTERNAL;
13700 /* check videosink element is created */
13701 if (!player->pipeline || !player->pipeline->videobin ||
13702 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13703 LOGD("videosink element is not yet ready");
13705 /* videobin is not created yet, so we just set attributes related to display surface */
13706 LOGD("store display attribute for given surface type(%d)", surface_type);
13707 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13708 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13709 if (mmf_attrs_commit(player->attrs)) {
13710 LOGE("failed to commit attribute");
13712 return MM_ERROR_PLAYER_INTERNAL;
13715 return MM_ERROR_NONE;
13717 /* get player command status */
13718 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13719 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13721 return MM_ERROR_PLAYER_INVALID_STATE;
13724 /* surface change */
13725 for (i = 0 ; i < num_of_dec ; i++) {
13726 if (player->pipeline->mainbin &&
13727 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13728 GstElementFactory *decfactory;
13729 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13731 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13732 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13733 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13734 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13738 LOGW("success to changing display surface(%d)", surface_type);
13740 return MM_ERROR_NONE;
13742 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13743 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13747 LOGW("success to changing display surface(%d)", surface_type);
13749 return MM_ERROR_NONE;
13752 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13753 ret = MM_ERROR_PLAYER_INTERNAL;
13762 /* rollback to previous attributes */
13763 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13764 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13765 if (mmf_attrs_commit(player->attrs)) {
13766 LOGE("failed to commit attributes to rollback");
13768 return MM_ERROR_PLAYER_INTERNAL;
13774 /* NOTE : It does not support some use cases, eg using colorspace converter */
13776 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13778 GstPad *src_pad_dec = NULL;
13779 GstPad *sink_pad_videosink = NULL;
13780 GstPad *sink_pad_videobin = NULL;
13781 GstClock *clock = NULL;
13782 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13783 int ret = MM_ERROR_NONE;
13784 gboolean is_audiobin_created = TRUE;
13788 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13789 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13790 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13792 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13793 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13795 /* get information whether if audiobin is created */
13796 if (!player->pipeline->audiobin ||
13797 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13798 LOGW("audiobin is null, this video content may not have audio data");
13799 is_audiobin_created = FALSE;
13802 /* get current state of player */
13803 previous_state = MMPLAYER_CURRENT_STATE(player);
13804 LOGD("previous state(%d)", previous_state);
13807 /* get src pad of decoder and block it */
13808 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13809 if (!src_pad_dec) {
13810 LOGE("failed to get src pad from decode in mainbin");
13811 return MM_ERROR_PLAYER_INTERNAL;
13814 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13815 LOGW("trying to block pad(video)");
13816 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13817 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13820 LOGE("failed to set block pad(video)");
13821 return MM_ERROR_PLAYER_INTERNAL;
13823 LOGW("pad is blocked(video)");
13825 /* no data flows, so no need to do pad_block */
13826 if (player->doing_seek)
13827 LOGW("not completed seek(%d), do nothing", player->doing_seek);
13829 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13833 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13834 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13835 LOGE("failed to remove previous ghost_pad for videobin");
13836 return MM_ERROR_PLAYER_INTERNAL;
13839 /* change state of videobin to NULL */
13840 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13841 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13842 if (ret != GST_STATE_CHANGE_SUCCESS) {
13843 LOGE("failed to change state of videobin to NULL");
13844 return MM_ERROR_PLAYER_INTERNAL;
13847 /* unlink between decoder and videobin and remove previous videosink from videobin */
13848 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13849 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13850 LOGE("failed to remove former videosink from videobin");
13851 return MM_ERROR_PLAYER_INTERNAL;
13854 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13856 /* create a new videosink and add it to videobin */
13857 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13858 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13859 LOGE("failed to create videosink element\n");
13861 return MM_ERROR_PLAYER_INTERNAL;
13863 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13864 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13865 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13867 /* save attributes */
13868 if (player->attrs) {
13869 /* set a new display surface type */
13870 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13871 /* set a new diplay overlay */
13872 switch (surface_type) {
13873 case MM_DISPLAY_SURFACE_OVERLAY:
13874 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13875 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13878 LOGE("invalid type(%d) for changing display surface", surface_type);
13880 return MM_ERROR_INVALID_ARGUMENT;
13882 if (mmf_attrs_commit(player->attrs)) {
13883 LOGE("failed to commit");
13885 return MM_ERROR_PLAYER_INTERNAL;
13888 LOGE("player->attrs is null, failed to save attributes");
13890 return MM_ERROR_PLAYER_INTERNAL;
13893 /* update video param */
13894 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13895 LOGE("failed to update video param");
13896 return MM_ERROR_PLAYER_INTERNAL;
13899 /* change state of videobin to READY */
13900 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13901 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13902 if (ret != GST_STATE_CHANGE_SUCCESS) {
13903 LOGE("failed to change state of videobin to READY");
13904 return MM_ERROR_PLAYER_INTERNAL;
13907 /* change ghostpad */
13908 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13909 if (!sink_pad_videosink) {
13910 LOGE("failed to get sink pad from videosink element");
13911 return MM_ERROR_PLAYER_INTERNAL;
13913 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13914 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13915 LOGE("failed to set active to ghost_pad");
13916 return MM_ERROR_PLAYER_INTERNAL;
13918 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13919 LOGE("failed to change ghostpad for videobin");
13920 return MM_ERROR_PLAYER_INTERNAL;
13922 gst_object_unref(sink_pad_videosink);
13924 /* link decoder with videobin */
13925 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13926 if (!sink_pad_videobin) {
13927 LOGE("failed to get sink pad from videobin");
13928 return MM_ERROR_PLAYER_INTERNAL;
13930 if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13931 LOGE("failed to link");
13932 return MM_ERROR_PLAYER_INTERNAL;
13934 gst_object_unref(sink_pad_videobin);
13936 /* clock setting for a new videosink plugin */
13937 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13938 so we set it from audiosink plugin or pipeline(system clock) */
13939 if (!is_audiobin_created) {
13940 LOGW("audiobin is not created, get clock from pipeline..");
13941 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13943 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13947 GstClockTime base_time;
13948 LOGD("set the clock to videosink");
13949 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13950 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13952 LOGD("got clock of videosink");
13953 now = gst_clock_get_time(clock);
13954 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13955 LOGD("at time %" GST_TIME_FORMAT ", base %"
13956 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13958 LOGE("failed to get clock of videosink after setting clock");
13959 return MM_ERROR_PLAYER_INTERNAL;
13962 LOGW("failed to get clock, maybe it is the time before first playing");
13964 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13965 /* change state of videobin to PAUSED */
13966 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13967 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13968 if (ret != GST_STATE_CHANGE_FAILURE) {
13969 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13971 LOGE("failed to change state of videobin to PLAYING");
13972 return MM_ERROR_PLAYER_INTERNAL;
13975 /* release blocked and unref src pad of video decoder */
13977 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13978 LOGE("failed to set pad blocked FALSE(video)");
13979 return MM_ERROR_PLAYER_INTERNAL;
13982 LOGW("pad is unblocked(video)");
13984 if (player->doing_seek)
13985 LOGW("not completed seek(%d)", player->doing_seek);
13986 /* change state of videobin to PAUSED */
13987 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13988 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13989 if (ret != GST_STATE_CHANGE_FAILURE) {
13990 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13992 LOGE("failed to change state of videobin to PLAYING");
13993 return MM_ERROR_PLAYER_INTERNAL;
13996 /* already skipped pad block */
13997 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14000 /* do get/set position for new videosink plugin */
14002 unsigned long position = 0;
14003 gint64 pos_msec = 0;
14005 LOGD("do get/set position for new videosink plugin");
14006 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14007 LOGE("failed to get position");
14008 return MM_ERROR_PLAYER_INTERNAL;
14010 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14011 /* accurate seek */
14012 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14013 LOGE("failed to set position");
14014 return MM_ERROR_PLAYER_INTERNAL;
14017 /* key unit seek */
14018 pos_msec = position * G_GINT64_CONSTANT(1000000);
14019 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14020 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14021 GST_SEEK_TYPE_SET, pos_msec,
14022 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14024 LOGE("failed to set position");
14025 return MM_ERROR_PLAYER_INTERNAL;
14031 gst_object_unref(src_pad_dec);
14032 LOGD("success to change sink");
14036 return MM_ERROR_NONE;
14040 /* Note : if silent is true, then subtitle would not be displayed. :*/
14041 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14043 mm_player_t* player = (mm_player_t*) hplayer;
14047 /* check player handle */
14048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14050 player->set_mode.subtitle_off = silent;
14052 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14056 return MM_ERROR_NONE;
14059 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
14061 int result = MM_ERROR_NONE;
14062 GstPad *peer = NULL, *pad = NULL;
14063 GstElement *Element = NULL;
14064 MMPlayerGstElement* mainbin = NULL;
14065 mainbin = player->pipeline->mainbin;
14068 if (!gst_pad_set_blocked(inpad, TRUE)) {
14069 result = MM_ERROR_PLAYER_INTERNAL;
14073 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14076 /*Getting pad connected to demuxer audio pad */
14077 peer = gst_pad_get_peer(inpad);
14078 /* Disconnecting Demuxer and its peer plugin [audio] */
14080 if (!gst_pad_unlink(inpad, peer)) {
14081 result = MM_ERROR_PLAYER_INTERNAL;
14085 result = MM_ERROR_PLAYER_INTERNAL;
14088 /*Removing elements between Demuxer and audiobin*/
14089 while (peer != NULL) {
14090 gchar *Element_name = NULL;
14091 gchar *factory_name = NULL;
14092 GList *elements = NULL;
14093 GstElementFactory *factory = NULL;
14094 /*Getting peer element*/
14095 Element = gst_pad_get_parent_element(peer);
14096 if (Element == NULL) {
14097 gst_object_unref(peer);
14098 result = MM_ERROR_PLAYER_INTERNAL;
14102 Element_name = gst_element_get_name(Element);
14103 factory = gst_element_get_factory(Element);
14104 /*checking the element is audio bin*/
14105 if (!strcmp(Element_name, "audiobin")) {
14106 gst_object_unref(peer);
14107 result = MM_ERROR_NONE;
14108 g_free(Element_name);
14111 factory_name = GST_OBJECT_NAME(factory);
14112 pad = gst_element_get_static_pad(Element, "src");
14114 result = MM_ERROR_PLAYER_INTERNAL;
14115 g_free(Element_name);
14118 gst_object_unref(peer);
14119 peer = gst_pad_get_peer(pad);
14121 if (!gst_pad_unlink(pad, peer)) {
14122 gst_object_unref(peer);
14123 gst_object_unref(pad);
14124 result = MM_ERROR_PLAYER_INTERNAL;
14125 g_free(Element_name);
14129 elements = player->parsers;
14130 /* Removing the element form the list*/
14131 for (; elements; elements = g_list_next(elements)) {
14132 Element_name = elements->data;
14133 if (g_strrstr(Element_name, factory_name))
14134 player->parsers = g_list_remove(player->parsers, elements->data);
14136 gst_element_set_state(Element, GST_STATE_NULL);
14137 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
14138 gst_object_unref(pad);
14139 if (Element == mainbin[MMPLAYER_M_Q1].gst)
14140 mainbin[MMPLAYER_M_Q1].gst = NULL;
14141 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
14142 mainbin[MMPLAYER_M_Q2].gst = NULL;
14143 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
14144 mainbin[MMPLAYER_M_DEC1].gst = NULL;
14145 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14146 mainbin[MMPLAYER_M_DEC2].gst = NULL;
14148 gst_object_unref(Element);
14154 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14156 MMPlayerGstElement* mainbin = NULL;
14157 MMPlayerGstElement* textbin = NULL;
14158 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14159 GstState current_state = GST_STATE_VOID_PENDING;
14160 GstState element_state = GST_STATE_VOID_PENDING;
14161 GstState element_pending_state = GST_STATE_VOID_PENDING;
14163 GstEvent *event = NULL;
14164 int result = MM_ERROR_NONE;
14166 GstClock *curr_clock = NULL;
14167 GstClockTime base_time, start_time, curr_time;
14172 /* check player handle */
14173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14175 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14176 LOGE("Pipeline is not in proper state\n");
14177 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14181 mainbin = player->pipeline->mainbin;
14182 textbin = player->pipeline->textbin;
14184 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14186 // sync clock with current pipeline
14187 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14188 curr_time = gst_clock_get_time(curr_clock);
14190 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14191 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14193 LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14194 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14196 if (current_state > GST_STATE_READY) {
14197 // sync state with current pipeline
14198 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14199 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14200 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14202 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14203 if (GST_STATE_CHANGE_FAILURE == ret)
14204 LOGE("fail to state change.\n");
14207 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14208 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14211 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14212 gst_object_unref(curr_clock);
14215 // seek to current position
14216 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14217 result = MM_ERROR_PLAYER_INVALID_STATE;
14218 LOGE("gst_element_query_position failed, invalid state\n");
14222 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14223 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);
14225 __gst_send_event_to_sink(player, event);
14227 result = MM_ERROR_PLAYER_INTERNAL;
14228 LOGE("gst_event_new_seek failed\n");
14232 // sync state with current pipeline
14233 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14234 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14235 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14242 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14244 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14245 GstState current_state = GST_STATE_VOID_PENDING;
14247 MMHandleType attrs = 0;
14248 MMPlayerGstElement* mainbin = NULL;
14249 MMPlayerGstElement* textbin = NULL;
14251 gchar* subtitle_uri = NULL;
14252 int result = MM_ERROR_NONE;
14253 const gchar *charset = NULL;
14257 /* check player handle */
14258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14259 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14261 if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14262 result = MM_ERROR_PLAYER_INVALID_STATE;
14263 LOGE("Pipeline is not in proper state\n");
14267 mainbin = player->pipeline->mainbin;
14268 textbin = player->pipeline->textbin;
14270 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14271 if (current_state < GST_STATE_READY) {
14272 result = MM_ERROR_PLAYER_INVALID_STATE;
14273 LOGE("Pipeline is not in proper state\n");
14277 attrs = MMPLAYER_GET_ATTRS(player);
14279 LOGE("cannot get content attribute\n");
14280 result = MM_ERROR_PLAYER_INTERNAL;
14284 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14285 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14286 LOGE("subtitle uri is not proper filepath\n");
14287 result = MM_ERROR_PLAYER_INVALID_URI;
14291 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14292 LOGD("new subtitle file path is [%s]\n", filepath);
14294 if (!strcmp(filepath, subtitle_uri)) {
14295 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14298 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14299 if (mmf_attrs_commit(player->attrs)) {
14300 LOGE("failed to commit.\n");
14305 //gst_pad_set_blocked_async(src-srcpad, TRUE)
14307 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14308 if (ret != GST_STATE_CHANGE_SUCCESS) {
14309 LOGE("failed to change state of textbin to READY");
14310 result = MM_ERROR_PLAYER_INTERNAL;
14314 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14315 if (ret != GST_STATE_CHANGE_SUCCESS) {
14316 LOGE("failed to change state of subparse to READY");
14317 result = MM_ERROR_PLAYER_INTERNAL;
14321 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14322 if (ret != GST_STATE_CHANGE_SUCCESS) {
14323 LOGE("failed to change state of filesrc to READY");
14324 result = MM_ERROR_PLAYER_INTERNAL;
14328 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14330 charset = util_get_charset(filepath);
14332 LOGD("detected charset is %s\n", charset);
14333 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14336 result = _mmplayer_sync_subtitle_pipeline(player);
14343 /* API to switch between external subtitles */
14344 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14346 int result = MM_ERROR_NONE;
14347 mm_player_t* player = (mm_player_t*)hplayer;
14351 /* check player handle */
14352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14354 if (!player->pipeline) {
14356 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14357 if (mmf_attrs_commit(player->attrs)) {
14358 LOGE("failed to commit.\n");
14359 result = MM_ERROR_PLAYER_INTERNAL;
14362 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14363 if (filepath == NULL)
14364 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14366 if (!__mmplayer_check_subtitle(player)) {
14367 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14368 if (mmf_attrs_commit(player->attrs)) {
14369 LOGE("failed to commit.\n");
14370 result = MM_ERROR_PLAYER_INTERNAL;
14373 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14374 LOGE("fail to create subtitle src\n");
14376 result = _mmplayer_sync_subtitle_pipeline(player);
14378 result = __mmplayer_change_external_subtitle_language(player, filepath);
14380 player->is_external_subtitle_added_now = TRUE;
14388 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14390 int result = MM_ERROR_NONE;
14391 gchar* change_pad_name = NULL;
14392 GstPad* sinkpad = NULL;
14393 MMPlayerGstElement* mainbin = NULL;
14394 enum MainElementID elemId = MMPLAYER_M_NUM;
14395 GstCaps* caps = NULL;
14396 gint total_track_num = 0;
14400 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14401 MM_ERROR_PLAYER_NOT_INITIALIZED);
14403 LOGD("Change Track(%d) to %d\n", type, index);
14405 mainbin = player->pipeline->mainbin;
14407 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14408 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14409 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14410 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14412 /* Changing Video Track is not supported. */
14413 LOGE("Track Type Error\n");
14417 if (mainbin[elemId].gst == NULL) {
14418 result = MM_ERROR_PLAYER_NO_OP;
14419 LOGD("Req track doesn't exist\n");
14423 total_track_num = player->selector[type].total_track_num;
14424 if (total_track_num <= 0) {
14425 result = MM_ERROR_PLAYER_NO_OP;
14426 LOGD("Language list is not available \n");
14430 if ((index < 0) || (index >= total_track_num)) {
14431 result = MM_ERROR_INVALID_ARGUMENT;
14432 LOGD("Not a proper index : %d \n", index);
14436 /*To get the new pad from the selector*/
14437 change_pad_name = g_strdup_printf("sink_%u", index);
14438 if (change_pad_name == NULL) {
14439 result = MM_ERROR_PLAYER_INTERNAL;
14440 LOGD("Pad does not exists\n");
14444 LOGD("new active pad name: %s\n", change_pad_name);
14446 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14447 if (sinkpad == NULL) {
14448 LOGD("sinkpad is NULL");
14449 result = MM_ERROR_PLAYER_INTERNAL;
14453 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14454 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14456 caps = gst_pad_get_current_caps(sinkpad);
14457 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14460 gst_object_unref(sinkpad);
14462 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14463 __mmplayer_set_audio_attrs(player, caps);
14467 MMPLAYER_FREEIF(change_pad_name);
14471 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14473 int result = MM_ERROR_NONE;
14474 mm_player_t* player = NULL;
14475 MMPlayerGstElement* mainbin = NULL;
14477 gint current_active_index = 0;
14479 GstState current_state = GST_STATE_VOID_PENDING;
14480 GstEvent* event = NULL;
14485 player = (mm_player_t*)hplayer;
14486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14488 if (!player->pipeline) {
14489 LOGE("Track %d pre setting -> %d\n", type, index);
14491 player->selector[type].active_pad_index = index;
14495 mainbin = player->pipeline->mainbin;
14497 current_active_index = player->selector[type].active_pad_index;
14499 /*If index is same as running index no need to change the pad*/
14500 if (current_active_index == index)
14503 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14504 result = MM_ERROR_PLAYER_INVALID_STATE;
14508 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14509 if (current_state < GST_STATE_PAUSED) {
14510 result = MM_ERROR_PLAYER_INVALID_STATE;
14511 LOGW("Pipeline not in porper state\n");
14515 result = __mmplayer_change_selector_pad(player, type, index);
14516 if (result != MM_ERROR_NONE) {
14517 LOGE("change selector pad error\n");
14521 player->selector[type].active_pad_index = index;
14523 if (current_state == GST_STATE_PLAYING) {
14524 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);
14526 __gst_send_event_to_sink(player, event);
14528 result = MM_ERROR_PLAYER_INTERNAL;
14537 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14539 mm_player_t* player = (mm_player_t*) hplayer;
14543 /* check player handle */
14544 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14546 *silent = player->set_mode.subtitle_off;
14548 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14552 return MM_ERROR_NONE;
14556 __is_ms_buff_src(mm_player_t* player)
14558 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14560 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14564 __has_suffix(mm_player_t* player, const gchar* suffix)
14566 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14567 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14569 gboolean ret = FALSE;
14570 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14571 gchar* t_suffix = g_ascii_strdown(suffix, -1);
14573 if (g_str_has_suffix(player->profile.uri, suffix))
14576 MMPLAYER_FREEIF(t_url);
14577 MMPLAYER_FREEIF(t_suffix);
14583 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14585 mm_player_t* player = (mm_player_t*) hplayer;
14587 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14589 MMPLAYER_VIDEO_SINK_CHECK(player);
14591 LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14593 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14595 return MM_ERROR_NONE;
14598 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14601 mm_player_t* player = (mm_player_t*) hplayer;
14602 float _level = 0.0;
14606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14608 MMPLAYER_VIDEO_SINK_CHECK(player);
14610 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14612 LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14618 return MM_ERROR_NONE;
14622 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14624 mm_player_t* player = (mm_player_t*) hplayer;
14626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14628 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14629 MMPLAYER_PRINT_STATE(player);
14630 LOGE("wrong-state : can't set the download mode to parse");
14631 return MM_ERROR_PLAYER_INVALID_STATE;
14634 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14635 player->video_hub_download_mode = mode;
14637 return MM_ERROR_NONE;
14641 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14643 mm_player_t* player = (mm_player_t*) hplayer;
14645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14647 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14648 player->sync_handler = enable;
14650 return MM_ERROR_NONE;
14654 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14656 long long clock_delta,
14657 long long video_time,
14658 long long media_clock,
14659 long long audio_time)
14661 mm_player_t* player = (mm_player_t*) hplayer;
14662 MMPlayerGstElement* mainbin = NULL;
14663 GstClockTime start_time_audio = 0, start_time_video = 0;
14664 GstClockTimeDiff base_time = 0, new_base_time = 0;
14665 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14666 gint64 api_delta = 0;
14667 gint64 position = 0, position_delta = 0;
14668 gint64 adj_base_time = 0;
14669 GstClock *curr_clock = NULL;
14670 GstClockTime curr_time = 0;
14671 gboolean query_ret = TRUE;
14672 int result = MM_ERROR_NONE;
14676 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14677 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14678 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14680 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14682 if ((video_time < 0) || (player->doing_seek)) {
14683 LOGD("skip setting master clock. %lld", video_time);
14687 mainbin = player->pipeline->mainbin;
14689 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14690 curr_time = gst_clock_get_time(curr_clock);
14692 current_state = MMPLAYER_CURRENT_STATE(player);
14694 if (current_state == MM_PLAYER_STATE_PLAYING)
14695 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14697 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14699 position = player->last_position;
14700 LOGD("query fail. %lld", position);
14703 clock *= GST_USECOND;
14704 clock_delta *= GST_USECOND;
14706 api_delta = clock - curr_time;
14707 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14708 player->video_share_api_delta = api_delta;
14710 clock_delta += (api_delta - player->video_share_api_delta);
14712 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14713 player->video_share_clock_delta = (gint64)clock_delta;
14715 position_delta = (position/GST_USECOND) - video_time;
14716 position_delta *= GST_USECOND;
14718 adj_base_time = position_delta;
14719 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14722 gint64 new_play_time = 0;
14723 gint64 network_delay = 0;
14725 video_time *= GST_USECOND;
14727 network_delay = clock_delta - player->video_share_clock_delta;
14728 new_play_time = video_time + network_delay;
14730 adj_base_time = position - new_play_time;
14732 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14733 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14736 /* Adjust Current Stream Time with base_time of sink
14737 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14738 * 2. Set new base time
14739 * if adj_base_time is positive value, the stream time will be decreased.
14740 * 3. If seek event is occurred, the start time will be reset. */
14741 if ((player->pipeline->audiobin) &&
14742 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14743 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14745 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14746 LOGD("audio sink : gst_element_set_start_time -> NONE");
14747 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14750 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14753 if ((player->pipeline->videobin) &&
14754 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14755 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14757 if (start_time_video != GST_CLOCK_TIME_NONE) {
14758 LOGD("video sink : gst_element_set_start_time -> NONE");
14759 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14762 // if videobin exist, get base_time from videobin.
14763 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14766 new_base_time = base_time + adj_base_time;
14768 if ((player->pipeline->audiobin) &&
14769 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14770 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14772 if ((player->pipeline->videobin) &&
14773 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14774 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14783 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14784 long long *video_time,
14785 long long *media_clock,
14786 long long *audio_time)
14788 mm_player_t* player = (mm_player_t*) hplayer;
14789 MMPlayerGstElement* mainbin = NULL;
14790 GstClock *curr_clock = NULL;
14791 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14792 gint64 position = 0;
14793 gboolean query_ret = TRUE;
14797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14798 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14799 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14801 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14802 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14803 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14805 mainbin = player->pipeline->mainbin;
14807 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14809 current_state = MMPLAYER_CURRENT_STATE(player);
14811 if (current_state != MM_PLAYER_STATE_PAUSED)
14812 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14814 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14816 position = player->last_position;
14818 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14820 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14823 gst_object_unref(curr_clock);
14827 return MM_ERROR_NONE;
14831 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14833 mm_player_t* player = (mm_player_t*) hplayer;
14838 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14839 MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14841 if (player->v_stream_caps) {
14842 GstStructure *str = NULL;
14844 str = gst_caps_get_structure(player->v_stream_caps, 0);
14845 if (!gst_structure_get_int(str, "orientation", &org_angle))
14846 LOGD("missing 'orientation' field in video caps");
14849 LOGD("orientation: %d", org_angle);
14850 *angle = org_angle;
14853 return MM_ERROR_NONE;
14857 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14859 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14860 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14862 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14863 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14867 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14868 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14869 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14870 mm_player_dump_t *dump_s;
14871 dump_s = g_malloc(sizeof(mm_player_dump_t));
14873 if (dump_s == NULL) {
14874 LOGE("malloc fail");
14878 dump_s->dump_element_file = NULL;
14879 dump_s->dump_pad = NULL;
14880 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14882 if (dump_s->dump_pad) {
14883 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14884 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]);
14885 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14886 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);
14887 /* add list for removed buffer probe and close FILE */
14888 player->dump_list = g_list_append(player->dump_list, dump_s);
14889 LOGD("%s sink pad added buffer probe for dump", factory_name);
14894 LOGE("failed to get %s sink pad added", factory_name);
14903 static GstPadProbeReturn
14904 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
14906 FILE *dump_data = (FILE *) u_data;
14907 // int written = 0;
14908 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14909 GstMapInfo probe_info = GST_MAP_INFO_INIT;
14911 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14913 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14915 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14917 fwrite(probe_info.data, 1, probe_info.size , dump_data);
14919 return GST_PAD_PROBE_OK;
14923 __mmplayer_release_dump_list(GList *dump_list)
14926 GList *d_list = dump_list;
14927 for (; d_list; d_list = g_list_next(d_list)) {
14928 mm_player_dump_t *dump_s = d_list->data;
14929 if (dump_s->dump_pad) {
14930 if (dump_s->probe_handle_id)
14931 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14933 if (dump_s->dump_element_file) {
14934 fclose(dump_s->dump_element_file);
14935 dump_s->dump_element_file = NULL;
14937 MMPLAYER_FREEIF(dump_s);
14939 g_list_free(dump_list);
14945 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14947 mm_player_t* player = (mm_player_t*) hplayer;
14951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14952 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14954 *exist = player->has_closed_caption;
14958 return MM_ERROR_NONE;
14961 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14965 /* increase ref count of gst buffer */
14967 ret = gst_buffer_ref((GstBuffer *)buffer);
14973 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14977 gst_buffer_unref((GstBuffer *)buffer);
14984 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14986 mm_player_t *player = (mm_player_t*)user_data;
14987 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14988 guint64 current_level_bytes = 0;
14990 MMPLAYER_RETURN_IF_FAIL(player);
14992 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14994 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14995 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14997 if (player->media_stream_buffer_status_cb[type])
14998 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14999 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15004 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15006 mm_player_t *player = (mm_player_t*)user_data;
15007 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15008 guint64 current_level_bytes = 0;
15010 MMPLAYER_RETURN_IF_FAIL(player);
15012 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15014 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15016 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15017 if (player->media_stream_buffer_status_cb[type])
15018 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15019 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15023 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15025 mm_player_t *player = (mm_player_t*)user_data;
15026 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15027 guint64 current_level_bytes = 0;
15029 MMPLAYER_RETURN_IF_FAIL(player);
15031 LOGI("app-src: feed subtitle\n");
15033 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15035 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15036 if (player->media_stream_buffer_status_cb[type])
15037 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15039 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15043 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15045 mm_player_t *player = (mm_player_t*)user_data;
15046 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15047 guint64 current_level_bytes = 0;
15049 MMPLAYER_RETURN_IF_FAIL(player);
15051 LOGI("app-src: audio buffer is full.\n");
15053 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15055 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15057 if (player->media_stream_buffer_status_cb[type])
15058 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15060 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15064 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15066 mm_player_t *player = (mm_player_t*)user_data;
15067 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15068 guint64 current_level_bytes = 0;
15070 MMPLAYER_RETURN_IF_FAIL(player);
15072 LOGI("app-src: video buffer is full.\n");
15074 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15076 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15077 if (player->media_stream_buffer_status_cb[type])
15078 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15080 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15084 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15086 mm_player_t *player = (mm_player_t*)user_data;
15087 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15089 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15091 LOGD("app-src: seek audio data %llu\n", position);
15092 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15094 if (player->media_stream_seek_data_cb[type])
15095 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15096 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15102 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15104 mm_player_t *player = (mm_player_t*)user_data;
15105 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15107 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15109 LOGD("app-src: seek video data %llu\n", position);
15110 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15111 if (player->media_stream_seek_data_cb[type])
15112 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15113 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15119 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15121 mm_player_t *player = (mm_player_t*)user_data;
15122 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15124 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15126 LOGD("app-src: seek subtitle data\n");
15127 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15129 if (player->media_stream_seek_data_cb[type])
15130 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15131 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15137 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15139 mm_player_t* player = (mm_player_t*) hplayer;
15143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15145 player->pcm_samplerate = samplerate;
15146 player->pcm_channel = channel;
15149 return MM_ERROR_NONE;
15152 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15154 mm_player_t* player = (mm_player_t*) hplayer;
15158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15159 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15161 if (MMPLAYER_IS_STREAMING(player))
15162 *timeout = player->ini.live_state_change_timeout;
15164 *timeout = player->ini.localplayback_state_change_timeout;
15166 LOGD("timeout = %d\n", *timeout);
15169 return MM_ERROR_NONE;
15172 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15174 mm_player_t* player = (mm_player_t*) hplayer;
15178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15179 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15181 *num = player->video_num_buffers;
15182 *extra_num = player->video_extra_num_buffers;
15184 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15187 return MM_ERROR_NONE;