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 /*===========================================================================================
56 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
58 ========================================================================================== */
60 /*---------------------------------------------------------------------------
61 | GLOBAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | IMPORTED VARIABLE DECLARATIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED FUNCTION DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
74 ---------------------------------------------------------------------------*/
75 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
76 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
78 #define MM_VOLUME_FACTOR_DEFAULT 1.0
79 #define MM_VOLUME_FACTOR_MIN 0
80 #define MM_VOLUME_FACTOR_MAX 1.0
82 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
84 #define MM_PLAYER_MPEG_VNAME "mpegversion"
85 #define MM_PLAYER_DIVX_VNAME "divxversion"
86 #define MM_PLAYER_WMV_VNAME "wmvversion"
87 #define MM_PLAYER_WMA_VNAME "wmaversion"
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
91 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
92 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
93 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
94 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
96 #define GST_QUEUE_DEFAULT_TIME 4
97 #define GST_QUEUE_HLS_TIME 8
99 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
100 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
101 (player->ini.http_use_file_buffer) && \
102 (player->http_file_buffering_path) && \
103 (strlen(player->http_file_buffering_path) > 0))
104 #define MM_PLAYER_NAME "mmplayer"
106 #define PLAYER_DISPLAY_MODE_DST_ROI 5
108 /*---------------------------------------------------------------------------
109 | LOCAL CONSTANT DEFINITIONS: |
110 ---------------------------------------------------------------------------*/
112 /*---------------------------------------------------------------------------
113 | LOCAL DATA TYPE DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | GLOBAL VARIABLE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | LOCAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL FUNCTION PROTOTYPES: |
126 ---------------------------------------------------------------------------*/
127 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
128 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
129 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
130 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
131 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
132 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
135 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
136 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
137 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
138 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
139 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
140 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
141 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
142 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
143 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
144 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
145 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
146 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
147 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
149 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
150 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
155 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
157 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
158 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
159 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
161 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
162 //static void __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
164 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
165 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static void __mmplayer_init_factories(mm_player_t* player);
169 static void __mmplayer_release_factories(mm_player_t* player);
170 static void __mmplayer_release_misc(mm_player_t* player);
171 static void __mmplayer_release_misc_post(mm_player_t* player);
172 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
173 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
174 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
176 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
177 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
179 int __mmplayer_switch_audio_sink(mm_player_t* player);
180 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
181 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
182 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
183 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
184 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
185 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
187 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
188 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
189 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
190 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
191 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
192 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
193 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
194 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
195 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
196 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
197 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
198 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
199 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
200 static gpointer __mmplayer_next_play_thread(gpointer data);
201 static gpointer __mmplayer_repeat_thread(gpointer data);
202 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
205 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
206 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
207 static void __mmplayer_release_dump_list(GList *dump_list);
209 static int __gst_realize(mm_player_t* player);
210 static int __gst_unrealize(mm_player_t* player);
211 static int __gst_start(mm_player_t* player);
212 static int __gst_stop(mm_player_t* player);
213 static int __gst_pause(mm_player_t* player, gboolean async);
214 static int __gst_resume(mm_player_t* player, gboolean async);
215 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
216 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
217 gint64 cur, GstSeekType stop_type, gint64 stop);
218 static int __gst_pending_seek(mm_player_t* player);
220 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
221 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
222 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
223 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
224 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
226 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
228 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
229 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
232 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
233 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
235 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
236 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
239 static gboolean __is_ms_buff_src(mm_player_t* player);
240 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
242 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
243 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
244 static int __mmplayer_start_streaming_ext(mm_player_t *player);
245 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
246 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
248 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
249 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
250 static void __mmplayer_check_pipeline(mm_player_t* player);
251 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
252 static void __mmplayer_deactivate_old_path(mm_player_t *player);
253 #if 0 // We'll need this in future.
254 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
257 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
258 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
260 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
261 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
262 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
263 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
264 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
265 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
266 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
267 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
268 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
269 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
270 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
271 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
272 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
274 /*===========================================================================================
276 | FUNCTION DEFINITIONS |
278 ========================================================================================== */
282 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
286 count = gst_tag_list_get_tag_size(list, tag);
288 LOGD("count = %d", count);
290 for (i = 0; i < count; i++) {
293 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
294 if (!gst_tag_list_get_string_index(list, tag, i, &str))
295 g_assert_not_reached();
297 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
300 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
302 g_print(" : %s\n", str);
309 /* This function should be called after the pipeline goes PAUSED or higher
312 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
314 static gboolean has_duration = FALSE;
315 static gboolean has_video_attrs = FALSE;
316 static gboolean has_audio_attrs = FALSE;
317 static gboolean has_bitrate = FALSE;
318 gboolean missing_only = FALSE;
319 gboolean all = FALSE;
321 GstStructure* p = NULL;
322 MMHandleType attrs = 0;
324 gint stream_service_type = STREAMING_SERVICE_NONE;
329 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
331 /* check player state here */
332 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
333 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
334 /* give warning now only */
335 LOGW("be careful. content attributes may not available in this state ");
338 /* get content attribute first */
339 attrs = MMPLAYER_GET_ATTRS(player);
341 LOGE("cannot get content attribute");
345 /* get update flag */
347 if (flag & ATTR_MISSING_ONLY) {
349 LOGD("updating missed attr only");
352 if (flag & ATTR_ALL) {
354 has_duration = FALSE;
355 has_video_attrs = FALSE;
356 has_audio_attrs = FALSE;
359 LOGD("updating all attrs");
362 if (missing_only && all) {
363 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
364 missing_only = FALSE;
367 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
368 LOGD("try to update duration");
369 has_duration = FALSE;
371 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
372 player->duration = dur_nsec;
373 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
376 /* try to get streaming service type */
377 stream_service_type = __mmplayer_get_stream_service_type(player);
378 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
380 /* check duration is OK */
381 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
382 /* FIXIT : find another way to get duration here. */
383 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
386 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
391 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
392 /* update audio params
393 NOTE : We need original audio params and it can be only obtained from src pad of audio
394 decoder. Below code only valid when we are not using 'resampler' just before
397 LOGD("try to update audio attrs");
398 has_audio_attrs = FALSE;
400 if (player->pipeline->audiobin &&
401 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
402 GstCaps *caps_a = NULL;
404 gint samplerate = 0, channels = 0;
406 pad = gst_element_get_static_pad(
407 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
410 caps_a = gst_pad_get_current_caps(pad);
413 p = gst_caps_get_structure(caps_a, 0);
415 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
417 gst_structure_get_int(p, "rate", &samplerate);
418 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
420 gst_structure_get_int(p, "channels", &channels);
421 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
423 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
425 gst_caps_unref(caps_a);
428 has_audio_attrs = TRUE;
430 LOGW("not ready to get audio caps");
432 gst_object_unref(pad);
434 LOGW("failed to get pad from audiosink");
438 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
439 LOGD("try to update video attrs");
440 has_video_attrs = FALSE;
442 if (player->pipeline->videobin &&
443 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
444 GstCaps *caps_v = NULL;
449 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
451 caps_v = gst_pad_get_current_caps(pad);
453 /* Use v_stream_caps, if fail to get video_sink sink pad*/
454 if (!caps_v && player->v_stream_caps) {
455 caps_v = player->v_stream_caps;
456 gst_caps_ref(caps_v);
460 p = gst_caps_get_structure(caps_v, 0);
461 gst_structure_get_int(p, "width", &width);
462 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
464 gst_structure_get_int(p, "height", &height);
465 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
467 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
469 SECURE_LOGD("width : %d height : %d", width, height);
471 gst_caps_unref(caps_v);
475 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
476 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
479 has_video_attrs = TRUE;
481 LOGD("no negitiated caps from videosink");
482 gst_object_unref(pad);
485 LOGD("no videosink sink pad");
490 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
493 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
494 if (player->duration) {
495 guint64 data_size = 0;
497 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
498 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
500 if (stat(path, &sb) == 0)
501 data_size = (guint64)sb.st_size;
502 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
503 data_size = player->http_content_size;
504 LOGD("try to update bitrate : data_size = %lld", data_size);
508 guint64 msec_dur = 0;
510 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
511 bitrate = data_size * 8 * 1000 / msec_dur;
512 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
513 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
518 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
519 if (player->total_bitrate) {
520 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
528 if (mmf_attrs_commit(attrs)) {
529 LOGE("failed to update attributes\n");
538 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
540 gint streaming_type = STREAMING_SERVICE_NONE;
544 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
546 player->pipeline->mainbin &&
547 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
550 /* streaming service type if streaming */
551 if (!MMPLAYER_IS_STREAMING(player))
552 return STREAMING_SERVICE_NONE;
554 if (MMPLAYER_IS_HTTP_STREAMING(player))
555 streaming_type = (player->duration == 0) ?
556 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
558 switch (streaming_type) {
559 case STREAMING_SERVICE_LIVE:
560 LOGD("it's live streaming");
562 case STREAMING_SERVICE_VOD:
563 LOGD("it's vod streaming");
565 case STREAMING_SERVICE_NONE:
566 LOGE("should not get here");
569 LOGE("should not get here");
572 player->streaming_type = streaming_type;
575 return streaming_type;
579 /* this function sets the player state and also report
580 * it to applicaton by calling callback function
583 __mmplayer_set_state(mm_player_t* player, int state) // @
585 MMMessageParamType msg = {0, };
586 int sound_result = MM_ERROR_NONE;
587 gboolean post_bos = FALSE;
588 gboolean interrupted_by_focus = FALSE;
589 gboolean interrupted_by_resource = FALSE;
590 int ret = MM_ERROR_NONE;
592 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
594 if (MMPLAYER_CURRENT_STATE(player) == state) {
595 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
596 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
600 /* update player states */
601 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
602 MMPLAYER_CURRENT_STATE(player) = state;
604 /* FIXIT : it's better to do like below code
605 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
606 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
607 and add more code to handling PENDING_STATE.
609 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
610 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
613 MMPLAYER_PRINT_STATE(player);
615 /* do some FSM stuffs before posting new state to application */
616 interrupted_by_focus = player->sound_focus.by_asm_cb;
617 interrupted_by_resource = player->resource_manager.by_rm_cb;
619 switch (MMPLAYER_CURRENT_STATE(player)) {
620 case MM_PLAYER_STATE_NULL:
621 case MM_PLAYER_STATE_READY:
623 if (player->cmd == MMPLAYER_COMMAND_STOP) {
624 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
625 if (sound_result != MM_ERROR_NONE) {
626 LOGE("failed to release sound focus\n");
627 return MM_ERROR_POLICY_INTERNAL;
633 case MM_PLAYER_STATE_PAUSED:
635 if (!player->sent_bos) {
637 #define MMPLAYER_MAX_SOUND_PRIORITY 3
639 /* it's first time to update all content attrs. */
640 _mmplayer_update_content_attrs(player, ATTR_ALL);
641 /* set max sound priority to keep own sound and not to mute other's one */
642 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
644 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
646 LOGD("set max audio priority");
647 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
653 /* add audio callback probe if condition is satisfied */
654 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
655 __mmplayer_configure_audio_callback(player);
656 /* FIXIT : handle return value */
658 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
659 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
660 if (sound_result != MM_ERROR_NONE) {
661 LOGE("failed to release sound focus\n");
662 return MM_ERROR_POLICY_INTERNAL;
668 case MM_PLAYER_STATE_PLAYING:
670 /* try to get content metadata */
671 if (!player->sent_bos) {
672 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
673 * c-api since c-api doesn't use _start() anymore. It may not work propery with
674 * legacy mmfw-player api */
675 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
678 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
679 if (!player->sent_bos)
680 __mmplayer_handle_missed_plugin(player);
681 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
682 if (sound_result != MM_ERROR_NONE) {
683 // FIXME : need to check history
684 if (player->pipeline->videobin) {
685 MMMessageParamType msg = {0, };
687 LOGE("failed to go ahead because of video conflict\n");
689 msg.union_type = MM_MSG_UNION_CODE;
690 msg.code = MM_ERROR_POLICY_INTERRUPTED;
691 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
693 _mmplayer_unrealize((MMHandleType)player);
695 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
696 _mmplayer_pause((MMHandleType)player);
700 return MM_ERROR_POLICY_INTERNAL;
704 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
705 /* initialize because auto resume is done well. */
706 player->resumed_by_rewind = FALSE;
707 player->playback_rate = 1.0;
710 if (!player->sent_bos) {
711 /* check audio codec field is set or not
712 * we can get it from typefinder or codec's caps.
714 gchar *audio_codec = NULL;
715 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
717 /* The codec format can't be sent for audio only case like amr, mid etc.
718 * Because, parser don't make related TAG.
719 * So, if it's not set yet, fill it with found data.
722 if (g_strrstr(player->type, "audio/midi"))
723 audio_codec = g_strdup("MIDI");
724 else if (g_strrstr(player->type, "audio/x-amr"))
725 audio_codec = g_strdup("AMR");
726 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
727 audio_codec = g_strdup("AAC");
729 audio_codec = g_strdup("unknown");
730 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
732 MMPLAYER_FREEIF(audio_codec);
733 mmf_attrs_commit(player->attrs);
734 LOGD("set audio codec type with caps\n");
742 case MM_PLAYER_STATE_NONE:
744 LOGW("invalid target state, there is nothing to do.\n");
749 /* post message to application */
750 if (MMPLAYER_TARGET_STATE(player) == state) {
751 /* fill the message with state of player */
752 msg.state.previous = MMPLAYER_PREV_STATE(player);
753 msg.state.current = MMPLAYER_CURRENT_STATE(player);
755 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
757 /* state changed by focus or resource callback */
758 if (interrupted_by_focus || interrupted_by_resource) {
759 msg.union_type = MM_MSG_UNION_CODE;
760 if (interrupted_by_focus)
761 msg.code = player->sound_focus.focus_changed_msg; /* FIXME: player.c convert function have to be modified. */
762 else if (interrupted_by_resource)
763 msg.code = MM_MSG_CODE_INTERRUPTED_BY_RESOURCE_CONFLICT;
764 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
765 } else /* state changed by usecase */
766 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
768 LOGD("intermediate state, do nothing.\n");
769 MMPLAYER_PRINT_STATE(player);
774 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
775 player->sent_bos = TRUE;
781 static gpointer __mmplayer_next_play_thread(gpointer data)
783 mm_player_t* player = (mm_player_t*) data;
784 MMPlayerGstElement *mainbin = NULL;
786 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
788 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
789 while (!player->next_play_thread_exit) {
790 LOGD("next play thread started. waiting for signal.\n");
791 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
793 LOGD("reconfigure pipeline for gapless play.\n");
795 if (player->next_play_thread_exit) {
796 if (player->gapless.reconfigure) {
797 player->gapless.reconfigure = false;
798 MMPLAYER_PLAYBACK_UNLOCK(player);
800 LOGD("exiting gapless play thread\n");
804 mainbin = player->pipeline->mainbin;
806 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
807 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
808 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
809 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
810 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
812 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
814 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
819 static gpointer __mmplayer_repeat_thread(gpointer data)
821 mm_player_t* player = (mm_player_t*) data;
822 gboolean ret_value = FALSE;
823 MMHandleType attrs = 0;
826 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
828 MMPLAYER_REPEAT_THREAD_LOCK(player);
829 while (!player->repeat_thread_exit) {
830 LOGD("repeat thread started. waiting for signal.\n");
831 MMPLAYER_REPEAT_THREAD_WAIT(player);
833 if (player->repeat_thread_exit) {
834 LOGD("exiting repeat thread\n");
840 MMPLAYER_CMD_LOCK(player);
842 attrs = MMPLAYER_GET_ATTRS(player);
844 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
845 LOGE("can not get play count\n");
849 if (player->section_repeat) {
850 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
852 if (player->playback_rate < 0.0) {
853 player->resumed_by_rewind = TRUE;
854 _mmplayer_set_mute((MMHandleType)player, 0);
855 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
858 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
859 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
860 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
863 player->sent_bos = FALSE;
867 LOGE("failed to set position to zero for rewind\n");
871 /* decrease play count */
873 /* we successeded to rewind. update play count and then wait for next EOS */
876 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
878 /* commit attribute */
879 if (mmf_attrs_commit(attrs))
880 LOGE("failed to commit attribute\n");
884 MMPLAYER_CMD_UNLOCK(player);
887 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
892 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
894 MMHandleType attrs = 0;
895 guint64 data_size = 0;
897 unsigned long pos_msec = 0;
900 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
902 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
904 attrs = MMPLAYER_GET_ATTRS(player);
906 LOGE("fail to get attributes.\n");
910 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
911 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
913 if (stat(path, &sb) == 0)
914 data_size = (guint64)sb.st_size;
915 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
916 data_size = player->http_content_size;
918 __mm_player_streaming_buffering(player->streamer,
921 player->last_position,
924 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
930 __mmplayer_handle_buffering_message(mm_player_t* player)
932 int ret = MM_ERROR_NONE;
933 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
934 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
935 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
936 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
938 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
939 LOGW("do nothing for buffering msg\n");
940 ret = MM_ERROR_PLAYER_INVALID_STATE;
944 prev_state = MMPLAYER_PREV_STATE(player);
945 current_state = MMPLAYER_CURRENT_STATE(player);
946 target_state = MMPLAYER_TARGET_STATE(player);
947 pending_state = MMPLAYER_PENDING_STATE(player);
949 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
950 MMPLAYER_STATE_GET_NAME(prev_state),
951 MMPLAYER_STATE_GET_NAME(current_state),
952 MMPLAYER_STATE_GET_NAME(pending_state),
953 MMPLAYER_STATE_GET_NAME(target_state),
954 player->streamer->is_buffering);
956 if (!player->streamer->is_buffering) {
957 /* NOTE : if buffering has done, player has to go to target state. */
958 switch (target_state) {
959 case MM_PLAYER_STATE_PAUSED:
961 switch (pending_state) {
962 case MM_PLAYER_STATE_PLAYING:
963 __gst_pause(player, TRUE);
966 case MM_PLAYER_STATE_PAUSED:
967 LOGD("player is already going to paused state, there is nothing to do.\n");
970 case MM_PLAYER_STATE_NONE:
971 case MM_PLAYER_STATE_NULL:
972 case MM_PLAYER_STATE_READY:
974 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
980 case MM_PLAYER_STATE_PLAYING:
982 switch (pending_state) {
983 case MM_PLAYER_STATE_NONE:
985 if (current_state != MM_PLAYER_STATE_PLAYING)
986 __gst_resume(player, TRUE);
990 case MM_PLAYER_STATE_PAUSED:
991 /* NOTE: It should be worked as asynchronously.
992 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
994 __gst_resume(player, TRUE);
997 case MM_PLAYER_STATE_PLAYING:
998 LOGD("player is already going to playing state, there is nothing to do.\n");
1001 case MM_PLAYER_STATE_NULL:
1002 case MM_PLAYER_STATE_READY:
1004 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1010 case MM_PLAYER_STATE_NULL:
1011 case MM_PLAYER_STATE_READY:
1012 case MM_PLAYER_STATE_NONE:
1014 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1018 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1019 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1021 switch (pending_state) {
1022 case MM_PLAYER_STATE_NONE:
1024 if (current_state != MM_PLAYER_STATE_PAUSED) {
1025 LOGD("set pause state during buffering\n");
1026 __gst_pause(player, TRUE);
1028 // to cover the weak-signal environment.
1029 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
1030 unsigned long position = 0;
1031 gint64 pos_msec = 0;
1033 LOGD("[RTSP] seek to the buffering start point\n");
1035 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
1036 LOGE("failed to get position\n");
1041 pos_msec = position * G_GINT64_CONSTANT(1000000);
1043 __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1044 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1045 pos_msec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1051 case MM_PLAYER_STATE_PLAYING:
1052 __gst_pause(player, TRUE);
1055 case MM_PLAYER_STATE_PAUSED:
1058 case MM_PLAYER_STATE_NULL:
1059 case MM_PLAYER_STATE_READY:
1061 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1071 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1073 MMPlayerGstElement *textbin;
1076 MMPLAYER_RETURN_IF_FAIL(player &&
1078 player->pipeline->textbin);
1080 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1082 textbin = player->pipeline->textbin;
1085 LOGD("Drop subtitle text after getting EOS\n");
1087 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1088 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1090 player->is_subtitle_force_drop = TRUE;
1092 if (player->is_subtitle_force_drop == TRUE) {
1093 LOGD("Enable subtitle data path without drop\n");
1095 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1096 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1098 LOGD("non-connected with external display");
1100 player->is_subtitle_force_drop = FALSE;
1106 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1108 mm_player_t* player = (mm_player_t*) data;
1109 gboolean ret = TRUE;
1110 static gboolean async_done = FALSE;
1112 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1113 MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1115 switch (GST_MESSAGE_TYPE(msg)) {
1116 case GST_MESSAGE_UNKNOWN:
1117 LOGD("unknown message received\n");
1120 case GST_MESSAGE_EOS:
1122 MMHandleType attrs = 0;
1125 LOGD("GST_MESSAGE_EOS received\n");
1127 /* NOTE : EOS event is comming multiple time. watch out it */
1128 /* check state. we only process EOS when pipeline state goes to PLAYING */
1129 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1130 LOGD("EOS received on non-playing state. ignoring it\n");
1134 if (player->pipeline) {
1135 if (player->pipeline->textbin)
1136 __mmplayer_drop_subtitle(player, TRUE);
1138 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1141 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1143 LOGD("release audio callback\n");
1145 /* release audio callback */
1146 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1147 player->audio_cb_probe_id = 0;
1148 /* audio callback should be free because it can be called even though probe remove.*/
1149 player->audio_stream_cb = NULL;
1150 player->audio_stream_cb_user_param = NULL;
1154 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1155 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1157 /* rewind if repeat count is greater then zero */
1158 /* get play count */
1159 attrs = MMPLAYER_GET_ATTRS(player);
1162 gboolean smooth_repeat = FALSE;
1164 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1165 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1167 player->play_count = count;
1169 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1171 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1172 if (smooth_repeat) {
1173 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1175 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1181 if (player->section_repeat) {
1182 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1184 if (player->playback_rate < 0.0) {
1185 player->resumed_by_rewind = TRUE;
1186 _mmplayer_set_mute((MMHandleType)player, 0);
1187 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1190 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1193 player->sent_bos = FALSE;
1196 if (MM_ERROR_NONE != ret_value)
1197 LOGE("failed to set position to zero for rewind\n");
1199 /* not posting eos when repeating */
1205 if (player->pipeline)
1206 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1208 /* post eos message to application */
1209 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1211 /* reset last position */
1212 player->last_position = 0;
1216 case GST_MESSAGE_ERROR:
1218 GError *error = NULL;
1219 gchar* debug = NULL;
1221 /* generating debug info before returning error */
1222 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1224 /* get error code */
1225 gst_message_parse_error(msg, &error, &debug);
1227 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1228 /* Note : the streaming error from the streaming source is handled
1229 * using __mmplayer_handle_streaming_error.
1231 __mmplayer_handle_streaming_error(player, msg);
1233 /* dump state of all element */
1234 __mmplayer_dump_pipeline_state(player);
1236 /* traslate gst error code to msl error code. then post it
1237 * to application if needed
1239 __mmplayer_handle_gst_error(player, msg, error);
1242 LOGE("error debug : %s", debug);
1245 if (MMPLAYER_IS_HTTP_PD(player))
1246 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1248 MMPLAYER_FREEIF(debug);
1249 g_error_free(error);
1253 case GST_MESSAGE_WARNING:
1256 GError* error = NULL;
1258 gst_message_parse_warning(msg, &error, &debug);
1260 LOGD("warning : %s\n", error->message);
1261 LOGD("debug : %s\n", debug);
1263 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1265 MMPLAYER_FREEIF(debug);
1266 g_error_free(error);
1270 case GST_MESSAGE_TAG:
1272 LOGD("GST_MESSAGE_TAG\n");
1273 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1274 LOGW("failed to extract tags from gstmessage\n");
1278 case GST_MESSAGE_BUFFERING:
1280 MMMessageParamType msg_param = {0, };
1282 if (!MMPLAYER_IS_STREAMING(player))
1285 /* ignore the buffering messages during building pipeline, *
1286 * not to block the main loop */
1287 if (MMPLAYER_CURRENT_STATE(player) <= MM_PLAYER_STATE_READY) {
1288 LOGW("ignore the buffering msg(state:%d)", MMPLAYER_CURRENT_STATE(player));
1292 /* ignore the prev buffering message */
1293 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1294 gint buffer_percent = 0;
1296 gst_message_parse_buffering(msg, &buffer_percent);
1298 if (buffer_percent == MAX_BUFFER_PERCENT) {
1299 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1300 player->streamer->is_buffering_done = FALSE;
1306 MMPLAYER_CMD_LOCK(player);
1307 __mmplayer_update_buffer_setting(player, msg);
1309 if (__mmplayer_handle_buffering_message(player) == MM_ERROR_NONE) {
1310 msg_param.connection.buffering = player->streamer->buffering_percent;
1311 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1312 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1313 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1314 if (player->doing_seek) {
1315 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1316 player->doing_seek = FALSE;
1317 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1318 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1323 MMPLAYER_CMD_UNLOCK(player);
1327 case GST_MESSAGE_STATE_CHANGED:
1329 MMPlayerGstElement *mainbin;
1330 const GValue *voldstate, *vnewstate, *vpending;
1331 GstState oldstate = GST_STATE_NULL;
1332 GstState newstate = GST_STATE_NULL;
1333 GstState pending = GST_STATE_NULL;
1335 if (!(player->pipeline && player->pipeline->mainbin)) {
1336 LOGE("player pipeline handle is null");
1340 mainbin = player->pipeline->mainbin;
1342 /* we only handle messages from pipeline */
1343 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1346 /* get state info from msg */
1347 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1348 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1349 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1351 if (!voldstate || !vnewstate) {
1352 LOGE("received msg has wrong format.");
1356 oldstate = (GstState)voldstate->data[0].v_int;
1357 newstate = (GstState)vnewstate->data[0].v_int;
1359 pending = (GstState)vpending->data[0].v_int;
1361 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1362 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1363 gst_element_state_get_name((GstState)oldstate),
1364 gst_element_state_get_name((GstState)newstate),
1365 gst_element_state_get_name((GstState)pending));
1367 if (oldstate == newstate) {
1368 LOGD("pipeline reports state transition to old state");
1373 case GST_STATE_VOID_PENDING:
1376 case GST_STATE_NULL:
1379 case GST_STATE_READY:
1382 case GST_STATE_PAUSED:
1384 gboolean prepare_async = FALSE;
1386 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1387 __mmplayer_configure_audio_callback(player);
1389 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1390 // managed prepare async case
1391 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1392 LOGD("checking prepare mode for async transition - %d", prepare_async);
1395 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1396 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1398 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1399 __mm_player_streaming_set_content_bitrate(player->streamer,
1400 player->total_maximum_bitrate, player->total_bitrate);
1405 case GST_STATE_PLAYING:
1407 if (MMPLAYER_IS_STREAMING(player)) {
1408 // managed prepare async case when buffering is completed
1409 // pending state should be reset oyherwise, it's still playing even though it's resumed after bufferging.
1410 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1411 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1412 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1415 if (player->gapless.stream_changed) {
1416 _mmplayer_update_content_attrs(player, ATTR_ALL);
1417 player->gapless.stream_changed = FALSE;
1420 if (player->doing_seek && async_done) {
1421 player->doing_seek = FALSE;
1423 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1434 case GST_MESSAGE_CLOCK_LOST:
1436 GstClock *clock = NULL;
1437 gboolean need_new_clock = FALSE;
1439 gst_message_parse_clock_lost(msg, &clock);
1440 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1442 if (!player->videodec_linked)
1443 need_new_clock = TRUE;
1444 else if (!player->ini.use_system_clock)
1445 need_new_clock = TRUE;
1447 if (need_new_clock) {
1448 LOGD("Provide clock is TRUE, do pause->resume\n");
1449 __gst_pause(player, FALSE);
1450 __gst_resume(player, FALSE);
1455 case GST_MESSAGE_NEW_CLOCK:
1457 GstClock *clock = NULL;
1458 gst_message_parse_new_clock(msg, &clock);
1459 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1463 case GST_MESSAGE_ELEMENT:
1465 const gchar *structure_name;
1467 MMHandleType attrs = 0;
1469 attrs = MMPLAYER_GET_ATTRS(player);
1471 LOGE("cannot get content attribute");
1476 if (gst_message_get_structure(msg) == NULL)
1479 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1480 if (!structure_name)
1483 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1484 gint num_buffers = 0;
1485 gint extra_num_buffers = 0;
1487 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1488 player->video_num_buffers = num_buffers;
1489 LOGD("video_num_buffers : %d", player->video_num_buffers);
1492 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1493 player->video_extra_num_buffers = extra_num_buffers;
1494 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1499 if (!strcmp(structure_name, "Language_list")) {
1500 const GValue *lang_list = NULL;
1501 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1502 if (lang_list != NULL) {
1503 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1505 LOGD("Total audio tracks(from parser) = %d \n", count);
1509 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1510 const GValue *lang_list = NULL;
1511 MMPlayerLangStruct *temp = NULL;
1513 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1514 if (lang_list != NULL) {
1515 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1517 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1518 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1519 if (mmf_attrs_commit(attrs))
1520 LOGE("failed to commit.\n");
1521 LOGD("Total subtitle tracks = %d \n", count);
1524 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1526 LOGD("value of lang_key is %s and lang_code is %s",
1527 temp->language_key, temp->language_code);
1533 /* custom message */
1534 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1535 MMMessageParamType msg_param = {0,};
1536 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1537 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1542 case GST_MESSAGE_DURATION_CHANGED:
1544 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1545 ret = __mmplayer_gst_handle_duration(player, msg);
1547 LOGW("failed to update duration");
1552 case GST_MESSAGE_ASYNC_START:
1553 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1556 case GST_MESSAGE_ASYNC_DONE:
1558 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1560 /* we only handle messages from pipeline */
1561 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1564 if (player->doing_seek) {
1565 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1566 player->doing_seek = FALSE;
1567 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1568 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1569 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1570 (player->streamer) &&
1571 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1572 (player->streamer->is_buffering == FALSE)) {
1573 GstQuery *query = NULL;
1574 gboolean busy = FALSE;
1577 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1578 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1579 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1580 gst_query_parse_buffering_percent(query, &busy, &percent);
1581 gst_query_unref(query);
1583 LOGD("buffered percent(%s): %d\n",
1584 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1587 if (percent >= 100) {
1588 player->streamer->is_buffering = FALSE;
1589 __mmplayer_handle_buffering_message(player);
1599 #if 0 /* delete unnecessary logs */
1600 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1601 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1602 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1603 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1604 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1605 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1606 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1607 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1608 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1609 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1610 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1611 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1612 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1613 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1614 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1621 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1622 * gst_element_post_message api takes ownership of the message.
1624 //gst_message_unref(msg);
1630 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1636 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1637 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1639 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1640 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1641 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1643 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1644 LOGD("data total size of http content: %lld", bytes);
1645 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1648 /* handling audio clip which has vbr. means duration is keep changing */
1649 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1658 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1661 /* macro for better code readability */
1662 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1663 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1664 if (string != NULL) {\
1665 SECURE_LOGD("update tag string : %s\n", string); \
1666 mm_attrs_set_string_by_name(attribute, playertag, string); \
1672 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1673 GstSample *sample = NULL;\
1674 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1675 GstMapInfo info = GST_MAP_INFO_INIT;\
1676 buffer = gst_sample_get_buffer(sample);\
1677 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1678 LOGD("failed to get image data from tag");\
1681 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1682 MMPLAYER_FREEIF(player->album_art);\
1683 player->album_art = (gchar *)g_malloc(info.size);\
1684 if (player->album_art) {\
1685 memcpy(player->album_art, info.data, info.size);\
1686 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1687 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1688 msg_param.data = (void *)player->album_art;\
1689 msg_param.size = info.size;\
1690 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1691 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1694 gst_buffer_unmap(buffer, &info);\
1697 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1698 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1700 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1701 if (player->updated_bitrate_count == 0) \
1702 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1703 if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1704 player->bitrate[player->updated_bitrate_count] = v_uint;\
1705 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1706 player->updated_bitrate_count++; \
1707 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1708 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1711 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1712 if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1713 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1714 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1715 player->updated_maximum_bitrate_count++; \
1716 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1717 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1720 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1725 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1726 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1727 if (date != NULL) {\
1728 string = g_strdup_printf("%d", g_date_get_year(date));\
1729 mm_attrs_set_string_by_name(attribute, playertag, string);\
1730 SECURE_LOGD("metainfo year : %s\n", string);\
1731 MMPLAYER_FREEIF(string);\
1736 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1737 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1739 /* FIXIT : don't know how to store date */\
1745 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1746 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1748 /* FIXIT : don't know how to store date */\
1754 /* function start */
1755 GstTagList* tag_list = NULL;
1757 MMHandleType attrs = 0;
1759 char *string = NULL;
1763 GstBuffer *buffer = NULL;
1765 MMMessageParamType msg_param = {0, };
1767 /* currently not used. but those are needed for above macro */
1768 //guint64 v_uint64 = 0;
1769 //gdouble v_double = 0;
1771 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1773 attrs = MMPLAYER_GET_ATTRS(player);
1775 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1777 /* get tag list from gst message */
1778 gst_message_parse_tag(msg, &tag_list);
1780 /* store tags to player attributes */
1781 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1782 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1783 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1784 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1785 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1786 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1787 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1788 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1789 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1790 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1791 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1792 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1793 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1794 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1795 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1796 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1797 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1798 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1799 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1800 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1801 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1802 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1803 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1804 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1805 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1806 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1807 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1808 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1809 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1810 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1811 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1812 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1813 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1814 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1815 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1816 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1817 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1818 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1819 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1820 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1821 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1822 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1823 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1824 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1825 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1826 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1828 if (mmf_attrs_commit(attrs))
1829 LOGE("failed to commit.\n");
1831 gst_tag_list_free(tag_list);
1837 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) // @
1839 mm_player_t* player = (mm_player_t*) data;
1843 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1844 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1845 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1846 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1848 * [1] audio and video will be dumped with filesink.
1849 * [2] autoplugging is done by just using pad caps.
1850 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1851 * and the video will be dumped via filesink.
1853 if (player->num_dynamic_pad == 0) {
1854 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1856 if (!__mmplayer_gst_remove_fakesink(player,
1857 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1858 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1859 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1860 * source element are not same. To overcome this situation, this function will called
1861 * several places and several times. Therefore, this is not an error case.
1866 /* create dot before error-return. for debugging */
1867 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1869 player->no_more_pad = TRUE;
1875 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1877 GstElement* parent = NULL;
1879 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1881 /* if we have no fakesink. this meas we are using decodebin which doesn'
1882 t need to add extra fakesink */
1883 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
1886 MMPLAYER_FSINK_LOCK(player);
1891 /* get parent of fakesink */
1892 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
1894 LOGD("fakesink already removed\n");
1898 gst_element_set_locked_state(fakesink->gst, TRUE);
1900 /* setting the state to NULL never returns async
1901 * so no need to wait for completion of state transiton
1903 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
1904 LOGE("fakesink state change failure!\n");
1905 /* FIXIT : should I return here? or try to proceed to next? */
1908 /* remove fakesink from it's parent */
1909 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
1910 LOGE("failed to remove fakesink\n");
1912 gst_object_unref(parent);
1917 gst_object_unref(parent);
1919 LOGD("state-holder removed\n");
1921 gst_element_set_locked_state(fakesink->gst, FALSE);
1923 MMPLAYER_FSINK_UNLOCK(player);
1928 gst_element_set_locked_state(fakesink->gst, FALSE);
1930 MMPLAYER_FSINK_UNLOCK(player);
1936 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
1938 GstPad *sinkpad = NULL;
1939 GstCaps* caps = NULL;
1940 GstElement* new_element = NULL;
1941 GstStructure* str = NULL;
1942 const gchar* name = NULL;
1944 mm_player_t* player = (mm_player_t*) data;
1948 MMPLAYER_RETURN_IF_FAIL(element && pad);
1949 MMPLAYER_RETURN_IF_FAIL(player &&
1951 player->pipeline->mainbin);
1954 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
1955 * num_dynamic_pad will decreased after creating a sinkbin.
1957 player->num_dynamic_pad++;
1958 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
1960 caps = gst_pad_query_caps(pad, NULL);
1962 MMPLAYER_CHECK_NULL(caps);
1964 /* clear previous result*/
1965 player->have_dynamic_pad = FALSE;
1967 str = gst_caps_get_structure(caps, 0);
1970 LOGE("cannot get structure from caps.\n");
1974 name = gst_structure_get_name(str);
1976 LOGE("cannot get mimetype from structure.\n");
1980 if (strstr(name, "video")) {
1982 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1984 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
1985 if (player->v_stream_caps) {
1986 gst_caps_unref(player->v_stream_caps);
1987 player->v_stream_caps = NULL;
1990 new_element = gst_element_factory_make("fakesink", NULL);
1991 player->num_dynamic_pad--;
1996 /* clear previous result*/
1997 player->have_dynamic_pad = FALSE;
1999 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2000 LOGE("failed to autoplug for caps");
2004 /* check if there's dynamic pad*/
2005 if (player->have_dynamic_pad) {
2006 LOGE("using pad caps assums there's no dynamic pad !\n");
2010 gst_caps_unref(caps);
2015 /* excute new_element if created*/
2017 LOGD("adding new element to pipeline\n");
2019 /* set state to READY before add to bin */
2020 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2022 /* add new element to the pipeline */
2023 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2024 LOGE("failed to add autoplug element to bin\n");
2028 /* get pad from element */
2029 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2031 LOGE("failed to get sinkpad from autoplug element\n");
2036 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2037 LOGE("failed to link autoplug element\n");
2041 gst_object_unref(sinkpad);
2044 /* run. setting PLAYING here since streamming source is live source */
2045 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2052 STATE_CHANGE_FAILED:
2054 /* FIXIT : take care if new_element has already added to pipeline */
2056 gst_object_unref(GST_OBJECT(new_element));
2059 gst_object_unref(GST_OBJECT(sinkpad));
2062 gst_object_unref(GST_OBJECT(caps));
2064 /* FIXIT : how to inform this error to MSL ????? */
2065 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2066 * then post an error to application
2072 /* FIXIT : check indent */
2075 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2077 GstPad *sinkpad = NULL;
2078 GstCaps* caps = NULL;
2079 GstElement* new_element = NULL;
2080 enum MainElementID element_id = MMPLAYER_M_NUM;
2082 mm_player_t* player = (mm_player_t*) data;
2086 MMPLAYER_RETURN_IF_FAIL(element && pad);
2087 MMPLAYER_RETURN_IF_FAIL(player &&
2089 player->pipeline->mainbin);
2091 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2094 LOGD("using pad caps to autopluging instead of doing typefind\n");
2095 caps = gst_pad_query_caps(pad);
2096 MMPLAYER_CHECK_NULL(caps);
2097 /* clear previous result*/
2098 player->have_dynamic_pad = FALSE;
2099 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2101 LOGE("failed to create wfd rtp depay element\n");
2104 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2105 /* add new element to the pipeline */
2106 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2107 LOGD("failed to add autoplug element to bin\n");
2110 /* get pad from element */
2111 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2113 LOGD("failed to get sinkpad from autoplug element\n");
2117 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2118 LOGD("failed to link autoplug element\n");
2121 gst_object_unref(sinkpad);
2123 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2124 caps = gst_pad_query_caps(pad);
2125 MMPLAYER_CHECK_NULL(caps);
2126 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2127 /* create typefind */
2128 new_element = gst_element_factory_make("typefind", NULL);
2130 LOGD("failed to create typefind\n");
2134 MMPLAYER_SIGNAL_CONNECT(player,
2135 G_OBJECT(new_element),
2136 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2138 G_CALLBACK(__mmplayer_typefind_have_type),
2141 player->have_dynamic_pad = FALSE;
2144 /* excute new_element if created*/
2146 LOGD("adding new element to pipeline\n");
2148 /* set state to READY before add to bin */
2149 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2151 /* add new element to the pipeline */
2152 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2153 LOGD("failed to add autoplug element to bin\n");
2157 /* get pad from element */
2158 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2160 LOGD("failed to get sinkpad from autoplug element\n");
2165 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2166 LOGD("failed to link autoplug element\n");
2170 gst_object_unref(sinkpad);
2173 /* run. setting PLAYING here since streamming source is live source */
2174 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2177 /* store handle to futher manipulation */
2178 player->pipeline->mainbin[element_id].id = element_id;
2179 player->pipeline->mainbin[element_id].gst = new_element;
2185 STATE_CHANGE_FAILED:
2187 /* FIXIT : take care if new_element has already added to pipeline */
2189 gst_object_unref(GST_OBJECT(new_element));
2192 gst_object_unref(GST_OBJECT(sinkpad));
2195 gst_object_unref(GST_OBJECT(caps));
2197 /* FIXIT : how to inform this error to MSL ????? */
2198 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2199 * then post an error to application
2204 static GstPadProbeReturn
2205 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2207 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2208 return GST_PAD_PROBE_OK;
2211 static GstPadProbeReturn
2212 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2214 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2215 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2216 mm_player_t* player = (mm_player_t*)data;
2217 GstCaps* caps = NULL;
2218 GstStructure* str = NULL;
2219 const gchar* name = NULL;
2220 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2222 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2223 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2224 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT)
2227 caps = gst_pad_query_caps(pad, NULL);
2229 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2233 str = gst_caps_get_structure(caps, 0);
2235 LOGE("failed to get structure from caps");
2239 name = gst_structure_get_name(str);
2241 LOGE("failed to get name from str");
2245 if (strstr(name, "audio")) {
2246 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2247 } else if (strstr(name, "video")) {
2248 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2250 /* text track is not supportable */
2251 LOGE("invalid name %s", name);
2255 LOGD("stream type is %d", stream_type);
2257 switch (GST_EVENT_TYPE(event)) {
2258 case GST_EVENT_STREAM_START:
2260 gint64 stop_running_time = 0;
2261 gint64 position_running_time = 0;
2262 gint64 position = 0;
2265 LOGD("[%d] GST_EVENT_STREAM_START", stream_type);
2267 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2268 if ((player->gapless.update_segment[idx] == TRUE) ||
2269 !(player->selector[idx].event_probe_id)) {
2270 LOGW("[%d] skip", idx);
2274 if (player->gapless.segment[idx].stop != -1)
2276 gst_segment_to_running_time(&player->gapless.segment[idx],
2277 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2280 gst_segment_to_running_time(&player->gapless.segment[idx],
2281 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2283 position_running_time =
2284 gst_segment_to_running_time(&player->gapless.segment[idx],
2285 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2287 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2288 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2290 GST_TIME_ARGS(stop_running_time),
2291 GST_TIME_ARGS(position_running_time),
2292 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2293 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2295 position_running_time = MAX(position_running_time, stop_running_time);
2296 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2297 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2298 position_running_time = MAX(0, position_running_time);
2299 position = MAX(position, position_running_time);
2302 LOGD("start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2303 GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2304 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2306 player->gapless.start_time[stream_type] += position;
2309 case GST_EVENT_FLUSH_STOP:
2311 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2312 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2313 player->gapless.start_time[stream_type] = 0;
2316 case GST_EVENT_SEGMENT:
2321 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2322 gst_event_copy_segment(event, &segment);
2324 if (segment.format == GST_FORMAT_TIME) {
2325 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2326 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2327 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2328 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2329 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2330 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2332 /* keep the all the segment ev to cover the seeking */
2333 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2334 player->gapless.update_segment[stream_type] = TRUE;
2336 if (!player->gapless.running)
2339 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2341 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2343 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2344 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2345 gst_event_unref(event);
2346 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2356 gst_caps_unref(caps);
2361 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2363 mm_player_t* player = NULL;
2364 GstElement* pipeline = NULL;
2365 GstElement* selector = NULL;
2366 GstElement* fakesink = NULL;
2367 GstCaps* caps = NULL;
2368 GstStructure* str = NULL;
2369 const gchar* name = NULL;
2370 GstPad* sinkpad = NULL;
2371 GstPad* srcpad = NULL;
2372 gboolean first_track = FALSE;
2374 enum MainElementID elemId = MMPLAYER_M_NUM;
2375 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2378 player = (mm_player_t*)data;
2380 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2381 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2383 //LOGD("pad-added signal handling\n");
2385 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2387 /* get mimetype from caps */
2388 caps = gst_pad_query_caps(pad, NULL);
2390 LOGE("cannot get caps from pad.\n");
2394 str = gst_caps_get_structure(caps, 0);
2396 LOGE("cannot get structure from caps.\n");
2400 name = gst_structure_get_name(str);
2402 LOGE("cannot get mimetype from structure.\n");
2406 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2407 //LOGD("detected mimetype : %s\n", name);
2409 if (strstr(name, "video")) {
2411 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2413 /* don't make video because of not required, and not support multiple track */
2414 if (stype == MM_DISPLAY_SURFACE_NULL) {
2415 LOGD("no video sink by null surface");
2416 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2417 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2419 /* acquire resources for video playing */
2420 if (resource_state == RESOURCE_STATE_PREPARED) {
2421 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2423 LOGE("could not acquire resources for video playing\n");
2424 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2430 gchar *caps_str = gst_caps_to_string(caps);
2431 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2432 player->set_mode.video_zc = TRUE;
2434 MMPLAYER_FREEIF(caps_str);
2436 if (player->v_stream_caps) {
2437 gst_caps_unref(player->v_stream_caps);
2438 player->v_stream_caps = NULL;
2441 LOGD("create fakesink instead of videobin");
2444 fakesink = gst_element_factory_make("fakesink", NULL);
2445 if (fakesink == NULL) {
2446 LOGE("ERROR : fakesink create error\n");
2450 if (player->ini.set_dump_element_flag)
2451 __mmplayer_add_dump_buffer_probe(player, fakesink);
2453 player->video_fakesink = fakesink;
2455 /* store it as it's sink element */
2456 __mmplayer_add_sink(player, player->video_fakesink);
2458 gst_bin_add(GST_BIN(pipeline), fakesink);
2461 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2463 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2464 LOGW("failed to link fakesink\n");
2465 gst_object_unref(GST_OBJECT(fakesink));
2469 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2470 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2471 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2474 if (player->set_mode.media_packet_video_stream) {
2475 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2477 MMPLAYER_SIGNAL_CONNECT(player,
2479 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2481 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2484 MMPLAYER_SIGNAL_CONNECT(player,
2486 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2488 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2492 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2493 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2497 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2498 __mmplayer_gst_decode_callback(elem, pad, player);
2502 LOGD("video selector \n");
2503 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2504 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2506 if (strstr(name, "audio")) {
2507 gint samplerate = 0;
2510 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2511 __mmplayer_gst_decode_callback(elem, pad, player);
2515 LOGD("audio selector \n");
2516 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2517 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2519 gst_structure_get_int(str, "rate", &samplerate);
2520 gst_structure_get_int(str, "channels", &channels);
2522 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2524 fakesink = gst_element_factory_make("fakesink", NULL);
2525 if (fakesink == NULL) {
2526 LOGE("ERROR : fakesink create error\n");
2530 gst_bin_add(GST_BIN(pipeline), fakesink);
2533 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2535 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2536 LOGW("failed to link fakesink\n");
2537 gst_object_unref(GST_OBJECT(fakesink));
2541 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2542 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2543 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2547 } else if (strstr(name, "text")) {
2548 LOGD("text selector \n");
2549 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2550 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2552 LOGE("wrong elem id \n");
2557 selector = player->pipeline->mainbin[elemId].gst;
2558 if (selector == NULL) {
2559 selector = gst_element_factory_make("input-selector", NULL);
2560 LOGD("Creating input-selector\n");
2561 if (selector == NULL) {
2562 LOGE("ERROR : input-selector create error\n");
2565 g_object_set(selector, "sync-streams", TRUE, NULL);
2567 player->pipeline->mainbin[elemId].id = elemId;
2568 player->pipeline->mainbin[elemId].gst = selector;
2571 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2573 srcpad = gst_element_get_static_pad(selector, "src");
2575 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2576 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2577 __mmplayer_gst_selector_blocked, NULL, NULL);
2578 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2579 __mmplayer_gst_selector_event_probe, player, NULL);
2581 gst_element_set_state(selector, GST_STATE_PAUSED);
2582 gst_bin_add(GST_BIN(pipeline), selector);
2584 LOGD("input-selector is already created.\n");
2587 LOGD("Calling request pad with selector %p \n", selector);
2588 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2590 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2592 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2593 LOGW("failed to link selector\n");
2594 gst_object_unref(GST_OBJECT(selector));
2599 LOGD("this is first track --> active track \n");
2600 g_object_set(selector, "active-pad", sinkpad, NULL);
2603 _mmplayer_track_update_info(player, stream_type, sinkpad);
2610 gst_caps_unref(caps);
2613 gst_object_unref(GST_OBJECT(sinkpad));
2618 gst_object_unref(GST_OBJECT(srcpad));
2625 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2627 GstPad* srcpad = NULL;
2628 MMHandleType attrs = 0;
2629 gint active_index = 0;
2631 // [link] input-selector :: textbin
2632 srcpad = gst_element_get_static_pad(text_selector, "src");
2634 LOGE("failed to get srcpad from selector\n");
2638 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2640 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2641 if ((active_index != DEFAULT_TRACK) &&
2642 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2643 LOGW("failed to change text track\n");
2644 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2647 player->no_more_pad = TRUE;
2648 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2650 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2651 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2652 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2653 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2656 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2658 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2659 player->has_closed_caption = TRUE;
2661 attrs = MMPLAYER_GET_ATTRS(player);
2663 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2664 if (mmf_attrs_commit(attrs))
2665 LOGE("failed to commit.\n");
2667 LOGE("cannot get content attribute");
2670 gst_object_unref(GST_OBJECT(srcpad));
2675 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2677 int result = MM_ERROR_NONE;
2679 mm_player_t* player = (mm_player_t*)hplayer;
2680 MMPlayerGstElement* mainbin = NULL;
2681 gchar* change_pad_name = NULL;
2682 GstPad* sinkpad = NULL;
2683 GstCaps* caps = NULL;
2687 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2689 LOGD("Change Audio mode to %d\n", ch_idx);
2690 player->use_deinterleave = TRUE;
2692 if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2693 LOGD("pre setting : %d\n", ch_idx);
2695 player->audio_mode.active_pad_index = ch_idx;
2699 mainbin = player->pipeline->mainbin;
2701 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2702 if (player->max_audio_channels < 2) {
2703 LOGD("mono channel track only\n");
2707 LOGW("selector doesn't exist\n");
2708 return result; /* keep playing */
2711 LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2713 if (player->audio_mode.total_track_num < 2) {
2714 LOGW("there is no another audio path\n");
2715 return result; /* keep playing */
2718 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2719 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2720 return result; /* keep playing */
2723 /*To get the new pad from the selector*/
2724 change_pad_name = g_strdup_printf("sink%d", ch_idx);
2725 if (change_pad_name == NULL) {
2726 LOGW("Pad does not exists\n");
2727 goto ERROR; /* keep playing */
2730 LOGD("new active pad name: %s\n", change_pad_name);
2732 sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2733 if (sinkpad == NULL)
2734 //result = MM_ERROR_PLAYER_INTERNAL;
2735 goto ERROR; /* keep playing */
2737 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2738 g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2740 caps = gst_pad_get_current_caps(sinkpad);
2741 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2743 __mmplayer_set_audio_attrs(player, caps);
2744 player->audio_mode.active_pad_index = ch_idx;
2749 gst_object_unref(sinkpad);
2751 MMPLAYER_FREEIF(change_pad_name);
2760 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2762 mm_player_t* player = (mm_player_t*)data;
2763 GstElement* selector = NULL;
2764 GstElement* queue = NULL;
2766 GstPad* srcpad = NULL;
2767 GstPad* sinkpad = NULL;
2768 gchar* caps_str = NULL;
2771 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2773 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2774 LOGD("deinterleave new caps : %s\n", caps_str);
2775 MMPLAYER_FREEIF(caps_str);
2777 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2778 LOGE("ERROR : queue create error\n");
2782 g_object_set(G_OBJECT(queue),
2783 "max-size-buffers", 10,
2784 "max-size-bytes", 0,
2785 "max-size-time", (guint64)0,
2788 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2791 LOGE("there is no audio channel selector.\n");
2795 srcpad = gst_element_get_static_pad(queue, "src");
2796 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2798 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2800 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2801 LOGW("failed to link deinterleave - selector\n");
2805 gst_element_set_state(queue, GST_STATE_PAUSED);
2806 player->audio_mode.total_track_num++;
2811 gst_object_unref(GST_OBJECT(srcpad));
2816 gst_object_unref(GST_OBJECT(sinkpad));
2825 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2827 mm_player_t* player = NULL;
2828 GstElement* selector = NULL;
2829 GstPad* sinkpad = NULL;
2830 gint active_index = 0;
2831 gchar* change_pad_name = NULL;
2832 GstCaps* caps = NULL; // no need to unref
2833 gint default_audio_ch = 0;
2836 player = (mm_player_t*) data;
2838 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2841 LOGE("there is no audio channel selector.\n");
2845 active_index = player->audio_mode.active_pad_index;
2847 if (active_index != default_audio_ch) {
2848 gint audio_ch = default_audio_ch;
2850 /*To get the new pad from the selector*/
2851 change_pad_name = g_strdup_printf("sink%d", active_index);
2852 if (change_pad_name != NULL) {
2853 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2854 if (sinkpad != NULL) {
2855 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2856 g_object_set(selector, "active-pad", sinkpad, NULL);
2858 audio_ch = active_index;
2860 caps = gst_pad_get_current_caps(sinkpad);
2861 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2863 __mmplayer_set_audio_attrs(player, caps);
2865 MMPLAYER_FREEIF(change_pad_name);
2868 player->audio_mode.active_pad_index = audio_ch;
2869 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2875 gst_object_unref(sinkpad);
2882 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2884 mm_player_t* player = NULL;
2885 MMPlayerGstElement *mainbin = NULL;
2887 GstElement* tee = NULL;
2888 GstElement* stereo_queue = NULL;
2889 GstElement* mono_queue = NULL;
2890 GstElement* conv = NULL;
2891 GstElement* filter = NULL;
2892 GstElement* deinterleave = NULL;
2893 GstElement* selector = NULL;
2895 GstPad* srcpad = NULL;
2896 GstPad* selector_srcpad = NULL;
2897 GstPad* sinkpad = NULL;
2898 GstCaps* caps = NULL;
2899 gulong block_id = 0;
2904 player = (mm_player_t*) data;
2906 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2907 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2909 mainbin = player->pipeline->mainbin;
2912 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2913 LOGE("ERROR : tee create error\n");
2917 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2918 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2920 gst_element_set_state(tee, GST_STATE_PAUSED);
2923 srcpad = gst_element_get_request_pad(tee, "src_%u");
2924 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2925 LOGE("ERROR : stereo queue create error\n");
2929 g_object_set(G_OBJECT(stereo_queue),
2930 "max-size-buffers", 10,
2931 "max-size-bytes", 0,
2932 "max-size-time", (guint64)0,
2935 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2936 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2939 gst_object_unref(GST_OBJECT(srcpad));
2943 srcpad = gst_element_get_request_pad(tee, "src_%u");
2945 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2946 LOGE("ERROR : mono queue create error\n");
2950 g_object_set(G_OBJECT(mono_queue),
2951 "max-size-buffers", 10,
2952 "max-size-bytes", 0,
2953 "max-size-time", (guint64)0,
2956 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2957 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2959 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2960 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2963 srcpad = gst_element_get_static_pad(mono_queue, "src");
2964 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2965 LOGE("ERROR : audioconvert create error\n");
2969 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2970 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2974 gst_object_unref(GST_OBJECT(srcpad));
2977 srcpad = gst_element_get_static_pad(conv, "src");
2979 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2980 LOGE("ERROR : capsfilter create error\n");
2984 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2985 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2987 caps = gst_caps_from_string("audio/x-raw-int, "
2988 "width = (int) 16, "
2989 "depth = (int) 16, "
2990 "channels = (int) 2");
2992 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
2993 gst_caps_unref(caps);
2995 gst_element_set_state(conv, GST_STATE_PAUSED);
2996 gst_element_set_state(filter, GST_STATE_PAUSED);
3000 gst_object_unref(GST_OBJECT(srcpad));
3003 srcpad = gst_element_get_static_pad(filter, "src");
3005 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3006 LOGE("ERROR : deinterleave create error\n");
3010 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3012 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3013 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3015 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3016 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3018 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3019 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3022 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3023 if (selector == NULL) {
3024 LOGE("ERROR : audio-selector create error\n");
3028 g_object_set(selector, "sync-streams", TRUE, NULL);
3029 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3031 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3032 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3034 selector_srcpad = gst_element_get_static_pad(selector, "src");
3036 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3038 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3039 __mmplayer_gst_selector_blocked, NULL, NULL);
3042 gst_object_unref(GST_OBJECT(srcpad));
3046 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3047 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3049 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3050 LOGW("failed to link queue_stereo - selector\n");
3054 player->audio_mode.total_track_num++;
3056 g_object_set(selector, "active-pad", sinkpad, NULL);
3057 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3058 gst_element_set_state(selector, GST_STATE_PAUSED);
3060 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3064 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3065 if (block_id != 0) {
3066 gst_pad_remove_probe(selector_srcpad, block_id);
3071 gst_object_unref(GST_OBJECT(sinkpad));
3076 gst_object_unref(GST_OBJECT(srcpad));
3080 if (selector_srcpad) {
3081 gst_object_unref(GST_OBJECT(selector_srcpad));
3082 selector_srcpad = NULL;
3090 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3092 mm_player_t* player = NULL;
3093 GstPad* srcpad = NULL;
3094 GstElement* video_selector = NULL;
3095 GstElement* audio_selector = NULL;
3096 GstElement* text_selector = NULL;
3097 MMHandleType attrs = 0;
3098 gint active_index = 0;
3099 gint64 dur_bytes = 0L;
3101 player = (mm_player_t*) data;
3103 LOGD("no-more-pad signal handling\n");
3105 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3106 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3107 LOGW("no need to go more");
3109 if (player->gapless.reconfigure) {
3110 player->gapless.reconfigure = FALSE;
3111 MMPLAYER_PLAYBACK_UNLOCK(player);
3117 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3118 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3119 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3120 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3121 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3123 if (NULL == player->streamer) {
3124 LOGW("invalid state for buffering");
3128 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3129 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3131 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3132 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3134 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3136 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3137 LOGE("fail to get duration.\n");
3139 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3140 // use file information was already set on Q2 when it was created.
3141 __mm_player_streaming_set_queue2(player->streamer,
3142 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3143 TRUE, // use_buffering
3145 init_buffering_time,
3147 player->ini.http_buffering_limit, // high percent
3148 MUXED_BUFFER_TYPE_MEM_QUEUE,
3150 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3153 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3154 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3155 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3156 if (video_selector) {
3157 // [link] input-selector :: videobin
3158 srcpad = gst_element_get_static_pad(video_selector, "src");
3160 LOGE("failed to get srcpad from video selector\n");
3164 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3165 if (!text_selector && !audio_selector)
3166 player->no_more_pad = TRUE;
3168 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3170 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3171 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3172 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3173 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3177 if (audio_selector) {
3178 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3179 if ((active_index != DEFAULT_TRACK) &&
3180 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3181 LOGW("failed to change audio track\n");
3182 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3185 // [link] input-selector :: audiobin
3186 srcpad = gst_element_get_static_pad(audio_selector, "src");
3188 LOGE("failed to get srcpad from selector\n");
3192 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3194 player->no_more_pad = TRUE;
3196 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3197 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3198 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3199 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3200 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3203 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3205 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3207 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3208 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3209 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3210 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3214 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3216 attrs = MMPLAYER_GET_ATTRS(player);
3218 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3219 if (mmf_attrs_commit(attrs))
3220 LOGE("failed to commit.\n");
3222 LOGE("cannot get content attribute");
3224 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3225 LOGD("There is no audio track : remove audiobin");
3227 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3228 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3230 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3231 MMPLAYER_FREEIF(player->pipeline->audiobin)
3234 if (player->num_dynamic_pad == 0)
3235 __mmplayer_pipeline_complete(NULL, player);
3238 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3240 __mmplayer_handle_text_decode_path(player, text_selector);
3247 gst_object_unref(GST_OBJECT(srcpad));
3251 if (player->gapless.reconfigure) {
3252 player->gapless.reconfigure = FALSE;
3253 MMPLAYER_PLAYBACK_UNLOCK(player);
3258 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3260 mm_player_t* player = NULL;
3261 MMHandleType attrs = 0;
3262 GstElement* pipeline = NULL;
3263 GstCaps* caps = NULL;
3264 gchar* caps_str = NULL;
3265 GstStructure* str = NULL;
3266 const gchar* name = NULL;
3267 GstPad* sinkpad = NULL;
3268 GstElement* sinkbin = NULL;
3269 gboolean reusing = FALSE;
3270 GstElement *text_selector = NULL;
3271 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3274 player = (mm_player_t*) data;
3276 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3277 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3279 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3281 attrs = MMPLAYER_GET_ATTRS(player);
3283 LOGE("cannot get content attribute\n");
3287 /* get mimetype from caps */
3288 caps = gst_pad_query_caps(pad, NULL);
3290 LOGE("cannot get caps from pad.\n");
3293 caps_str = gst_caps_to_string(caps);
3295 str = gst_caps_get_structure(caps, 0);
3297 LOGE("cannot get structure from caps.\n");
3301 name = gst_structure_get_name(str);
3303 LOGE("cannot get mimetype from structure.\n");
3307 //LOGD("detected mimetype : %s\n", name);
3309 if (strstr(name, "audio")) {
3310 if (player->pipeline->audiobin == NULL) {
3311 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3312 LOGE("failed to create audiobin. continuing without audio\n");
3316 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3317 LOGD("creating audiosink bin success\n");
3320 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3321 LOGD("reusing audiobin\n");
3322 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3325 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3326 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3328 player->audiosink_linked = 1;
3330 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3332 LOGE("failed to get pad from sinkbin\n");
3335 } else if (strstr(name, "video")) {
3336 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3337 player->set_mode.video_zc = TRUE;
3339 if (player->pipeline->videobin == NULL) {
3340 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3341 /* get video surface type */
3342 int surface_type = 0;
3343 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3344 LOGD("display_surface_type(%d)\n", surface_type);
3346 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3347 LOGD("not make videobin because it dose not want\n");
3351 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3352 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3353 /* prepare resource manager for video overlay */
3354 if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3355 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3357 LOGE("could not prepare for video_overlay resource\n");
3364 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3366 /* acquire resources for video playing */
3367 if (resource_state == RESOURCE_STATE_PREPARED) {
3368 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3370 LOGE("could not acquire resources for video playing\n");
3371 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3377 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3378 LOGE("failed to create videobin. continuing without video\n");
3382 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3383 LOGD("creating videosink bin success\n");
3386 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3387 LOGD("re-using videobin\n");
3388 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3391 /* FIXIT : track number shouldn't be hardcoded */
3392 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3393 player->videosink_linked = 1;
3395 /* NOTE : intermediate code before doing H/W subtitle compositon */
3396 if (player->use_textoverlay && player->play_subtitle) {
3397 LOGD("using textoverlay for external subtitle");
3398 /* check text bin has created well */
3399 if (player->pipeline && player->pipeline->textbin) {
3400 /* get sinkpad from textoverlay */
3401 sinkpad = gst_element_get_static_pad(
3402 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3405 LOGE("failed to get sink pad from textoverlay");
3409 /* link new pad with textoverlay first */
3410 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3411 LOGE("failed to get pad from sinkbin\n");
3415 gst_object_unref(sinkpad);
3418 /* alright, override pad to textbin.src for futher link */
3419 pad = gst_element_get_static_pad(
3420 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3423 LOGE("failed to get sink pad from textoverlay");
3427 LOGE("should not reach here.");
3432 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3434 LOGE("failed to get pad from sinkbin\n");
3437 } else if (strstr(name, "text")) {
3438 if (player->pipeline->textbin == NULL) {
3439 MMPlayerGstElement* mainbin = NULL;
3441 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
3442 LOGE("failed to create textbin. continuing without text\n");
3446 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3447 LOGD("creating textsink bin success\n");
3449 /* FIXIT : track number shouldn't be hardcoded */
3450 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3452 player->textsink_linked = 1;
3453 LOGI("player->textsink_linked set to 1\n");
3455 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3457 LOGE("failed to get pad from sinkbin\n");
3461 mainbin = player->pipeline->mainbin;
3463 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3464 /* input selector */
3465 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3466 if (!text_selector) {
3467 LOGE("failed to create subtitle input selector element\n");
3470 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3472 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3473 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3476 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3477 LOGE("failed to set state(READY) to sinkbin\n");
3481 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3482 LOGW("failed to add subtitle input selector\n");
3486 LOGD("created element input-selector");
3489 LOGD("already having subtitle input selector");
3490 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3493 if (!player->textsink_linked) {
3494 LOGD("re-using textbin\n");
3497 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3499 player->textsink_linked = 1;
3500 LOGI("player->textsink_linked set to 1\n");
3502 LOGD("ignoring internal subtutle since external subtitle is available");
3505 LOGW("unknown type of elementary stream!ignoring it...\n");
3512 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3513 LOGE("failed to set state(READY) to sinkbin\n");
3517 /* Added for multi audio support to avoid adding audio bin again*/
3519 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3520 LOGE("failed to add sinkbin to pipeline\n");
3526 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3527 LOGE("failed to get pad from sinkbin\n");
3533 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3534 LOGE("failed to set state(PAUSED) to sinkbin\n");
3538 if (text_selector) {
3539 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3540 LOGE("failed to set state(PAUSED) to sinkbin\n");
3546 gst_object_unref(sinkpad);
3550 LOGD("linking sink bin success\n");
3552 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3553 * streaming task. if the task blocked, then buffer will not flow to the next element
3554 *(autoplugging element). so this is special hack for streaming. please try to remove it
3556 /* dec stream count. we can remove fakesink if it's zero */
3557 if (player->num_dynamic_pad)
3558 player->num_dynamic_pad--;
3560 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3562 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3563 __mmplayer_pipeline_complete(NULL, player);
3565 /* FIXIT : please leave a note why this code is needed */
3566 if (MMPLAYER_IS_WFD_STREAMING(player))
3567 player->no_more_pad = TRUE;
3571 MMPLAYER_FREEIF(caps_str);
3574 gst_caps_unref(caps);
3577 gst_object_unref(GST_OBJECT(sinkpad));
3579 /* flusing out new attributes */
3580 if (mmf_attrs_commit(attrs))
3581 LOGE("failed to comit attributes\n");
3587 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3589 int pro_value = 0; // in the case of expection, default will be returned.
3590 int dest_angle = rotation_angle;
3591 int rotation_type = -1;
3593 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3594 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3595 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3597 if (rotation_angle >= 360)
3598 dest_angle = rotation_angle - 360;
3600 /* chech if supported or not */
3601 if (dest_angle % 90) {
3602 LOGD("not supported rotation angle = %d", rotation_angle);
3607 * xvimagesink only (A)
3608 * custom_convert - no xv(e.g. memsink, evasimagesink (B)
3609 * videoflip - avsysmemsink(C)
3611 if (player->set_mode.video_zc) {
3612 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3613 rotation_type = ROTATION_USING_CUSTOM;
3615 rotation_type = ROTATION_USING_SINK;
3617 int surface_type = 0;
3618 rotation_type = ROTATION_USING_FLIP;
3620 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3621 LOGD("check display surface type attribute: %d", surface_type);
3623 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) ||
3624 (surface_type == MM_DISPLAY_SURFACE_EVAS && !strcmp(player->ini.videosink_element_evas, "evaspixmapsink")))
3625 rotation_type = ROTATION_USING_SINK;
3627 rotation_type = ROTATION_USING_FLIP; //C
3629 LOGD("using %d type for rotation", rotation_type);
3632 /* get property value for setting */
3633 switch (rotation_type) {
3634 case ROTATION_USING_SINK: // xvimagesink, pixmap
3636 switch (dest_angle) {
3640 pro_value = 3; // clockwise 90
3646 pro_value = 1; // counter-clockwise 90
3651 case ROTATION_USING_CUSTOM:
3653 gchar *ename = NULL;
3654 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3656 if (g_strrstr(ename, "fimcconvert")) {
3657 switch (dest_angle) {
3661 pro_value = 90; // clockwise 90
3667 pro_value = 270; // counter-clockwise 90
3673 case ROTATION_USING_FLIP: // videoflip
3675 switch (dest_angle) {
3679 pro_value = 1; // clockwise 90
3685 pro_value = 3; // counter-clockwise 90
3692 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3700 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3702 /* check video sinkbin is created */
3703 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3705 player->pipeline->videobin &&
3706 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3707 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3708 MM_ERROR_PLAYER_NOT_INITIALIZED);
3710 return MM_ERROR_NONE;
3714 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3716 int rotation_value = 0;
3717 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3721 /* check video sinkbin is created */
3722 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3725 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3727 /* get rotation value to set */
3728 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3729 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3730 LOGD("set video param : rotate %d", rotation_value);
3734 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3736 MMHandleType attrs = 0;
3740 /* check video sinkbin is created */
3741 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3744 attrs = MMPLAYER_GET_ATTRS(player);
3745 MMPLAYER_RETURN_IF_FAIL(attrs);
3747 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3748 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3749 LOGD("set video param : visible %d", visible);
3753 __mmplayer_video_param_set_display_method(mm_player_t* player)
3755 MMHandleType attrs = 0;
3756 int display_method = 0;
3759 /* check video sinkbin is created */
3760 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3763 attrs = MMPLAYER_GET_ATTRS(player);
3764 MMPLAYER_RETURN_IF_FAIL(attrs);
3766 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3767 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3768 LOGD("set video param : method %d", display_method);
3772 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3774 MMHandleType attrs = 0;
3775 int display_method = 0;
3776 void *handle = NULL;
3778 int wl_window_x = 0;
3779 int wl_window_y = 0;
3780 int wl_window_width = 0;
3781 int wl_window_height = 0;
3784 /* check video sinkbin is created */
3785 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3788 attrs = MMPLAYER_GET_ATTRS(player);
3789 MMPLAYER_RETURN_IF_FAIL(attrs);
3791 /* check roi mode is set */
3792 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3793 if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3794 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3797 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3800 /*It should be set after setting window*/
3801 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3802 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3803 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3804 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3806 /* After setting window handle, set render rectangle */
3807 gst_video_overlay_set_render_rectangle(
3808 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3809 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3810 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3811 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3816 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3818 MMHandleType attrs = 0;
3819 void *handle = NULL;
3821 gboolean use_wl_surface = 0;
3822 void * wl_display = NULL;
3823 GstContext *context = NULL;
3825 /* check video sinkbin is created */
3826 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3829 attrs = MMPLAYER_GET_ATTRS(player);
3830 MMPLAYER_RETURN_IF_FAIL(attrs);
3832 /* common case if using overlay surface */
3833 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3834 mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
3836 if (handle && !use_wl_surface) {
3837 /* default is using wl_surface_id */
3838 unsigned int wl_surface_id = 0;
3839 wl_surface_id = *(int*)handle;
3840 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3841 gst_video_overlay_set_wl_window_wl_surface_id(
3842 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3844 } else if (handle && use_wl_surface) {
3845 /* use wl_surface for legacy_player_test */
3846 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
3848 context = gst_wayland_display_handle_context_new(wl_display);
3850 gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
3852 guintptr wl_surface = (guintptr)handle;
3853 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
3854 gst_video_overlay_set_window_handle(
3855 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3858 /* FIXIT : is it error case? */
3859 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3864 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3866 bool update_all_param = FALSE;
3869 /* check video sinkbin is created */
3870 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3871 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3873 if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
3874 LOGE("can not find waylandsink");
3875 return MM_ERROR_PLAYER_INTERNAL;
3878 LOGD("param_name : %s", param_name);
3879 if (!g_strcmp0(param_name, "update_all_param"))
3880 update_all_param = TRUE;
3882 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3883 __mmplayer_video_param_set_display_overlay(player);
3884 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3885 __mmplayer_video_param_set_display_method(player);
3886 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3887 __mmplayer_video_param_set_render_rectangle(player);
3888 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3889 __mmplayer_video_param_set_display_visible(player);
3890 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3891 __mmplayer_video_param_set_display_rotation(player);
3893 return MM_ERROR_NONE;
3897 __mmplayer_update_evas_videosink_video_param(mm_player_t* player)
3899 MMHandleType attrs = 0;
3900 void *object = NULL;
3902 gboolean visible = TRUE;
3903 int display_method = 0;
3904 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3906 int rotation_value = 0;
3909 /* check video sinkbin is created */
3910 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3911 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3913 attrs = MMPLAYER_GET_ATTRS(player);
3914 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3916 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3918 /* common case if using evas surface */
3919 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
3920 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3921 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
3922 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3924 /* if evasimagesink */
3925 if (!strcmp(player->ini.videosink_element_evas, "evasimagesink")) {
3927 /* if it is evasimagesink, we are not supporting rotation */
3928 if (user_angle != 0) {
3929 mm_attrs_set_int_by_name(attrs, "display_rotation", MM_DISPLAY_ROTATION_NONE);
3930 if (mmf_attrs_commit(attrs)) /* return -1 if error */
3931 LOGE("failed to commit\n");
3932 LOGW("unsupported feature");
3933 return MM_ERROR_NOT_SUPPORT_API;
3935 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3936 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3937 "evas-object", object,
3939 "display-geometry-method", display_method,
3940 "rotate", rotation_value,
3942 LOGD("set video param : method %d", display_method);
3943 LOGD("set video param : evas-object %x, visible %d", object, visible);
3944 LOGD("set video param : evas-object %x, rotate %d", object, rotation_value);
3946 LOGE("no evas object");
3947 return MM_ERROR_PLAYER_INTERNAL;
3951 /* if evasimagesink using converter */
3952 if (player->set_mode.video_zc && player->pipeline->videobin[MMPLAYER_V_CONV].gst) {
3955 int no_scaling = !scaling;
3957 mm_attrs_get_int_by_name(attrs, "display_width", &width);
3958 mm_attrs_get_int_by_name(attrs, "display_height", &height);
3960 /* NOTE: fimcconvert does not manage index of src buffer from upstream src-plugin, decoder gives frame information in output buffer with no ordering */
3961 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "src-rand-idx", TRUE, NULL);
3962 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-buffer-num", 5, NULL);
3965 /* no-scaling order to fimcconvert, original width, height size of media src will be passed to sink plugin */
3966 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst,
3967 "dst-width", 0, /* setting 0, output video width will be media src's width */
3968 "dst-height", 0, /* setting 0, output video height will be media src's height */
3971 /* scaling order to fimcconvert */
3973 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-width", width, NULL);
3975 g_object_set(player->pipeline->videobin[MMPLAYER_V_CONV].gst, "dst-height", height, NULL);
3976 LOGD("set video param : video frame scaling down to width(%d) height(%d)", width, height);
3978 LOGD("set video param : display_evas_do_scaling %d", scaling);
3981 return MM_ERROR_NONE;
3985 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
3987 MMHandleType attrs = 0;
3988 int surface_type = 0;
3989 int ret = MM_ERROR_NONE;
3993 /* check video sinkbin is created */
3994 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3995 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3997 attrs = MMPLAYER_GET_ATTRS(player);
3999 LOGE("cannot get content attribute");
4000 return MM_ERROR_PLAYER_INTERNAL;
4002 LOGD("param_name : %s", param_name);
4004 /* update display surface */
4005 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4006 LOGD("check display surface type attribute: %d", surface_type);
4008 /* configuring display */
4009 switch (surface_type) {
4010 case MM_DISPLAY_SURFACE_OVERLAY:
4012 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4013 if (ret != MM_ERROR_NONE)
4017 case MM_DISPLAY_SURFACE_EVAS:
4019 ret = __mmplayer_update_evas_videosink_video_param(player);
4020 if (ret != MM_ERROR_NONE)
4024 case MM_DISPLAY_SURFACE_NULL:
4029 case MM_DISPLAY_SURFACE_REMOTE:
4038 return MM_ERROR_NONE;
4042 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4044 GList* bucket = element_bucket;
4045 MMPlayerGstElement* element = NULL;
4046 MMPlayerGstElement* prv_element = NULL;
4047 gint successful_link_count = 0;
4051 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4053 prv_element = (MMPlayerGstElement*)bucket->data;
4054 bucket = bucket->next;
4056 for (; bucket; bucket = bucket->next) {
4057 element = (MMPlayerGstElement*)bucket->data;
4059 if (element && element->gst) {
4060 /* If next element is audio appsrc then make a separate audio pipeline */
4061 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4062 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4063 prv_element = element;
4067 if (prv_element && prv_element->gst) {
4068 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4069 LOGD("linking [%s] to [%s] success\n",
4070 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4071 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4072 successful_link_count++;
4074 LOGD("linking [%s] to [%s] failed\n",
4075 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4076 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4082 prv_element = element;
4087 return successful_link_count;
4091 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4093 GList* bucket = element_bucket;
4094 MMPlayerGstElement* element = NULL;
4095 int successful_add_count = 0;
4099 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4100 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4102 for (; bucket; bucket = bucket->next) {
4103 element = (MMPlayerGstElement*)bucket->data;
4105 if (element && element->gst) {
4106 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4107 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4108 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4109 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4112 successful_add_count++;
4118 return successful_add_count;
4121 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4123 mm_player_t* player = (mm_player_t*) data;
4124 GstCaps *caps = NULL;
4125 GstStructure *str = NULL;
4130 MMPLAYER_RETURN_IF_FAIL(pad)
4131 MMPLAYER_RETURN_IF_FAIL(unused)
4132 MMPLAYER_RETURN_IF_FAIL(data)
4134 caps = gst_pad_get_current_caps(pad);
4138 str = gst_caps_get_structure(caps, 0);
4142 name = gst_structure_get_name(str);
4146 LOGD("name = %s\n", name);
4148 if (strstr(name, "audio")) {
4149 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4151 if (player->audio_stream_changed_cb) {
4152 LOGE("call the audio stream changed cb\n");
4153 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4155 } else if (strstr(name, "video")) {
4156 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4158 if (player->video_stream_changed_cb) {
4159 LOGE("call the video stream changed cb\n");
4160 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4167 gst_caps_unref(caps);
4177 * This function is to create audio pipeline for playing.
4179 * @param player [in] handle of player
4181 * @return This function returns zero on success.
4183 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4185 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4186 x_bin[x_id].id = x_id;\
4187 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4188 if (!x_bin[x_id].gst) {\
4189 LOGE("failed to create %s \n", x_factory);\
4193 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4194 x_bin[x_id].id = x_id;\
4195 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4196 if (!x_bin[x_id].gst) {\
4197 LOGE("failed to create %s \n", x_factory);\
4200 if (x_player->ini.set_dump_element_flag)\
4201 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4203 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4204 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
4205 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4206 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4210 /* macro for code readability. just for sinkbin-creation functions */
4211 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4213 x_bin[x_id].id = x_id;\
4214 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4215 if (!x_bin[x_id].gst) {\
4216 LOGE("failed to create %s \n", x_factory);\
4219 if (x_player->ini.set_dump_element_flag)\
4220 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4223 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4227 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4232 MMPLAYER_RETURN_IF_FAIL(player);
4234 if (player->audio_stream_buff_list) {
4235 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4236 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4239 LOGD("[%lld] send remained data.", tmp->channel_mask);
4240 __mmplayer_audio_stream_send_data(player, tmp);
4243 g_free(tmp->pcm_data);
4247 g_list_free(player->audio_stream_buff_list);
4248 player->audio_stream_buff_list = NULL;
4255 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4257 MMPlayerAudioStreamDataType audio_stream = { 0, };
4260 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4262 audio_stream.bitrate = a_buffer->bitrate;
4263 audio_stream.channel = a_buffer->channel;
4264 audio_stream.depth = a_buffer->depth;
4265 audio_stream.is_little_endian = a_buffer->is_little_endian;
4266 audio_stream.channel_mask = a_buffer->channel_mask;
4267 audio_stream.data_size = a_buffer->data_size;
4268 audio_stream.data = a_buffer->pcm_data;
4270 LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param);
4271 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4277 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4279 mm_player_t* player = (mm_player_t*) data;
4284 gint endianness = 0;
4285 guint64 channel_mask = 0;
4286 void *a_data = NULL;
4288 mm_player_audio_stream_buff_t *a_buffer = NULL;
4289 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4293 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4295 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4296 a_data = mapinfo.data;
4297 a_size = mapinfo.size;
4299 GstCaps *caps = gst_pad_get_current_caps(pad);
4300 GstStructure *structure = gst_caps_get_structure(caps, 0);
4302 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4303 gst_structure_get_int(structure, "rate", &rate);
4304 gst_structure_get_int(structure, "channels", &channel);
4305 gst_structure_get_int(structure, "depth", &depth);
4306 gst_structure_get_int(structure, "endianness", &endianness);
4307 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4308 gst_caps_unref(GST_CAPS(caps));
4310 /* In case of the sync is false, use buffer list. *
4311 * The num of buffer list depends on the num of audio channels */
4312 if (player->audio_stream_buff_list) {
4313 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4314 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4316 if (channel_mask == tmp->channel_mask) {
4317 LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
4319 if (tmp->data_size + a_size < tmp->buff_size) {
4320 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4321 tmp->data_size += a_size;
4323 /* send data to client */
4324 __mmplayer_audio_stream_send_data(player, tmp);
4326 if (a_size > tmp->buff_size) {
4327 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4328 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4329 if (tmp->pcm_data == NULL) {
4330 LOGE("failed to realloc data.");
4333 tmp->buff_size = a_size;
4335 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4336 memcpy(tmp->pcm_data, a_data, a_size);
4337 tmp->data_size = a_size;
4342 LOGE("data is empty in list.");
4348 /* create new audio stream data */
4349 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4350 if (a_buffer == NULL) {
4351 LOGE("failed to alloc data.");
4354 a_buffer->bitrate = rate;
4355 a_buffer->channel = channel;
4356 a_buffer->depth = depth;
4357 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4358 a_buffer->channel_mask = channel_mask;
4359 a_buffer->data_size = a_size;
4361 if (!player->audio_stream_sink_sync) {
4362 /* If sync is FALSE, use buffer list to reduce the IPC. */
4363 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4364 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4365 if (a_buffer->pcm_data == NULL) {
4366 LOGE("failed to alloc data.");
4370 memcpy(a_buffer->pcm_data, a_data, a_size);
4371 LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
4372 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4374 /* If sync is TRUE, send data directly. */
4375 a_buffer->pcm_data = a_data;
4376 __mmplayer_audio_stream_send_data(player, a_buffer);
4381 gst_buffer_unmap(buffer, &mapinfo);
4386 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4388 mm_player_t* player = (mm_player_t*)data;
4389 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4390 GstPad* sinkpad = NULL;
4391 GstElement *queue = NULL, *sink = NULL;
4394 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4396 queue = gst_element_factory_make("queue", NULL);
4397 if (queue == NULL) {
4398 LOGD("fail make queue\n");
4402 sink = gst_element_factory_make("fakesink", NULL);
4404 LOGD("fail make fakesink\n");
4408 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4410 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4411 LOGW("failed to link queue & sink\n");
4415 sinkpad = gst_element_get_static_pad(queue, "sink");
4417 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4418 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4422 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4424 gst_object_unref(sinkpad);
4425 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4426 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4428 gst_element_set_state(sink, GST_STATE_PAUSED);
4429 gst_element_set_state(queue, GST_STATE_PAUSED);
4431 MMPLAYER_SIGNAL_CONNECT(player,
4433 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4435 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4442 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4444 gst_object_unref(GST_OBJECT(queue));
4448 gst_object_unref(GST_OBJECT(sink));
4452 gst_object_unref(GST_OBJECT(sinkpad));
4459 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4461 #define MAX_PROPS_LEN 64
4462 gint latency_mode = 0;
4463 gchar *stream_type = NULL;
4464 gchar *latency = NULL;
4466 gchar stream_props[MAX_PROPS_LEN] = {0,};
4467 GstStructure *props = NULL;
4470 * It should be set after player creation through attribute.
4471 * But, it can not be changed during playing.
4474 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4475 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4478 LOGE("stream_type is null.\n");
4480 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4481 props = gst_structure_from_string(stream_props, NULL);
4482 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4483 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4486 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4488 switch (latency_mode) {
4489 case AUDIO_LATENCY_MODE_LOW:
4490 latency = g_strndup("low", 3);
4492 case AUDIO_LATENCY_MODE_MID:
4493 latency = g_strndup("mid", 3);
4495 case AUDIO_LATENCY_MODE_HIGH:
4496 latency = g_strndup("high", 4);
4500 #if 0 //need to check
4501 if (player->sound_focus.user_route_policy != 0)
4502 route_path = player->sound_focus.user_route_policy;
4504 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4505 "latency", latency_mode,
4508 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4509 volume_type, route_path, latency_mode);
4514 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4518 LOGD("audiosink property - latency=%s \n", latency);
4526 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4528 MMPlayerGstElement* first_element = NULL;
4529 MMPlayerGstElement* audiobin = NULL;
4530 MMHandleType attrs = 0;
4532 GstPad *ghostpad = NULL;
4533 GList* element_bucket = NULL;
4534 gboolean link_audio_sink_now = TRUE;
4539 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4542 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4544 LOGE("failed to allocate memory for audiobin\n");
4545 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4548 attrs = MMPLAYER_GET_ATTRS(player);
4551 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4552 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4553 if (!audiobin[MMPLAYER_A_BIN].gst) {
4554 LOGE("failed to create audiobin\n");
4559 player->pipeline->audiobin = audiobin;
4561 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4563 /* Adding audiotp plugin for reverse trickplay feature */
4564 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4567 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4570 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4572 if (player->set_mode.pcm_extraction) {
4573 // pcm extraction only and no sound output
4574 if (player->audio_stream_render_cb_ex) {
4575 char *caps_str = NULL;
4576 GstCaps* caps = NULL;
4577 gchar *format = NULL;
4580 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4582 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4584 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4586 caps = gst_caps_new_simple("audio/x-raw",
4587 "format", G_TYPE_STRING, format,
4588 "rate", G_TYPE_INT, player->pcm_samplerate,
4589 "channels", G_TYPE_INT, player->pcm_channel,
4591 caps_str = gst_caps_to_string(caps);
4592 LOGD("new caps : %s\n", caps_str);
4594 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4597 gst_caps_unref(caps);
4598 MMPLAYER_FREEIF(caps_str);
4600 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4602 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4603 /* raw pad handling signal */
4604 MMPLAYER_SIGNAL_CONNECT(player,
4605 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4606 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4607 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4609 int dst_samplerate = 0;
4610 int dst_channels = 0;
4612 char *caps_str = NULL;
4613 GstCaps* caps = NULL;
4615 /* get conf. values */
4616 mm_attrs_multiple_get(player->attrs,
4618 "pcm_extraction_samplerate", &dst_samplerate,
4619 "pcm_extraction_channels", &dst_channels,
4620 "pcm_extraction_depth", &dst_depth,
4624 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4625 caps = gst_caps_new_simple("audio/x-raw",
4626 "rate", G_TYPE_INT, dst_samplerate,
4627 "channels", G_TYPE_INT, dst_channels,
4628 "depth", G_TYPE_INT, dst_depth,
4630 caps_str = gst_caps_to_string(caps);
4631 LOGD("new caps : %s\n", caps_str);
4633 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4636 gst_caps_unref(caps);
4637 MMPLAYER_FREEIF(caps_str);
4640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4647 //GstCaps* caps = NULL;
4650 /* for logical volume control */
4651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4654 if (player->sound.mute) {
4655 LOGD("mute enabled\n");
4656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4662 caps = gst_caps_from_string("audio/x-raw-int, "
4663 "endianness = (int) LITTLE_ENDIAN, "
4664 "signed = (boolean) true, "
4665 "width = (int) 16, "
4666 "depth = (int) 16");
4667 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4668 gst_caps_unref(caps);
4671 /* chech if multi-chennels */
4672 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4673 GstPad *srcpad = NULL;
4674 GstCaps *caps = NULL;
4676 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4677 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4678 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4679 GstStructure *str = gst_caps_get_structure(caps, 0);
4681 gst_structure_get_int(str, "channels", &channels);
4682 gst_caps_unref(caps);
4684 gst_object_unref(srcpad);
4688 /* audio effect element. if audio effect is enabled */
4689 if ((strcmp(player->ini.audioeffect_element, ""))
4691 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4692 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4694 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4696 if ((!player->bypass_audio_effect)
4697 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4698 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4699 if (!_mmplayer_audio_effect_custom_apply(player))
4700 LOGI("apply audio effect(custom) setting success\n");
4704 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4705 && (player->set_mode.rich_audio))
4706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4708 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4709 if (player->set_mode.rich_audio && channels <= 2)
4710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4713 /* create audio sink */
4714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4720 if (player->videodec_linked && player->ini.use_system_clock) {
4721 LOGD("system clock will be used.\n");
4722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4725 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4726 __mmplayer_gst_set_audiosink_property(player, attrs);
4729 if (audiobin[MMPLAYER_A_SINK].gst) {
4730 GstPad *sink_pad = NULL;
4731 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4732 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4733 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4734 gst_object_unref(GST_OBJECT(sink_pad));
4737 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4739 /* adding created elements to bin */
4740 LOGD("adding created elements to bin\n");
4741 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4742 LOGE("failed to add elements\n");
4746 /* linking elements in the bucket by added order. */
4747 LOGD("Linking elements in the bucket by added order.\n");
4748 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4749 LOGE("failed to link elements\n");
4753 /* get first element's sinkpad for creating ghostpad */
4754 first_element = (MMPlayerGstElement *)element_bucket->data;
4755 if (!first_element) {
4756 LOGE("failed to get first elem\n");
4760 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4762 LOGE("failed to get pad from first element of audiobin\n");
4766 ghostpad = gst_ghost_pad_new("sink", pad);
4768 LOGE("failed to create ghostpad\n");
4772 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4773 LOGE("failed to add ghostpad to audiobin\n");
4777 gst_object_unref(pad);
4779 g_list_free(element_bucket);
4781 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4785 return MM_ERROR_NONE;
4789 LOGD("ERROR : releasing audiobin\n");
4792 gst_object_unref(GST_OBJECT(pad));
4795 gst_object_unref(GST_OBJECT(ghostpad));
4798 g_list_free(element_bucket);
4800 /* release element which are not added to bin */
4801 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4802 /* NOTE : skip bin */
4803 if (audiobin[i].gst) {
4804 GstObject* parent = NULL;
4805 parent = gst_element_get_parent(audiobin[i].gst);
4808 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4809 audiobin[i].gst = NULL;
4811 gst_object_unref(GST_OBJECT(parent));
4815 /* release audiobin with it's childs */
4816 if (audiobin[MMPLAYER_A_BIN].gst)
4817 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4819 MMPLAYER_FREEIF(audiobin);
4821 player->pipeline->audiobin = NULL;
4823 return MM_ERROR_PLAYER_INTERNAL;
4826 static GstPadProbeReturn
4827 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4829 mm_player_t* player = (mm_player_t*) u_data;
4830 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4831 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4833 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4835 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4836 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4838 return GST_PAD_PROBE_OK;
4841 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4843 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4846 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4848 int ret = MM_ERROR_NONE;
4850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4851 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4853 MMPLAYER_VIDEO_BO_LOCK(player);
4855 if (player->video_bo_list) {
4856 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4857 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4858 if (tmp && tmp->bo == bo) {
4860 LOGD("release bo %p", bo);
4861 MMPLAYER_VIDEO_BO_UNLOCK(player);
4862 MMPLAYER_VIDEO_BO_SIGNAL(player);
4867 /* hw codec is running or the list was reset for DRC. */
4868 LOGW("there is no bo list.");
4870 MMPLAYER_VIDEO_BO_UNLOCK(player);
4872 LOGW("failed to find bo %p", bo);
4877 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4882 MMPLAYER_RETURN_IF_FAIL(player);
4884 MMPLAYER_VIDEO_BO_LOCK(player);
4885 if (player->video_bo_list) {
4886 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4887 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4888 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4891 tbm_bo_unref(tmp->bo);
4895 g_list_free(player->video_bo_list);
4896 player->video_bo_list = NULL;
4898 player->video_bo_size = 0;
4899 MMPLAYER_VIDEO_BO_UNLOCK(player);
4906 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4909 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4910 gboolean ret = TRUE;
4912 /* check DRC, if it is, destroy the prev bo list to create again */
4913 if (player->video_bo_size != size) {
4914 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4915 __mmplayer_video_stream_destroy_bo_list(player);
4916 player->video_bo_size = size;
4919 MMPLAYER_VIDEO_BO_LOCK(player);
4921 if ((!player->video_bo_list) ||
4922 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4924 /* create bo list */
4926 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4928 if (player->video_bo_list) {
4929 /* if bo list did not created all, try it again. */
4930 idx = g_list_length(player->video_bo_list);
4931 LOGD("bo list exist(len: %d)", idx);
4934 for (; idx < player->ini.num_of_video_bo; idx++) {
4935 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4937 LOGE("Fail to alloc bo_info.");
4940 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4942 LOGE("Fail to tbm_bo_alloc.");
4946 bo_info->using = FALSE;
4947 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4950 /* update video num buffers */
4951 player->video_num_buffers = idx;
4952 if (idx == player->ini.num_of_video_bo)
4953 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4956 MMPLAYER_VIDEO_BO_UNLOCK(player);
4960 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4964 /* get bo from list*/
4965 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4966 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4967 if (tmp && (tmp->using == FALSE)) {
4968 LOGD("found bo %p to use", tmp->bo);
4970 MMPLAYER_VIDEO_BO_UNLOCK(player);
4975 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4976 MMPLAYER_VIDEO_BO_UNLOCK(player);
4980 if (player->ini.video_bo_timeout <= 0) {
4981 MMPLAYER_VIDEO_BO_WAIT(player);
4983 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4984 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4990 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4992 mm_player_t* player = (mm_player_t*)data;
4994 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4996 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4998 /* not to send prerolled pkt again */
4999 player->video_stream_prerolled = TRUE;
5003 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5005 mm_player_t* player = (mm_player_t*)data;
5006 GstCaps *caps = NULL;
5007 MMPlayerVideoStreamDataType stream;
5008 MMVideoBuffer *video_buffer = NULL;
5009 GstMemory *dataBlock = NULL;
5010 GstMemory *metaBlock = NULL;
5011 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5012 GstStructure *structure = NULL;
5013 const gchar *string_format = NULL;
5014 unsigned int fourcc = 0;
5017 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5019 if (player->video_stream_prerolled) {
5020 player->video_stream_prerolled = FALSE;
5021 LOGD("skip the prerolled pkt not to send it again");
5025 caps = gst_pad_get_current_caps(pad);
5027 LOGE("Caps is NULL.");
5031 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5033 /* clear stream data structure */
5034 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5036 structure = gst_caps_get_structure(caps, 0);
5037 gst_structure_get_int(structure, "width", & (stream.width));
5038 gst_structure_get_int(structure, "height", & (stream.height));
5039 string_format = gst_structure_get_string(structure, "format");
5041 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5042 stream.format = util_get_pixtype(fourcc);
5043 gst_caps_unref(caps);
5047 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5048 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5051 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5052 LOGE("Wrong condition!!");
5056 /* set size and timestamp */
5057 dataBlock = gst_buffer_peek_memory(buffer, 0);
5058 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5059 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5061 /* check zero-copy */
5062 if (player->set_mode.video_zc &&
5063 player->set_mode.media_packet_video_stream &&
5064 gst_buffer_n_memory(buffer) > 1) {
5065 metaBlock = gst_buffer_peek_memory(buffer, 1);
5066 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5067 video_buffer = (MMVideoBuffer *)mapinfo.data;
5070 if (video_buffer) { /* hw codec */
5072 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5073 /* copy pointer of tbm bo, stride, elevation */
5074 memcpy(stream.bo, video_buffer->handle.bo,
5075 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5076 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5077 /* FIXME: need to check this path */
5078 memcpy(stream.data, video_buffer->data,
5079 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5081 memcpy(stream.stride, video_buffer->stride_width,
5082 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5083 memcpy(stream.elevation, video_buffer->stride_height,
5084 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5085 /* set gst buffer */
5086 stream.internal_buffer = buffer;
5087 } else { /* sw codec */
5088 tbm_bo_handle thandle;
5089 int stride = GST_ROUND_UP_4(stream.width);
5090 int elevation = GST_ROUND_UP_2(stream.height);
5094 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5096 LOGE("fail to gst_memory_map");
5100 stream.stride[0] = stride;
5101 stream.elevation[0] = elevation;
5102 if (stream.format == MM_PIXEL_FORMAT_I420) {
5103 stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5104 stream.elevation[1] = stream.elevation[2] = elevation / 2;
5106 LOGE("Not support format %d", stream.format);
5107 gst_memory_unmap(dataBlock, &mapinfo);
5111 size = (stream.stride[0] + stream.stride[1]) * elevation;
5112 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5113 if (!stream.bo[0]) {
5114 LOGE("Fail to tbm_bo_alloc!!");
5115 gst_memory_unmap(dataBlock, &mapinfo);
5118 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5119 if (thandle.ptr && mapinfo.data)
5120 memcpy(thandle.ptr, mapinfo.data, size);
5122 LOGE("data pointer is wrong. dest : %p, src : %p",
5123 thandle.ptr, mapinfo.data);
5124 tbm_bo_unmap(stream.bo[0]);
5127 if (player->video_stream_cb)
5128 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5131 gst_memory_unmap(metaBlock, &mapinfo);
5133 gst_memory_unmap(dataBlock, &mapinfo);
5139 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5141 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5142 gchar* video_csc = "videoconvert"; // default colorspace converter
5143 GList* element_bucket = *bucket;
5145 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5151 if (player->set_mode.video_zc) {
5152 /* ST12 or SN12 , if player use omx, evasimagesink doesn't use videoconvert */
5153 if ((surface_type == MM_DISPLAY_SURFACE_EVAS) && (!strcmp(player->ini.videosink_element_evas, "evasimagesink")))
5154 video_csc = player->ini.videoconverter_element;
5156 video_csc = ""; /* Videosinks don't use videoconvert except evasimagesink which use normal video formats */
5158 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5159 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5160 video_csc = "videoconvert";
5162 if (video_csc && (strcmp(video_csc, ""))) {
5163 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5164 LOGD("using video converter: %s", video_csc);
5167 /* set video rotator */
5168 if (!player->set_mode.video_zc)
5169 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5172 #if !defined(__arm__)
5173 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE, player);
5176 *bucket = element_bucket;
5178 return MM_ERROR_NONE;
5183 return MM_ERROR_PLAYER_INTERNAL;
5187 * This function is to create video pipeline.
5189 * @param player [in] handle of player
5190 * caps [in] src caps of decoder
5191 * surface_type [in] surface type for video rendering
5193 * @return This function returns zero on success.
5195 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5199 * - video overlay surface(arm/x86) : waylandsink
5200 * - evas surface (arm) : evaspixmapsink
5201 * fimcconvert !evasimagesink
5202 * - evas surface (x86) : videoconvertor !videoflip !evasimagesink
5205 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5209 GList*element_bucket = NULL;
5210 MMPlayerGstElement* first_element = NULL;
5211 MMPlayerGstElement* videobin = NULL;
5212 gchar *videosink_element = NULL;
5216 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5219 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5221 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5223 player->pipeline->videobin = videobin;
5225 attrs = MMPLAYER_GET_ATTRS(player);
5227 LOGE("cannot get content attribute");
5228 return MM_ERROR_PLAYER_INTERNAL;
5232 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5233 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5234 if (!videobin[MMPLAYER_V_BIN].gst) {
5235 LOGE("failed to create videobin");
5239 if (!player->set_mode.media_packet_video_stream) {
5240 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5244 /* set video sink */
5245 switch (surface_type) {
5246 case MM_DISPLAY_SURFACE_OVERLAY:
5247 if (strlen(player->ini.videosink_element_overlay) > 0)
5248 videosink_element = player->ini.videosink_element_overlay;
5252 case MM_DISPLAY_SURFACE_EVAS:
5253 if (strlen(player->ini.videosink_element_evas) > 0)
5254 videosink_element = player->ini.videosink_element_evas;
5258 case MM_DISPLAY_SURFACE_NULL:
5259 if (strlen(player->ini.videosink_element_fake) > 0)
5260 videosink_element = player->ini.videosink_element_fake;
5264 case MM_DISPLAY_SURFACE_REMOTE:
5265 if (strlen(player->ini.videosink_element_fake) > 0)
5266 videosink_element = player->ini.videosink_element_fake;
5271 LOGE("unidentified surface type");
5274 LOGD("selected videosink name: %s", videosink_element);
5276 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5278 /* additional setting for sink plug-in */
5279 switch (surface_type) {
5280 case MM_DISPLAY_SURFACE_OVERLAY:
5282 bool use_tbm = player->set_mode.video_zc;
5284 LOGD("selected videosink name: %s", videosink_element);
5286 /* support shard memory with S/W codec on HawkP */
5287 if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5288 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5289 "use-tbm", use_tbm, NULL);
5295 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5298 LOGD("disable last-sample");
5299 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5303 if (player->set_mode.media_packet_video_stream) {
5305 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5307 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5309 MMPLAYER_SIGNAL_CONNECT(player,
5310 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5311 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5313 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5316 MMPLAYER_SIGNAL_CONNECT(player,
5317 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5318 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5320 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5325 case MM_DISPLAY_SURFACE_REMOTE:
5327 if (player->set_mode.media_packet_video_stream) {
5328 LOGE("add data probe at videosink");
5329 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5330 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5332 MMPLAYER_SIGNAL_CONNECT(player,
5333 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5334 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5336 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5339 MMPLAYER_SIGNAL_CONNECT(player,
5340 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5341 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5343 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5352 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5355 if (videobin[MMPLAYER_V_SINK].gst) {
5356 GstPad *sink_pad = NULL;
5357 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5359 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5360 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5361 gst_object_unref(GST_OBJECT(sink_pad));
5363 LOGW("failed to get sink pad from videosink\n");
5366 /* store it as it's sink element */
5367 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5369 /* adding created elements to bin */
5370 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5371 LOGE("failed to add elements\n");
5375 /* Linking elements in the bucket by added order */
5376 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5377 LOGE("failed to link elements\n");
5381 /* get first element's sinkpad for creating ghostpad */
5383 first_element = (MMPlayerGstElement *)element_bucket->data;
5384 if (!first_element) {
5385 LOGE("failed to get first element from bucket\n");
5389 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5391 LOGE("failed to get pad from first element\n");
5395 /* create ghostpad */
5396 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5397 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5398 LOGE("failed to add ghostpad to videobin\n");
5401 gst_object_unref(pad);
5403 /* done. free allocated variables */
5405 g_list_free(element_bucket);
5407 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5411 return MM_ERROR_NONE;
5414 LOGE("ERROR : releasing videobin\n");
5416 g_list_free(element_bucket);
5419 gst_object_unref(GST_OBJECT(pad));
5421 /* release videobin with it's childs */
5422 if (videobin[MMPLAYER_V_BIN].gst)
5423 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5426 MMPLAYER_FREEIF(videobin);
5428 player->pipeline->videobin = NULL;
5430 return MM_ERROR_PLAYER_INTERNAL;
5433 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5435 GList *element_bucket = NULL;
5436 MMPlayerGstElement *textbin = player->pipeline->textbin;
5438 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5439 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5440 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5441 "signal-handoffs", FALSE,
5444 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5445 MMPLAYER_SIGNAL_CONNECT(player,
5446 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5447 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5449 G_CALLBACK(__mmplayer_update_subtitle),
5452 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5453 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5454 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5456 if (!player->play_subtitle) {
5457 LOGD("add textbin sink as sink element of whole pipeline.\n");
5458 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5461 /* adding created elements to bin */
5462 LOGD("adding created elements to bin\n");
5463 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5464 LOGE("failed to add elements\n");
5468 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5469 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5470 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5472 /* linking elements in the bucket by added order. */
5473 LOGD("Linking elements in the bucket by added order.\n");
5474 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5475 LOGE("failed to link elements\n");
5479 /* done. free allocated variables */
5480 g_list_free(element_bucket);
5482 if (textbin[MMPLAYER_T_QUEUE].gst) {
5484 GstPad *ghostpad = NULL;
5486 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5488 LOGE("failed to get video pad of textbin\n");
5489 return MM_ERROR_PLAYER_INTERNAL;
5492 ghostpad = gst_ghost_pad_new("text_sink", pad);
5493 gst_object_unref(pad);
5496 LOGE("failed to create ghostpad of textbin\n");
5500 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5501 LOGE("failed to add ghostpad to textbin\n");
5506 return MM_ERROR_NONE;
5509 g_list_free(element_bucket);
5511 return MM_ERROR_PLAYER_INTERNAL;
5514 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5516 MMPlayerGstElement *textbin = NULL;
5517 GList *element_bucket = NULL;
5522 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5525 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5527 LOGE("failed to allocate memory for textbin\n");
5528 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5532 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5533 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5534 if (!textbin[MMPLAYER_T_BIN].gst) {
5535 LOGE("failed to create textbin\n");
5540 player->pipeline->textbin = textbin;
5543 if (player->use_textoverlay) {
5544 LOGD("use textoverlay for displaying \n");
5546 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5548 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5550 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5552 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5554 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5555 LOGE("failed to link queue and converter\n");
5559 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5560 LOGE("failed to link queue and textoverlay\n");
5564 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5565 LOGE("failed to link queue and textoverlay\n");
5569 int surface_type = 0;
5571 LOGD("use subtitle message for displaying \n");
5573 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5575 switch (surface_type) {
5576 case MM_DISPLAY_SURFACE_OVERLAY:
5577 case MM_DISPLAY_SURFACE_EVAS:
5578 case MM_DISPLAY_SURFACE_GL:
5579 case MM_DISPLAY_SURFACE_NULL:
5580 case MM_DISPLAY_SURFACE_REMOTE:
5581 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5582 LOGE("failed to make plain text elements\n");
5594 return MM_ERROR_NONE;
5598 LOGD("ERROR : releasing textbin\n");
5600 g_list_free(element_bucket);
5602 /* release element which are not added to bin */
5603 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5604 /* NOTE : skip bin */
5605 if (textbin[i].gst) {
5606 GstObject* parent = NULL;
5607 parent = gst_element_get_parent(textbin[i].gst);
5610 gst_object_unref(GST_OBJECT(textbin[i].gst));
5611 textbin[i].gst = NULL;
5613 gst_object_unref(GST_OBJECT(parent));
5617 /* release textbin with it's childs */
5618 if (textbin[MMPLAYER_T_BIN].gst)
5619 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5621 MMPLAYER_FREEIF(textbin);
5623 player->pipeline->textbin = NULL;
5625 return MM_ERROR_PLAYER_INTERNAL;
5630 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5632 MMPlayerGstElement* mainbin = NULL;
5633 MMHandleType attrs = 0;
5634 GstElement *subsrc = NULL;
5635 GstElement *subparse = NULL;
5636 gchar *subtitle_uri = NULL;
5637 const gchar *charset = NULL;
5643 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5645 mainbin = player->pipeline->mainbin;
5647 attrs = MMPLAYER_GET_ATTRS(player);
5649 LOGE("cannot get content attribute\n");
5650 return MM_ERROR_PLAYER_INTERNAL;
5653 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5654 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5655 LOGE("subtitle uri is not proper filepath.\n");
5656 return MM_ERROR_PLAYER_INVALID_URI;
5658 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5661 /* create the subtitle source */
5662 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5664 LOGE("failed to create filesrc element\n");
5667 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5669 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5670 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5672 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5673 LOGW("failed to add queue\n");
5678 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5680 LOGE("failed to create subparse element\n");
5684 charset = util_get_charset(subtitle_uri);
5686 LOGD("detected charset is %s\n", charset);
5687 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5690 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5691 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5693 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5694 LOGW("failed to add subparse\n");
5698 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5699 LOGW("failed to link subsrc and subparse\n");
5703 player->play_subtitle = TRUE;
5704 player->adjust_subtitle_pos = 0;
5706 LOGD("play subtitle using subtitle file\n");
5708 if (player->pipeline->textbin == NULL) {
5709 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
5710 LOGE("failed to create textbin. continuing without text\n");
5714 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5715 LOGW("failed to add textbin\n");
5719 LOGD("link text input selector and textbin ghost pad");
5721 player->textsink_linked = 1;
5722 player->external_text_idx = 0;
5723 LOGI("player->textsink_linked set to 1\n");
5725 LOGD("text bin has been created. reuse it.");
5726 player->external_text_idx = 1;
5729 if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5730 LOGW("failed to link subparse and textbin\n");
5734 pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5737 LOGE("failed to get sink pad from textsink to probe data");
5738 return MM_ERROR_PLAYER_INTERNAL;
5741 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5742 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5744 gst_object_unref(pad);
5747 /* create dot. for debugging */
5748 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5751 return MM_ERROR_NONE;
5754 player->textsink_linked = 0;
5755 return MM_ERROR_PLAYER_INTERNAL;
5759 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5761 mm_player_t* player = (mm_player_t*) data;
5762 MMMessageParamType msg = {0, };
5763 GstClockTime duration = 0;
5764 gpointer text = NULL;
5765 guint text_size = 0;
5766 gboolean ret = TRUE;
5767 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5771 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5772 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5774 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5775 text = mapinfo.data;
5776 text_size = mapinfo.size;
5777 duration = GST_BUFFER_DURATION(buffer);
5779 if (player->set_mode.subtitle_off) {
5780 LOGD("subtitle is OFF.\n");
5784 if (!text || (text_size == 0)) {
5785 LOGD("There is no subtitle to be displayed.\n");
5789 msg.data = (void *) text;
5790 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5792 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5794 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5795 gst_buffer_unmap(buffer, &mapinfo);
5802 static GstPadProbeReturn
5803 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5806 mm_player_t *player = (mm_player_t *) u_data;
5807 GstClockTime cur_timestamp = 0;
5808 gint64 adjusted_timestamp = 0;
5809 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5811 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5813 if (player->set_mode.subtitle_off) {
5814 LOGD("subtitle is OFF.\n");
5818 if (player->adjust_subtitle_pos == 0) {
5819 LOGD("nothing to do");
5823 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5824 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5826 if (adjusted_timestamp < 0) {
5827 LOGD("adjusted_timestamp under zero");
5832 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5833 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5834 GST_TIME_ARGS(cur_timestamp),
5835 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5837 return GST_PAD_PROBE_OK;
5839 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5843 /* check player and subtitlebin are created */
5844 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5845 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5847 if (position == 0) {
5848 LOGD("nothing to do\n");
5850 return MM_ERROR_NONE;
5854 case MM_PLAYER_POS_FORMAT_TIME:
5856 /* check current postion */
5857 player->adjust_subtitle_pos = position;
5859 LOGD("save adjust_subtitle_pos in player") ;
5865 LOGW("invalid format.\n");
5867 return MM_ERROR_INVALID_ARGUMENT;
5873 return MM_ERROR_NONE;
5875 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5878 LOGD("adjusting video_pos in player") ;
5879 int current_pos = 0;
5880 /* check player and videobin are created */
5881 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5882 if (!player->pipeline->videobin ||
5883 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5884 LOGD("no video pipeline or sink is there");
5885 return MM_ERROR_PLAYER_INVALID_STATE ;
5888 LOGD("nothing to do\n");
5890 return MM_ERROR_NONE;
5892 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
5893 LOGD("failed to get current position");
5894 return MM_ERROR_PLAYER_INTERNAL;
5896 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5897 LOGD("enter video delay is valid");
5899 LOGD("enter video delay is crossing content boundary");
5900 return MM_ERROR_INVALID_ARGUMENT ;
5902 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5903 LOGD("video delay has been done");
5906 return MM_ERROR_NONE;
5910 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5912 GstElement *appsrc = element;
5913 tBuffer *buf = (tBuffer *)user_data;
5914 GstBuffer *buffer = NULL;
5915 GstFlowReturn ret = GST_FLOW_OK;
5918 MMPLAYER_RETURN_IF_FAIL(element);
5919 MMPLAYER_RETURN_IF_FAIL(buf);
5921 buffer = gst_buffer_new();
5923 if (buf->offset >= buf->len) {
5924 LOGD("call eos appsrc\n");
5925 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
5929 if (buf->len - buf->offset < size)
5930 len = buf->len - buf->offset + buf->offset;
5932 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));
5933 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
5934 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
5936 //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
5937 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
5943 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
5945 tBuffer *buf = (tBuffer *)user_data;
5947 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
5949 buf->offset = (int)size;
5955 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
5957 mm_player_t *player = (mm_player_t*)user_data;
5958 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5959 guint64 current_level_bytes = 0;
5960 MMPLAYER_RETURN_IF_FAIL(player);
5962 LOGI("app-src: feed data\n");
5964 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
5965 if (player->media_stream_buffer_status_cb[type])
5966 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
5970 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
5972 mm_player_t *player = (mm_player_t*)user_data;
5973 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5975 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5977 LOGI("app-src: seek data, offset: %llu\n", offset);
5979 if (player->media_stream_seek_data_cb[type])
5980 player->media_stream_seek_data_cb[type](type, offset, player->buffer_cb_user_param);
5987 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
5989 mm_player_t *player = (mm_player_t*)user_data;
5990 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_DEFAULT;
5991 guint64 current_level_bytes = 0;
5993 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5995 LOGI("app-src: enough data:%p\n", player->media_stream_buffer_status_cb[type]);
5997 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
5999 if (player->media_stream_buffer_status_cb[type])
6000 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
6006 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
6008 mm_player_t* player = (mm_player_t*)hplayer;
6009 GstBuffer *buffer = NULL;
6010 GstFlowReturn gst_ret = GST_FLOW_OK;
6011 int ret = MM_ERROR_NONE;
6016 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6018 /* check current state */
6019 // MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
6022 /* NOTE : we should check and create pipeline again if not created as we destroy
6023 * whole pipeline when stopping in streamming playback
6025 if (!player->pipeline) {
6026 if (MM_ERROR_NONE != __gst_realize(player)) {
6027 LOGE("failed to realize before starting. only in streamming\n");
6028 return MM_ERROR_PLAYER_INTERNAL;
6032 LOGI("app-src: pushing data\n");
6035 LOGE("buf is null\n");
6036 return MM_ERROR_NONE;
6039 buffer = gst_buffer_new();
6042 LOGD("call eos appsrc\n");
6043 g_signal_emit_by_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
6044 return MM_ERROR_NONE;
6047 //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));
6049 LOGD("feed buffer %p, length %u\n", buf, size);
6050 g_signal_emit_by_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
6057 static GstBusSyncReply
6058 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6060 mm_player_t *player = (mm_player_t *)data;
6061 GstBusSyncReply reply = GST_BUS_DROP;
6063 if (!(player->pipeline && player->pipeline->mainbin)) {
6064 LOGE("player pipeline handle is null");
6065 return GST_BUS_PASS;
6068 if (!__mmplayer_check_useful_message(player, message)) {
6069 gst_message_unref(message);
6070 return GST_BUS_DROP;
6073 switch (GST_MESSAGE_TYPE(message)) {
6074 case GST_MESSAGE_STATE_CHANGED:
6075 /* post directly for fast launch */
6076 if (player->sync_handler) {
6077 __mmplayer_gst_callback(NULL, message, player);
6078 reply = GST_BUS_DROP;
6080 reply = GST_BUS_PASS;
6082 case GST_MESSAGE_TAG:
6083 __mmplayer_gst_extract_tag_from_msg(player, message);
6087 GstTagList *tags = NULL;
6089 gst_message_parse_tag(message, &tags);
6091 LOGE("TAGS received from element \"%s\".\n",
6092 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6094 gst_tag_list_foreach(tags, print_tag, NULL);
6095 gst_tag_list_free(tags);
6103 case GST_MESSAGE_DURATION_CHANGED:
6104 __mmplayer_gst_handle_duration(player, message);
6106 case GST_MESSAGE_ASYNC_DONE:
6107 /* NOTE:Don't call gst_callback directly
6108 * because previous frame can be showed even though this message is received for seek.
6111 reply = GST_BUS_PASS;
6115 if (reply == GST_BUS_DROP)
6116 gst_message_unref(message);
6122 __mmplayer_gst_create_decoder(mm_player_t *player,
6123 MMPlayerTrackType track,
6125 enum MainElementID elemId,
6128 gboolean ret = TRUE;
6129 GstPad *sinkpad = NULL;
6133 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6135 player->pipeline->mainbin, FALSE);
6136 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6137 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6138 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6140 GstElement *decodebin = NULL;
6141 GstCaps *dec_caps = NULL;
6143 /* create decodebin */
6144 decodebin = gst_element_factory_make("decodebin", name);
6147 LOGE("error : fail to create decodebin for %d decoder\n", track);
6152 /* raw pad handling signal */
6153 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6154 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6156 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6157 before looking for any elements that can handle that stream.*/
6158 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6159 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6161 /* This signal is emitted when a element is added to the bin.*/
6162 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6163 G_CALLBACK(__mmplayer_gst_element_added), player);
6165 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6166 LOGE("failed to add new decodebin\n");
6171 dec_caps = gst_pad_query_caps(srcpad, NULL);
6173 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6174 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6175 gst_caps_unref(dec_caps);
6178 player->pipeline->mainbin[elemId].id = elemId;
6179 player->pipeline->mainbin[elemId].gst = decodebin;
6181 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6183 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6184 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6185 gst_object_unref(GST_OBJECT(decodebin));
6188 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6189 LOGE("failed to sync second level decodebin state with parent\n");
6191 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6195 gst_object_unref(GST_OBJECT(sinkpad));
6204 * This function is to create audio or video pipeline for playing.
6206 * @param player [in] handle of player
6208 * @return This function returns zero on success.
6213 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6216 MMPlayerGstElement *mainbin = NULL;
6217 MMHandleType attrs = 0;
6218 GstElement* element = NULL;
6219 GstElement* elem_src_audio = NULL;
6220 GstElement* elem_src_subtitle = NULL;
6221 GstElement* es_video_queue = NULL;
6222 GstElement* es_audio_queue = NULL;
6223 GstElement* es_subtitle_queue = NULL;
6224 GList* element_bucket = NULL;
6225 gboolean need_state_holder = TRUE;
6227 #ifdef SW_CODEC_ONLY
6228 int surface_type = 0;
6232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6234 /* get profile attribute */
6235 attrs = MMPLAYER_GET_ATTRS(player);
6237 LOGE("cannot get content attribute\n");
6241 /* create pipeline handles */
6242 if (player->pipeline) {
6243 LOGW("pipeline should be released before create new one\n");
6247 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6248 if (player->pipeline == NULL)
6251 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6254 /* create mainbin */
6255 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6256 if (mainbin == NULL)
6259 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6261 /* create pipeline */
6262 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6263 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6264 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6265 LOGE("failed to create pipeline\n");
6268 player->demux_pad_index = 0;
6269 player->subtitle_language_list = NULL;
6271 player->is_subtitle_force_drop = FALSE;
6272 player->last_multiwin_status = FALSE;
6274 _mmplayer_track_initialize(player);
6276 /* create source element */
6277 switch (player->profile.uri_type) {
6278 /* rtsp streamming */
6279 case MM_PLAYER_URI_TYPE_URL_RTSP:
6281 gint network_bandwidth;
6282 gchar *user_agent, *wap_profile;
6284 element = gst_element_factory_make("rtspsrc", "rtsp source");
6287 LOGE("failed to create streaming source element\n");
6292 network_bandwidth = 0;
6293 user_agent = wap_profile = NULL;
6296 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6297 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6298 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6300 SECURE_LOGD("user_agent : %s\n", user_agent);
6301 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6303 /* setting property to streaming source */
6304 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6306 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6308 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6310 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6311 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6312 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6313 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6315 player->use_decodebin = FALSE;
6320 case MM_PLAYER_URI_TYPE_URL_HTTP:
6322 gchar *user_agent, *proxy, *cookies, **cookie_list;
6323 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6324 user_agent = proxy = cookies = NULL;
6326 gint mode = MM_PLAYER_PD_MODE_NONE;
6328 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6330 player->pd_mode = mode;
6332 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6334 if (!MMPLAYER_IS_HTTP_PD(player)) {
6335 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6337 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6340 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6343 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6344 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6345 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6346 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6348 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6349 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6350 LOGD("get timeout from ini\n");
6351 http_timeout = player->ini.http_timeout;
6355 SECURE_LOGD("location : %s\n", player->profile.uri);
6356 SECURE_LOGD("cookies : %s\n", cookies);
6357 SECURE_LOGD("proxy : %s\n", proxy);
6358 SECURE_LOGD("user_agent : %s\n", user_agent);
6359 LOGD("timeout : %d\n", http_timeout);
6361 /* setting property to streaming source */
6362 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6363 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6364 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6366 /* check if prosy is vailid or not */
6367 if (util_check_valid_url(proxy))
6368 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6369 /* parsing cookies */
6370 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6371 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6373 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6375 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6376 LOGW("it's dash. and it's still experimental feature.");
6378 // progressive download
6379 gchar* location = NULL;
6381 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6384 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6386 MMPLAYER_FREEIF(player->pd_file_save_path);
6388 LOGD("PD Location : %s\n", path);
6391 player->pd_file_save_path = g_strdup(path);
6393 LOGE("can't find pd location so, it should be set \n");
6398 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6400 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6404 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6405 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6407 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6409 g_object_get(element, "location", &location, NULL);
6410 LOGD("PD_LOCATION [%s].\n", location);
6418 case MM_PLAYER_URI_TYPE_FILE:
6421 LOGD("using filesrc for 'file://' handler.\n");
6423 element = gst_element_factory_make("filesrc", "source");
6426 LOGE("failed to create filesrc\n");
6430 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6431 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6435 case MM_PLAYER_URI_TYPE_SS:
6437 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6438 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6440 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6444 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6446 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6447 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6448 LOGD("get timeout from ini\n");
6449 http_timeout = player->ini.http_timeout;
6452 /* setting property to streaming source */
6453 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6454 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6459 case MM_PLAYER_URI_TYPE_BUFF:
6461 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
6463 LOGD("mem src is selected\n");
6465 element = gst_element_factory_make("appsrc", "buff-source");
6467 LOGE("failed to create appsrc element\n");
6471 g_object_set(element, "stream-type", stream_type, NULL);
6472 //g_object_set(element, "size", player->mem_buf.len, NULL);
6473 //g_object_set(element, "blocksize", (guint64)20480, NULL);
6475 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6476 G_CALLBACK(__gst_appsrc_seek_data), player);
6477 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6478 G_CALLBACK(__gst_appsrc_feed_data), player);
6479 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6480 G_CALLBACK(__gst_appsrc_enough_data), player);
6483 case MM_PLAYER_URI_TYPE_MS_BUFF:
6485 LOGD("MS buff src is selected\n");
6487 if (player->v_stream_caps) {
6488 element = gst_element_factory_make("appsrc", "video_appsrc");
6490 LOGF("failed to create video app source element[appsrc].\n");
6494 if (player->a_stream_caps) {
6495 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6496 if (!elem_src_audio) {
6497 LOGF("failed to create audio app source element[appsrc].\n");
6501 } else if (player->a_stream_caps) {
6502 /* no video, only audio pipeline*/
6503 element = gst_element_factory_make("appsrc", "audio_appsrc");
6505 LOGF("failed to create audio app source element[appsrc].\n");
6510 if (player->s_stream_caps) {
6511 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6512 if (!elem_src_subtitle) {
6513 LOGF("failed to create subtitle app source element[appsrc].\n");
6518 LOGD("setting app sources properties.\n");
6519 LOGD("location : %s\n", player->profile.uri);
6521 if (player->v_stream_caps && element) {
6522 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6523 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6524 "caps", player->v_stream_caps, NULL);
6526 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6527 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6528 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6529 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6531 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6532 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6533 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6534 G_CALLBACK(__gst_seek_video_data), player);
6536 if (player->a_stream_caps && elem_src_audio) {
6537 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6538 "caps", player->a_stream_caps, NULL);
6540 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6541 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6542 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6543 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6545 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6546 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6547 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6548 G_CALLBACK(__gst_seek_audio_data), player);
6550 } else if (player->a_stream_caps && element) {
6551 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6552 "caps", player->a_stream_caps, NULL);
6554 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6555 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6559 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6560 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6561 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6562 G_CALLBACK(__gst_seek_audio_data), player);
6565 if (player->s_stream_caps && elem_src_subtitle) {
6566 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6567 "caps", player->s_stream_caps, NULL);
6569 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6570 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6571 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6572 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6574 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6576 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6577 G_CALLBACK(__gst_seek_subtitle_data), player);
6580 if (player->v_stream_caps && element) {
6581 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6582 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6583 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6584 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6586 if (player->a_stream_caps && elem_src_audio) {
6587 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6588 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6589 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6590 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6592 } else if (player->a_stream_caps && element) {
6593 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6594 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6595 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6596 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6599 if (player->s_stream_caps && elem_src_subtitle)
6600 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6601 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6603 need_state_holder = FALSE;
6605 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6606 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6607 LOGE("failed to commit\n");
6611 case MM_PLAYER_URI_TYPE_MEM:
6613 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6615 LOGD("mem src is selected\n");
6617 element = gst_element_factory_make("appsrc", "mem-source");
6619 LOGE("failed to create appsrc element\n");
6623 g_object_set(element, "stream-type", stream_type, NULL);
6624 g_object_set(element, "size", player->mem_buf.len, NULL);
6625 g_object_set(element, "blocksize", (guint64)20480, NULL);
6627 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6628 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6629 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6630 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6633 case MM_PLAYER_URI_TYPE_URL:
6636 case MM_PLAYER_URI_TYPE_TEMP:
6639 case MM_PLAYER_URI_TYPE_NONE:
6644 /* check source element is OK */
6646 LOGE("no source element was created.\n");
6650 /* take source element */
6651 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6652 mainbin[MMPLAYER_M_SRC].gst = element;
6653 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6655 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6656 player->streamer = __mm_player_streaming_create();
6657 __mm_player_streaming_initialize(player->streamer);
6660 if (MMPLAYER_IS_HTTP_PD(player)) {
6661 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6663 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6664 element = gst_element_factory_make("queue2", "queue2");
6666 LOGE("failed to create http streaming buffer element\n");
6671 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6672 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6673 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6675 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6677 __mm_player_streaming_set_queue2(player->streamer,
6680 player->ini.http_max_size_bytes,
6683 player->ini.http_buffering_limit,
6684 MUXED_BUFFER_TYPE_MEM_QUEUE,
6688 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6689 if (player->v_stream_caps) {
6690 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6691 if (!es_video_queue) {
6692 LOGE("create es_video_queue for es player failed\n");
6695 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6696 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6697 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6698 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6700 /* Adding audio appsrc to bucket */
6701 if (player->a_stream_caps && elem_src_audio) {
6702 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6703 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6704 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6706 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6707 if (!es_audio_queue) {
6708 LOGE("create es_audio_queue for es player failed\n");
6711 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6713 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6714 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6715 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6717 } else if (player->a_stream_caps) {
6718 /* Only audio stream, no video */
6719 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6720 if (!es_audio_queue) {
6721 LOGE("create es_audio_queue for es player failed\n");
6724 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6725 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6726 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6729 if (player->s_stream_caps && elem_src_subtitle) {
6730 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6731 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6732 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6734 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6735 if (!es_subtitle_queue) {
6736 LOGE("create es_subtitle_queue for es player failed\n");
6739 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6740 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6741 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6745 /* create autoplugging element if src element is not a rtsp src */
6746 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6747 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6748 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6750 enum MainElementID elemId = MMPLAYER_M_NUM;
6752 if ((player->use_decodebin) &&
6753 ((MMPLAYER_IS_HTTP_PD(player)) ||
6754 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6755 elemId = MMPLAYER_M_AUTOPLUG;
6756 element = __mmplayer_create_decodebin(player);
6757 need_state_holder = FALSE;
6759 elemId = MMPLAYER_M_TYPEFIND;
6760 element = gst_element_factory_make("typefind", "typefinder");
6761 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6762 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6766 /* check autoplug element is OK */
6768 LOGE("can not create element(%d)\n", elemId);
6772 mainbin[elemId].id = elemId;
6773 mainbin[elemId].gst = element;
6775 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6778 /* add elements to pipeline */
6779 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6780 LOGE("Failed to add elements to pipeline\n");
6785 /* linking elements in the bucket by added order. */
6786 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6787 LOGE("Failed to link some elements\n");
6792 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6793 if (need_state_holder) {
6795 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6796 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6798 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6799 LOGE("fakesink element could not be created\n");
6802 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6804 /* take ownership of fakesink. we are reusing it */
6805 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6808 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6809 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6810 LOGE("failed to add fakesink to bin\n");
6815 /* now we have completed mainbin. take it */
6816 player->pipeline->mainbin = mainbin;
6818 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6819 GstPad *srcpad = NULL;
6821 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6822 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6824 __mmplayer_gst_create_decoder(player,
6825 MM_PLAYER_TRACK_TYPE_VIDEO,
6827 MMPLAYER_M_AUTOPLUG_V_DEC,
6830 gst_object_unref(GST_OBJECT(srcpad));
6835 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6836 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6838 __mmplayer_gst_create_decoder(player,
6839 MM_PLAYER_TRACK_TYPE_AUDIO,
6841 MMPLAYER_M_AUTOPLUG_A_DEC,
6844 gst_object_unref(GST_OBJECT(srcpad));
6849 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6850 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6853 /* connect bus callback */
6854 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6856 LOGE("cannot get bus from pipeline.\n");
6860 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6862 player->context.thread_default = g_main_context_get_thread_default();
6864 if (NULL == player->context.thread_default) {
6865 player->context.thread_default = g_main_context_default();
6866 LOGD("thread-default context is the global default context");
6868 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6870 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6871 if (__mmplayer_check_subtitle(player)) {
6872 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6873 LOGE("fail to create subtitle src\n");
6876 /* set sync handler to get tag synchronously */
6877 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6880 gst_object_unref(GST_OBJECT(bus));
6881 g_list_free(element_bucket);
6885 return MM_ERROR_NONE;
6889 __mmplayer_gst_destroy_pipeline(player);
6890 g_list_free(element_bucket);
6893 /* release element which are not added to bin */
6894 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6895 /* NOTE : skip pipeline */
6896 if (mainbin[i].gst) {
6897 GstObject* parent = NULL;
6898 parent = gst_element_get_parent(mainbin[i].gst);
6901 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6902 mainbin[i].gst = NULL;
6904 gst_object_unref(GST_OBJECT(parent));
6908 /* release pipeline with it's childs */
6909 if (mainbin[MMPLAYER_M_PIPE].gst)
6910 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6912 MMPLAYER_FREEIF(mainbin);
6915 MMPLAYER_FREEIF(player->pipeline);
6916 return MM_ERROR_PLAYER_INTERNAL;
6920 __mmplayer_reset_gapless_state(mm_player_t* player)
6923 MMPLAYER_RETURN_IF_FAIL(player
6925 && player->pipeline->audiobin
6926 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6928 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6935 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6938 int ret = MM_ERROR_NONE;
6942 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6944 /* cleanup stuffs */
6945 MMPLAYER_FREEIF(player->type);
6946 player->have_dynamic_pad = FALSE;
6947 player->no_more_pad = FALSE;
6948 player->num_dynamic_pad = 0;
6949 player->demux_pad_index = 0;
6950 player->subtitle_language_list = NULL;
6951 player->use_deinterleave = FALSE;
6952 player->max_audio_channels = 0;
6953 player->video_share_api_delta = 0;
6954 player->video_share_clock_delta = 0;
6955 player->video_hub_download_mode = 0;
6956 __mmplayer_reset_gapless_state(player);
6958 if (player->streamer) {
6959 __mm_player_streaming_deinitialize(player->streamer);
6960 __mm_player_streaming_destroy(player->streamer);
6961 player->streamer = NULL;
6964 /* cleanup unlinked mime type */
6965 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6966 MMPLAYER_FREEIF(player->unlinked_video_mime);
6967 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6969 /* cleanup running stuffs */
6970 __mmplayer_cancel_eos_timer(player);
6972 /* cleanup gst stuffs */
6973 if (player->pipeline) {
6974 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6975 GstTagList* tag_list = player->pipeline->tag_list;
6977 /* first we need to disconnect all signal hander */
6978 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6980 /* disconnecting bus watch */
6981 if (player->bus_watcher)
6982 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6983 player->bus_watcher = 0;
6986 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6987 MMPlayerGstElement* videobin = player->pipeline->videobin;
6988 MMPlayerGstElement* textbin = player->pipeline->textbin;
6989 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6990 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6991 gst_object_unref(bus);
6993 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6994 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6995 if (ret != MM_ERROR_NONE) {
6996 LOGE("fail to change state to NULL\n");
6997 return MM_ERROR_PLAYER_INTERNAL;
7000 LOGW("succeeded in chaning state to NULL\n");
7002 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7005 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7006 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7008 /* free avsysaudiosink
7009 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7010 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7012 MMPLAYER_FREEIF(audiobin);
7013 MMPLAYER_FREEIF(videobin);
7014 MMPLAYER_FREEIF(textbin);
7015 MMPLAYER_FREEIF(mainbin);
7019 gst_tag_list_free(tag_list);
7021 MMPLAYER_FREEIF(player->pipeline);
7023 MMPLAYER_FREEIF(player->album_art);
7025 if (player->v_stream_caps) {
7026 gst_caps_unref(player->v_stream_caps);
7027 player->v_stream_caps = NULL;
7029 if (player->a_stream_caps) {
7030 gst_caps_unref(player->a_stream_caps);
7031 player->a_stream_caps = NULL;
7034 if (player->s_stream_caps) {
7035 gst_caps_unref(player->s_stream_caps);
7036 player->s_stream_caps = NULL;
7038 _mmplayer_track_destroy(player);
7040 if (player->sink_elements)
7041 g_list_free(player->sink_elements);
7042 player->sink_elements = NULL;
7044 if (player->bufmgr) {
7045 tbm_bufmgr_deinit(player->bufmgr);
7046 player->bufmgr = NULL;
7049 LOGW("finished destroy pipeline\n");
7056 static int __gst_realize(mm_player_t* player) // @
7059 int ret = MM_ERROR_NONE;
7063 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7065 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7067 ret = __mmplayer_gst_create_pipeline(player);
7069 LOGE("failed to create pipeline\n");
7073 /* set pipeline state to READY */
7074 /* NOTE : state change to READY must be performed sync. */
7075 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7076 ret = __mmplayer_gst_set_state(player,
7077 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7079 if (ret != MM_ERROR_NONE) {
7080 /* return error if failed to set state */
7081 LOGE("failed to set READY state");
7084 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7086 /* create dot before error-return. for debugging */
7087 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7094 static int __gst_unrealize(mm_player_t* player) // @
7096 int ret = MM_ERROR_NONE;
7100 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7102 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7103 MMPLAYER_PRINT_STATE(player);
7105 /* release miscellaneous information */
7106 __mmplayer_release_misc(player);
7108 /* destroy pipeline */
7109 ret = __mmplayer_gst_destroy_pipeline(player);
7110 if (ret != MM_ERROR_NONE) {
7111 LOGE("failed to destory pipeline\n");
7115 /* release miscellaneous information.
7116 these info needs to be released after pipeline is destroyed. */
7117 __mmplayer_release_misc_post(player);
7119 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7126 static int __gst_pending_seek(mm_player_t* player)
7128 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7129 int ret = MM_ERROR_NONE;
7133 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7135 if (!player->pending_seek.is_pending) {
7136 LOGD("pending seek is not reserved. nothing to do.\n");
7140 /* check player state if player could pending seek or not. */
7141 current_state = MMPLAYER_CURRENT_STATE(player);
7143 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7144 LOGW("try to pending seek in %s state, try next time. \n",
7145 MMPLAYER_STATE_GET_NAME(current_state));
7149 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7151 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7153 if (MM_ERROR_NONE != ret)
7154 LOGE("failed to seek pending postion. just keep staying current position.\n");
7156 player->pending_seek.is_pending = FALSE;
7163 static int __gst_start(mm_player_t* player) // @
7165 gboolean sound_extraction = 0;
7166 int ret = MM_ERROR_NONE;
7167 gboolean async = FALSE;
7171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7173 /* get sound_extraction property */
7174 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7176 /* NOTE : if SetPosition was called before Start. do it now */
7177 /* streaming doesn't support it. so it should be always sync */
7178 /* !!create one more api to check if there is pending seek rather than checking variables */
7179 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7180 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7181 ret = __gst_pause(player, FALSE);
7182 if (ret != MM_ERROR_NONE) {
7183 LOGE("failed to set state to PAUSED for pending seek\n");
7187 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7189 if (sound_extraction) {
7190 LOGD("setting pcm extraction\n");
7192 ret = __mmplayer_set_pcm_extraction(player);
7193 if (MM_ERROR_NONE != ret) {
7194 LOGW("failed to set pcm extraction\n");
7198 if (MM_ERROR_NONE != __gst_pending_seek(player))
7199 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7203 LOGD("current state before doing transition");
7204 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7205 MMPLAYER_PRINT_STATE(player);
7207 /* set pipeline state to PLAYING */
7208 if (player->es_player_push_mode)
7210 /* set pipeline state to PLAYING */
7211 ret = __mmplayer_gst_set_state(player,
7212 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7214 if (ret == MM_ERROR_NONE) {
7215 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7217 LOGE("failed to set state to PLAYING");
7221 /* generating debug info before returning error */
7222 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7229 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7233 MMPLAYER_RETURN_IF_FAIL(player
7235 && player->pipeline->audiobin
7236 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7238 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
7245 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7249 MMPLAYER_RETURN_IF_FAIL(player
7251 && player->pipeline->audiobin
7252 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7254 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
7259 static int __gst_stop(mm_player_t* player) // @
7261 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7262 MMHandleType attrs = 0;
7263 gboolean fadedown = FALSE;
7264 gboolean rewind = FALSE;
7266 int ret = MM_ERROR_NONE;
7268 gboolean async = FALSE;
7272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7273 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7275 LOGD("current state before doing transition");
7276 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7277 MMPLAYER_PRINT_STATE(player);
7279 attrs = MMPLAYER_GET_ATTRS(player);
7281 LOGE("cannot get content attribute\n");
7282 return MM_ERROR_PLAYER_INTERNAL;
7285 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7287 /* enable fadedown */
7288 if (fadedown || player->sound_focus.by_asm_cb)
7289 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7291 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7292 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7294 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF ||
7295 player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) {
7296 state = GST_STATE_READY;
7298 state = GST_STATE_PAUSED;
7300 if (!MMPLAYER_IS_STREAMING(player) ||
7301 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7305 if (player->es_player_push_mode)
7308 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, state, async, timeout);
7310 /* disable fadeout */
7311 if (fadedown || player->sound_focus.by_asm_cb)
7312 __mmplayer_undo_sound_fadedown(player);
7314 /* return if set_state has failed */
7315 if (ret != MM_ERROR_NONE) {
7316 LOGE("failed to set state.\n");
7322 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7323 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7324 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7325 LOGW("failed to rewind\n");
7326 ret = MM_ERROR_PLAYER_SEEK;
7331 player->sent_bos = FALSE;
7333 if (player->es_player_push_mode) //for cloudgame
7336 /* wait for seek to complete */
7337 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7338 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7339 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7341 LOGE("fail to stop player.\n");
7342 ret = MM_ERROR_PLAYER_INTERNAL;
7343 __mmplayer_dump_pipeline_state(player);
7346 /* generate dot file if enabled */
7347 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7354 int __gst_pause(mm_player_t* player, gboolean async) // @
7356 int ret = MM_ERROR_NONE;
7360 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7361 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7363 LOGD("current state before doing transition");
7364 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7365 MMPLAYER_PRINT_STATE(player);
7367 /* set pipeline status to PAUSED */
7368 player->ignore_asyncdone = TRUE;
7370 ret = __mmplayer_gst_set_state(player,
7371 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7373 player->ignore_asyncdone = FALSE;
7375 if (FALSE == async) {
7376 if (ret != MM_ERROR_NONE) {
7377 GstMessage *msg = NULL;
7378 GTimer *timer = NULL;
7379 gdouble MAX_TIMEOUT_SEC = 3;
7381 LOGE("failed to set state to PAUSED");
7383 timer = g_timer_new();
7384 g_timer_start(timer);
7386 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7387 gboolean got_msg = FALSE;
7388 /* check if gst error posted or not */
7390 msg = gst_bus_timed_pop(bus, GST_SECOND / 2);
7392 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7393 GError *error = NULL;
7395 /* parse error code */
7396 gst_message_parse_error(msg, &error, NULL);
7398 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7399 /* Note : the streaming error from the streaming source is handled
7400 * using __mmplayer_handle_streaming_error.
7402 __mmplayer_handle_streaming_error(player, msg);
7405 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7407 if (error->domain == GST_STREAM_ERROR)
7408 ret = __gst_handle_stream_error(player, error, msg);
7409 else if (error->domain == GST_RESOURCE_ERROR)
7410 ret = __gst_handle_resource_error(player, error->code);
7411 else if (error->domain == GST_LIBRARY_ERROR)
7412 ret = __gst_handle_library_error(player, error->code);
7413 else if (error->domain == GST_CORE_ERROR)
7414 ret = __gst_handle_core_error(player, error->code);
7418 player->msg_posted = TRUE;
7420 gst_message_unref(msg);
7422 } while (!got_msg && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7424 gst_object_unref(bus);
7425 g_timer_stop(timer);
7426 g_timer_destroy(timer);
7429 } else if (!player->video_stream_cb && (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7430 if (MMPLAYER_IS_RTSP_STREAMING(player))
7432 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7433 } else if (ret == MM_ERROR_NONE)
7434 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7437 /* generate dot file before returning error */
7438 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7445 int __gst_resume(mm_player_t* player, gboolean async) // @
7447 int ret = MM_ERROR_NONE;
7452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7453 MM_ERROR_PLAYER_NOT_INITIALIZED);
7455 LOGD("current state before doing transition");
7456 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7457 MMPLAYER_PRINT_STATE(player);
7459 /* generate dot file before returning error */
7460 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7463 LOGD("do async state transition to PLAYING.\n");
7465 /* set pipeline state to PLAYING */
7466 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7468 ret = __mmplayer_gst_set_state(player,
7469 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7470 if (ret != MM_ERROR_NONE) {
7471 LOGE("failed to set state to PLAYING\n");
7474 if (async == FALSE) {
7475 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7476 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7477 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7481 /* generate dot file before returning error */
7482 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7490 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7492 unsigned long dur_msec = 0;
7493 gint64 dur_nsec = 0;
7494 gint64 pos_nsec = 0;
7495 gboolean ret = TRUE;
7496 gboolean accurated = FALSE;
7497 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7500 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7501 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7503 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7504 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7507 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7508 /* check duration */
7509 /* NOTE : duration cannot be zero except live streaming.
7510 * Since some element could have some timing problemn with quering duration, try again.
7512 if (!player->duration) {
7513 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7515 player->duration = dur_nsec;
7518 if (player->duration) {
7519 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7521 LOGE("could not get the duration. fail to seek.\n");
7525 LOGD("playback rate: %f\n", player->playback_rate);
7527 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7529 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7531 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7535 case MM_PLAYER_POS_FORMAT_TIME:
7537 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7538 /* check position is valid or not */
7539 if (position > dur_msec)
7542 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7544 if (player->doing_seek) {
7545 LOGD("not completed seek");
7546 return MM_ERROR_PLAYER_DOING_SEEK;
7550 if (!internal_called)
7551 player->doing_seek = TRUE;
7553 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7555 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7556 gint64 cur_time = 0;
7558 /* get current position */
7559 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7562 GstEvent *event = gst_event_new_seek(1.0,
7564 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7565 GST_SEEK_TYPE_SET, cur_time,
7566 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7568 __gst_send_event_to_sink(player, event);
7570 __gst_pause(player, FALSE);
7573 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7574 GST_FORMAT_TIME, seek_flags,
7575 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7577 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7583 case MM_PLAYER_POS_FORMAT_PERCENT:
7585 LOGD("seeking to(%lu)%% \n", position);
7587 if (player->doing_seek) {
7588 LOGD("not completed seek");
7589 return MM_ERROR_PLAYER_DOING_SEEK;
7592 if (!internal_called)
7593 player->doing_seek = TRUE;
7595 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7596 pos_nsec = (gint64)((position * player->duration) / 100);
7597 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7598 GST_FORMAT_TIME, seek_flags,
7599 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7601 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7611 /* NOTE : store last seeking point to overcome some bad operation
7612 * (returning zero when getting current position) of some elements
7614 player->last_position = pos_nsec;
7616 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7617 if (player->playback_rate > 1.0)
7618 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7621 return MM_ERROR_NONE;
7624 player->pending_seek.is_pending = TRUE;
7625 player->pending_seek.format = format;
7626 player->pending_seek.pos = position;
7628 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7629 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7631 return MM_ERROR_NONE;
7634 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7635 return MM_ERROR_INVALID_ARGUMENT;
7638 player->doing_seek = FALSE;
7639 return MM_ERROR_PLAYER_SEEK;
7642 #define TRICKPLAY_OFFSET GST_MSECOND
7645 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7647 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7648 gint64 pos_msec = 0;
7649 gboolean ret = TRUE;
7651 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7652 MM_ERROR_PLAYER_NOT_INITIALIZED);
7654 current_state = MMPLAYER_CURRENT_STATE(player);
7656 /* NOTE : query position except paused state to overcome some bad operation
7657 * please refer to below comments in details
7659 if (current_state != MM_PLAYER_STATE_PAUSED)
7660 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7662 /* NOTE : get last point to overcome some bad operation of some elements
7663 *(returning zero when getting current position in paused state
7664 * and when failed to get postion during seeking
7666 if ((current_state == MM_PLAYER_STATE_PAUSED)
7668 //|| (player->last_position != 0 && pos_msec == 0))
7669 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7671 if (player->playback_rate < 0.0)
7672 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7674 pos_msec = player->last_position;
7677 pos_msec = player->last_position;
7679 player->last_position = pos_msec;
7681 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7684 if (player->duration > 0 && pos_msec > player->duration)
7685 pos_msec = player->duration;
7687 if (player->sound_focus.keep_last_pos) {
7688 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7689 pos_msec = player->last_position;
7691 player->last_position = pos_msec;
7695 case MM_PLAYER_POS_FORMAT_TIME:
7696 *position = GST_TIME_AS_MSECONDS(pos_msec);
7699 case MM_PLAYER_POS_FORMAT_PERCENT:
7704 dur = player->duration / GST_SECOND;
7706 LOGD("duration is [%d], so returning position 0\n", dur);
7709 pos = pos_msec / GST_SECOND;
7710 *position = pos * 100 / dur;
7715 return MM_ERROR_PLAYER_INTERNAL;
7718 return MM_ERROR_NONE;
7722 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7724 #define STREAMING_IS_FINISHED 0
7725 #define BUFFERING_MAX_PER 100
7726 #define DEFAULT_PER_VALUE -1
7727 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7729 MMPlayerGstElement *mainbin = NULL;
7730 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7731 gint64 buffered_total = 0;
7732 unsigned long position = 0;
7733 gint buffered_sec = -1;
7734 GstBufferingMode mode = GST_BUFFERING_STREAM;
7735 gint64 content_size_time = player->duration;
7736 guint64 content_size_bytes = player->http_content_size;
7738 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7740 player->pipeline->mainbin,
7741 MM_ERROR_PLAYER_NOT_INITIALIZED);
7743 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7748 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7749 /* and rtsp is not ready yet. */
7750 LOGW("it's only used for http streaming case.\n");
7751 return MM_ERROR_PLAYER_NO_OP;
7754 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7755 LOGW("Time format is not supported yet.\n");
7756 return MM_ERROR_INVALID_ARGUMENT;
7759 if (content_size_time <= 0 || content_size_bytes <= 0) {
7760 LOGW("there is no content size.");
7761 return MM_ERROR_NONE;
7764 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7765 LOGW("fail to get current position.");
7766 return MM_ERROR_NONE;
7769 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7770 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7772 mainbin = player->pipeline->mainbin;
7773 start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7775 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7776 GstQuery *query = NULL;
7777 gint byte_in_rate = 0, byte_out_rate = 0;
7778 gint64 estimated_total = 0;
7780 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7781 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7782 LOGW("fail to get buffering query from queue2");
7784 gst_query_unref(query);
7785 return MM_ERROR_NONE;
7788 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7789 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7791 if (mode == GST_BUFFERING_STREAM) {
7792 /* using only queue in case of push mode(ts / mp3) */
7793 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7794 GST_FORMAT_BYTES, &buffered_total)) {
7795 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7796 stop_per = 100 * buffered_total / content_size_bytes;
7799 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7801 guint num_of_ranges = 0;
7802 gint64 start_byte = 0, stop_byte = 0;
7804 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7805 if (estimated_total != STREAMING_IS_FINISHED) {
7806 /* buffered size info from queue2 */
7807 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7808 for (idx = 0; idx < num_of_ranges; idx++) {
7809 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7810 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7812 buffered_total += (stop_byte - start_byte);
7815 stop_per = BUFFERING_MAX_PER;
7817 gst_query_unref(query);
7820 if (stop_per == DEFAULT_PER_VALUE) {
7821 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7823 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7825 /* buffered size info from multiqueue */
7826 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7827 guint curr_size_bytes = 0;
7828 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7829 "curr-size-bytes", &curr_size_bytes, NULL);
7830 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7831 buffered_total += curr_size_bytes;
7834 if (avg_byterate > 0)
7835 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7836 else if (player->total_maximum_bitrate > 0)
7837 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7838 else if (player->total_bitrate > 0)
7839 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7841 if (buffered_sec >= 0)
7842 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7846 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7847 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7849 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7850 buffered_total, buffered_sec, *start_pos, *stop_pos);
7852 return MM_ERROR_NONE;
7856 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7861 LOGW("set_message_callback is called with invalid player handle\n");
7862 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7865 player->msg_cb = callback;
7866 player->msg_cb_param = user_param;
7868 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7872 return MM_ERROR_NONE;
7875 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7877 int ret = MM_ERROR_PLAYER_INVALID_URI;
7882 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7883 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7884 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7886 memset(data, 0, sizeof(MMPlayerParseProfile));
7888 if ((path = strstr(uri, "es_buff://"))) {
7890 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7891 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7892 ret = MM_ERROR_NONE;
7894 } else if ((path = strstr(uri, "buff://"))) {
7895 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
7896 ret = MM_ERROR_NONE;
7897 } else if ((path = strstr(uri, "rtsp://"))) {
7899 if ((path = strstr(uri, "/wfd1.0/"))) {
7900 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7901 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7902 ret = MM_ERROR_NONE;
7903 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7905 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7906 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7907 ret = MM_ERROR_NONE;
7910 } else if ((path = strstr(uri, "http://"))) {
7912 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7914 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7915 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7916 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7918 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7920 ret = MM_ERROR_NONE;
7922 } else if ((path = strstr(uri, "https://"))) {
7924 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7926 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7927 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7928 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7930 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7932 ret = MM_ERROR_NONE;
7934 } else if ((path = strstr(uri, "rtspu://"))) {
7936 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7937 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7938 ret = MM_ERROR_NONE;
7940 } else if ((path = strstr(uri, "rtspr://"))) {
7941 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7942 char *separater = strstr(path, "*");
7946 char *urgent = separater + strlen("*");
7948 if ((urgent_len = strlen(urgent))) {
7949 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7950 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7951 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7952 ret = MM_ERROR_NONE;
7955 } else if ((path = strstr(uri, "mms://"))) {
7957 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7958 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7959 ret = MM_ERROR_NONE;
7961 } else if ((path = strstr(uri, "mem://"))) {
7964 char *buffer = NULL;
7965 char *seperator = strchr(path, ',');
7966 char ext[100] = {0,}, size[100] = {0,};
7969 if ((buffer = strstr(path, "ext="))) {
7970 buffer += strlen("ext=");
7972 if (strlen(buffer)) {
7973 strncpy(ext, buffer, 99);
7975 if ((seperator = strchr(ext, ','))
7976 || (seperator = strchr(ext, ' '))
7977 || (seperator = strchr(ext, '\0'))) {
7978 seperator[0] = '\0';
7983 if ((buffer = strstr(path, "size="))) {
7984 buffer += strlen("size=");
7986 if (strlen(buffer) > 0) {
7987 strncpy(size, buffer, 99);
7989 if ((seperator = strchr(size, ','))
7990 || (seperator = strchr(size, ' '))
7991 || (seperator = strchr(size, '\0'))) {
7992 seperator[0] = '\0';
7995 mem_size = atoi(size);
8000 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8001 if (mem_size && param) {
8003 data->mem_size = mem_size;
8004 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8005 ret = MM_ERROR_NONE;
8009 gchar *location = NULL;
8012 if ((path = strstr(uri, "file://"))) {
8014 location = g_filename_from_uri(uri, NULL, &err);
8016 if (!location || (err != NULL)) {
8017 LOGE("Invalid URI '%s' for filesrc: %s", path,
8018 (err != NULL) ? err->message : "unknown error");
8020 if (err) g_error_free(err);
8021 if (location) g_free(location);
8023 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8027 LOGD("path from uri: %s", location);
8030 path = (location != NULL) ? (location) : ((char*)uri);
8031 int file_stat = MM_ERROR_NONE;
8033 file_stat = util_exist_file_path(path);
8035 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8036 if (file_stat == MM_ERROR_NONE) {
8037 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8039 if (util_is_sdp_file(path)) {
8040 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8041 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8043 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8044 ret = MM_ERROR_NONE;
8045 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8046 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8048 LOGE("invalid uri, could not play..\n");
8049 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8052 if (location) g_free(location);
8056 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8057 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8058 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8059 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8061 /* dump parse result */
8062 SECURE_LOGW("incomming uri : %s\n", uri);
8063 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8064 data->uri_type, data->mem, data->mem_size, data->urgent);
8071 gboolean _asm_postmsg(gpointer *data)
8073 mm_player_t* player = (mm_player_t*)data;
8074 MMMessageParamType msg = {0, };
8077 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8078 LOGW("get notified");
8080 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8081 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8087 msg.union_type = MM_MSG_UNION_CODE;
8088 msg.code = player->sound_focus.focus_changed_msg;
8090 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8091 player->resume_event_id = 0;
8097 gboolean _asm_lazy_pause(gpointer *data)
8099 mm_player_t* player = (mm_player_t*)data;
8100 int ret = MM_ERROR_NONE;
8104 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8106 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8107 LOGD("Ready to proceed lazy pause\n");
8108 ret = _mmplayer_pause((MMHandleType)player);
8109 if (MM_ERROR_NONE != ret)
8110 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8112 LOGD("Invalid state to proceed lazy pause\n");
8115 if (player->pipeline && player->pipeline->audiobin)
8116 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8118 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8126 __mmplayer_can_do_interrupt(mm_player_t *player)
8128 if (!player || !player->pipeline || !player->attrs) {
8129 LOGW("not initialized");
8133 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8134 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8138 /* check if seeking */
8139 if (player->doing_seek) {
8140 MMMessageParamType msg_param;
8141 memset(&msg_param, 0, sizeof(MMMessageParamType));
8142 msg_param.code = MM_ERROR_PLAYER_SEEK;
8143 player->doing_seek = FALSE;
8144 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8148 /* check other thread */
8149 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8150 LOGW("locked already, cmd state : %d", player->cmd);
8152 /* check application command */
8153 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8154 LOGW("playing.. should wait cmd lock then, will be interrupted");
8156 /* lock will be released at mrp_resource_release_cb() */
8157 MMPLAYER_CMD_LOCK(player);
8160 LOGW("nothing to do");
8163 LOGW("can interrupt immediately");
8167 FAILED: /* with CMD UNLOCKED */
8170 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8174 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8176 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8178 int ret = MM_ERROR_NONE;
8179 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8181 if (strstr(reason_for_change, "alarm")) {
8182 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8184 } else if (strstr(reason_for_change, "notification")) {
8185 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8187 } else if (strstr(reason_for_change, "emergency")) {
8188 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8190 } else if (strstr(reason_for_change, "call-voice") ||
8191 strstr(reason_for_change, "call-video") ||
8192 strstr(reason_for_change, "voip") ||
8193 strstr(reason_for_change, "ringtone-voip") ||
8194 strstr(reason_for_change, "ringtone-call")) {
8195 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8197 } else if (strstr(reason_for_change, "media") ||
8198 strstr(reason_for_change, "radio") ||
8199 strstr(reason_for_change, "loopback") ||
8200 strstr(reason_for_change, "system") ||
8201 strstr(reason_for_change, "voice-information") ||
8202 strstr(reason_for_change, "voice-recognition")) {
8203 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8206 ret = MM_ERROR_INVALID_ARGUMENT;
8207 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8211 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8213 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8215 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8222 /* FIXME: will be updated with new funct */
8223 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8224 const char *reason_for_change, const char *additional_info, void *user_data)
8226 mm_player_t* player = (mm_player_t*) user_data;
8227 int result = MM_ERROR_NONE;
8228 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8230 LOGW("focus watch notified");
8232 if (!__mmplayer_can_do_interrupt(player)) {
8233 LOGW("no need to interrupt, so leave");
8234 goto EXIT_WITHOUT_UNLOCK;
8237 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8238 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8242 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8243 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8245 player->sound_focus.cb_pending = TRUE;
8246 player->sound_focus.by_asm_cb = TRUE;
8248 if (focus_state == FOCUS_IS_ACQUIRED) {
8249 LOGW("watch: FOCUS_IS_ACQUIRED");
8250 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8251 player->sound_focus.focus_changed_msg = (int)msg;
8253 if (strstr(reason_for_change, "call") ||
8254 strstr(reason_for_change, "voip") || /* FIXME: to check */
8255 strstr(reason_for_change, "alarm") ||
8256 strstr(reason_for_change, "media")) {
8257 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8258 // hold 0.7 second to excute "fadedown mute" effect
8259 LOGW("do fade down->pause->undo fade down");
8261 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8263 result = _mmplayer_pause((MMHandleType)player);
8264 if (result != MM_ERROR_NONE) {
8265 LOGW("fail to set Pause state by asm");
8268 __mmplayer_undo_sound_fadedown(player);
8270 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8271 _mmplayer_unrealize((MMHandleType)player);
8273 LOGW("pause immediately");
8274 result = _mmplayer_pause((MMHandleType)player);
8275 if (result != MM_ERROR_NONE) {
8276 LOGW("fail to set Pause state by asm");
8280 } else if (focus_state == FOCUS_IS_RELEASED) {
8281 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8282 player->sound_focus.antishock = TRUE;
8283 player->sound_focus.by_asm_cb = FALSE;
8285 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8286 player->sound_focus.focus_changed_msg = (int)msg;
8288 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8289 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8292 LOGW("unknown focus state %d", focus_state);
8295 player->sound_focus.by_asm_cb = FALSE;
8296 player->sound_focus.cb_pending = FALSE;
8299 MMPLAYER_CMD_UNLOCK(player);
8303 EXIT_WITHOUT_UNLOCK:
8309 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8310 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8312 mm_player_t* player = (mm_player_t*) user_data;
8313 int result = MM_ERROR_NONE;
8314 gboolean lazy_pause = FALSE;
8315 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8317 LOGW("get focus notified");
8319 if (!__mmplayer_can_do_interrupt(player)) {
8320 LOGW("no need to interrupt, so leave");
8321 goto EXIT_WITHOUT_UNLOCK;
8324 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8325 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8329 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8330 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8332 player->sound_focus.cb_pending = TRUE;
8333 player->sound_focus.by_asm_cb = TRUE;
8334 // player->sound_focus.event_src = event_src;
8336 if (focus_state == FOCUS_IS_RELEASED) {
8337 LOGW("FOCUS_IS_RELEASED");
8339 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8340 player->sound_focus.focus_changed_msg = (int)msg;
8342 if (strstr(reason_for_change, "call") ||
8343 strstr(reason_for_change, "voip") || /* FIXME: to check */
8344 strstr(reason_for_change, "alarm") ||
8345 strstr(reason_for_change, "media")) {
8346 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8347 //hold 0.7 second to excute "fadedown mute" effect
8348 LOGW("do fade down->pause->undo fade down");
8350 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8352 result = _mmplayer_pause((MMHandleType)player);
8353 if (result != MM_ERROR_NONE) {
8354 LOGW("fail to set Pause state by asm");
8357 __mmplayer_undo_sound_fadedown(player);
8359 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8360 _mmplayer_unrealize((MMHandleType)player);
8362 LOGW("pause immediately");
8363 result = _mmplayer_pause((MMHandleType)player);
8364 if (result != MM_ERROR_NONE) {
8365 LOGW("fail to set Pause state by asm");
8369 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8370 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8371 player->sound_focus.antishock = TRUE;
8372 player->sound_focus.by_asm_cb = FALSE;
8374 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8375 player->sound_focus.focus_changed_msg = (int)msg;
8377 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8378 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8381 LOGW("unknown focus state %d", focus_state);
8385 player->sound_focus.by_asm_cb = FALSE;
8386 player->sound_focus.cb_pending = FALSE;
8389 MMPLAYER_CMD_UNLOCK(player);
8393 EXIT_WITHOUT_UNLOCK:
8400 _mmplayer_create_player(MMHandleType handle) // @
8402 int ret = MM_ERROR_PLAYER_INTERNAL;
8403 mm_player_t* player = MM_PLAYER_CAST(handle);
8407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8409 /* initialize player state */
8410 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8411 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8412 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8413 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8415 /* check current state */
8416 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8418 /* construct attributes */
8419 player->attrs = _mmplayer_construct_attribute(handle);
8421 if (!player->attrs) {
8422 LOGE("Failed to construct attributes\n");
8426 /* initialize gstreamer with configured parameter */
8427 if (!__mmplayer_init_gstreamer(player)) {
8428 LOGE("Initializing gstreamer failed\n");
8429 _mmplayer_deconstruct_attribute(handle);
8433 /* initialize factories if not using decodebin */
8434 if (player->factories == NULL)
8435 __mmplayer_init_factories(player);
8437 /* create lock. note that g_tread_init() has already called in gst_init() */
8438 g_mutex_init(&player->fsink_lock);
8440 /* create repeat mutex */
8441 g_mutex_init(&player->repeat_thread_mutex);
8443 /* create repeat cond */
8444 g_cond_init(&player->repeat_thread_cond);
8446 /* create repeat thread */
8447 player->repeat_thread =
8448 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8449 if (!player->repeat_thread) {
8450 LOGE("failed to create repeat_thread(%s)");
8451 g_mutex_clear(&player->repeat_thread_mutex);
8452 g_cond_clear(&player->repeat_thread_cond);
8453 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8457 /* create next play mutex */
8458 g_mutex_init(&player->next_play_thread_mutex);
8460 /* create next play cond */
8461 g_cond_init(&player->next_play_thread_cond);
8463 /* create next play thread */
8464 player->next_play_thread =
8465 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8466 if (!player->next_play_thread) {
8467 LOGE("failed to create next play thread");
8468 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8469 g_mutex_clear(&player->next_play_thread_mutex);
8470 g_cond_clear(&player->next_play_thread_cond);
8474 ret = _mmplayer_initialize_video_capture(player);
8475 if (ret != MM_ERROR_NONE) {
8476 LOGE("failed to initialize video capture\n");
8480 /* initialize resource manager */
8481 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8482 LOGE("failed to initialize resource manager\n");
8486 if (MMPLAYER_IS_HTTP_PD(player)) {
8487 player->pd_downloader = NULL;
8488 player->pd_file_save_path = NULL;
8491 /* create video bo lock and cond */
8492 g_mutex_init(&player->video_bo_mutex);
8493 g_cond_init(&player->video_bo_cond);
8495 player->streaming_type = STREAMING_SERVICE_NONE;
8497 /* give default value of audio effect setting */
8498 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8499 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8501 player->play_subtitle = FALSE;
8502 player->use_textoverlay = FALSE;
8503 player->play_count = 0;
8504 player->use_decodebin = TRUE;
8505 player->ignore_asyncdone = FALSE;
8506 player->use_deinterleave = FALSE;
8507 player->max_audio_channels = 0;
8508 player->video_share_api_delta = 0;
8509 player->video_share_clock_delta = 0;
8510 player->has_closed_caption = FALSE;
8511 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8512 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8513 if (player->ini.dump_element_keyword[0][0] == '\0')
8514 player->ini.set_dump_element_flag = FALSE;
8516 player->ini.set_dump_element_flag = TRUE;
8518 /* set player state to null */
8519 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8520 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8522 return MM_ERROR_NONE;
8526 g_mutex_clear(&player->fsink_lock);
8529 if (player->repeat_thread) {
8530 player->repeat_thread_exit = TRUE;
8531 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8533 g_thread_join(player->repeat_thread);
8534 player->repeat_thread = NULL;
8536 g_mutex_clear(&player->repeat_thread_mutex);
8537 g_cond_clear(&player->repeat_thread_cond);
8540 /* free next play thread */
8541 if (player->next_play_thread) {
8542 player->next_play_thread_exit = TRUE;
8543 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8545 g_thread_join(player->next_play_thread);
8546 player->next_play_thread = NULL;
8548 g_mutex_clear(&player->next_play_thread_mutex);
8549 g_cond_clear(&player->next_play_thread_cond);
8552 /* release attributes */
8553 _mmplayer_deconstruct_attribute(handle);
8561 __mmplayer_init_gstreamer(mm_player_t* player) // @
8563 static gboolean initialized = FALSE;
8564 static const int max_argc = 50;
8566 gchar** argv = NULL;
8567 gchar** argv2 = NULL;
8573 LOGD("gstreamer already initialized.\n");
8578 argc = malloc(sizeof(int));
8579 argv = malloc(sizeof(gchar*) * max_argc);
8580 argv2 = malloc(sizeof(gchar*) * max_argc);
8582 if (!argc || !argv || !argv2)
8585 memset(argv, 0, sizeof(gchar*) * max_argc);
8586 memset(argv2, 0, sizeof(gchar*) * max_argc);
8590 argv[0] = g_strdup("mmplayer");
8593 for (i = 0; i < 5; i++) {
8594 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8595 if (strlen(player->ini.gst_param[i]) > 0) {
8596 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8601 /* we would not do fork for scanning plugins */
8602 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8605 /* check disable registry scan */
8606 if (player->ini.skip_rescan) {
8607 argv[*argc] = g_strdup("--gst-disable-registry-update");
8611 /* check disable segtrap */
8612 if (player->ini.disable_segtrap) {
8613 argv[*argc] = g_strdup("--gst-disable-segtrap");
8617 LOGD("initializing gstreamer with following parameter\n");
8618 LOGD("argc : %d\n", *argc);
8621 for (i = 0; i < arg_count; i++) {
8623 LOGD("argv[%d] : %s\n", i, argv2[i]);
8627 /* initializing gstreamer */
8628 if (!gst_init_check(argc, &argv, &err)) {
8629 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8636 for (i = 0; i < arg_count; i++) {
8637 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8638 MMPLAYER_FREEIF(argv2[i]);
8641 MMPLAYER_FREEIF(argv);
8642 MMPLAYER_FREEIF(argv2);
8643 MMPLAYER_FREEIF(argc);
8653 for (i = 0; i < arg_count; i++) {
8654 LOGD("free[%d] : %s\n", i, argv2[i]);
8655 MMPLAYER_FREEIF(argv2[i]);
8658 MMPLAYER_FREEIF(argv);
8659 MMPLAYER_FREEIF(argv2);
8660 MMPLAYER_FREEIF(argc);
8666 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670 if (player->pd_downloader) {
8671 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8672 MMPLAYER_FREEIF(player->pd_downloader);
8675 if (MMPLAYER_IS_HTTP_PD(player)) {
8676 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8677 MMPLAYER_FREEIF(player->pd_file_save_path);
8680 return MM_ERROR_NONE;
8684 _mmplayer_destroy(MMHandleType handle) // @
8686 mm_player_t* player = MM_PLAYER_CAST(handle);
8690 /* check player handle */
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 /* destroy can called at anytime */
8694 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8696 __mmplayer_destroy_streaming_ext(player);
8698 /* release repeat thread */
8699 if (player->repeat_thread) {
8700 player->repeat_thread_exit = TRUE;
8701 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8703 LOGD("waitting for repeat thread exit\n");
8704 g_thread_join(player->repeat_thread);
8705 g_mutex_clear(&player->repeat_thread_mutex);
8706 g_cond_clear(&player->repeat_thread_cond);
8707 LOGD("repeat thread released\n");
8710 /* release next play thread */
8711 if (player->next_play_thread) {
8712 player->next_play_thread_exit = TRUE;
8713 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8715 LOGD("waitting for next play thread exit\n");
8716 g_thread_join(player->next_play_thread);
8717 g_mutex_clear(&player->next_play_thread_mutex);
8718 g_cond_clear(&player->next_play_thread_cond);
8719 LOGD("next play thread released\n");
8722 _mmplayer_release_video_capture(player);
8724 /* flush any pending asm_cb */
8725 if (player->sound_focus.cb_pending) {
8726 /* set a flag for make sure asm_cb to be returned immediately */
8727 LOGW("asm cb has pending state");
8728 player->sound_focus.exit_cb = TRUE;
8730 /* make sure to release any pending asm_cb which locked by cmd_lock */
8731 MMPLAYER_CMD_UNLOCK(player);
8733 MMPLAYER_CMD_LOCK(player);
8737 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8738 LOGE("failed to deregister asm server\n");
8740 /* de-initialize resource manager */
8741 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8742 LOGE("failed to deinitialize resource manager\n");
8744 #ifdef USE_LAZY_PAUSE
8745 if (player->lazy_pause_event_id) {
8746 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8747 player->lazy_pause_event_id = 0;
8751 if (player->resume_event_id) {
8752 g_source_remove(player->resume_event_id);
8753 player->resume_event_id = 0;
8756 if (player->resumable_cancel_id) {
8757 g_source_remove(player->resumable_cancel_id);
8758 player->resumable_cancel_id = 0;
8761 /* release pipeline */
8762 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8763 LOGE("failed to destory pipeline\n");
8764 return MM_ERROR_PLAYER_INTERNAL;
8767 if (player->is_external_subtitle_present && player->subtitle_language_list) {
8768 g_list_free(player->subtitle_language_list);
8769 player->subtitle_language_list = NULL;
8772 __mmplayer_release_dump_list(player->dump_list);
8774 /* release miscellaneous information.
8775 these info needs to be released after pipeline is destroyed. */
8776 __mmplayer_release_misc_post(player);
8778 /* release attributes */
8779 _mmplayer_deconstruct_attribute(handle);
8781 /* release factories */
8782 __mmplayer_release_factories(player);
8785 g_mutex_clear(&player->fsink_lock);
8787 /* release video bo lock and cond */
8788 g_mutex_clear(&player->video_bo_mutex);
8789 g_cond_clear(&player->video_bo_cond);
8793 return MM_ERROR_NONE;
8797 __mmplayer_realize_streaming_ext(mm_player_t* player)
8799 int ret = MM_ERROR_NONE;
8802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8804 if (MMPLAYER_IS_HTTP_PD(player)) {
8805 gboolean bret = FALSE;
8807 player->pd_downloader = _mmplayer_create_pd_downloader();
8808 if (!player->pd_downloader) {
8809 LOGE("Unable to create PD Downloader...");
8810 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8813 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8815 if (FALSE == bret) {
8816 LOGE("Unable to create PD Downloader...");
8817 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8826 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8828 mm_player_t* player = (mm_player_t*)hplayer;
8829 MMHandleType attrs = 0;
8830 int ret = MM_ERROR_NONE;
8832 attrs = MMPLAYER_GET_ATTRS(player);
8834 LOGE("fail to get attributes.\n");
8835 return MM_ERROR_PLAYER_INTERNAL;
8838 player->sound_focus.pid = pid;
8840 /* register to asm */
8841 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8842 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8843 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8845 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8846 LOGE("failed to register asm server\n");
8847 return MM_ERROR_POLICY_INTERNAL;
8853 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8855 mm_player_t* player = (mm_player_t*) hplayer;
8859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8861 *pid = player->sound_focus.pid;
8863 LOGD("registered pid[%d] %p", *pid, player);
8867 return MM_ERROR_NONE;
8871 _mmplayer_realize(MMHandleType hplayer) // @
8873 mm_player_t* player = (mm_player_t*)hplayer;
8876 gboolean update_registry = FALSE;
8877 MMHandleType attrs = 0;
8878 int ret = MM_ERROR_NONE;
8882 /* check player handle */
8883 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8885 /* check current state */
8886 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8888 attrs = MMPLAYER_GET_ATTRS(player);
8890 LOGE("fail to get attributes.\n");
8891 return MM_ERROR_PLAYER_INTERNAL;
8893 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8894 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8896 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8897 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8899 if (ret != MM_ERROR_NONE) {
8900 LOGE("failed to parse profile\n");
8905 /* FIXIT : we can use thouse in player->profile directly */
8906 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8907 player->mem_buf.buf = (char *)player->profile.mem;
8908 player->mem_buf.len = player->profile.mem_size;
8909 player->mem_buf.offset = 0;
8912 if (uri && (strstr(uri, "es_buff://"))) {
8913 if (strstr(uri, "es_buff://push_mode"))
8914 player->es_player_push_mode = TRUE;
8916 player->es_player_push_mode = FALSE;
8919 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8920 LOGW("mms protocol is not supported format.\n");
8921 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8924 if (MMPLAYER_IS_STREAMING(player))
8925 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8927 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8929 player->smooth_streaming = FALSE;
8930 player->videodec_linked = 0;
8931 player->videosink_linked = 0;
8932 player->audiodec_linked = 0;
8933 player->audiosink_linked = 0;
8934 player->textsink_linked = 0;
8935 player->is_external_subtitle_present = FALSE;
8936 /* set the subtitle ON default */
8937 player->is_subtitle_off = FALSE;
8939 /* registry should be updated for downloadable codec */
8940 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8942 if (update_registry) {
8943 LOGD("updating registry...\n");
8944 gst_update_registry();
8946 /* then we have to rebuild factories */
8947 __mmplayer_release_factories(player);
8948 __mmplayer_init_factories(player);
8951 /* realize pipeline */
8952 ret = __gst_realize(player);
8953 if (ret != MM_ERROR_NONE)
8954 LOGE("fail to realize the player.\n");
8956 ret = __mmplayer_realize_streaming_ext(player);
8964 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8967 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8969 /* destroy can called at anytime */
8970 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
8971 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8972 MMPLAYER_FREEIF(player->pd_downloader);
8976 return MM_ERROR_NONE;
8980 _mmplayer_unrealize(MMHandleType hplayer)
8982 mm_player_t* player = (mm_player_t*)hplayer;
8983 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
8984 int ret = MM_ERROR_NONE;
8988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8990 /* check current state */
8991 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8993 __mmplayer_unrealize_streaming_ext(player);
8995 /* unrealize pipeline */
8996 ret = __gst_unrealize(player);
8998 /* set asm stop if success */
8999 if (MM_ERROR_NONE == ret) {
9000 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9001 if (ret != MM_ERROR_NONE)
9002 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9004 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9005 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9006 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9007 if (ret != MM_ERROR_NONE)
9008 LOGE("failed to release resource, ret(0x%x)\n", ret);
9012 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9013 if (resource_state == RESOURCE_STATE_PREPARED) {
9014 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9015 if (ret != MM_ERROR_NONE)
9016 LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9020 LOGE("failed and don't change asm state to stop");
9028 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9030 mm_player_t* player = (mm_player_t*)hplayer;
9032 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9034 return __gst_set_message_callback(player, callback, user_param);
9038 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9040 mm_player_t *player = (mm_player_t*)hplayer;
9042 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9044 *state = MMPLAYER_CURRENT_STATE(player);
9046 return MM_ERROR_NONE;
9051 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9053 mm_player_t* player = (mm_player_t*) hplayer;
9054 GstElement* vol_element = NULL;
9059 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9061 LOGD("volume [L]=%f:[R]=%f\n",
9062 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9064 /* invalid factor range or not */
9065 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9066 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9067 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9068 return MM_ERROR_INVALID_ARGUMENT;
9072 /* not support to set other value into each channel */
9073 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9074 return MM_ERROR_INVALID_ARGUMENT;
9076 /* Save volume to handle. Currently the first array element will be saved. */
9077 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9079 /* check pipeline handle */
9080 if (!player->pipeline || !player->pipeline->audiobin) {
9081 LOGD("audiobin is not created yet\n");
9082 LOGD("but, current stored volume will be set when it's created.\n");
9084 /* NOTE : stored volume will be used in create_audiobin
9085 * returning MM_ERROR_NONE here makes application to able to
9086 * set volume at anytime.
9088 return MM_ERROR_NONE;
9091 /* setting volume to volume element */
9092 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9095 LOGD("volume is set [%f]\n", player->sound.volume);
9096 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9101 return MM_ERROR_NONE;
9106 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9108 mm_player_t* player = (mm_player_t*) hplayer;
9113 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9116 /* returning stored volume */
9117 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9118 volume->level[i] = player->sound.volume;
9122 return MM_ERROR_NONE;
9128 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9130 mm_player_t* player = (mm_player_t*) hplayer;
9131 GstElement* vol_element = NULL;
9135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9137 /* mute value shoud 0 or 1 */
9138 if (mute != 0 && mute != 1) {
9139 LOGE("bad mute value\n");
9141 /* FIXIT : definitly, we need _BAD_PARAM error code */
9142 return MM_ERROR_INVALID_ARGUMENT;
9145 player->sound.mute = mute;
9147 /* just hold mute value if pipeline is not ready */
9148 if (!player->pipeline || !player->pipeline->audiobin) {
9149 LOGD("pipeline is not ready. holding mute value\n");
9150 return MM_ERROR_NONE;
9153 vol_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
9155 /* NOTE : volume will only created when the bt is enabled */
9157 LOGD("mute : %d\n", mute);
9158 g_object_set(vol_element, "mute", mute, NULL);
9160 LOGD("volume elemnet is not created. using volume in audiosink\n");
9164 return MM_ERROR_NONE;
9168 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9170 mm_player_t* player = (mm_player_t*) hplayer;
9174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9175 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9177 /* just hold mute value if pipeline is not ready */
9178 if (!player->pipeline || !player->pipeline->audiobin) {
9179 LOGD("pipeline is not ready. returning stored value\n");
9180 *pmute = player->sound.mute;
9181 return MM_ERROR_NONE;
9184 *pmute = player->sound.mute;
9188 return MM_ERROR_NONE;
9192 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9194 mm_player_t* player = (mm_player_t*) hplayer;
9198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9200 player->video_stream_changed_cb = callback;
9201 player->video_stream_changed_cb_user_param = user_param;
9202 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9206 return MM_ERROR_NONE;
9210 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9212 mm_player_t* player = (mm_player_t*) hplayer;
9216 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9218 player->audio_stream_changed_cb = callback;
9219 player->audio_stream_changed_cb_user_param = user_param;
9220 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9224 return MM_ERROR_NONE;
9228 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9230 mm_player_t* player = (mm_player_t*) hplayer;
9234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9236 player->audio_stream_render_cb_ex = callback;
9237 player->audio_stream_cb_user_param = user_param;
9238 player->audio_stream_sink_sync = sync;
9239 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);
9243 return MM_ERROR_NONE;
9247 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9249 mm_player_t* player = (mm_player_t*) hplayer;
9253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9255 if (callback && !player->bufmgr)
9256 player->bufmgr = tbm_bufmgr_init(-1);
9258 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9259 player->video_stream_cb = callback;
9260 player->video_stream_cb_user_param = user_param;
9262 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9266 return MM_ERROR_NONE;
9270 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9272 mm_player_t* player = (mm_player_t*) hplayer;
9276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9278 player->audio_stream_cb = callback;
9279 player->audio_stream_cb_user_param = user_param;
9280 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9284 return MM_ERROR_NONE;
9289 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9291 mm_player_t* player = (mm_player_t*) hplayer;
9295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9297 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9298 return MM_ERROR_PLAYER_INVALID_STATE;
9300 LOGD("pre buffer size : %d sec\n", second);
9303 LOGE("bad size value\n");
9304 return MM_ERROR_INVALID_ARGUMENT;
9307 if (player->streamer == NULL) {
9308 player->streamer = __mm_player_streaming_create();
9309 __mm_player_streaming_initialize(player->streamer);
9312 player->streamer->buffering_req.initial_second = second;
9316 return MM_ERROR_NONE;
9321 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9323 mm_player_t* player = (mm_player_t*) hplayer;
9327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9329 LOGD("mode %d\n", mode);
9331 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9332 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9333 return MM_ERROR_INVALID_ARGUMENT;
9335 if (player->streamer == NULL) {
9336 player->streamer = __mm_player_streaming_create();
9337 __mm_player_streaming_initialize(player->streamer);
9340 player->streamer->buffering_req.mode = mode;
9343 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9344 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9345 player->streamer->buffering_req.runtime_second = second;
9349 return MM_ERROR_NONE;
9353 __mmplayer_start_streaming_ext(mm_player_t *player)
9355 gint ret = MM_ERROR_NONE;
9358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9360 if (MMPLAYER_IS_HTTP_PD(player)) {
9361 if (!player->pd_downloader) {
9362 ret = __mmplayer_realize_streaming_ext(player);
9364 if (ret != MM_ERROR_NONE) {
9365 LOGE("failed to realize streaming ext\n");
9370 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9371 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9373 LOGE("ERROR while starting PD...\n");
9374 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9376 ret = MM_ERROR_NONE;
9385 _mmplayer_start(MMHandleType hplayer) // @
9387 mm_player_t* player = (mm_player_t*) hplayer;
9388 gint ret = MM_ERROR_NONE;
9392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9394 /* check current state */
9395 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9397 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9398 if (ret != MM_ERROR_NONE) {
9399 LOGE("failed to acquire sound focus.\n");
9403 /* NOTE : we should check and create pipeline again if not created as we destroy
9404 * whole pipeline when stopping in streamming playback
9406 if (!player->pipeline) {
9407 ret = __gst_realize(player);
9408 if (MM_ERROR_NONE != ret) {
9409 LOGE("failed to realize before starting. only in streamming\n");
9415 ret = __mmplayer_start_streaming_ext(player);
9416 if (ret != MM_ERROR_NONE)
9417 LOGE("failed to start streaming ext \n");
9419 /* start pipeline */
9420 ret = __gst_start(player);
9421 if (ret != MM_ERROR_NONE)
9422 LOGE("failed to start player.\n");
9429 /* NOTE: post "not supported codec message" to application
9430 * when one codec is not found during AUTOPLUGGING in MSL.
9431 * So, it's separated with error of __mmplayer_gst_callback().
9432 * And, if any codec is not found, don't send message here.
9433 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9436 __mmplayer_handle_missed_plugin(mm_player_t* player)
9438 MMMessageParamType msg_param;
9439 memset(&msg_param, 0, sizeof(MMMessageParamType));
9440 gboolean post_msg_direct = FALSE;
9444 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9446 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9447 player->not_supported_codec, player->can_support_codec);
9449 if (player->not_found_demuxer) {
9450 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9451 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9453 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9454 MMPLAYER_FREEIF(msg_param.data);
9456 return MM_ERROR_NONE;
9459 if (player->not_supported_codec) {
9460 if (player->can_support_codec) {
9461 // There is one codec to play
9462 post_msg_direct = TRUE;
9464 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9465 post_msg_direct = TRUE;
9468 if (post_msg_direct) {
9469 MMMessageParamType msg_param;
9470 memset(&msg_param, 0, sizeof(MMMessageParamType));
9472 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9473 LOGW("not found AUDIO codec, posting error code to application.\n");
9475 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9476 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9477 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9478 LOGW("not found VIDEO codec, posting error code to application.\n");
9480 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9481 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9484 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9486 MMPLAYER_FREEIF(msg_param.data);
9488 return MM_ERROR_NONE;
9490 // no any supported codec case
9491 LOGW("not found any codec, posting error code to application.\n");
9493 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9494 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9495 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9497 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9498 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9501 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9503 MMPLAYER_FREEIF(msg_param.data);
9509 return MM_ERROR_NONE;
9512 static void __mmplayer_check_pipeline(mm_player_t* player)
9514 GstState element_state = GST_STATE_VOID_PENDING;
9515 GstState element_pending_state = GST_STATE_VOID_PENDING;
9517 int ret = MM_ERROR_NONE;
9519 if (player->gapless.reconfigure) {
9520 LOGW("pipeline is under construction.\n");
9522 MMPLAYER_PLAYBACK_LOCK(player);
9523 MMPLAYER_PLAYBACK_UNLOCK(player);
9525 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9527 /* wait for state transition */
9528 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9530 if (ret == GST_STATE_CHANGE_FAILURE)
9531 LOGE("failed to change pipeline state within %d sec\n", timeout);
9535 /* NOTE : it should be able to call 'stop' anytime*/
9537 _mmplayer_stop(MMHandleType hplayer) // @
9539 mm_player_t* player = (mm_player_t*)hplayer;
9540 int ret = MM_ERROR_NONE;
9544 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9546 /* check current state */
9547 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9549 /* check pipline building state */
9550 __mmplayer_check_pipeline(player);
9551 __mmplayer_reset_gapless_state(player);
9553 /* NOTE : application should not wait for EOS after calling STOP */
9554 __mmplayer_cancel_eos_timer(player);
9556 __mmplayer_unrealize_streaming_ext(player);
9559 player->doing_seek = FALSE;
9562 ret = __gst_stop(player);
9564 if (ret != MM_ERROR_NONE)
9565 LOGE("failed to stop player.\n");
9573 _mmplayer_pause(MMHandleType hplayer) // @
9575 mm_player_t* player = (mm_player_t*)hplayer;
9576 gint64 pos_msec = 0;
9577 gboolean async = FALSE;
9578 gint ret = MM_ERROR_NONE;
9582 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9584 /* check current state */
9585 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9587 /* check pipline building state */
9588 __mmplayer_check_pipeline(player);
9590 switch (MMPLAYER_CURRENT_STATE(player)) {
9591 case MM_PLAYER_STATE_READY:
9593 /* check prepare async or not.
9594 * In the case of streaming playback, it's recommned to avoid blocking wait.
9596 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9597 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9601 case MM_PLAYER_STATE_PLAYING:
9603 /* NOTE : store current point to overcome some bad operation
9604 *(returning zero when getting current position in paused state) of some
9607 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9608 LOGW("getting current position failed in paused\n");
9610 player->last_position = pos_msec;
9615 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9616 LOGD("doing async pause in case of ms buff src");
9620 /* pause pipeline */
9621 ret = __gst_pause(player, async);
9623 if (ret != MM_ERROR_NONE)
9624 LOGE("failed to pause player. ret : 0x%x\n", ret);
9626 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9627 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9628 LOGE("failed to update display_rotation");
9637 _mmplayer_resume(MMHandleType hplayer)
9639 mm_player_t* player = (mm_player_t*)hplayer;
9640 int ret = MM_ERROR_NONE;
9641 gboolean async = FALSE;
9645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9647 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9648 if (ret != MM_ERROR_NONE) {
9649 LOGE("failed to acquire sound focus.\n");
9653 /* check current state */
9654 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9656 ret = __gst_resume(player, async);
9658 if (ret != MM_ERROR_NONE)
9659 LOGE("failed to resume player.\n");
9667 __mmplayer_set_play_count(mm_player_t* player, gint count)
9669 MMHandleType attrs = 0;
9673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9675 attrs = MMPLAYER_GET_ATTRS(player);
9677 LOGE("fail to get attributes.\n");
9678 return MM_ERROR_PLAYER_INTERNAL;
9681 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9682 if (mmf_attrs_commit(attrs)) /* return -1 if error */
9683 LOGE("failed to commit\n");
9687 return MM_ERROR_NONE;
9691 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9693 mm_player_t* player = (mm_player_t*)hplayer;
9694 gint64 start_pos = 0;
9700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9701 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9703 player->section_repeat = TRUE;
9704 player->section_repeat_start = start;
9705 player->section_repeat_end = end;
9707 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9708 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9710 __mmplayer_set_play_count(player, infinity);
9712 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9713 player->playback_rate,
9715 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9716 GST_SEEK_TYPE_SET, start_pos,
9717 GST_SEEK_TYPE_SET, end_pos))) {
9718 LOGE("failed to activate section repeat\n");
9720 return MM_ERROR_PLAYER_SEEK;
9723 LOGD("succeeded to set section repeat from %d to %d\n",
9724 player->section_repeat_start, player->section_repeat_end);
9728 return MM_ERROR_NONE;
9732 __mmplayer_set_pcm_extraction(mm_player_t* player)
9734 gint64 start_nsec = 0;
9735 gint64 end_nsec = 0;
9736 gint64 dur_nsec = 0;
9737 gint64 dur_msec = 0;
9738 int required_start = 0;
9739 int required_end = 0;
9744 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9746 mm_attrs_multiple_get(player->attrs,
9748 "pcm_extraction_start_msec", &required_start,
9749 "pcm_extraction_end_msec", &required_end,
9752 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9754 if (required_start == 0 && required_end == 0) {
9755 LOGD("extracting entire stream");
9756 return MM_ERROR_NONE;
9757 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9758 LOGD("invalid range for pcm extraction");
9759 return MM_ERROR_INVALID_ARGUMENT;
9763 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9765 LOGE("failed to get duration");
9766 return MM_ERROR_PLAYER_INTERNAL;
9768 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9770 if (dur_msec < required_end) {
9772 LOGD("invalid end pos for pcm extraction");
9773 return MM_ERROR_INVALID_ARGUMENT;
9776 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9777 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9779 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9782 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9783 GST_SEEK_TYPE_SET, start_nsec,
9784 GST_SEEK_TYPE_SET, end_nsec))) {
9785 LOGE("failed to seek for pcm extraction\n");
9787 return MM_ERROR_PLAYER_SEEK;
9790 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9794 return MM_ERROR_NONE;
9798 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9800 mm_player_t* player = (mm_player_t*)hplayer;
9806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9808 player->section_repeat = FALSE;
9810 __mmplayer_set_play_count(player, onetime);
9812 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9814 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9817 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9818 GST_SEEK_TYPE_SET, cur_pos,
9819 GST_SEEK_TYPE_SET, player->duration))) {
9820 LOGE("failed to deactivate section repeat\n");
9822 return MM_ERROR_PLAYER_SEEK;
9827 return MM_ERROR_NONE;
9831 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9833 mm_player_t* player = (mm_player_t*)hplayer;
9834 gint64 pos_msec = 0;
9835 int ret = MM_ERROR_NONE;
9837 signed long long start = 0, stop = 0;
9838 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9841 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9842 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9844 /* The sound of video is not supported under 0.0 and over 2.0. */
9845 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9846 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9849 _mmplayer_set_mute(hplayer, mute);
9851 if (player->playback_rate == rate)
9852 return MM_ERROR_NONE;
9854 /* If the position is reached at start potion during fast backward, EOS is posted.
9855 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9857 player->playback_rate = rate;
9859 current_state = MMPLAYER_CURRENT_STATE(player);
9861 if (current_state != MM_PLAYER_STATE_PAUSED)
9862 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9864 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9866 if ((current_state == MM_PLAYER_STATE_PAUSED)
9867 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9868 LOGW("returning last point : %lld\n", player->last_position);
9869 pos_msec = player->last_position;
9875 stop = GST_CLOCK_TIME_NONE;
9877 start = GST_CLOCK_TIME_NONE;
9880 if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9883 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9884 GST_SEEK_TYPE_SET, start,
9885 GST_SEEK_TYPE_SET, stop))) {
9886 LOGE("failed to set speed playback\n");
9887 return MM_ERROR_PLAYER_SEEK;
9890 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9894 return MM_ERROR_NONE;;
9898 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9900 mm_player_t* player = (mm_player_t*)hplayer;
9901 int ret = MM_ERROR_NONE;
9905 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9907 /* check pipline building state */
9908 __mmplayer_check_pipeline(player);
9910 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9918 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
9920 mm_player_t* player = (mm_player_t*)hplayer;
9921 int ret = MM_ERROR_NONE;
9923 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9925 ret = __gst_get_position(player, format, position);
9931 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
9933 mm_player_t* player = (mm_player_t*)hplayer;
9934 int ret = MM_ERROR_NONE;
9936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9938 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9944 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
9946 mm_player_t* player = (mm_player_t*)hplayer;
9947 int ret = MM_ERROR_NONE;
9951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9953 ret = __gst_adjust_subtitle_position(player, format, position);
9960 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
9962 mm_player_t* player = (mm_player_t*)hplayer;
9963 int ret = MM_ERROR_NONE;
9967 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9969 ret = __gst_adjust_video_position(player, offset);
9977 __mmplayer_is_midi_type(gchar* str_caps)
9979 if ((g_strrstr(str_caps, "audio/midi")) ||
9980 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9981 (g_strrstr(str_caps, "application/x-smaf")) ||
9982 (g_strrstr(str_caps, "audio/x-imelody")) ||
9983 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9984 (g_strrstr(str_caps, "audio/xmf")) ||
9985 (g_strrstr(str_caps, "audio/mxmf"))) {
9994 __mmplayer_is_only_mp3_type(gchar *str_caps)
9996 if (g_strrstr(str_caps, "application/x-id3") ||
9997 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10003 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10005 GstStructure* caps_structure = NULL;
10006 gint samplerate = 0;
10010 MMPLAYER_RETURN_IF_FAIL(player && caps);
10012 caps_structure = gst_caps_get_structure(caps, 0);
10014 /* set stream information */
10015 gst_structure_get_int(caps_structure, "rate", &samplerate);
10016 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10018 gst_structure_get_int(caps_structure, "channels", &channels);
10019 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10021 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10025 __mmplayer_update_content_type_info(mm_player_t* player)
10028 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10030 if (__mmplayer_is_midi_type(player->type)) {
10031 player->bypass_audio_effect = TRUE;
10032 } else if (g_strrstr(player->type, "application/x-hls")) {
10033 /* If it can't know exact type when it parses uri because of redirection case,
10034 * it will be fixed by typefinder or when doing autoplugging.
10036 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10037 if (player->streamer) {
10038 player->streamer->is_adaptive_streaming = TRUE;
10039 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10040 player->streamer->buffering_req.runtime_second = 5;
10042 } else if (g_strrstr(player->type, "application/dash+xml")) {
10043 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10050 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10051 GstCaps *caps, gpointer data)
10053 mm_player_t* player = (mm_player_t*)data;
10054 GstPad* pad = NULL;
10058 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10060 /* store type string */
10061 MMPLAYER_FREEIF(player->type);
10062 player->type = gst_caps_to_string(caps);
10064 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10066 if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10067 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10068 (g_strrstr(player->type, "audio/x-raw-int"))) {
10069 LOGE("not support media format\n");
10071 if (player->msg_posted == FALSE) {
10072 MMMessageParamType msg_param;
10073 memset(&msg_param, 0, sizeof(MMMessageParamType));
10075 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10076 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10078 /* don't post more if one was sent already */
10079 player->msg_posted = TRUE;
10084 __mmplayer_update_content_type_info(player);
10086 pad = gst_element_get_static_pad(tf, "src");
10088 LOGE("fail to get typefind src pad.\n");
10092 if (player->use_decodebin) {
10093 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10094 gboolean async = FALSE;
10095 LOGE("failed to autoplug %s\n", player->type);
10097 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10099 if (async && player->msg_posted == FALSE)
10100 __mmplayer_handle_missed_plugin(player);
10106 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10107 gboolean async = FALSE;
10108 LOGE("failed to autoplug %s\n", player->type);
10110 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10112 if (async && player->msg_posted == FALSE)
10113 __mmplayer_handle_missed_plugin(player);
10118 /* finish autopluging if no dynamic pad waiting */
10119 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10120 if (!MMPLAYER_IS_RTSP_STREAMING(player))
10121 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10126 gst_object_unref(GST_OBJECT(pad));
10133 static GstElement *
10134 __mmplayer_create_decodebin(mm_player_t* player)
10136 GstElement *decodebin = NULL;
10140 /* create decodebin */
10141 decodebin = gst_element_factory_make("decodebin", NULL);
10144 LOGE("fail to create decodebin\n");
10148 /* raw pad handling signal */
10149 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10150 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10152 /* no-more-pad pad handling signal */
10153 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10154 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10156 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10157 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10159 /* This signal is emitted when a pad for which there is no further possible
10160 decoding is added to the decodebin.*/
10161 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10162 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10164 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10165 before looking for any elements that can handle that stream.*/
10166 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10167 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10169 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10170 before looking for any elements that can handle that stream.*/
10171 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10172 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10174 /* This signal is emitted once decodebin has finished decoding all the data.*/
10175 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10176 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10178 /* This signal is emitted when a element is added to the bin.*/
10179 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10180 G_CALLBACK(__mmplayer_gst_element_added), player);
10187 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10189 MMPlayerGstElement* mainbin = NULL;
10190 GstElement* decodebin = NULL;
10191 GstElement* queue2 = NULL;
10192 GstPad* sinkpad = NULL;
10193 GstPad* qsrcpad = NULL;
10194 gchar *caps_str = NULL;
10195 gint64 dur_bytes = 0L;
10197 guint max_buffer_size_bytes = 0;
10198 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10201 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10203 mainbin = player->pipeline->mainbin;
10205 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10206 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10207 LOGD("creating http streaming buffering queue(queue2)\n");
10209 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10210 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10212 queue2 = gst_element_factory_make("queue2", "queue2");
10214 LOGE("failed to create buffering queue element\n");
10218 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10219 LOGE("failed to add buffering queue\n");
10223 sinkpad = gst_element_get_static_pad(queue2, "sink");
10224 qsrcpad = gst_element_get_static_pad(queue2, "src");
10226 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10227 LOGE("failed to link buffering queue\n");
10231 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10232 LOGE("fail to get duration.\n");
10234 LOGD("dur_bytes = %lld\n", dur_bytes);
10236 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10238 if (dur_bytes > 0) {
10239 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10240 type = MUXED_BUFFER_TYPE_FILE;
10242 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10243 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10249 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10250 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10251 if (!g_strrstr(player->type, "video/mpegts")) {
10252 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10253 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10255 __mm_player_streaming_set_queue2(player->streamer,
10258 max_buffer_size_bytes,
10259 player->ini.http_buffering_time,
10261 player->ini.http_buffering_limit, // no meaning
10263 player->http_file_buffering_path,
10264 (guint64)dur_bytes);
10267 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10268 LOGE("failed to sync queue2 state with parent\n");
10274 gst_object_unref(GST_OBJECT(sinkpad));
10276 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10277 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10281 /* create decodebin */
10282 decodebin = __mmplayer_create_decodebin(player);
10285 LOGE("can not create autoplug element\n");
10289 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10290 LOGE("failed to add decodebin\n");
10294 /* to force caps on the decodebin element and avoid reparsing stuff by
10295 * typefind. It also avoids a deadlock in the way typefind activates pads in
10296 * the state change */
10297 g_object_set(decodebin, "sink-caps", caps, NULL);
10299 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10301 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10302 LOGE("failed to link decodebin\n");
10306 gst_object_unref(GST_OBJECT(sinkpad));
10308 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10309 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10311 /* set decodebin property about buffer in streaming playback. *
10312 * in case of hls, it does not need to have big buffer *
10313 * because it is kind of adaptive streaming. */
10314 if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10315 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10316 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10317 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10318 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10320 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10321 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10322 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10325 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10326 "high-percent", (gint)player->ini.http_buffering_limit,
10327 "low-percent", 1, // 1%
10328 "max-size-bytes", max_size_bytes,
10329 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10330 "max-size-buffers", 0, NULL); // disable or automatic
10333 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10334 LOGE("failed to sync decodebin state with parent\n");
10344 MMPLAYER_FREEIF(caps_str);
10347 gst_object_unref(GST_OBJECT(sinkpad));
10350 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10351 * You need to explicitly set elements to the NULL state before
10352 * dropping the final reference, to allow them to clean up.
10354 gst_element_set_state(queue2, GST_STATE_NULL);
10356 /* And, it still has a parent "player".
10357 * You need to let the parent manage the object instead of unreffing the object directly.
10359 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10360 gst_object_unref(queue2);
10365 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10366 * You need to explicitly set elements to the NULL state before
10367 * dropping the final reference, to allow them to clean up.
10369 gst_element_set_state(decodebin, GST_STATE_NULL);
10371 /* And, it still has a parent "player".
10372 * You need to let the parent manage the object instead of unreffing the object directly.
10375 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10376 gst_object_unref(decodebin);
10383 /* it will return first created element */
10385 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10387 MMPlayerGstElement* mainbin = NULL;
10388 const char* mime = NULL;
10389 const GList* item = NULL;
10390 const gchar* klass = NULL;
10391 GstCaps* res = NULL;
10392 gboolean skip = FALSE;
10393 GstPad* queue_pad = NULL;
10394 GstElement* queue = NULL;
10395 GstElement *element = NULL;
10399 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10401 mainbin = player->pipeline->mainbin;
10403 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10405 /* return if we got raw output */
10406 if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10407 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10409 element = (GstElement*)gst_pad_get_parent(pad);
10410 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10411 * No queue will be added. I think it can caused breaking sound when playing raw audio
10412 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10413 * Anyway, currentely raw-queue seems not necessary.
10416 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10417 * has linked. if so, we need to add queue for quality of output. note that
10418 * decodebin also has same problem.
10420 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10422 /* add queue if needed */
10423 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10424 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) {
10425 LOGD("adding raw queue\n");
10427 queue = gst_element_factory_make("queue", NULL);
10429 LOGW("failed to create queue\n");
10434 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10435 LOGW("failed to set state READY to queue\n");
10439 /* add to pipeline */
10440 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10441 LOGW("failed to add queue\n");
10446 queue_pad = gst_element_get_static_pad(queue, "sink");
10448 if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10449 LOGW("failed to link queue\n");
10452 gst_object_unref(GST_OBJECT(queue_pad));
10456 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10457 LOGW("failed to set state PAUSED to queue\n");
10461 /* replace given pad to queue:src */
10462 pad = gst_element_get_static_pad(queue, "src");
10464 LOGW("failed to get pad from queue\n");
10469 /* check if player can do start continually */
10470 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10472 if (__mmplayer_link_sink(player, pad))
10473 __mmplayer_gst_decode_callback(element, pad, player);
10475 gst_object_unref(GST_OBJECT(element));
10481 item = player->factories;
10482 for (; item != NULL; item = item->next) {
10483 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10489 /* filtering exclude keyword */
10490 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10491 if (g_strrstr(GST_OBJECT_NAME(factory),
10492 player->ini.exclude_element_keyword[idx])) {
10493 LOGW("skipping [%s] by exculde keyword [%s]\n",
10494 GST_OBJECT_NAME(factory),
10495 player->ini.exclude_element_keyword[idx]);
10502 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10503 // omx decoder can not support mpeg4video data partitioned
10504 // rtsp streaming didn't know mpeg4video data partitioned format
10505 // so, if rtsp playback, player will skip omx_mpeg4dec.
10506 LOGW("skipping [%s] when rtsp streaming \n",
10507 GST_OBJECT_NAME(factory));
10512 if (skip) continue;
10514 /* check factory class for filtering */
10515 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10517 /*parsers are not required in case of external feeder*/
10518 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10521 /* NOTE : msl don't need to use image plugins.
10522 * So, those plugins should be skipped for error handling.
10524 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10525 LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10529 /* check pad compatability */
10530 for (pads = gst_element_factory_get_static_pad_templates(factory);
10531 pads != NULL; pads = pads->next) {
10532 GstStaticPadTemplate *temp1 = pads->data;
10533 GstCaps* static_caps = NULL;
10535 if (temp1->direction != GST_PAD_SINK
10536 || temp1->presence != GST_PAD_ALWAYS)
10539 /* using existing caps */
10540 if (GST_IS_CAPS(&temp1->static_caps.caps))
10541 static_caps = gst_caps_ref(temp1->static_caps.caps);
10544 static_caps = gst_caps_from_string(temp1->static_caps.string);
10546 res = gst_caps_intersect((GstCaps*)caps, static_caps);
10547 gst_caps_unref(static_caps);
10548 static_caps = NULL;
10550 if (res && !gst_caps_is_empty(res)) {
10551 GstElement *new_element;
10552 GList *elements = player->parsers;
10553 char *name_template = g_strdup(temp1->name_template);
10554 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10555 gst_caps_unref(res);
10557 /* check ALP Codec can be used or not */
10558 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10559 /* consider mp3 audio only */
10560 if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10561 /* try to use ALP decoder first instead of selected decoder */
10562 GstElement *element = NULL;
10563 GstElementFactory * element_facory;
10564 gchar *path = NULL;
10565 guint64 data_size = 0;
10566 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
10569 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10571 if (stat(path, &sb) == 0)
10572 data_size = (guint64)sb.st_size;
10573 LOGD("file size : %u", data_size);
10575 if (data_size > MIN_THRESHOLD_SIZE) {
10576 LOGD("checking if ALP can be used or not");
10577 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10579 /* check availability because multi-instance is not supported */
10580 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10582 if (ret != GST_STATE_CHANGE_SUCCESS) {
10583 // use just selected decoder
10584 gst_object_unref(element);
10585 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10586 // replace facotry to use omx
10588 gst_element_set_state(element, GST_STATE_NULL);
10589 gst_object_unref(element);
10591 element_facory = gst_element_factory_find("omx_mp3dec");
10592 /* replace, otherwise use selected thing instead */
10593 if (element_facory) {
10594 factory = element_facory;
10595 name_to_plug = GST_OBJECT_NAME(factory);
10601 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10602 if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10603 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10605 if (strncasecmp(env, "yes", 3) == 0) {
10606 LOGD("skipping [%s] by disabled\n", name_to_plug);
10607 MMPLAYER_FREEIF(name_template);
10614 LOGD("found %s to plug\n", name_to_plug);
10616 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10617 if (!new_element) {
10618 LOGE("failed to create element [%s]. continue with next.\n",
10619 GST_OBJECT_NAME(factory));
10621 MMPLAYER_FREEIF(name_template);
10626 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10627 * because parser can accept its own output as input.
10629 if (g_strrstr(klass, "Parser")) {
10630 gchar *selected = NULL;
10632 for (; elements; elements = g_list_next(elements)) {
10633 gchar *element_name = elements->data;
10635 if (g_strrstr(element_name, name_to_plug)) {
10636 LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10642 MMPLAYER_FREEIF(name_template);
10646 selected = g_strdup(name_to_plug);
10647 player->parsers = g_list_append(player->parsers, selected);
10650 /* store specific handles for futher control */
10651 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10652 /* FIXIT : first value will be overwritten if there's more
10653 * than 1 demuxer/parser
10655 LOGD("plugged element is demuxer. take it\n");
10656 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10657 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10659 /*Added for multi audio support */
10660 if (g_strrstr(klass, "Demux")) {
10661 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10662 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10664 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10665 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10666 this code should be removed after mpegtsdemux is fixed */
10667 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10668 LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10669 player->no_more_pad = TRUE;
10672 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10673 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10674 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10675 if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10676 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10677 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10678 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10679 } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10680 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10681 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10682 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10684 /* NOTE : IF one codec is found, add it to supported_codec and remove from
10685 * missing plugin. Both of them are used to check what's supported codec
10686 * before returning result of play start. And, missing plugin should be
10687 * updated here for multi track files.
10689 if (g_str_has_prefix(mime, "video")) {
10690 GstPad *src_pad = NULL;
10691 GstPadTemplate *pad_templ = NULL;
10692 GstCaps *caps = NULL;
10693 gchar *caps_str = NULL;
10695 LOGD("found VIDEO decoder\n");
10696 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10697 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10699 src_pad = gst_element_get_static_pad(new_element, "src");
10700 pad_templ = gst_pad_get_pad_template(src_pad);
10701 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10703 caps_str = gst_caps_to_string(caps);
10706 MMPLAYER_FREEIF(caps_str);
10707 gst_object_unref(src_pad);
10708 } else if (g_str_has_prefix(mime, "audio")) {
10709 LOGD("found AUDIO decoder\n");
10710 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10711 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10715 if (!__mmplayer_close_link(player, pad, new_element,
10716 name_template, gst_element_factory_get_static_pad_templates(factory))) {
10717 MMPLAYER_FREEIF(name_template);
10718 if (player->keep_detecting_vcodec)
10721 /* Link is failed even though a supportable codec is found. */
10722 __mmplayer_check_not_supported_codec(player, klass, mime);
10724 LOGE("failed to call _close_link\n");
10728 MMPLAYER_FREEIF(name_template);
10732 gst_caps_unref(res);
10737 /* There is no available codec. */
10738 __mmplayer_check_not_supported_codec(player, klass, mime);
10746 gst_object_unref(queue);
10749 gst_object_unref(queue_pad);
10752 gst_object_unref(element);
10759 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10763 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10764 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10766 LOGD("class : %s, mime : %s \n", factory_class, mime);
10768 /* add missing plugin */
10769 /* NOTE : msl should check missing plugin for image mime type.
10770 * Some motion jpeg clips can have playable audio track.
10771 * So, msl have to play audio after displaying popup written video format not supported.
10773 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10774 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10775 LOGD("not found demuxer\n");
10776 player->not_found_demuxer = TRUE;
10777 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10783 if (!g_strrstr(factory_class, "Demuxer")) {
10784 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10785 LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10786 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10788 /* check that clip have multi tracks or not */
10789 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10790 LOGD("video plugin is already linked\n");
10792 LOGW("add VIDEO to missing plugin\n");
10793 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10795 } else if (g_str_has_prefix(mime, "audio")) {
10796 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10797 LOGD("audio plugin is already linked\n");
10799 LOGW("add AUDIO to missing plugin\n");
10800 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10808 return MM_ERROR_NONE;
10813 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10815 mm_player_t* player = (mm_player_t*)data;
10819 MMPLAYER_RETURN_IF_FAIL(player);
10821 /* remove fakesink. */
10822 if (!__mmplayer_gst_remove_fakesink(player,
10823 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10824 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10825 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10826 * source element are not same. To overcome this situation, this function will called
10827 * several places and several times. Therefore, this is not an error case.
10832 LOGD("pipeline has completely constructed\n");
10834 if ((player->ini.async_start) &&
10835 (player->msg_posted == FALSE) &&
10836 (player->cmd >= MMPLAYER_COMMAND_START))
10837 __mmplayer_handle_missed_plugin(player);
10839 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10843 __mmplayer_verify_next_play_path(mm_player_t *player)
10845 MMHandleType attrs = 0;
10846 MMPlayerParseProfile profile;
10847 gint uri_idx = 0, check_cnt = 0;
10849 gint mode = MM_PLAYER_PD_MODE_NONE;
10853 guint num_of_list = 0;
10857 LOGD("checking for gapless play");
10859 if (player->pipeline->textbin) {
10860 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10864 attrs = MMPLAYER_GET_ATTRS(player);
10866 LOGE("fail to get attributes.\n");
10870 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10873 /* gapless playback is not supported in case of video at TV profile. */
10875 LOGW("not support video gapless playback");
10880 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10881 if (mode == TRUE) {
10887 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10888 LOGE("can not get play count\n");
10890 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10891 LOGE("can not get gapless mode\n");
10893 if (video && !gapless) {
10894 LOGW("not enabled video gapless playback");
10898 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10902 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10906 num_of_list = g_list_length(player->uri_info.uri_list);
10908 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10910 if (num_of_list == 0) {
10911 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10912 LOGE("can not get profile_uri\n");
10917 LOGE("uri list is empty.\n");
10921 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10922 LOGD("add original path : %s ", uri);
10928 uri_idx = player->uri_info.uri_idx;
10933 if (check_cnt > num_of_list) {
10934 LOGE("there is no valid uri.");
10938 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10940 if (uri_idx < num_of_list-1) {
10943 if ((count <= 1) && (count != -1)) {
10944 LOGD("no repeat.");
10946 } else if (count > 1) {
10947 /* decrease play count */
10948 /* we succeeded to rewind. update play count and then wait for next EOS */
10951 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10953 /* commit attribute */
10954 if (mmf_attrs_commit(attrs))
10955 LOGE("failed to commit attribute\n");
10958 /* count < 0 : repeat continually */
10962 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10963 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10966 LOGW("next uri does not exist\n");
10970 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10971 LOGE("failed to parse profile\n");
10975 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10976 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10977 LOGW("uri type is not supported(%d).", profile.uri_type);
10984 player->uri_info.uri_idx = uri_idx;
10985 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10987 if (mmf_attrs_commit(player->attrs)) {
10988 LOGE("failed to commit.\n");
10992 LOGD("next uri %s(%d)\n", uri, uri_idx);
10998 LOGE("unable to play next path. EOS will be posted soon.\n");
11003 __mmplayer_initialize_next_play(mm_player_t *player)
11009 player->smooth_streaming = FALSE;
11010 player->videodec_linked = 0;
11011 player->audiodec_linked = 0;
11012 player->videosink_linked = 0;
11013 player->audiosink_linked = 0;
11014 player->textsink_linked = 0;
11015 player->is_external_subtitle_present = FALSE;
11016 player->not_supported_codec = MISSING_PLUGIN_NONE;
11017 player->can_support_codec = FOUND_PLUGIN_NONE;
11018 player->pending_seek.is_pending = FALSE;
11019 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11020 player->pending_seek.pos = 0;
11021 player->msg_posted = FALSE;
11022 player->has_many_types = FALSE;
11023 player->no_more_pad = FALSE;
11024 player->not_found_demuxer = 0;
11025 player->doing_seek = FALSE;
11026 player->max_audio_channels = 0;
11027 player->is_subtitle_force_drop = FALSE;
11028 player->play_subtitle = FALSE;
11029 player->use_textoverlay = FALSE;
11030 player->adjust_subtitle_pos = 0;
11032 player->updated_bitrate_count = 0;
11033 player->total_bitrate = 0;
11034 player->updated_maximum_bitrate_count = 0;
11035 player->total_maximum_bitrate = 0;
11037 _mmplayer_track_initialize(player);
11039 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11040 player->bitrate[i] = 0;
11041 player->maximum_bitrate[i] = 0;
11044 if (player->v_stream_caps) {
11045 gst_caps_unref(player->v_stream_caps);
11046 player->v_stream_caps = NULL;
11049 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11050 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11052 /* clean found parsers */
11053 if (player->parsers) {
11054 GList *parsers = player->parsers;
11055 for (; parsers; parsers = g_list_next(parsers)) {
11056 gchar *name = parsers->data;
11057 MMPLAYER_FREEIF(name);
11059 g_list_free(player->parsers);
11060 player->parsers = NULL;
11063 /* clean found audio decoders */
11064 if (player->audio_decoders) {
11065 GList *a_dec = player->audio_decoders;
11066 for (; a_dec; a_dec = g_list_next(a_dec)) {
11067 gchar *name = a_dec->data;
11068 MMPLAYER_FREEIF(name);
11070 g_list_free(player->audio_decoders);
11071 player->audio_decoders = NULL;
11078 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11080 MMPlayerGstElement *mainbin = NULL;
11081 MMMessageParamType msg_param = {0,};
11082 GstElement *element = NULL;
11083 MMHandleType attrs = 0;
11085 enum MainElementID elemId = MMPLAYER_M_NUM;
11089 if ((player == NULL) ||
11090 (player->pipeline == NULL) ||
11091 (player->pipeline->mainbin == NULL)) {
11092 LOGE("player is null.\n");
11096 mainbin = player->pipeline->mainbin;
11097 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11099 attrs = MMPLAYER_GET_ATTRS(player);
11101 LOGE("fail to get attributes.\n");
11105 /* Initialize Player values */
11106 __mmplayer_initialize_next_play(player);
11108 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11110 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11111 LOGE("failed to parse profile\n");
11112 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11116 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11117 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11118 LOGE("it's dash or hls. not support.");
11119 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11124 switch (player->profile.uri_type) {
11126 case MM_PLAYER_URI_TYPE_FILE:
11128 LOGD("using filesrc for 'file://' handler.\n");
11130 element = gst_element_factory_make("filesrc", "source");
11133 LOGE("failed to create filesrc\n");
11137 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11140 case MM_PLAYER_URI_TYPE_URL_HTTP:
11142 gchar *user_agent, *proxy, *cookies, **cookie_list;
11143 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11144 user_agent = proxy = cookies = NULL;
11145 cookie_list = NULL;
11147 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11149 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11152 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11154 /* get attribute */
11155 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11156 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11157 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11158 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11160 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11161 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11162 LOGD("get timeout from ini\n");
11163 http_timeout = player->ini.http_timeout;
11166 /* get attribute */
11167 SECURE_LOGD("location : %s\n", player->profile.uri);
11168 SECURE_LOGD("cookies : %s\n", cookies);
11169 SECURE_LOGD("proxy : %s\n", proxy);
11170 SECURE_LOGD("user_agent : %s\n", user_agent);
11171 LOGD("timeout : %d\n", http_timeout);
11173 /* setting property to streaming source */
11174 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11175 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11176 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11178 /* check if prosy is vailid or not */
11179 if (util_check_valid_url(proxy))
11180 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11181 /* parsing cookies */
11182 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11183 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11185 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11189 LOGE("not support uri type %d\n", player->profile.uri_type);
11194 LOGE("no source element was created.\n");
11198 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11199 LOGE("failed to add source element to pipeline\n");
11200 gst_object_unref(GST_OBJECT(element));
11205 /* take source element */
11206 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11207 mainbin[MMPLAYER_M_SRC].gst = element;
11211 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11212 if (player->streamer == NULL) {
11213 player->streamer = __mm_player_streaming_create();
11214 __mm_player_streaming_initialize(player->streamer);
11217 elemId = MMPLAYER_M_TYPEFIND;
11218 element = gst_element_factory_make("typefind", "typefinder");
11219 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11220 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11222 elemId = MMPLAYER_M_AUTOPLUG;
11223 element = __mmplayer_create_decodebin(player);
11226 /* check autoplug element is OK */
11228 LOGE("can not create element(%d)\n", elemId);
11232 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11233 LOGE("failed to add sinkbin to pipeline\n");
11234 gst_object_unref(GST_OBJECT(element));
11239 mainbin[elemId].id = elemId;
11240 mainbin[elemId].gst = element;
11242 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11243 LOGE("Failed to link src - autoplug(or typefind)\n");
11247 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11248 LOGE("Failed to change state of src element\n");
11252 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11253 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11254 LOGE("Failed to change state of decodebin\n");
11258 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11259 LOGE("Failed to change state of src element\n");
11264 player->gapless.stream_changed = TRUE;
11265 player->gapless.running = TRUE;
11271 MMPLAYER_PLAYBACK_UNLOCK(player);
11273 if (!player->msg_posted) {
11274 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11275 player->msg_posted = TRUE;
11282 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11284 mm_player_selector_t *selector = &player->selector[type];
11285 MMPlayerGstElement *sinkbin = NULL;
11286 enum MainElementID selectorId = MMPLAYER_M_NUM;
11287 enum MainElementID sinkId = MMPLAYER_M_NUM;
11288 GstPad *srcpad = NULL;
11289 GstPad *sinkpad = NULL;
11290 gboolean send_notice = FALSE;
11293 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11295 LOGD("type %d", type);
11298 case MM_PLAYER_TRACK_TYPE_AUDIO:
11299 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11300 sinkId = MMPLAYER_A_BIN;
11301 sinkbin = player->pipeline->audiobin;
11303 case MM_PLAYER_TRACK_TYPE_VIDEO:
11304 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11305 sinkId = MMPLAYER_V_BIN;
11306 sinkbin = player->pipeline->videobin;
11307 send_notice = TRUE;
11309 case MM_PLAYER_TRACK_TYPE_TEXT:
11310 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11311 sinkId = MMPLAYER_T_BIN;
11312 sinkbin = player->pipeline->textbin;
11315 LOGE("requested type is not supportable");
11320 if (player->pipeline->mainbin[selectorId].gst) {
11323 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11325 if (selector->event_probe_id != 0)
11326 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11327 selector->event_probe_id = 0;
11329 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11330 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11332 if (srcpad && sinkpad) {
11333 /* after getting drained signal there is no data flows, so no need to do pad_block */
11334 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11335 gst_pad_unlink(srcpad, sinkpad);
11337 /* send custom event to sink pad to handle it at video sink */
11339 LOGD("send custom event to sinkpad");
11340 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11341 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11342 gst_pad_send_event(sinkpad, event);
11346 gst_object_unref(sinkpad);
11349 gst_object_unref(srcpad);
11352 LOGD("selector release");
11354 /* release and unref requests pad from the selector */
11355 for (n = 0; n < selector->channels->len; n++) {
11356 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11357 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11359 g_ptr_array_set_size(selector->channels, 0);
11361 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11362 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11364 player->pipeline->mainbin[selectorId].gst = NULL;
11372 __mmplayer_deactivate_old_path(mm_player_t *player)
11375 MMPLAYER_RETURN_IF_FAIL(player);
11377 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11378 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11379 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11380 LOGE("deactivate selector error");
11384 _mmplayer_track_destroy(player);
11385 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11387 if (player->streamer) {
11388 __mm_player_streaming_deinitialize(player->streamer);
11389 __mm_player_streaming_destroy(player->streamer);
11390 player->streamer = NULL;
11393 MMPLAYER_PLAYBACK_LOCK(player);
11394 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11401 if (!player->msg_posted) {
11402 MMMessageParamType msg = {0,};
11405 msg.code = MM_ERROR_PLAYER_INTERNAL;
11406 LOGE("next_uri_play> deactivate error");
11408 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11409 player->msg_posted = TRUE;
11414 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11416 int result = MM_ERROR_NONE;
11417 mm_player_t* player = (mm_player_t*) hplayer;
11420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11423 player->http_file_buffering_path = (gchar*)file_path;
11424 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11430 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11432 int result = MM_ERROR_NONE;
11433 mm_player_t* player = (mm_player_t*) hplayer;
11436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11438 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11439 if (mmf_attrs_commit(player->attrs)) {
11440 LOGE("failed to commit the original uri.\n");
11441 result = MM_ERROR_PLAYER_INTERNAL;
11443 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11444 LOGE("failed to add the original uri in the uri list.\n");
11451 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11453 mm_player_t* player = (mm_player_t*) hplayer;
11454 guint num_of_list = 0;
11458 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11459 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11461 if (player->pipeline && player->pipeline->textbin) {
11462 LOGE("subtitle path is enabled.\n");
11463 return MM_ERROR_PLAYER_INVALID_STATE;
11466 num_of_list = g_list_length(player->uri_info.uri_list);
11468 if (is_first_path == TRUE) {
11469 if (num_of_list == 0) {
11470 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11471 LOGD("add original path : %s", uri);
11473 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11474 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11476 LOGD("change original path : %s", uri);
11479 MMHandleType attrs = 0;
11480 attrs = MMPLAYER_GET_ATTRS(player);
11482 if (num_of_list == 0) {
11483 char *original_uri = NULL;
11486 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11488 if (!original_uri) {
11489 LOGE("there is no original uri.");
11490 return MM_ERROR_PLAYER_INVALID_STATE;
11493 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11494 player->uri_info.uri_idx = 0;
11496 LOGD("add original path at first : %s(%d)", original_uri);
11500 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11501 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11505 return MM_ERROR_NONE;
11508 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11510 mm_player_t* player = (mm_player_t*) hplayer;
11511 char *next_uri = NULL;
11512 guint num_of_list = 0;
11515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11517 num_of_list = g_list_length(player->uri_info.uri_list);
11519 if (num_of_list > 0) {
11520 gint uri_idx = player->uri_info.uri_idx;
11522 if (uri_idx < num_of_list-1)
11527 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11528 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11530 *uri = g_strdup(next_uri);
11534 return MM_ERROR_NONE;
11538 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11539 GstCaps *caps, gpointer data)
11541 mm_player_t* player = (mm_player_t*)data;
11542 const gchar* klass = NULL;
11543 const gchar* mime = NULL;
11544 gchar* caps_str = NULL;
11546 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11547 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11548 caps_str = gst_caps_to_string(caps);
11550 LOGW("unknown type of caps : %s from %s",
11551 caps_str, GST_ELEMENT_NAME(elem));
11553 MMPLAYER_FREEIF(caps_str);
11555 /* There is no available codec. */
11556 __mmplayer_check_not_supported_codec(player, klass, mime);
11560 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11561 GstCaps * caps, gpointer data)
11563 mm_player_t* player = (mm_player_t*)data;
11564 const char* mime = NULL;
11565 gboolean ret = TRUE;
11567 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11568 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11570 if (g_str_has_prefix(mime, "audio")) {
11571 GstStructure* caps_structure = NULL;
11572 gint samplerate = 0;
11574 gchar *caps_str = NULL;
11576 caps_structure = gst_caps_get_structure(caps, 0);
11577 gst_structure_get_int(caps_structure, "rate", &samplerate);
11578 gst_structure_get_int(caps_structure, "channels", &channels);
11580 if ((channels > 0 && samplerate == 0)) {
11581 LOGD("exclude audio...");
11585 caps_str = gst_caps_to_string(caps);
11586 /* set it directly because not sent by TAG */
11587 if (g_strrstr(caps_str, "mobile-xmf"))
11588 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11589 MMPLAYER_FREEIF(caps_str);
11590 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11591 MMMessageParamType msg_param;
11592 memset(&msg_param, 0, sizeof(MMMessageParamType));
11593 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11594 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11595 LOGD("video file is not supported on this device");
11597 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11598 LOGD("already video linked");
11601 LOGD("found new stream");
11608 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11609 GstCaps* caps, GstElementFactory* factory, gpointer data)
11611 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11612 We are defining our own and will be removed when it actually exposed */
11614 GST_AUTOPLUG_SELECT_TRY,
11615 GST_AUTOPLUG_SELECT_EXPOSE,
11616 GST_AUTOPLUG_SELECT_SKIP
11617 } GstAutoplugSelectResult;
11619 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11620 mm_player_t* player = (mm_player_t*)data;
11622 gchar* factory_name = NULL;
11623 gchar* caps_str = NULL;
11624 const gchar* klass = NULL;
11626 int surface_type = 0;
11628 factory_name = GST_OBJECT_NAME(factory);
11629 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11630 caps_str = gst_caps_to_string(caps);
11632 LOGD("found new element [%s] to link", factory_name);
11634 /* store type string */
11635 if (player->type == NULL) {
11636 player->type = gst_caps_to_string(caps);
11637 __mmplayer_update_content_type_info(player);
11640 /* To support evasimagesink, omx is excluded temporarily*/
11641 mm_attrs_get_int_by_name(player->attrs,
11642 "display_surface_type", &surface_type);
11643 LOGD("check display surface type attribute: %d", surface_type);
11644 if (surface_type == MM_DISPLAY_SURFACE_EVAS && strstr(factory_name, "omx")) {
11645 LOGW("skipping [%s] for supporting evasimagesink temporarily.\n", factory_name);
11646 result = GST_AUTOPLUG_SELECT_SKIP;
11650 /* filtering exclude keyword */
11651 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11652 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11653 LOGW("skipping [%s] by exculde keyword [%s]\n",
11654 factory_name, player->ini.exclude_element_keyword[idx]);
11656 // NOTE : does we need to check n_value against the number of item selected?
11657 result = GST_AUTOPLUG_SELECT_SKIP;
11662 /* check factory class for filtering */
11663 /* NOTE : msl don't need to use image plugins.
11664 * So, those plugins should be skipped for error handling.
11666 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11667 LOGD("skipping [%s] by not required\n", factory_name);
11668 result = GST_AUTOPLUG_SELECT_SKIP;
11672 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11673 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11674 // TO CHECK : subtitle if needed, add subparse exception.
11675 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11676 result = GST_AUTOPLUG_SELECT_SKIP;
11680 if (g_strrstr(factory_name, "mpegpsdemux")) {
11681 LOGD("skipping PS container - not support\n");
11682 result = GST_AUTOPLUG_SELECT_SKIP;
11686 if (g_strrstr(factory_name, "mssdemux"))
11687 player->smooth_streaming = TRUE;
11689 /* check ALP Codec can be used or not */
11690 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11691 GstStructure* str = NULL;
11694 str = gst_caps_get_structure(caps, 0);
11696 gst_structure_get_int(str, "channels", &channels);
11698 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11699 if (player->max_audio_channels < channels)
11700 player->max_audio_channels = channels;
11702 /* set stream information */
11703 if (!player->audiodec_linked)
11704 __mmplayer_set_audio_attrs(player, caps);
11705 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11706 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11707 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11708 /* prepare resource manager for video decoder */
11709 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11711 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11712 /* prepare resource manager for video decoder */
11713 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11714 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11715 != MM_ERROR_NONE) {
11716 LOGW("could not prepare for video_decoder resource, skip it.");
11717 result = GST_AUTOPLUG_SELECT_SKIP;
11725 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11726 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11729 GstStructure *str = NULL;
11730 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11732 /* don't make video because of not required */
11733 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11734 (player->set_mode.media_packet_video_stream == FALSE)) {
11735 LOGD("no video because it's not required. -> return expose");
11736 result = GST_AUTOPLUG_SELECT_EXPOSE;
11740 /* get w/h for omx state-tune */
11741 str = gst_caps_get_structure(caps, 0);
11742 gst_structure_get_int(str, "width", &width);
11745 if (player->v_stream_caps) {
11746 gst_caps_unref(player->v_stream_caps);
11747 player->v_stream_caps = NULL;
11750 player->v_stream_caps = gst_caps_copy(caps);
11751 LOGD("take caps for video state tune");
11752 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11756 if (g_strrstr(klass, "Decoder")) {
11757 const char* mime = NULL;
11758 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11760 if (g_str_has_prefix(mime, "video")) {
11761 // __mmplayer_check_video_zero_cpoy(player, factory);
11763 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11764 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11766 player->videodec_linked = 1;
11767 } else if (g_str_has_prefix(mime, "audio")) {
11768 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11769 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11771 player->audiodec_linked = 1;
11776 MMPLAYER_FREEIF(caps_str);
11783 static GValueArray*
11784 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
11785 GstCaps * caps, gpointer data)
11787 //mm_player_t* player = (mm_player_t*)data;
11789 LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11790 gst_caps_to_string(caps),
11791 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11798 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11799 gpointer data) // @
11801 //mm_player_t* player = (mm_player_t*)data;
11802 GstCaps* caps = NULL;
11804 LOGD("[Decodebin2] pad-removed signal\n");
11806 caps = gst_pad_query_caps(new_pad, NULL);
11808 gchar* caps_str = NULL;
11809 caps_str = gst_caps_to_string(caps);
11811 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11813 MMPLAYER_FREEIF(caps_str);
11818 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11820 mm_player_t* player = (mm_player_t*)data;
11823 MMPLAYER_RETURN_IF_FAIL(player);
11825 LOGD("__mmplayer_gst_decode_drained");
11827 if (player->use_deinterleave == TRUE) {
11828 LOGD("group playing mode.");
11832 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11833 LOGW("Fail to get cmd lock");
11837 if (!__mmplayer_verify_next_play_path(player)) {
11838 LOGD("decoding is finished.");
11839 __mmplayer_reset_gapless_state(player);
11840 MMPLAYER_CMD_UNLOCK(player);
11844 player->gapless.reconfigure = TRUE;
11845 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11846 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11848 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11849 __mmplayer_deactivate_old_path(player);
11850 MMPLAYER_CMD_UNLOCK(player);
11856 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11858 mm_player_t* player = (mm_player_t*)data;
11859 const gchar* klass = NULL;
11860 gchar* factory_name = NULL;
11862 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11863 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11865 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11867 if (__mmplayer_add_dump_buffer_probe(player, element))
11868 LOGD("add buffer probe");
11871 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11872 gchar* selected = NULL;
11873 selected = g_strdup(GST_ELEMENT_NAME(element));
11874 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11878 if (g_strrstr(klass, "Parser")) {
11879 gchar* selected = NULL;
11881 selected = g_strdup(factory_name);
11882 player->parsers = g_list_append(player->parsers, selected);
11885 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
11886 /* FIXIT : first value will be overwritten if there's more
11887 * than 1 demuxer/parser
11890 //LOGD("plugged element is demuxer. take it\n");
11891 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11892 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11894 /*Added for multi audio support */ // Q. del?
11895 if (g_strrstr(klass, "Demux")) {
11896 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11897 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11901 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11902 int surface_type = 0;
11904 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11907 // to support trust-zone only
11908 if (g_strrstr(factory_name, "asfdemux")) {
11909 LOGD("set file-location %s\n", player->profile.uri);
11910 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11912 if (player->video_hub_download_mode == TRUE)
11913 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11914 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11915 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11916 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11917 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11918 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11919 (__mmplayer_is_only_mp3_type(player->type))) {
11920 LOGD("[mpegaudioparse] set streaming pull mode.");
11921 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11923 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
11924 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11927 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11928 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11929 LOGD("plugged element is multiqueue. take it\n");
11931 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11932 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11934 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11935 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
11936 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11937 __mm_player_streaming_set_multiqueue(player->streamer,
11940 player->ini.http_buffering_time,
11942 player->ini.http_buffering_limit);
11944 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11951 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11954 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11956 if (MMPLAYER_IS_STREAMING(player))
11959 /* This callback can be set to music player only. */
11960 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11961 LOGW("audio callback is not supported for video");
11965 if (player->audio_stream_cb) {
11966 GstPad *pad = NULL;
11968 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11971 LOGE("failed to get sink pad from audiosink to probe data\n");
11974 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11975 __mmplayer_audio_stream_probe, player, NULL);
11977 gst_object_unref(pad);
11981 LOGE("There is no audio callback to configure.\n");
11991 __mmplayer_init_factories(mm_player_t* player) // @
11993 MMPLAYER_RETURN_IF_FAIL(player);
11995 player->factories = gst_registry_feature_filter(gst_registry_get(),
11996 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
11997 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12001 __mmplayer_release_factories(mm_player_t* player) // @
12004 MMPLAYER_RETURN_IF_FAIL(player);
12006 if (player->factories) {
12007 gst_plugin_feature_list_free(player->factories);
12008 player->factories = NULL;
12015 __mmplayer_release_misc(mm_player_t* player)
12018 gboolean cur_mode = player->set_mode.rich_audio;
12021 MMPLAYER_RETURN_IF_FAIL(player);
12023 player->video_stream_cb = NULL;
12024 player->video_stream_cb_user_param = NULL;
12025 player->video_stream_prerolled = FALSE;
12027 player->audio_stream_cb = NULL;
12028 player->audio_stream_render_cb_ex = NULL;
12029 player->audio_stream_cb_user_param = NULL;
12030 player->audio_stream_sink_sync = false;
12032 player->video_stream_changed_cb = NULL;
12033 player->video_stream_changed_cb_user_param = NULL;
12035 player->audio_stream_changed_cb = NULL;
12036 player->audio_stream_changed_cb_user_param = NULL;
12038 player->sent_bos = FALSE;
12039 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12041 player->doing_seek = FALSE;
12043 player->updated_bitrate_count = 0;
12044 player->total_bitrate = 0;
12045 player->updated_maximum_bitrate_count = 0;
12046 player->total_maximum_bitrate = 0;
12048 player->not_found_demuxer = 0;
12050 player->last_position = 0;
12051 player->duration = 0;
12052 player->http_content_size = 0;
12053 player->not_supported_codec = MISSING_PLUGIN_NONE;
12054 player->can_support_codec = FOUND_PLUGIN_NONE;
12055 player->pending_seek.is_pending = FALSE;
12056 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12057 player->pending_seek.pos = 0;
12058 player->msg_posted = FALSE;
12059 player->has_many_types = FALSE;
12060 player->max_audio_channels = 0;
12061 player->video_share_api_delta = 0;
12062 player->video_share_clock_delta = 0;
12063 player->sound_focus.keep_last_pos = FALSE;
12064 player->sound_focus.acquired = FALSE;
12065 player->is_subtitle_force_drop = FALSE;
12066 player->play_subtitle = FALSE;
12067 player->use_textoverlay = FALSE;
12068 player->adjust_subtitle_pos = 0;
12069 player->last_multiwin_status = FALSE;
12070 player->has_closed_caption = FALSE;
12071 player->set_mode.media_packet_video_stream = FALSE;
12072 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12073 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12075 player->set_mode.rich_audio = cur_mode;
12077 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12078 player->bitrate[i] = 0;
12079 player->maximum_bitrate[i] = 0;
12082 /* remove media stream cb(appsrc cb) */
12083 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12084 player->media_stream_buffer_status_cb[i] = NULL;
12085 player->media_stream_seek_data_cb[i] = NULL;
12088 /* free memory related to audio effect */
12089 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12091 if (player->state_tune_caps) {
12092 gst_caps_unref(player->state_tune_caps);
12093 player->state_tune_caps = NULL;
12100 __mmplayer_release_misc_post(mm_player_t* player)
12102 char *original_uri = NULL;
12105 /* player->pipeline is already released before. */
12107 MMPLAYER_RETURN_IF_FAIL(player);
12109 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12110 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12112 /* clean found parsers */
12113 if (player->parsers) {
12114 GList *parsers = player->parsers;
12115 for (; parsers; parsers = g_list_next(parsers)) {
12116 gchar *name = parsers->data;
12117 MMPLAYER_FREEIF(name);
12119 g_list_free(player->parsers);
12120 player->parsers = NULL;
12123 /* clean found audio decoders */
12124 if (player->audio_decoders) {
12125 GList *a_dec = player->audio_decoders;
12126 for (; a_dec; a_dec = g_list_next(a_dec)) {
12127 gchar *name = a_dec->data;
12128 MMPLAYER_FREEIF(name);
12130 g_list_free(player->audio_decoders);
12131 player->audio_decoders = NULL;
12134 /* clean the uri list except original uri */
12135 if (player->uri_info.uri_list) {
12136 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12138 if (player->attrs) {
12139 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12140 LOGD("restore original uri = %s\n", original_uri);
12142 if (mmf_attrs_commit(player->attrs))
12143 LOGE("failed to commit the original uri.\n");
12146 GList *uri_list = player->uri_info.uri_list;
12147 for (; uri_list; uri_list = g_list_next(uri_list)) {
12148 gchar *uri = uri_list->data;
12149 MMPLAYER_FREEIF(uri);
12151 g_list_free(player->uri_info.uri_list);
12152 player->uri_info.uri_list = NULL;
12155 /* clear the audio stream buffer list */
12156 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12158 /* clear the video stream bo list */
12159 __mmplayer_video_stream_destroy_bo_list(player);
12161 player->uri_info.uri_idx = 0;
12165 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12167 GstElement *element = NULL;
12170 LOGD("creating %s to plug\n", name);
12172 element = gst_element_factory_make(name, NULL);
12174 LOGE("failed to create queue\n");
12178 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12179 LOGE("failed to set state READY to %s\n", name);
12180 gst_object_unref(element);
12184 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12185 LOGE("failed to add %s\n", name);
12186 gst_object_unref(element);
12190 sinkpad = gst_element_get_static_pad(element, "sink");
12192 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12193 LOGE("failed to link %s\n", name);
12194 gst_object_unref(sinkpad);
12195 gst_object_unref(element);
12199 LOGD("linked %s to pipeline successfully\n", name);
12201 gst_object_unref(sinkpad);
12207 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12208 const char *padname, const GList *templlist)
12210 GstPad *pad = NULL;
12211 gboolean has_dynamic_pads = FALSE;
12212 gboolean has_many_types = FALSE;
12213 const char *klass = NULL;
12214 GstStaticPadTemplate *padtemplate = NULL;
12215 GstElementFactory *factory = NULL;
12216 GstElement* queue = NULL;
12217 GstElement* parser = NULL;
12218 GstPad *pssrcpad = NULL;
12219 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12220 MMPlayerGstElement *mainbin = NULL;
12221 GstStructure* str = NULL;
12222 GstCaps* srccaps = NULL;
12223 GstState target_state = GST_STATE_READY;
12224 gboolean isvideo_decoder = FALSE;
12225 guint q_max_size_time = 0;
12229 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12230 player->pipeline &&
12231 player->pipeline->mainbin,
12234 mainbin = player->pipeline->mainbin;
12236 LOGD("plugging pad %s:%s to newly create %s:%s\n",
12237 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12238 GST_PAD_NAME(srcpad),
12239 GST_ELEMENT_NAME(sinkelement),
12242 factory = gst_element_get_factory(sinkelement);
12243 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12245 /* check if player can do start continually */
12246 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12248 /* need it to warm up omx before linking to pipeline */
12249 if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12250 LOGD("get demux caps.\n");
12251 if (player->state_tune_caps) {
12252 gst_caps_unref(player->state_tune_caps);
12253 player->state_tune_caps = NULL;
12255 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12258 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12259 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12260 if (player->state_tune_caps != NULL) {
12261 LOGD("set demux's caps to omx codec if resource is available");
12262 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12263 target_state = GST_STATE_PAUSED;
12264 isvideo_decoder = TRUE;
12265 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12267 LOGW("failed to set caps for state tuning");
12269 gst_caps_unref(player->state_tune_caps);
12270 player->state_tune_caps = NULL;
12273 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12274 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12275 if (isvideo_decoder) {
12276 gst_element_set_state(sinkelement, GST_STATE_NULL);
12277 gst_object_unref(G_OBJECT(sinkelement));
12278 player->keep_detecting_vcodec = TRUE;
12283 /* add to pipeline */
12284 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12285 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12289 LOGD("element klass : %s\n", klass);
12291 /* added to support multi track files */
12292 /* only decoder case and any of the video/audio still need to link*/
12293 if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12294 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12296 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12297 gchar *src_demux_caps_str = NULL;
12298 gchar *needed_parser = NULL;
12299 GstCaps *src_demux_caps = NULL;
12300 gboolean smooth_streaming = FALSE;
12302 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12303 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12305 gst_caps_unref(src_demux_caps);
12307 if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12308 if (g_strrstr(name, "mssdemux")) {
12309 needed_parser = g_strdup("legacyh264parse");
12310 smooth_streaming = TRUE;
12312 needed_parser = g_strdup("h264parse");
12313 } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12314 needed_parser = g_strdup("mpeg4videoparse");
12316 MMPLAYER_FREEIF(src_demux_caps_str);
12318 if (needed_parser) {
12319 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12320 MMPLAYER_FREEIF(needed_parser);
12323 LOGE("failed to create parser\n");
12325 if (smooth_streaming)
12326 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12328 /* update srcpad if parser is created */
12329 pssrcpad = gst_element_get_static_pad(parser, "src");
12334 MMPLAYER_FREEIF(name);
12336 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12338 LOGE("failed to create queue\n");
12342 /* update srcpad to link with decoder */
12343 qsrcpad = gst_element_get_static_pad(queue, "src");
12346 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12348 /* assigning queue handle for futher manipulation purpose */
12349 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12350 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12351 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12352 mainbin[MMPLAYER_M_Q1].gst = queue;
12354 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12355 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12356 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12357 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12359 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12360 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12362 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12363 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12364 mainbin[MMPLAYER_M_Q2].gst = queue;
12366 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12367 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12368 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12369 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12371 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12372 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12375 LOGE("Not supporting more then two elementary stream\n");
12379 pad = gst_element_get_static_pad(sinkelement, padname);
12382 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12383 padname, GST_ELEMENT_NAME(sinkelement));
12385 pad = gst_element_get_static_pad(sinkelement, "sink");
12387 LOGE("failed to get pad(sink) from %s. \n",
12388 GST_ELEMENT_NAME(sinkelement));
12393 /* to check the video/audio type set the proper flag*/
12394 const gchar *mime_type = NULL;
12395 srccaps = gst_pad_query_caps(srcpad, NULL);
12398 str = gst_caps_get_structure(srccaps, 0);
12401 mime_type = gst_structure_get_name(str);
12405 /* link queue and decoder. so, it will be queue - decoder. */
12406 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12407 gst_object_unref(GST_OBJECT(pad));
12408 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12410 /* reconstitute supportable codec */
12411 if (strstr(mime_type, "video"))
12412 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12413 else if (strstr(mime_type, "audio"))
12414 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12418 if (strstr(mime_type, "video")) {
12419 player->videodec_linked = 1;
12420 LOGI("player->videodec_linked set to 1\n");
12422 } else if (strstr(mime_type, "audio")) {
12423 player->audiodec_linked = 1;
12424 LOGI("player->auddiodec_linked set to 1\n");
12427 gst_object_unref(GST_OBJECT(pad));
12428 gst_caps_unref(GST_CAPS(srccaps));
12432 if (!MMPLAYER_IS_HTTP_PD(player)) {
12433 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12434 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12435 gint64 dur_bytes = 0L;
12436 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12438 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12439 LOGD("creating http streaming buffering queue\n");
12441 queue = gst_element_factory_make("queue2", "queue2");
12443 LOGE("failed to create buffering queue element\n");
12447 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12448 LOGE("failed to set state READY to buffering queue\n");
12452 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12453 LOGE("failed to add buffering queue\n");
12457 qsinkpad = gst_element_get_static_pad(queue, "sink");
12458 qsrcpad = gst_element_get_static_pad(queue, "src");
12460 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12461 LOGE("failed to link buffering queue\n");
12467 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12468 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12470 if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12471 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12472 LOGE("fail to get duration.\n");
12474 if (dur_bytes > 0) {
12475 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12476 type = MUXED_BUFFER_TYPE_FILE;
12478 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12479 if (player->streamer)
12480 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12487 /* NOTE : we cannot get any duration info from ts container in case of streaming */
12488 if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12489 __mm_player_streaming_set_queue2(player->streamer,
12492 player->ini.http_max_size_bytes,
12493 player->ini.http_buffering_time,
12495 player->ini.http_buffering_limit,
12497 player->http_file_buffering_path,
12498 (guint64)dur_bytes);
12504 /* if it is not decoder or */
12505 /* in decoder case any of the video/audio still need to link*/
12506 if (!g_strrstr(klass, "Decoder")) {
12507 pad = gst_element_get_static_pad(sinkelement, padname);
12509 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12510 padname, GST_ELEMENT_NAME(sinkelement));
12512 pad = gst_element_get_static_pad(sinkelement, "sink");
12515 LOGE("failed to get pad(sink) from %s. \n",
12516 GST_ELEMENT_NAME(sinkelement));
12521 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12522 gst_object_unref(GST_OBJECT(pad));
12523 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12527 gst_object_unref(GST_OBJECT(pad));
12530 for (; templlist != NULL; templlist = templlist->next) {
12531 padtemplate = templlist->data;
12533 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12535 if (padtemplate->direction != GST_PAD_SRC ||
12536 padtemplate->presence == GST_PAD_REQUEST)
12539 switch (padtemplate->presence) {
12540 case GST_PAD_ALWAYS:
12542 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12543 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12545 /* Check whether caps has many types */
12546 if (!gst_caps_is_fixed(caps)) {
12547 LOGD("always pad but, caps has many types");
12548 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12549 has_many_types = TRUE;
12553 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12554 gst_object_unref(GST_OBJECT(srcpad));
12555 gst_caps_unref(GST_CAPS(caps));
12557 LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12561 gst_caps_unref(GST_CAPS(caps));
12562 gst_object_unref(GST_OBJECT(srcpad));
12568 case GST_PAD_SOMETIMES:
12569 has_dynamic_pads = TRUE;
12577 /* check if player can do start continually */
12578 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12580 if (has_dynamic_pads) {
12581 player->have_dynamic_pad = TRUE;
12582 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12583 G_CALLBACK(__mmplayer_add_new_pad), player);
12585 /* for streaming, more then one typefind will used for each elementary stream
12586 * so this doesn't mean the whole pipeline completion
12588 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12589 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12590 G_CALLBACK(__mmplayer_pipeline_complete), player);
12594 if (has_many_types) {
12595 GstPad *pad = NULL;
12597 player->has_many_types = has_many_types;
12599 pad = gst_element_get_static_pad(sinkelement, "src");
12600 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12601 gst_object_unref(GST_OBJECT(pad));
12605 /* check if player can do start continually */
12606 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12608 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12609 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12614 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12615 LOGE("failed to set state PAUSED to queue\n");
12621 gst_object_unref(GST_OBJECT(qsrcpad));
12626 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12627 LOGE("failed to set state PAUSED to queue\n");
12633 gst_object_unref(GST_OBJECT(pssrcpad));
12644 gst_object_unref(GST_OBJECT(qsrcpad));
12646 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12647 * You need to explicitly set elements to the NULL state before
12648 * dropping the final reference, to allow them to clean up.
12650 gst_element_set_state(queue, GST_STATE_NULL);
12651 /* And, it still has a parent "player".
12652 * You need to let the parent manage the object instead of unreffing the object directly.
12655 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12656 //gst_object_unref(queue);
12660 gst_caps_unref(GST_CAPS(srccaps));
12665 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12667 const gchar *klass;
12669 /* we only care about element factories */
12670 if (!GST_IS_ELEMENT_FACTORY(feature))
12673 /* only parsers, demuxers and decoders */
12674 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12676 if (g_strrstr(klass, "Demux") == NULL &&
12677 g_strrstr(klass, "Codec/Decoder") == NULL &&
12678 g_strrstr(klass, "Depayloader") == NULL &&
12679 g_strrstr(klass, "Parse") == NULL)
12685 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12687 mm_player_t* player = (mm_player_t*) data;
12688 GstCaps *caps = NULL;
12689 GstStructure *str = NULL;
12694 MMPLAYER_RETURN_IF_FAIL(pad)
12695 MMPLAYER_RETURN_IF_FAIL(unused)
12696 MMPLAYER_RETURN_IF_FAIL(data)
12698 caps = gst_pad_query_caps(pad, NULL);
12702 str = gst_caps_get_structure(caps, 0);
12706 name = gst_structure_get_name(str);
12709 LOGD("name=%s\n", name);
12711 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12712 LOGE("failed to autoplug for type(%s)\n", name);
12713 gst_caps_unref(caps);
12717 gst_caps_unref(caps);
12719 __mmplayer_pipeline_complete(NULL, (gpointer)player);
12726 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12730 const char *stream_type;
12731 gchar *version_field = NULL;
12735 MMPLAYER_RETURN_IF_FAIL(player);
12736 MMPLAYER_RETURN_IF_FAIL(caps);
12738 str = gst_caps_get_structure(caps, 0);
12742 stream_type = gst_structure_get_name(str);
12747 /* set unlinked mime type for downloadable codec */
12748 if (g_str_has_prefix(stream_type, "video/")) {
12749 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12750 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12751 version_field = MM_PLAYER_MPEG_VNAME;
12752 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12753 gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12754 version_field = MM_PLAYER_WMV_VNAME;
12756 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12757 gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12758 version_field = MM_PLAYER_DIVX_VNAME;
12762 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12764 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12765 } else if (g_str_has_prefix(stream_type, "audio/")) {
12766 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12768 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12769 version_field = MM_PLAYER_MPEG_VNAME;
12770 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12771 gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12772 version_field = MM_PLAYER_WMA_VNAME;
12776 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12778 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12784 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12786 mm_player_t* player = (mm_player_t*) data;
12787 GstCaps *caps = NULL;
12788 GstStructure *str = NULL;
12792 MMPLAYER_RETURN_IF_FAIL(player);
12793 MMPLAYER_RETURN_IF_FAIL(pad);
12795 GST_OBJECT_LOCK(pad);
12796 if ((caps = gst_pad_get_current_caps(pad)))
12797 gst_caps_ref(caps);
12798 GST_OBJECT_UNLOCK(pad);
12800 if (NULL == caps) {
12801 caps = gst_pad_query_caps(pad, NULL);
12805 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12807 str = gst_caps_get_structure(caps, 0);
12811 name = gst_structure_get_name(str);
12815 player->num_dynamic_pad++;
12816 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12818 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12819 * If want to play it, remove this code.
12821 if (g_strrstr(name, "application")) {
12822 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12823 /* If id3/ape tag comes, keep going */
12824 LOGD("application mime exception : id3/ape tag");
12826 /* Otherwise, we assume that this stream is subtile. */
12827 LOGD(" application mime type pad is closed.");
12830 } else if (g_strrstr(name, "audio")) {
12831 gint samplerate = 0, channels = 0;
12833 if (player->audiodec_linked) {
12834 gst_caps_unref(caps);
12835 LOGD("multi tracks. skip to plug");
12839 /* set stream information */
12840 /* if possible, set it here because the caps is not distrubed by resampler. */
12841 gst_structure_get_int(str, "rate", &samplerate);
12842 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12844 gst_structure_get_int(str, "channels", &channels);
12845 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12847 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
12848 } else if (g_strrstr(name, "video")) {
12850 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12852 /* don't make video because of not required */
12853 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
12854 LOGD("no video because it's not required");
12858 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
12861 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12862 LOGE("failed to autoplug for type(%s)", name);
12864 __mmplayer_set_unlinked_mime_type(player, caps);
12867 gst_caps_unref(caps);
12874 __mmplayer_check_subtitle(mm_player_t* player)
12876 MMHandleType attrs = 0;
12877 char *subtitle_uri = NULL;
12881 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12883 /* get subtitle attribute */
12884 attrs = MMPLAYER_GET_ATTRS(player);
12888 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12889 if (!subtitle_uri || !strlen(subtitle_uri))
12892 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
12893 player->is_external_subtitle_present = TRUE;
12901 __mmplayer_can_extract_pcm(mm_player_t* player)
12903 MMHandleType attrs = 0;
12904 gboolean sound_extraction = FALSE;
12906 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12908 attrs = MMPLAYER_GET_ATTRS(player);
12910 LOGE("fail to get attributes.");
12914 /* get sound_extraction property */
12915 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
12917 if (!sound_extraction) {
12918 LOGD("checking pcm extraction mode : %d ", sound_extraction);
12926 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
12929 MMMessageParamType msg_param;
12930 gchar *msg_src_element = NULL;
12931 GstStructure *s = NULL;
12932 guint error_id = 0;
12933 gchar *error_string = NULL;
12937 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12938 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
12940 s = malloc(sizeof(GstStructure));
12941 memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
12943 if (!gst_structure_get_uint(s, "error_id", &error_id))
12944 error_id = MMPLAYER_STREAMING_ERROR_NONE;
12946 switch (error_id) {
12947 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
12948 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
12950 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
12951 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
12953 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
12954 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
12956 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
12957 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
12959 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
12960 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
12962 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
12963 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
12965 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
12966 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
12968 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
12969 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
12971 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
12972 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
12974 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
12975 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
12977 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
12978 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
12980 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
12981 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
12983 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
12984 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
12986 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
12987 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
12989 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
12990 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
12992 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
12993 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
12995 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
12996 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
12998 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
12999 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13001 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13002 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13004 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13005 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13007 case MMPLAYER_STREAMING_ERROR_GONE:
13008 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13010 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13011 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13013 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13014 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13016 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13017 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13019 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13020 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13022 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13023 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13025 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13026 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13028 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13029 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13031 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13032 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13034 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13035 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13037 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13038 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13040 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13041 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13043 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13044 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13046 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13047 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13049 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13050 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13052 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13053 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13055 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13056 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13058 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13059 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13061 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13062 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13064 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13065 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13067 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13068 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13070 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13071 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13073 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13074 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13076 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13077 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13079 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13080 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13084 MMPLAYER_FREEIF(s);
13085 return MM_ERROR_PLAYER_STREAMING_FAIL;
13089 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13091 msg_param.data = (void *) error_string;
13093 if (message->src) {
13094 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13096 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13097 msg_src_element, msg_param.code, (char*)msg_param.data);
13100 /* post error to application */
13101 if (!player->msg_posted) {
13102 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13104 /* don't post more if one was sent already */
13105 player->msg_posted = TRUE;
13107 LOGD("skip error post because it's sent already.\n");
13109 MMPLAYER_FREEIF(s);
13111 g_free(error_string);
13118 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13120 MMPLAYER_RETURN_IF_FAIL(player);
13123 /* post now if delay is zero */
13124 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13125 LOGD("eos delay is zero. posting EOS now\n");
13126 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13128 if (player->set_mode.pcm_extraction)
13129 __mmplayer_cancel_eos_timer(player);
13134 /* cancel if existing */
13135 __mmplayer_cancel_eos_timer(player);
13137 /* init new timeout */
13138 /* NOTE : consider give high priority to this timer */
13139 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13141 player->eos_timer = g_timeout_add(delay_in_ms,
13142 __mmplayer_eos_timer_cb, player);
13144 player->context.global_default = g_main_context_default();
13145 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13147 /* check timer is valid. if not, send EOS now */
13148 if (player->eos_timer == 0) {
13149 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13150 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13155 __mmplayer_cancel_eos_timer(mm_player_t* player)
13157 MMPLAYER_RETURN_IF_FAIL(player);
13159 if (player->eos_timer) {
13160 LOGD("cancel eos timer");
13161 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13162 player->eos_timer = 0;
13169 __mmplayer_eos_timer_cb(gpointer u_data)
13171 mm_player_t* player = NULL;
13172 player = (mm_player_t*) u_data;
13174 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13176 if (player->play_count > 1) {
13177 gint ret_value = 0;
13178 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13179 if (ret_value == MM_ERROR_NONE) {
13180 MMHandleType attrs = 0;
13181 attrs = MMPLAYER_GET_ATTRS(player);
13183 /* we successeded to rewind. update play count and then wait for next EOS */
13184 player->play_count--;
13186 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13187 mmf_attrs_commit(attrs);
13189 LOGE("seeking to 0 failed in repeat play");
13192 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13194 /* we are returning FALSE as we need only one posting */
13199 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13201 const gchar* name = NULL;
13202 GstStructure* str = NULL;
13203 GstCaps* srccaps = NULL;
13207 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13208 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13210 /* to check any of the decoder(video/audio) need to be linked to parser*/
13211 srccaps = gst_pad_query_caps(srcpad, NULL);
13215 str = gst_caps_get_structure(srccaps, 0);
13219 name = gst_structure_get_name(str);
13223 if (strstr(name, "video")) {
13224 if (player->videodec_linked) {
13225 LOGI("Video decoder already linked\n");
13229 if (strstr(name, "audio")) {
13230 if (player->audiodec_linked) {
13231 LOGI("Audio decoder already linked\n");
13236 gst_caps_unref(srccaps);
13244 gst_caps_unref(srccaps);
13250 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13252 const gchar* name = NULL;
13253 GstStructure* str = NULL;
13254 GstCaps* srccaps = NULL;
13258 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13259 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13261 /* to check any of the decoder(video/audio) need to be linked to parser*/
13262 srccaps = gst_pad_query_caps(srcpad, NULL);
13266 str = gst_caps_get_structure(srccaps, 0);
13270 name = gst_structure_get_name(str);
13274 if (strstr(name, "video")) {
13275 if (player->videosink_linked) {
13276 LOGI("Video Sink already linked\n");
13280 if (strstr(name, "audio")) {
13281 if (player->audiosink_linked) {
13282 LOGI("Audio Sink already linked\n");
13286 if (strstr(name, "text")) {
13287 if (player->textsink_linked) {
13288 LOGI("Text Sink already linked\n");
13293 gst_caps_unref(srccaps);
13297 //return (!player->videosink_linked || !player->audiosink_linked);
13302 gst_caps_unref(srccaps);
13308 /* sending event to one of sinkelements */
13310 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13312 GstEvent * event2 = NULL;
13313 GList *sinks = NULL;
13314 gboolean res = FALSE;
13317 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13318 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13320 if (player->play_subtitle && !player->use_textoverlay)
13321 event2 = gst_event_copy((const GstEvent *)event);
13323 sinks = player->sink_elements;
13325 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13327 if (GST_IS_ELEMENT(sink)) {
13328 /* keep ref to the event */
13329 gst_event_ref(event);
13331 if ((res = gst_element_send_event(sink, event))) {
13332 LOGD("sending event[%s] to sink element [%s] success!\n",
13333 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13335 /* rtsp case, asyn_done is not called after seek during pause state */
13336 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13337 if (strstr(GST_EVENT_TYPE_NAME(event), "seek")) {
13338 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13339 LOGD("RTSP seek completed, after pause state..\n");
13340 player->doing_seek = FALSE;
13341 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13347 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13348 sinks = g_list_next(sinks);
13354 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13355 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13358 sinks = g_list_next(sinks);
13363 request pad name = sink0;
13365 request pad name = sink1; // external
13368 /* Note : Textbin is not linked to the video or audio bin.
13369 * It needs to send the event to the text sink seperatelly.
13371 if (player->play_subtitle && !player->use_textoverlay) {
13372 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13374 if (GST_IS_ELEMENT(text_sink)) {
13375 /* keep ref to the event */
13376 gst_event_ref(event2);
13378 if ((res = gst_element_send_event(text_sink, event2)))
13379 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13380 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13382 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13383 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13385 gst_event_unref(event2);
13389 gst_event_unref(event);
13397 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13401 MMPLAYER_RETURN_IF_FAIL(player);
13402 MMPLAYER_RETURN_IF_FAIL(sink);
13404 player->sink_elements =
13405 g_list_append(player->sink_elements, sink);
13411 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13415 MMPLAYER_RETURN_IF_FAIL(player);
13416 MMPLAYER_RETURN_IF_FAIL(sink);
13418 player->sink_elements =
13419 g_list_remove(player->sink_elements, sink);
13425 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13426 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13427 gint64 cur, GstSeekType stop_type, gint64 stop)
13429 GstEvent* event = NULL;
13430 gboolean result = FALSE;
13434 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13436 if (player->pipeline && player->pipeline->textbin)
13437 __mmplayer_drop_subtitle(player, FALSE);
13439 event = gst_event_new_seek(rate, format, flags, cur_type,
13440 cur, stop_type, stop);
13442 result = __gst_send_event_to_sink(player, event);
13449 /* NOTE : be careful with calling this api. please refer to below glib comment
13450 * glib comment : Note that there is a bug in GObject that makes this function much
13451 * less useful than it might seem otherwise. Once gobject is disposed, the callback
13452 * will no longer be called, but, the signal handler is not currently disconnected.
13453 * If the instance is itself being freed at the same time than this doesn't matter,
13454 * since the signal will automatically be removed, but if instance persists,
13455 * then the signal handler will leak. You should not remove the signal yourself
13456 * because in a future versions of GObject, the handler will automatically be
13459 * It's possible to work around this problem in a way that will continue to work
13460 * with future versions of GObject by checking that the signal handler is still
13461 * connected before disconnected it:
13463 * if (g_signal_handler_is_connected(instance, id))
13464 * g_signal_handler_disconnect(instance, id);
13467 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13469 GList* sig_list = NULL;
13470 MMPlayerSignalItem* item = NULL;
13474 MMPLAYER_RETURN_IF_FAIL(player);
13476 LOGD("release signals type : %d", type);
13478 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13479 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13480 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13481 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13482 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13483 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13487 sig_list = player->signals[type];
13489 for (; sig_list; sig_list = sig_list->next) {
13490 item = sig_list->data;
13492 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13493 if (g_signal_handler_is_connected(item->obj, item->sig))
13494 g_signal_handler_disconnect(item->obj, item->sig);
13497 MMPLAYER_FREEIF(item);
13500 g_list_free(player->signals[type]);
13501 player->signals[type] = NULL;
13508 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13510 mm_player_t* player = 0;
13511 int prev_display_surface_type = 0;
13512 void *prev_display_overlay = NULL;
13513 const gchar *klass = NULL;
13514 gchar *cur_videosink_name = NULL;
13517 int num_of_dec = 2; /* DEC1, DEC2 */
13521 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13522 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13524 player = MM_PLAYER_CAST(handle);
13526 if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13527 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13529 return MM_ERROR_INVALID_ARGUMENT;
13532 /* load previous attributes */
13533 if (player->attrs) {
13534 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13535 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13536 LOGD("[0: Video surface, 1: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13537 if (prev_display_surface_type == surface_type) {
13538 LOGD("incoming display surface type is same as previous one, do nothing..");
13540 return MM_ERROR_NONE;
13543 LOGE("failed to load attributes");
13545 return MM_ERROR_PLAYER_INTERNAL;
13548 /* check videosink element is created */
13549 if (!player->pipeline || !player->pipeline->videobin ||
13550 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13551 LOGD("videosink element is not yet ready");
13553 /* videobin is not created yet, so we just set attributes related to display surface */
13554 LOGD("store display attribute for given surface type(%d)", surface_type);
13555 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13556 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13557 if (mmf_attrs_commit(player->attrs)) {
13558 LOGE("failed to commit attribute");
13560 return MM_ERROR_PLAYER_INTERNAL;
13563 return MM_ERROR_NONE;
13565 /* get player command status */
13566 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13567 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13569 return MM_ERROR_PLAYER_INVALID_STATE;
13572 /* get a current videosink name */
13573 cur_videosink_name = GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13575 /* surface change */
13576 for (i = 0 ; i < num_of_dec ; i++) {
13577 if (player->pipeline->mainbin &&
13578 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13579 GstElementFactory *decfactory;
13580 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13582 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13583 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13584 if (!strncmp(cur_videosink_name, "x", 1) && (surface_type == MM_DISPLAY_SURFACE_EVAS)) {
13585 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_evas, surface_type, display_overlay);
13589 LOGW("success to changing display surface(%d)", surface_type);
13591 return MM_ERROR_NONE;
13593 } else if (!strncmp(cur_videosink_name, "evas", 4) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13594 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13598 LOGW("success to changing display surface(%d)", surface_type);
13600 return MM_ERROR_NONE;
13603 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13604 ret = MM_ERROR_PLAYER_INTERNAL;
13613 /* rollback to previous attributes */
13614 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13615 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13616 if (mmf_attrs_commit(player->attrs)) {
13617 LOGE("failed to commit attributes to rollback");
13619 return MM_ERROR_PLAYER_INTERNAL;
13625 /* NOTE : It does not support some use cases, eg using colorspace converter */
13627 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13629 GstPad *src_pad_dec = NULL;
13630 GstPad *sink_pad_videosink = NULL;
13631 GstPad *sink_pad_videobin = NULL;
13632 GstClock *clock = NULL;
13633 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13634 int ret = MM_ERROR_NONE;
13635 gboolean is_audiobin_created = TRUE;
13639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13640 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13641 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13643 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13644 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13646 /* get information whether if audiobin is created */
13647 if (!player->pipeline->audiobin ||
13648 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13649 LOGW("audiobin is null, this video content may not have audio data");
13650 is_audiobin_created = FALSE;
13653 /* get current state of player */
13654 previous_state = MMPLAYER_CURRENT_STATE(player);
13655 LOGD("previous state(%d)", previous_state);
13658 /* get src pad of decoder and block it */
13659 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13660 if (!src_pad_dec) {
13661 LOGE("failed to get src pad from decode in mainbin");
13662 return MM_ERROR_PLAYER_INTERNAL;
13665 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13666 LOGW("trying to block pad(video)");
13667 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13668 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13671 LOGE("failed to set block pad(video)");
13672 return MM_ERROR_PLAYER_INTERNAL;
13674 LOGW("pad is blocked(video)");
13676 /* no data flows, so no need to do pad_block */
13677 if (player->doing_seek)
13678 LOGW("not completed seek(%d), do nothing", player->doing_seek);
13680 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13684 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13685 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13686 LOGE("failed to remove previous ghost_pad for videobin");
13687 return MM_ERROR_PLAYER_INTERNAL;
13690 /* change state of videobin to NULL */
13691 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13692 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13693 if (ret != GST_STATE_CHANGE_SUCCESS) {
13694 LOGE("failed to change state of videobin to NULL");
13695 return MM_ERROR_PLAYER_INTERNAL;
13698 /* unlink between decoder and videobin and remove previous videosink from videobin */
13699 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13700 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13701 LOGE("failed to remove former videosink from videobin");
13702 return MM_ERROR_PLAYER_INTERNAL;
13705 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13707 /* create a new videosink and add it to videobin */
13708 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13709 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13710 LOGE("failed to create videosink element\n");
13712 return MM_ERROR_PLAYER_INTERNAL;
13714 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13715 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13716 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13718 /* save attributes */
13719 if (player->attrs) {
13720 /* set a new display surface type */
13721 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13722 /* set a new diplay overlay */
13723 switch (surface_type) {
13724 case MM_DISPLAY_SURFACE_OVERLAY:
13725 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13726 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13728 case MM_DISPLAY_SURFACE_EVAS:
13729 LOGD("save attributes related to display surface to EVAS : evas image object = %x", display_overlay);
13730 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(void*));
13733 LOGE("invalid type(%d) for changing display surface", surface_type);
13735 return MM_ERROR_INVALID_ARGUMENT;
13737 if (mmf_attrs_commit(player->attrs)) {
13738 LOGE("failed to commit");
13740 return MM_ERROR_PLAYER_INTERNAL;
13743 LOGE("player->attrs is null, failed to save attributes");
13745 return MM_ERROR_PLAYER_INTERNAL;
13748 /* update video param */
13749 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13750 LOGE("failed to update video param");
13751 return MM_ERROR_PLAYER_INTERNAL;
13754 /* change state of videobin to READY */
13755 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13756 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13757 if (ret != GST_STATE_CHANGE_SUCCESS) {
13758 LOGE("failed to change state of videobin to READY");
13759 return MM_ERROR_PLAYER_INTERNAL;
13762 /* change ghostpad */
13763 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13764 if (!sink_pad_videosink) {
13765 LOGE("failed to get sink pad from videosink element");
13766 return MM_ERROR_PLAYER_INTERNAL;
13768 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13769 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13770 LOGE("failed to set active to ghost_pad");
13771 return MM_ERROR_PLAYER_INTERNAL;
13773 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13774 LOGE("failed to change ghostpad for videobin");
13775 return MM_ERROR_PLAYER_INTERNAL;
13777 gst_object_unref(sink_pad_videosink);
13779 /* link decoder with videobin */
13780 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13781 if (!sink_pad_videobin) {
13782 LOGE("failed to get sink pad from videobin");
13783 return MM_ERROR_PLAYER_INTERNAL;
13785 if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13786 LOGE("failed to link");
13787 return MM_ERROR_PLAYER_INTERNAL;
13789 gst_object_unref(sink_pad_videobin);
13791 /* clock setting for a new videosink plugin */
13792 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13793 so we set it from audiosink plugin or pipeline(system clock) */
13794 if (!is_audiobin_created) {
13795 LOGW("audiobin is not created, get clock from pipeline..");
13796 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13798 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13802 GstClockTime base_time;
13803 LOGD("set the clock to videosink");
13804 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13805 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13807 LOGD("got clock of videosink");
13808 now = gst_clock_get_time(clock);
13809 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13810 LOGD("at time %" GST_TIME_FORMAT ", base %"
13811 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13813 LOGE("failed to get clock of videosink after setting clock");
13814 return MM_ERROR_PLAYER_INTERNAL;
13817 LOGW("failed to get clock, maybe it is the time before first playing");
13819 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13820 /* change state of videobin to PAUSED */
13821 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13822 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13823 if (ret != GST_STATE_CHANGE_FAILURE) {
13824 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13826 LOGE("failed to change state of videobin to PLAYING");
13827 return MM_ERROR_PLAYER_INTERNAL;
13830 /* release blocked and unref src pad of video decoder */
13832 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13833 LOGE("failed to set pad blocked FALSE(video)");
13834 return MM_ERROR_PLAYER_INTERNAL;
13837 LOGW("pad is unblocked(video)");
13839 if (player->doing_seek)
13840 LOGW("not completed seek(%d)", player->doing_seek);
13841 /* change state of videobin to PAUSED */
13842 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13843 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13844 if (ret != GST_STATE_CHANGE_FAILURE) {
13845 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13847 LOGE("failed to change state of videobin to PLAYING");
13848 return MM_ERROR_PLAYER_INTERNAL;
13851 /* already skipped pad block */
13852 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
13855 /* do get/set position for new videosink plugin */
13857 unsigned long position = 0;
13858 gint64 pos_msec = 0;
13860 LOGD("do get/set position for new videosink plugin");
13861 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
13862 LOGE("failed to get position");
13863 return MM_ERROR_PLAYER_INTERNAL;
13865 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
13866 /* accurate seek */
13867 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
13868 LOGE("failed to set position");
13869 return MM_ERROR_PLAYER_INTERNAL;
13872 /* key unit seek */
13873 pos_msec = position * G_GINT64_CONSTANT(1000000);
13874 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
13875 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
13876 GST_SEEK_TYPE_SET, pos_msec,
13877 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
13879 LOGE("failed to set position");
13880 return MM_ERROR_PLAYER_INTERNAL;
13886 gst_object_unref(src_pad_dec);
13887 LOGD("success to change sink");
13891 return MM_ERROR_NONE;
13895 /* Note : if silent is true, then subtitle would not be displayed. :*/
13896 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
13898 mm_player_t* player = (mm_player_t*) hplayer;
13902 /* check player handle */
13903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13905 player->set_mode.subtitle_off = silent;
13907 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
13911 return MM_ERROR_NONE;
13914 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
13916 int result = MM_ERROR_NONE;
13917 GstPad *peer = NULL, *pad = NULL;
13918 GstElement *Element = NULL;
13919 MMPlayerGstElement* mainbin = NULL;
13920 mainbin = player->pipeline->mainbin;
13923 if (!gst_pad_set_blocked(inpad, TRUE)) {
13924 result = MM_ERROR_PLAYER_INTERNAL;
13928 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13931 /*Getting pad connected to demuxer audio pad */
13932 peer = gst_pad_get_peer(inpad);
13933 /* Disconnecting Demuxer and its peer plugin [audio] */
13935 if (!gst_pad_unlink(inpad, peer)) {
13936 result = MM_ERROR_PLAYER_INTERNAL;
13940 result = MM_ERROR_PLAYER_INTERNAL;
13943 /*Removing elements between Demuxer and audiobin*/
13944 while (peer != NULL) {
13945 gchar *Element_name = NULL;
13946 gchar *factory_name = NULL;
13947 GList *elements = NULL;
13948 GstElementFactory *factory = NULL;
13949 /*Getting peer element*/
13950 Element = gst_pad_get_parent_element(peer);
13951 if (Element == NULL) {
13952 gst_object_unref(peer);
13953 result = MM_ERROR_PLAYER_INTERNAL;
13957 Element_name = gst_element_get_name(Element);
13958 factory = gst_element_get_factory(Element);
13959 /*checking the element is audio bin*/
13960 if (!strcmp(Element_name, "audiobin")) {
13961 gst_object_unref(peer);
13962 result = MM_ERROR_NONE;
13963 g_free(Element_name);
13966 factory_name = GST_OBJECT_NAME(factory);
13967 pad = gst_element_get_static_pad(Element, "src");
13969 result = MM_ERROR_PLAYER_INTERNAL;
13970 g_free(Element_name);
13973 gst_object_unref(peer);
13974 peer = gst_pad_get_peer(pad);
13976 if (!gst_pad_unlink(pad, peer)) {
13977 gst_object_unref(peer);
13978 gst_object_unref(pad);
13979 result = MM_ERROR_PLAYER_INTERNAL;
13980 g_free(Element_name);
13984 elements = player->parsers;
13985 /* Removing the element form the list*/
13986 for (; elements; elements = g_list_next(elements)) {
13987 Element_name = elements->data;
13988 if (g_strrstr(Element_name, factory_name))
13989 player->parsers = g_list_remove(player->parsers, elements->data);
13991 gst_element_set_state(Element, GST_STATE_NULL);
13992 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
13993 gst_object_unref(pad);
13994 if (Element == mainbin[MMPLAYER_M_Q1].gst)
13995 mainbin[MMPLAYER_M_Q1].gst = NULL;
13996 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
13997 mainbin[MMPLAYER_M_Q2].gst = NULL;
13998 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
13999 mainbin[MMPLAYER_M_DEC1].gst = NULL;
14000 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14001 mainbin[MMPLAYER_M_DEC2].gst = NULL;
14003 gst_object_unref(Element);
14009 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14011 MMPlayerGstElement* mainbin = NULL;
14012 MMPlayerGstElement* textbin = NULL;
14013 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14014 GstState current_state = GST_STATE_VOID_PENDING;
14015 GstState element_state = GST_STATE_VOID_PENDING;
14016 GstState element_pending_state = GST_STATE_VOID_PENDING;
14018 GstEvent *event = NULL;
14019 int result = MM_ERROR_NONE;
14021 GstClock *curr_clock = NULL;
14022 GstClockTime base_time, start_time, curr_time;
14027 /* check player handle */
14028 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14030 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14031 LOGE("Pipeline is not in proper state\n");
14032 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14036 mainbin = player->pipeline->mainbin;
14037 textbin = player->pipeline->textbin;
14039 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14041 // sync clock with current pipeline
14042 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14043 curr_time = gst_clock_get_time(curr_clock);
14045 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14046 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14048 LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14049 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14051 if (current_state > GST_STATE_READY) {
14052 // sync state with current pipeline
14053 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14054 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14055 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14057 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14058 if (GST_STATE_CHANGE_FAILURE == ret)
14059 LOGE("fail to state change.\n");
14062 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14063 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14066 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14067 gst_object_unref(curr_clock);
14070 // seek to current position
14071 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14072 result = MM_ERROR_PLAYER_INVALID_STATE;
14073 LOGE("gst_element_query_position failed, invalid state\n");
14077 LOGD("seek time = %lld\n", time);
14078 event = gst_event_new_seek(1.0, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
14080 __gst_send_event_to_sink(player, event);
14082 result = MM_ERROR_PLAYER_INTERNAL;
14083 LOGE("gst_event_new_seek failed\n");
14087 // sync state with current pipeline
14088 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14089 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14090 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14097 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14099 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14100 GstState current_state = GST_STATE_VOID_PENDING;
14102 MMHandleType attrs = 0;
14103 MMPlayerGstElement* mainbin = NULL;
14104 MMPlayerGstElement* textbin = NULL;
14106 gchar* subtitle_uri = NULL;
14107 int result = MM_ERROR_NONE;
14108 const gchar *charset = NULL;
14112 /* check player handle */
14113 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14114 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14116 if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14117 result = MM_ERROR_PLAYER_INVALID_STATE;
14118 LOGE("Pipeline is not in proper state\n");
14122 mainbin = player->pipeline->mainbin;
14123 textbin = player->pipeline->textbin;
14125 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14126 if (current_state < GST_STATE_READY) {
14127 result = MM_ERROR_PLAYER_INVALID_STATE;
14128 LOGE("Pipeline is not in proper state\n");
14132 attrs = MMPLAYER_GET_ATTRS(player);
14134 LOGE("cannot get content attribute\n");
14135 result = MM_ERROR_PLAYER_INTERNAL;
14139 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14140 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14141 LOGE("subtitle uri is not proper filepath\n");
14142 result = MM_ERROR_PLAYER_INVALID_URI;
14146 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14147 LOGD("new subtitle file path is [%s]\n", filepath);
14149 if (!strcmp(filepath, subtitle_uri)) {
14150 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14153 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14154 if (mmf_attrs_commit(player->attrs)) {
14155 LOGE("failed to commit.\n");
14160 //gst_pad_set_blocked_async(src-srcpad, TRUE)
14162 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14163 if (ret != GST_STATE_CHANGE_SUCCESS) {
14164 LOGE("failed to change state of textbin to READY");
14165 result = MM_ERROR_PLAYER_INTERNAL;
14169 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14170 if (ret != GST_STATE_CHANGE_SUCCESS) {
14171 LOGE("failed to change state of subparse to READY");
14172 result = MM_ERROR_PLAYER_INTERNAL;
14176 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14177 if (ret != GST_STATE_CHANGE_SUCCESS) {
14178 LOGE("failed to change state of filesrc to READY");
14179 result = MM_ERROR_PLAYER_INTERNAL;
14183 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14185 charset = util_get_charset(filepath);
14187 LOGD("detected charset is %s\n", charset);
14188 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14191 result = _mmplayer_sync_subtitle_pipeline(player);
14198 /* API to switch between external subtitles */
14199 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14201 int result = MM_ERROR_NONE;
14202 mm_player_t* player = (mm_player_t*)hplayer;
14206 /* check player handle */
14207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14209 if (!player->pipeline) {
14211 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14212 if (mmf_attrs_commit(player->attrs)) {
14213 LOGE("failed to commit.\n");
14214 result = MM_ERROR_PLAYER_INTERNAL;
14217 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14218 if (filepath == NULL)
14219 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14221 if (!__mmplayer_check_subtitle(player)) {
14222 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14223 if (mmf_attrs_commit(player->attrs)) {
14224 LOGE("failed to commit.\n");
14225 result = MM_ERROR_PLAYER_INTERNAL;
14228 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14229 LOGE("fail to create subtitle src\n");
14231 result = _mmplayer_sync_subtitle_pipeline(player);
14233 result = __mmplayer_change_external_subtitle_language(player, filepath);
14241 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14243 int result = MM_ERROR_NONE;
14244 gchar* change_pad_name = NULL;
14245 GstPad* sinkpad = NULL;
14246 MMPlayerGstElement* mainbin = NULL;
14247 enum MainElementID elemId = MMPLAYER_M_NUM;
14248 GstCaps* caps = NULL;
14249 gint total_track_num = 0;
14253 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14254 MM_ERROR_PLAYER_NOT_INITIALIZED);
14256 LOGD("Change Track(%d) to %d\n", type, index);
14258 mainbin = player->pipeline->mainbin;
14260 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14261 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14262 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14263 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14265 /* Changing Video Track is not supported. */
14266 LOGE("Track Type Error\n");
14270 if (mainbin[elemId].gst == NULL) {
14271 result = MM_ERROR_PLAYER_NO_OP;
14272 LOGD("Req track doesn't exist\n");
14276 total_track_num = player->selector[type].total_track_num;
14277 if (total_track_num <= 0) {
14278 result = MM_ERROR_PLAYER_NO_OP;
14279 LOGD("Language list is not available \n");
14283 if ((index < 0) || (index >= total_track_num)) {
14284 result = MM_ERROR_INVALID_ARGUMENT;
14285 LOGD("Not a proper index : %d \n", index);
14289 /*To get the new pad from the selector*/
14290 change_pad_name = g_strdup_printf("sink_%u", index);
14291 if (change_pad_name == NULL) {
14292 result = MM_ERROR_PLAYER_INTERNAL;
14293 LOGD("Pad does not exists\n");
14297 LOGD("new active pad name: %s\n", change_pad_name);
14299 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14300 if (sinkpad == NULL) {
14301 LOGD("sinkpad is NULL");
14302 result = MM_ERROR_PLAYER_INTERNAL;
14306 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14307 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14309 caps = gst_pad_get_current_caps(sinkpad);
14310 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14313 gst_object_unref(sinkpad);
14315 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14316 __mmplayer_set_audio_attrs(player, caps);
14320 MMPLAYER_FREEIF(change_pad_name);
14324 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14326 int result = MM_ERROR_NONE;
14327 mm_player_t* player = NULL;
14328 MMPlayerGstElement* mainbin = NULL;
14330 gint current_active_index = 0;
14332 GstState current_state = GST_STATE_VOID_PENDING;
14333 GstEvent* event = NULL;
14338 player = (mm_player_t*)hplayer;
14339 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14341 if (!player->pipeline) {
14342 LOGE("Track %d pre setting -> %d\n", type, index);
14344 player->selector[type].active_pad_index = index;
14348 mainbin = player->pipeline->mainbin;
14350 current_active_index = player->selector[type].active_pad_index;
14352 /*If index is same as running index no need to change the pad*/
14353 if (current_active_index == index)
14356 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14357 result = MM_ERROR_PLAYER_INVALID_STATE;
14361 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14362 if (current_state < GST_STATE_PAUSED) {
14363 result = MM_ERROR_PLAYER_INVALID_STATE;
14364 LOGW("Pipeline not in porper state\n");
14368 result = __mmplayer_change_selector_pad(player, type, index);
14369 if (result != MM_ERROR_NONE) {
14370 LOGE("change selector pad error\n");
14374 player->selector[type].active_pad_index = index;
14376 if (current_state == GST_STATE_PLAYING) {
14377 event = gst_event_new_seek(1.0, 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);
14379 __gst_send_event_to_sink(player, event);
14381 result = MM_ERROR_PLAYER_INTERNAL;
14390 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14392 mm_player_t* player = (mm_player_t*) hplayer;
14396 /* check player handle */
14397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14399 *silent = player->set_mode.subtitle_off;
14401 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14405 return MM_ERROR_NONE;
14409 __is_ms_buff_src(mm_player_t* player)
14411 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14413 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14417 __has_suffix(mm_player_t* player, const gchar* suffix)
14419 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14420 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14422 gboolean ret = FALSE;
14423 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14424 gchar* t_suffix = g_ascii_strdown(suffix, -1);
14426 if (g_str_has_suffix(player->profile.uri, suffix))
14429 MMPLAYER_FREEIF(t_url);
14430 MMPLAYER_FREEIF(t_suffix);
14436 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14438 mm_player_t* player = (mm_player_t*) hplayer;
14440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14442 MMPLAYER_VIDEO_SINK_CHECK(player);
14444 LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14446 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14448 return MM_ERROR_NONE;
14451 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14454 mm_player_t* player = (mm_player_t*) hplayer;
14455 float _level = 0.0;
14459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14461 MMPLAYER_VIDEO_SINK_CHECK(player);
14463 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14465 LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14471 return MM_ERROR_NONE;
14475 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14477 mm_player_t* player = (mm_player_t*) hplayer;
14479 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14481 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14482 MMPLAYER_PRINT_STATE(player);
14483 LOGE("wrong-state : can't set the download mode to parse");
14484 return MM_ERROR_PLAYER_INVALID_STATE;
14487 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14488 player->video_hub_download_mode = mode;
14490 return MM_ERROR_NONE;
14494 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14496 mm_player_t* player = (mm_player_t*) hplayer;
14498 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14500 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14501 player->sync_handler = enable;
14503 return MM_ERROR_NONE;
14507 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14509 long long clock_delta,
14510 long long video_time,
14511 long long media_clock,
14512 long long audio_time)
14514 mm_player_t* player = (mm_player_t*) hplayer;
14515 MMPlayerGstElement* mainbin = NULL;
14516 GstClockTime start_time_audio = 0, start_time_video = 0;
14517 GstClockTimeDiff base_time = 0, new_base_time = 0;
14518 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14519 gint64 api_delta = 0;
14520 gint64 position = 0, position_delta = 0;
14521 gint64 adj_base_time = 0;
14522 GstClock *curr_clock = NULL;
14523 GstClockTime curr_time = 0;
14524 gboolean query_ret = TRUE;
14525 int result = MM_ERROR_NONE;
14529 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14530 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14531 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14533 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14535 if ((video_time < 0) || (player->doing_seek)) {
14536 LOGD("skip setting master clock. %lld", video_time);
14540 mainbin = player->pipeline->mainbin;
14542 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14543 curr_time = gst_clock_get_time(curr_clock);
14545 current_state = MMPLAYER_CURRENT_STATE(player);
14547 if (current_state == MM_PLAYER_STATE_PLAYING)
14548 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14550 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14552 position = player->last_position;
14553 LOGD("query fail. %lld", position);
14556 clock *= GST_USECOND;
14557 clock_delta *= GST_USECOND;
14559 api_delta = clock - curr_time;
14560 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14561 player->video_share_api_delta = api_delta;
14563 clock_delta += (api_delta - player->video_share_api_delta);
14565 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14566 player->video_share_clock_delta = (gint64)clock_delta;
14568 position_delta = (position/GST_USECOND) - video_time;
14569 position_delta *= GST_USECOND;
14571 adj_base_time = position_delta;
14572 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14575 gint64 new_play_time = 0;
14576 gint64 network_delay = 0;
14578 video_time *= GST_USECOND;
14580 network_delay = clock_delta - player->video_share_clock_delta;
14581 new_play_time = video_time + network_delay;
14583 adj_base_time = position - new_play_time;
14585 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14586 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14589 /* Adjust Current Stream Time with base_time of sink
14590 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14591 * 2. Set new base time
14592 * if adj_base_time is positive value, the stream time will be decreased.
14593 * 3. If seek event is occurred, the start time will be reset. */
14594 if ((player->pipeline->audiobin) &&
14595 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14596 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14598 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14599 LOGD("audio sink : gst_element_set_start_time -> NONE");
14600 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14603 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14606 if ((player->pipeline->videobin) &&
14607 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14608 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14610 if (start_time_video != GST_CLOCK_TIME_NONE) {
14611 LOGD("video sink : gst_element_set_start_time -> NONE");
14612 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14615 // if videobin exist, get base_time from videobin.
14616 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14619 new_base_time = base_time + adj_base_time;
14621 if ((player->pipeline->audiobin) &&
14622 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14623 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14625 if ((player->pipeline->videobin) &&
14626 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14627 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14636 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14637 long long *video_time,
14638 long long *media_clock,
14639 long long *audio_time)
14641 mm_player_t* player = (mm_player_t*) hplayer;
14642 MMPlayerGstElement* mainbin = NULL;
14643 GstClock *curr_clock = NULL;
14644 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14645 gint64 position = 0;
14646 gboolean query_ret = TRUE;
14650 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14651 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14652 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14654 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14655 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14656 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14658 mainbin = player->pipeline->mainbin;
14660 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14662 current_state = MMPLAYER_CURRENT_STATE(player);
14664 if (current_state != MM_PLAYER_STATE_PAUSED)
14665 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14667 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14669 position = player->last_position;
14671 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14673 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14676 gst_object_unref(curr_clock);
14680 return MM_ERROR_NONE;
14684 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14686 mm_player_t* player = (mm_player_t*) hplayer;
14691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14692 MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14694 if (player->v_stream_caps) {
14695 GstStructure *str = NULL;
14697 str = gst_caps_get_structure(player->v_stream_caps, 0);
14698 if (!gst_structure_get_int(str, "orientation", &org_angle))
14699 LOGD("missing 'orientation' field in video caps");
14702 LOGD("orientation: %d", org_angle);
14703 *angle = org_angle;
14706 return MM_ERROR_NONE;
14710 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14712 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14713 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14715 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14716 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14720 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14721 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14722 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14723 mm_player_dump_t *dump_s;
14724 dump_s = g_malloc(sizeof(mm_player_dump_t));
14726 if (dump_s == NULL) {
14727 LOGE("malloc fail");
14731 dump_s->dump_element_file = NULL;
14732 dump_s->dump_pad = NULL;
14733 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14735 if (dump_s->dump_pad) {
14736 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14737 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]);
14738 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14739 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);
14740 /* add list for removed buffer probe and close FILE */
14741 player->dump_list = g_list_append(player->dump_list, dump_s);
14742 LOGD("%s sink pad added buffer probe for dump", factory_name);
14747 LOGE("failed to get %s sink pad added", factory_name);
14756 static GstPadProbeReturn
14757 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
14759 FILE *dump_data = (FILE *) u_data;
14760 // int written = 0;
14761 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14762 GstMapInfo probe_info = GST_MAP_INFO_INIT;
14764 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14766 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14768 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14770 fwrite(probe_info.data, 1, probe_info.size , dump_data);
14772 return GST_PAD_PROBE_OK;
14776 __mmplayer_release_dump_list(GList *dump_list)
14779 GList *d_list = dump_list;
14780 for (; d_list; d_list = g_list_next(d_list)) {
14781 mm_player_dump_t *dump_s = d_list->data;
14782 if (dump_s->dump_pad) {
14783 if (dump_s->probe_handle_id)
14784 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14786 if (dump_s->dump_element_file) {
14787 fclose(dump_s->dump_element_file);
14788 dump_s->dump_element_file = NULL;
14790 MMPLAYER_FREEIF(dump_s);
14792 g_list_free(dump_list);
14798 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14800 mm_player_t* player = (mm_player_t*) hplayer;
14804 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14805 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14807 *exist = player->has_closed_caption;
14811 return MM_ERROR_NONE;
14814 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14818 /* increase ref count of gst buffer */
14820 ret = gst_buffer_ref((GstBuffer *)buffer);
14826 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14830 gst_buffer_unref((GstBuffer *)buffer);
14837 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14839 mm_player_t *player = (mm_player_t*)user_data;
14840 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14841 guint64 current_level_bytes = 0;
14843 MMPLAYER_RETURN_IF_FAIL(player);
14845 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14847 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14849 if (player->media_stream_buffer_status_cb[type])
14850 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14854 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
14856 mm_player_t *player = (mm_player_t*)user_data;
14857 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14858 guint64 current_level_bytes = 0;
14860 MMPLAYER_RETURN_IF_FAIL(player);
14862 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14864 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
14866 if (player->media_stream_buffer_status_cb[type])
14867 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14871 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
14873 mm_player_t *player = (mm_player_t*)user_data;
14874 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14875 guint64 current_level_bytes = 0;
14877 MMPLAYER_RETURN_IF_FAIL(player);
14879 LOGI("app-src: feed subtitle\n");
14881 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14883 if (player->media_stream_buffer_status_cb[type])
14884 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14888 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
14890 mm_player_t *player = (mm_player_t*)user_data;
14891 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14892 guint64 current_level_bytes = 0;
14894 MMPLAYER_RETURN_IF_FAIL(player);
14896 LOGI("app-src: audio buffer is full.\n");
14898 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14900 if (player->media_stream_buffer_status_cb[type])
14901 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
14905 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
14907 mm_player_t *player = (mm_player_t*)user_data;
14908 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14909 guint64 current_level_bytes = 0;
14911 MMPLAYER_RETURN_IF_FAIL(player);
14913 LOGI("app-src: video buffer is full.\n");
14915 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14917 if (player->media_stream_buffer_status_cb[type])
14918 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
14922 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
14924 mm_player_t *player = (mm_player_t*)user_data;
14925 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14927 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14929 LOGD("app-src: seek audio data %llu\n", position);
14931 if (player->media_stream_seek_data_cb[type])
14932 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14938 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
14940 mm_player_t *player = (mm_player_t*)user_data;
14941 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14943 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14945 LOGD("app-src: seek video data %llu\n", position);
14947 if (player->media_stream_seek_data_cb[type])
14948 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14954 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
14956 mm_player_t *player = (mm_player_t*)user_data;
14957 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14959 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14961 LOGD("app-src: seek subtitle data\n");
14963 if (player->media_stream_seek_data_cb[type])
14964 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
14970 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
14972 mm_player_t* player = (mm_player_t*) hplayer;
14976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14978 player->pcm_samplerate = samplerate;
14979 player->pcm_channel = channel;
14982 return MM_ERROR_NONE;
14985 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
14987 mm_player_t* player = (mm_player_t*) hplayer;
14991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14992 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
14994 if (MMPLAYER_IS_STREAMING(player))
14995 *timeout = player->ini.live_state_change_timeout;
14997 *timeout = player->ini.localplayback_state_change_timeout;
14999 LOGD("timeout = %d\n", *timeout);
15002 return MM_ERROR_NONE;
15005 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15007 mm_player_t* player = (mm_player_t*) hplayer;
15011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15012 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15014 *num = player->video_num_buffers;
15015 *extra_num = player->video_extra_num_buffers;
15017 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15020 return MM_ERROR_NONE;