4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/wayland/wayland.h>
33 #include <gst/audio/gstaudiobasesink.h>
43 #include <mm_attrs_private.h>
45 #include <mm_sound_focus.h>
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
54 #include <system_info.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define MM_PLAYER_MPEG_VNAME "mpegversion"
90 #define MM_PLAYER_DIVX_VNAME "divxversion"
91 #define MM_PLAYER_WMV_VNAME "wmvversion"
92 #define MM_PLAYER_WMA_VNAME "wmaversion"
94 #define DEFAULT_PLAYBACK_RATE 1.0
95 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
96 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
97 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
98 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
99 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
101 #define GST_QUEUE_DEFAULT_TIME 4
102 #define GST_QUEUE_HLS_TIME 8
104 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
105 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
106 (player->ini.http_use_file_buffer) && \
107 (player->http_file_buffering_path) && \
108 (strlen(player->http_file_buffering_path) > 0))
109 #define MM_PLAYER_NAME "mmplayer"
111 #define PLAYER_DISPLAY_MODE_DST_ROI 5
113 /*---------------------------------------------------------------------------
114 | LOCAL CONSTANT DEFINITIONS: |
115 ---------------------------------------------------------------------------*/
117 /*---------------------------------------------------------------------------
118 | LOCAL DATA TYPE DEFINITIONS: |
119 ---------------------------------------------------------------------------*/
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
133 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
136 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
151 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
152 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
154 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
155 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
156 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
160 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
162 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
163 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
164 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
166 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
167 //static void __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
168 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
169 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
170 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static void __mmplayer_init_factories(mm_player_t* player);
174 static void __mmplayer_release_factories(mm_player_t* player);
175 static void __mmplayer_release_misc(mm_player_t* player);
176 static void __mmplayer_release_misc_post(mm_player_t* player);
177 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
178 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
179 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
181 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
182 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
184 int __mmplayer_switch_audio_sink(mm_player_t* player);
185 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
186 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
187 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
188 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
189 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
190 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
192 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
193 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
194 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
195 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
196 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
197 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
198 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
199 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
200 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
201 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
202 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
203 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
204 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
205 static gpointer __mmplayer_next_play_thread(gpointer data);
206 static gpointer __mmplayer_repeat_thread(gpointer data);
207 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
210 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
211 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
212 static void __mmplayer_release_dump_list(GList *dump_list);
214 static int __gst_realize(mm_player_t* player);
215 static int __gst_unrealize(mm_player_t* player);
216 static int __gst_start(mm_player_t* player);
217 static int __gst_stop(mm_player_t* player);
218 static int __gst_pause(mm_player_t* player, gboolean async);
219 static int __gst_resume(mm_player_t* player, gboolean async);
220 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
221 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
222 gint64 cur, GstSeekType stop_type, gint64 stop);
223 static int __gst_pending_seek(mm_player_t* player);
225 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
226 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
227 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
228 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
229 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
231 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
233 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
234 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
237 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
238 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
240 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
241 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
244 static gboolean __is_ms_buff_src(mm_player_t* player);
245 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
247 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
248 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
249 static int __mmplayer_start_streaming_ext(mm_player_t *player);
250 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
251 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
253 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
254 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
255 static void __mmplayer_check_pipeline(mm_player_t* player);
256 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
257 static void __mmplayer_deactivate_old_path(mm_player_t *player);
258 #if 0 // We'll need this in future.
259 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
262 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
263 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
265 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
266 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
267 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
268 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
269 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
270 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
271 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
272 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
273 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
274 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
275 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
276 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
277 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
279 /*===========================================================================================
281 | FUNCTION DEFINITIONS |
283 ========================================================================================== */
287 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
291 count = gst_tag_list_get_tag_size(list, tag);
293 LOGD("count = %d", count);
295 for (i = 0; i < count; i++) {
298 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
299 if (!gst_tag_list_get_string_index(list, tag, i, &str))
300 g_assert_not_reached();
302 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
305 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
307 g_print(" : %s\n", str);
314 /* This function should be called after the pipeline goes PAUSED or higher
317 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
319 static gboolean has_duration = FALSE;
320 static gboolean has_video_attrs = FALSE;
321 static gboolean has_audio_attrs = FALSE;
322 static gboolean has_bitrate = FALSE;
323 gboolean missing_only = FALSE;
324 gboolean all = FALSE;
326 GstStructure* p = NULL;
327 MMHandleType attrs = 0;
329 gint stream_service_type = STREAMING_SERVICE_NONE;
334 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
336 /* check player state here */
337 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
338 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
339 /* give warning now only */
340 LOGW("be careful. content attributes may not available in this state ");
343 /* get content attribute first */
344 attrs = MMPLAYER_GET_ATTRS(player);
346 LOGE("cannot get content attribute");
350 /* get update flag */
352 if (flag & ATTR_MISSING_ONLY) {
354 LOGD("updating missed attr only");
357 if (flag & ATTR_ALL) {
359 has_duration = FALSE;
360 has_video_attrs = FALSE;
361 has_audio_attrs = FALSE;
364 LOGD("updating all attrs");
367 if (missing_only && all) {
368 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
369 missing_only = FALSE;
372 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
373 LOGD("try to update duration");
374 has_duration = FALSE;
376 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
377 player->duration = dur_nsec;
378 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
381 if (player->duration < 0) {
382 LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
383 player->duration = 0;
386 /* try to get streaming service type */
387 stream_service_type = __mmplayer_get_stream_service_type(player);
388 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
390 /* check duration is OK */
391 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
392 /* FIXIT : find another way to get duration here. */
393 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
396 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
401 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
402 /* update audio params
403 NOTE : We need original audio params and it can be only obtained from src pad of audio
404 decoder. Below code only valid when we are not using 'resampler' just before
407 LOGD("try to update audio attrs");
408 has_audio_attrs = FALSE;
410 if (player->pipeline->audiobin &&
411 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
412 GstCaps *caps_a = NULL;
414 gint samplerate = 0, channels = 0;
416 pad = gst_element_get_static_pad(
417 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
420 caps_a = gst_pad_get_current_caps(pad);
423 p = gst_caps_get_structure(caps_a, 0);
425 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
427 gst_structure_get_int(p, "rate", &samplerate);
428 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
430 gst_structure_get_int(p, "channels", &channels);
431 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
433 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
435 gst_caps_unref(caps_a);
438 has_audio_attrs = TRUE;
440 LOGW("not ready to get audio caps");
442 gst_object_unref(pad);
444 LOGW("failed to get pad from audiosink");
448 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
449 LOGD("try to update video attrs");
450 has_video_attrs = FALSE;
452 if (player->pipeline->videobin &&
453 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
454 GstCaps *caps_v = NULL;
459 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
461 caps_v = gst_pad_get_current_caps(pad);
463 /* Use v_stream_caps, if fail to get video_sink sink pad*/
464 if (!caps_v && player->v_stream_caps) {
465 caps_v = player->v_stream_caps;
466 gst_caps_ref(caps_v);
470 p = gst_caps_get_structure(caps_v, 0);
471 gst_structure_get_int(p, "width", &width);
472 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
474 gst_structure_get_int(p, "height", &height);
475 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
477 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
479 SECURE_LOGD("width : %d height : %d", width, height);
481 gst_caps_unref(caps_v);
485 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
486 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
489 has_video_attrs = TRUE;
491 LOGD("no negitiated caps from videosink");
492 gst_object_unref(pad);
495 LOGD("no videosink sink pad");
500 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
503 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
504 if (player->duration) {
505 guint64 data_size = 0;
507 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
508 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
510 if (stat(path, &sb) == 0)
511 data_size = (guint64)sb.st_size;
512 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
513 data_size = player->http_content_size;
514 LOGD("try to update bitrate : data_size = %lld", data_size);
518 guint64 msec_dur = 0;
520 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
521 bitrate = data_size * 8 * 1000 / msec_dur;
522 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
523 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
528 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
529 if (player->total_bitrate) {
530 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
538 if (mmf_attrs_commit(attrs)) {
539 LOGE("failed to update attributes\n");
548 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
550 gint streaming_type = STREAMING_SERVICE_NONE;
554 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
556 player->pipeline->mainbin &&
557 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
560 /* streaming service type if streaming */
561 if (!MMPLAYER_IS_STREAMING(player))
562 return STREAMING_SERVICE_NONE;
564 if (MMPLAYER_IS_HTTP_STREAMING(player))
565 streaming_type = (player->duration == 0) ?
566 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
568 switch (streaming_type) {
569 case STREAMING_SERVICE_LIVE:
570 LOGD("it's live streaming");
572 case STREAMING_SERVICE_VOD:
573 LOGD("it's vod streaming");
576 LOGE("should not get here");
579 player->streaming_type = streaming_type;
582 return streaming_type;
586 /* this function sets the player state and also report
587 * it to applicaton by calling callback function
590 __mmplayer_set_state(mm_player_t* player, int state) // @
592 MMMessageParamType msg = {0, };
593 int sound_result = MM_ERROR_NONE;
594 gboolean post_bos = FALSE;
595 gboolean interrupted_by_focus = FALSE;
596 gboolean interrupted_by_resource = FALSE;
597 int ret = MM_ERROR_NONE;
599 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
601 if (MMPLAYER_CURRENT_STATE(player) == state) {
602 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
603 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
607 /* update player states */
608 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
609 MMPLAYER_CURRENT_STATE(player) = state;
611 /* FIXIT : it's better to do like below code
612 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
613 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
614 and add more code to handling PENDING_STATE.
616 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
617 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
620 MMPLAYER_PRINT_STATE(player);
622 /* do some FSM stuffs before posting new state to application */
623 interrupted_by_focus = player->sound_focus.by_asm_cb;
624 interrupted_by_resource = player->resource_manager.by_rm_cb;
626 switch (MMPLAYER_CURRENT_STATE(player)) {
627 case MM_PLAYER_STATE_NULL:
628 case MM_PLAYER_STATE_READY:
630 if (player->cmd == MMPLAYER_COMMAND_STOP) {
631 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
632 if (sound_result != MM_ERROR_NONE) {
633 LOGE("failed to release sound focus\n");
634 return MM_ERROR_POLICY_INTERNAL;
640 case MM_PLAYER_STATE_PAUSED:
642 if (!player->sent_bos) {
644 #define MMPLAYER_MAX_SOUND_PRIORITY 3
646 /* rtsp case, get content attrs by GstMessage */
647 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
648 /* it's first time to update all content attrs. */
649 _mmplayer_update_content_attrs( player, ATTR_ALL );
652 /* set max sound priority to keep own sound and not to mute other's one */
653 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
655 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
657 LOGD("set max audio priority");
658 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
664 /* add audio callback probe if condition is satisfied */
665 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
666 __mmplayer_configure_audio_callback(player);
667 /* FIXIT : handle return value */
669 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
670 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
671 if (sound_result != MM_ERROR_NONE) {
672 LOGE("failed to release sound focus\n");
673 return MM_ERROR_POLICY_INTERNAL;
679 case MM_PLAYER_STATE_PLAYING:
681 /* try to get content metadata */
682 if (!player->sent_bos) {
683 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
684 * c-api since c-api doesn't use _start() anymore. It may not work propery with
685 * legacy mmfw-player api */
686 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
689 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
690 if (!player->sent_bos)
691 __mmplayer_handle_missed_plugin(player);
692 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
693 if (sound_result != MM_ERROR_NONE) {
694 // FIXME : need to check history
695 if (player->pipeline->videobin) {
696 MMMessageParamType msg = {0, };
698 LOGE("failed to go ahead because of video conflict\n");
700 msg.union_type = MM_MSG_UNION_CODE;
701 msg.code = MM_ERROR_POLICY_INTERRUPTED;
702 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
704 _mmplayer_unrealize((MMHandleType)player);
706 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
707 _mmplayer_pause((MMHandleType)player);
711 return MM_ERROR_POLICY_INTERNAL;
715 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
716 /* initialize because auto resume is done well. */
717 player->resumed_by_rewind = FALSE;
718 player->playback_rate = 1.0;
721 if (!player->sent_bos) {
722 /* check audio codec field is set or not
723 * we can get it from typefinder or codec's caps.
725 gchar *audio_codec = NULL;
726 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
728 /* The codec format can't be sent for audio only case like amr, mid etc.
729 * Because, parser don't make related TAG.
730 * So, if it's not set yet, fill it with found data.
733 if (g_strrstr(player->type, "audio/midi"))
734 audio_codec = g_strdup("MIDI");
735 else if (g_strrstr(player->type, "audio/x-amr"))
736 audio_codec = g_strdup("AMR");
737 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
738 audio_codec = g_strdup("AAC");
740 audio_codec = g_strdup("unknown");
741 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
743 MMPLAYER_FREEIF(audio_codec);
744 mmf_attrs_commit(player->attrs);
745 LOGD("set audio codec type with caps\n");
753 case MM_PLAYER_STATE_NONE:
755 LOGW("invalid target state, there is nothing to do.\n");
760 /* post message to application */
761 if (MMPLAYER_TARGET_STATE(player) == state) {
762 /* fill the message with state of player */
763 msg.state.previous = MMPLAYER_PREV_STATE(player);
764 msg.state.current = MMPLAYER_CURRENT_STATE(player);
766 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
768 /* state changed by focus or resource callback */
769 if (interrupted_by_focus || interrupted_by_resource) {
770 msg.union_type = MM_MSG_UNION_CODE;
771 if (interrupted_by_focus)
772 msg.code = player->sound_focus.focus_changed_msg;
773 else if (interrupted_by_resource)
774 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
775 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
776 } else /* state changed by usecase */
777 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
779 LOGD("intermediate state, do nothing.\n");
780 MMPLAYER_PRINT_STATE(player);
785 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
786 player->sent_bos = TRUE;
792 static gpointer __mmplayer_next_play_thread(gpointer data)
794 mm_player_t* player = (mm_player_t*) data;
795 MMPlayerGstElement *mainbin = NULL;
797 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
799 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
800 while (!player->next_play_thread_exit) {
801 LOGD("next play thread started. waiting for signal.\n");
802 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
804 LOGD("reconfigure pipeline for gapless play.\n");
806 if (player->next_play_thread_exit) {
807 if (player->gapless.reconfigure) {
808 player->gapless.reconfigure = false;
809 MMPLAYER_PLAYBACK_UNLOCK(player);
811 LOGD("exiting gapless play thread\n");
815 mainbin = player->pipeline->mainbin;
817 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
818 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
819 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
820 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
821 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
823 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
825 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
830 static gpointer __mmplayer_repeat_thread(gpointer data)
832 mm_player_t* player = (mm_player_t*) data;
833 gboolean ret_value = FALSE;
834 MMHandleType attrs = 0;
837 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
839 MMPLAYER_REPEAT_THREAD_LOCK(player);
840 while (!player->repeat_thread_exit) {
841 LOGD("repeat thread started. waiting for signal.\n");
842 MMPLAYER_REPEAT_THREAD_WAIT(player);
844 if (player->repeat_thread_exit) {
845 LOGD("exiting repeat thread\n");
851 MMPLAYER_CMD_LOCK(player);
853 attrs = MMPLAYER_GET_ATTRS(player);
855 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
856 LOGE("can not get play count\n");
857 MMPLAYER_CMD_UNLOCK(player);
861 if (player->section_repeat) {
862 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
864 if (player->playback_rate < 0.0) {
865 player->resumed_by_rewind = TRUE;
866 _mmplayer_set_mute((MMHandleType)player, 0);
867 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
870 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
871 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
872 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
875 player->sent_bos = FALSE;
879 LOGE("failed to set position to zero for rewind\n");
880 MMPLAYER_CMD_UNLOCK(player);
884 /* decrease play count */
886 /* we successeded to rewind. update play count and then wait for next EOS */
889 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
891 /* commit attribute */
892 if (mmf_attrs_commit(attrs))
893 LOGE("failed to commit attribute\n");
897 MMPLAYER_CMD_UNLOCK(player);
900 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
905 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
907 MMHandleType attrs = 0;
908 guint64 data_size = 0;
910 unsigned long pos_msec = 0;
913 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
915 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
917 attrs = MMPLAYER_GET_ATTRS(player);
919 LOGE("fail to get attributes.\n");
923 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
924 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
926 if (stat(path, &sb) == 0)
927 data_size = (guint64)sb.st_size;
928 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
929 data_size = player->http_content_size;
931 __mm_player_streaming_buffering(player->streamer,
934 player->last_position,
937 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
943 __mmplayer_handle_buffering_message(mm_player_t* player)
945 int ret = MM_ERROR_NONE;
946 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
947 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
948 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
949 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
951 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
952 LOGW("do nothing for buffering msg\n");
953 ret = MM_ERROR_PLAYER_INVALID_STATE;
957 prev_state = MMPLAYER_PREV_STATE(player);
958 current_state = MMPLAYER_CURRENT_STATE(player);
959 target_state = MMPLAYER_TARGET_STATE(player);
960 pending_state = MMPLAYER_PENDING_STATE(player);
962 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
963 MMPLAYER_STATE_GET_NAME(prev_state),
964 MMPLAYER_STATE_GET_NAME(current_state),
965 MMPLAYER_STATE_GET_NAME(pending_state),
966 MMPLAYER_STATE_GET_NAME(target_state),
967 player->streamer->is_buffering);
969 if (!player->streamer->is_buffering) {
970 /* NOTE : if buffering has done, player has to go to target state. */
971 switch (target_state) {
972 case MM_PLAYER_STATE_PAUSED:
974 switch (pending_state) {
975 case MM_PLAYER_STATE_PLAYING:
976 __gst_pause(player, TRUE);
979 case MM_PLAYER_STATE_PAUSED:
980 LOGD("player is already going to paused state, there is nothing to do.\n");
983 case MM_PLAYER_STATE_NONE:
984 case MM_PLAYER_STATE_NULL:
985 case MM_PLAYER_STATE_READY:
987 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
993 case MM_PLAYER_STATE_PLAYING:
995 switch (pending_state) {
996 case MM_PLAYER_STATE_NONE:
998 if (current_state != MM_PLAYER_STATE_PLAYING)
999 __gst_resume(player, TRUE);
1003 case MM_PLAYER_STATE_PAUSED:
1004 /* NOTE: It should be worked as asynchronously.
1005 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1007 __gst_resume(player, TRUE);
1010 case MM_PLAYER_STATE_PLAYING:
1011 LOGD("player is already going to playing state, there is nothing to do.\n");
1014 case MM_PLAYER_STATE_NULL:
1015 case MM_PLAYER_STATE_READY:
1017 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1023 case MM_PLAYER_STATE_NULL:
1024 case MM_PLAYER_STATE_READY:
1025 case MM_PLAYER_STATE_NONE:
1027 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1031 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1032 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1034 switch (pending_state) {
1035 case MM_PLAYER_STATE_NONE:
1037 if (current_state != MM_PLAYER_STATE_PAUSED) {
1038 /* rtsp streaming pause makes rtsp server stop sending data. */
1039 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1040 LOGD("set pause state during buffering\n");
1041 __gst_pause( player, TRUE );
1047 case MM_PLAYER_STATE_PLAYING:
1048 /* rtsp streaming pause makes rtsp server stop sending data. */
1049 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1050 __gst_pause ( player, TRUE );
1054 case MM_PLAYER_STATE_PAUSED:
1057 case MM_PLAYER_STATE_NULL:
1058 case MM_PLAYER_STATE_READY:
1060 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1070 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1072 MMPlayerGstElement *textbin;
1075 MMPLAYER_RETURN_IF_FAIL(player &&
1077 player->pipeline->textbin);
1079 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1081 textbin = player->pipeline->textbin;
1084 LOGD("Drop subtitle text after getting EOS\n");
1086 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1087 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1089 player->is_subtitle_force_drop = TRUE;
1091 if (player->is_subtitle_force_drop == TRUE) {
1092 LOGD("Enable subtitle data path without drop\n");
1094 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1095 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1097 LOGD("non-connected with external display");
1099 player->is_subtitle_force_drop = FALSE;
1105 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1107 mm_player_t* player = (mm_player_t*) data;
1108 gboolean ret = TRUE;
1109 static gboolean async_done = FALSE;
1111 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1112 MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1114 switch (GST_MESSAGE_TYPE(msg)) {
1115 case GST_MESSAGE_UNKNOWN:
1116 LOGD("unknown message received\n");
1119 case GST_MESSAGE_EOS:
1121 MMHandleType attrs = 0;
1124 LOGD("GST_MESSAGE_EOS received\n");
1126 /* NOTE : EOS event is comming multiple time. watch out it */
1127 /* check state. we only process EOS when pipeline state goes to PLAYING */
1128 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1129 LOGD("EOS received on non-playing state. ignoring it\n");
1133 if (player->pipeline) {
1134 if (player->pipeline->textbin)
1135 __mmplayer_drop_subtitle(player, TRUE);
1137 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1140 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1142 LOGD("release audio callback\n");
1144 /* release audio callback */
1145 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1146 player->audio_cb_probe_id = 0;
1147 /* audio callback should be free because it can be called even though probe remove.*/
1148 player->audio_stream_cb = NULL;
1149 player->audio_stream_cb_user_param = NULL;
1153 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1154 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1156 /* rewind if repeat count is greater then zero */
1157 /* get play count */
1158 attrs = MMPLAYER_GET_ATTRS(player);
1161 gboolean smooth_repeat = FALSE;
1163 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1164 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1166 player->play_count = count;
1168 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1170 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1171 if (smooth_repeat) {
1172 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1174 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1180 if (player->section_repeat) {
1181 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1183 if (player->playback_rate < 0.0) {
1184 player->resumed_by_rewind = TRUE;
1185 _mmplayer_set_mute((MMHandleType)player, 0);
1186 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1189 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1192 player->sent_bos = FALSE;
1195 if (MM_ERROR_NONE != ret_value)
1196 LOGE("failed to set position to zero for rewind\n");
1198 /* not posting eos when repeating */
1204 if (player->pipeline)
1205 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1207 /* post eos message to application */
1208 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1210 /* reset last position */
1211 player->last_position = 0;
1215 case GST_MESSAGE_ERROR:
1217 GError *error = NULL;
1218 gchar* debug = NULL;
1220 /* generating debug info before returning error */
1221 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1223 /* get error code */
1224 gst_message_parse_error(msg, &error, &debug);
1226 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1227 /* Note : the streaming error from the streaming source is handled
1228 * using __mmplayer_handle_streaming_error.
1230 __mmplayer_handle_streaming_error(player, msg);
1232 /* dump state of all element */
1233 __mmplayer_dump_pipeline_state(player);
1235 /* traslate gst error code to msl error code. then post it
1236 * to application if needed
1238 __mmplayer_handle_gst_error(player, msg, error);
1241 LOGE("error debug : %s", debug);
1244 if (MMPLAYER_IS_HTTP_PD(player))
1245 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1247 MMPLAYER_FREEIF(debug);
1248 g_error_free(error);
1252 case GST_MESSAGE_WARNING:
1255 GError* error = NULL;
1257 gst_message_parse_warning(msg, &error, &debug);
1259 LOGD("warning : %s\n", error->message);
1260 LOGD("debug : %s\n", debug);
1262 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1264 MMPLAYER_FREEIF(debug);
1265 g_error_free(error);
1269 case GST_MESSAGE_TAG:
1271 LOGD("GST_MESSAGE_TAG\n");
1272 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1273 LOGW("failed to extract tags from gstmessage\n");
1277 case GST_MESSAGE_BUFFERING:
1279 MMMessageParamType msg_param = {0, };
1280 int bRet = MM_ERROR_NONE;
1282 if (!MMPLAYER_IS_STREAMING(player))
1285 /* ignore the prev buffering message */
1286 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1287 gint buffer_percent = 0;
1289 gst_message_parse_buffering(msg, &buffer_percent);
1291 if (buffer_percent == MAX_BUFFER_PERCENT) {
1292 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1293 player->streamer->is_buffering_done = FALSE;
1299 MMPLAYER_CMD_LOCK(player);
1300 __mmplayer_update_buffer_setting(player, msg);
1302 bRet = __mmplayer_handle_buffering_message(player);
1304 if (bRet == MM_ERROR_NONE) {
1305 msg_param.connection.buffering = player->streamer->buffering_percent;
1306 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1308 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1309 player->pending_resume &&
1310 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1312 player->is_external_subtitle_added_now = FALSE;
1313 player->pending_resume = FALSE;
1314 _mmplayer_resume((MMHandleType)player);
1317 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1318 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1320 if (player->doing_seek) {
1321 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1322 player->doing_seek = FALSE;
1323 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1324 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1329 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1330 if (!player->streamer) {
1331 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1332 MMPLAYER_CMD_UNLOCK(player);
1336 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1338 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1339 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1341 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1342 msg_param.connection.buffering = player->streamer->buffering_percent;
1343 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1345 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1348 msg_param.connection.buffering = player->streamer->buffering_percent;
1349 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1352 MMPLAYER_CMD_UNLOCK(player);
1356 case GST_MESSAGE_STATE_CHANGED:
1358 MMPlayerGstElement *mainbin;
1359 const GValue *voldstate, *vnewstate, *vpending;
1360 GstState oldstate = GST_STATE_NULL;
1361 GstState newstate = GST_STATE_NULL;
1362 GstState pending = GST_STATE_NULL;
1364 if (!(player->pipeline && player->pipeline->mainbin)) {
1365 LOGE("player pipeline handle is null");
1369 mainbin = player->pipeline->mainbin;
1371 /* we only handle messages from pipeline */
1372 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1375 /* get state info from msg */
1376 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1377 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1378 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1380 if (!voldstate || !vnewstate) {
1381 LOGE("received msg has wrong format.");
1385 oldstate = (GstState)voldstate->data[0].v_int;
1386 newstate = (GstState)vnewstate->data[0].v_int;
1388 pending = (GstState)vpending->data[0].v_int;
1390 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1391 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1392 gst_element_state_get_name((GstState)oldstate),
1393 gst_element_state_get_name((GstState)newstate),
1394 gst_element_state_get_name((GstState)pending));
1396 if (newstate == GST_STATE_PLAYING) {
1397 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1399 int retVal = MM_ERROR_NONE;
1400 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1402 retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1404 if (MM_ERROR_NONE != retVal)
1405 LOGE("failed to seek pending postion. just keep staying current position.\n");
1407 player->pending_seek.is_pending = FALSE;
1411 if (oldstate == newstate) {
1412 LOGD("pipeline reports state transition to old state");
1417 case GST_STATE_VOID_PENDING:
1420 case GST_STATE_NULL:
1423 case GST_STATE_READY:
1426 case GST_STATE_PAUSED:
1428 gboolean prepare_async = FALSE;
1430 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1431 __mmplayer_configure_audio_callback(player);
1433 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1434 // managed prepare async case
1435 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1436 LOGD("checking prepare mode for async transition - %d", prepare_async);
1439 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1440 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1442 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1443 __mm_player_streaming_set_content_bitrate(player->streamer,
1444 player->total_maximum_bitrate, player->total_bitrate);
1449 case GST_STATE_PLAYING:
1451 if (MMPLAYER_IS_STREAMING(player)) {
1452 // managed prepare async case when buffering is completed
1453 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1454 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1455 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1456 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1458 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1460 LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1461 if (player->streamer->buffering_percent < 100) {
1463 MMMessageParamType msg_param = {0, };
1464 LOGW("Posting Buffering Completed Message to Application !!!");
1466 msg_param.connection.buffering = 100;
1467 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1472 if (player->gapless.stream_changed) {
1473 _mmplayer_update_content_attrs(player, ATTR_ALL);
1474 player->gapless.stream_changed = FALSE;
1477 if (player->doing_seek && async_done) {
1478 player->doing_seek = FALSE;
1480 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1491 case GST_MESSAGE_CLOCK_LOST:
1493 GstClock *clock = NULL;
1494 gboolean need_new_clock = FALSE;
1496 gst_message_parse_clock_lost(msg, &clock);
1497 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1499 if (!player->videodec_linked)
1500 need_new_clock = TRUE;
1501 else if (!player->ini.use_system_clock)
1502 need_new_clock = TRUE;
1504 if (need_new_clock) {
1505 LOGD("Provide clock is TRUE, do pause->resume\n");
1506 __gst_pause(player, FALSE);
1507 __gst_resume(player, FALSE);
1512 case GST_MESSAGE_NEW_CLOCK:
1514 GstClock *clock = NULL;
1515 gst_message_parse_new_clock(msg, &clock);
1516 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1520 case GST_MESSAGE_ELEMENT:
1522 const gchar *structure_name;
1524 MMHandleType attrs = 0;
1526 attrs = MMPLAYER_GET_ATTRS(player);
1528 LOGE("cannot get content attribute");
1533 if (gst_message_get_structure(msg) == NULL)
1536 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1537 if (!structure_name)
1540 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1541 gint num_buffers = 0;
1542 gint extra_num_buffers = 0;
1544 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1545 player->video_num_buffers = num_buffers;
1546 LOGD("video_num_buffers : %d", player->video_num_buffers);
1549 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1550 player->video_extra_num_buffers = extra_num_buffers;
1551 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1556 if (!strcmp(structure_name, "Language_list")) {
1557 const GValue *lang_list = NULL;
1558 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1559 if (lang_list != NULL) {
1560 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1562 LOGD("Total audio tracks(from parser) = %d \n", count);
1566 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1567 const GValue *lang_list = NULL;
1568 MMPlayerLangStruct *temp = NULL;
1570 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1571 if (lang_list != NULL) {
1572 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1574 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1575 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1576 if (mmf_attrs_commit(attrs))
1577 LOGE("failed to commit.\n");
1578 LOGD("Total subtitle tracks = %d \n", count);
1581 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1583 LOGD("value of lang_key is %s and lang_code is %s",
1584 temp->language_key, temp->language_code);
1590 /* custom message */
1591 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1592 MMMessageParamType msg_param = {0,};
1593 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1594 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1597 /* custom message for RTSP attribute :
1598 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1599 sdp which has contents info is received when rtsp connection is opened.
1600 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1601 if (!strcmp(structure_name, "rtspsrc_properties")) {
1603 gchar *audio_codec = NULL;
1604 gchar *video_codec = NULL;
1605 gchar *video_frame_size = NULL;
1607 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1608 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1609 __mmplayer_get_stream_service_type(player);
1610 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1612 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1613 LOGD("rtsp_audio_codec : %s", audio_codec);
1615 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1617 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1618 LOGD("rtsp_video_codec : %s", video_codec);
1620 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1622 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1623 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1624 if (video_frame_size) {
1626 char *seperator = strchr(video_frame_size, '-');
1629 char video_width[10]={0,};
1630 int frame_size_len = strlen(video_frame_size);
1631 int separtor_len = strlen(seperator);
1633 strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1634 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1637 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1641 if (mmf_attrs_commit(attrs))
1642 LOGE("failed to commit.\n");
1647 case GST_MESSAGE_DURATION_CHANGED:
1649 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1650 ret = __mmplayer_gst_handle_duration(player, msg);
1652 LOGW("failed to update duration");
1657 case GST_MESSAGE_ASYNC_START:
1658 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1661 case GST_MESSAGE_ASYNC_DONE:
1663 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1665 /* we only handle messages from pipeline */
1666 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1669 if (player->doing_seek) {
1670 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1671 player->doing_seek = FALSE;
1672 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1673 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1674 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1675 (player->streamer) &&
1676 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1677 (player->streamer->is_buffering == FALSE)) {
1678 GstQuery *query = NULL;
1679 gboolean busy = FALSE;
1682 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1683 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1684 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1685 gst_query_parse_buffering_percent(query, &busy, &percent);
1686 gst_query_unref(query);
1688 LOGD("buffered percent(%s): %d\n",
1689 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1692 if (percent >= 100) {
1693 player->streamer->is_buffering = FALSE;
1694 __mmplayer_handle_buffering_message(player);
1704 #if 0 /* delete unnecessary logs */
1705 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1706 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1707 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1708 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1709 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1710 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1711 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1712 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1713 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1714 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1715 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1716 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1717 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1718 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1719 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1726 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1727 * gst_element_post_message api takes ownership of the message.
1729 //gst_message_unref(msg);
1735 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1741 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1742 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1744 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1745 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1746 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1748 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1749 LOGD("data total size of http content: %lld", bytes);
1750 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1753 /* handling audio clip which has vbr. means duration is keep changing */
1754 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1763 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1766 /* macro for better code readability */
1767 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1768 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1769 if (string != NULL) {\
1770 SECURE_LOGD("update tag string : %s\n", string); \
1771 mm_attrs_set_string_by_name(attribute, playertag, string); \
1777 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1778 GstSample *sample = NULL;\
1779 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1780 GstMapInfo info = GST_MAP_INFO_INIT;\
1781 buffer = gst_sample_get_buffer(sample);\
1782 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1783 LOGD("failed to get image data from tag");\
1786 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1787 MMPLAYER_FREEIF(player->album_art);\
1788 player->album_art = (gchar *)g_malloc(info.size);\
1789 if (player->album_art) {\
1790 memcpy(player->album_art, info.data, info.size);\
1791 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1792 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1793 msg_param.data = (void *)player->album_art;\
1794 msg_param.size = info.size;\
1795 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1796 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1799 gst_buffer_unmap(buffer, &info);\
1802 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1803 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1805 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1806 if (player->updated_bitrate_count == 0) \
1807 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1808 if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1809 player->bitrate[player->updated_bitrate_count] = v_uint;\
1810 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1811 player->updated_bitrate_count++; \
1812 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1813 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1816 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1817 if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1818 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1819 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1820 player->updated_maximum_bitrate_count++; \
1821 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1822 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1825 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1830 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1832 if (date != NULL) {\
1833 string = g_strdup_printf("%d", g_date_get_year(date));\
1834 mm_attrs_set_string_by_name(attribute, playertag, string);\
1835 SECURE_LOGD("metainfo year : %s\n", string);\
1836 MMPLAYER_FREEIF(string);\
1841 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1842 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1843 if (datetime != NULL) {\
1844 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1845 mm_attrs_set_string_by_name(attribute, playertag, string);\
1846 SECURE_LOGD("metainfo year : %s\n", string);\
1847 MMPLAYER_FREEIF(string);\
1848 gst_date_time_unref(datetime);\
1852 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1853 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1855 /* FIXIT : don't know how to store date */\
1861 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1862 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1864 /* FIXIT : don't know how to store date */\
1870 /* function start */
1871 GstTagList* tag_list = NULL;
1873 MMHandleType attrs = 0;
1875 char *string = NULL;
1878 GstDateTime *datetime = NULL;
1880 GstBuffer *buffer = NULL;
1882 MMMessageParamType msg_param = {0, };
1884 /* currently not used. but those are needed for above macro */
1885 //guint64 v_uint64 = 0;
1886 //gdouble v_double = 0;
1888 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1890 attrs = MMPLAYER_GET_ATTRS(player);
1892 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1894 /* get tag list from gst message */
1895 gst_message_parse_tag(msg, &tag_list);
1897 /* store tags to player attributes */
1898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1901 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1902 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1903 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1904 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1905 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1906 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1907 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1908 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1909 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1910 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1911 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1912 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1913 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1915 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1916 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1917 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1918 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1919 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1920 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1923 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1924 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1925 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1926 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1927 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1929 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1930 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1931 MMPLAYER_UPDATE_TAG_LOCK(player);
1932 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1933 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1934 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1940 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1941 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1942 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1943 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1944 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1945 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1946 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1948 if (mmf_attrs_commit(attrs))
1949 LOGE("failed to commit.\n");
1951 gst_tag_list_free(tag_list);
1957 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) // @
1959 mm_player_t* player = (mm_player_t*) data;
1963 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1964 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1965 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1966 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1968 * [1] audio and video will be dumped with filesink.
1969 * [2] autoplugging is done by just using pad caps.
1970 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1971 * and the video will be dumped via filesink.
1973 if (player->num_dynamic_pad == 0) {
1974 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1976 if (!__mmplayer_gst_remove_fakesink(player,
1977 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1978 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1979 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1980 * source element are not same. To overcome this situation, this function will called
1981 * several places and several times. Therefore, this is not an error case.
1986 /* create dot before error-return. for debugging */
1987 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1989 player->no_more_pad = TRUE;
1995 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1997 GstElement* parent = NULL;
1999 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2001 /* if we have no fakesink. this meas we are using decodebin which doesn'
2002 t need to add extra fakesink */
2003 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2006 MMPLAYER_FSINK_LOCK(player);
2011 /* get parent of fakesink */
2012 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2014 LOGD("fakesink already removed\n");
2018 gst_element_set_locked_state(fakesink->gst, TRUE);
2020 /* setting the state to NULL never returns async
2021 * so no need to wait for completion of state transiton
2023 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2024 LOGE("fakesink state change failure!\n");
2025 /* FIXIT : should I return here? or try to proceed to next? */
2028 /* remove fakesink from it's parent */
2029 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2030 LOGE("failed to remove fakesink\n");
2032 gst_object_unref(parent);
2037 gst_object_unref(parent);
2039 LOGD("state-holder removed\n");
2041 gst_element_set_locked_state(fakesink->gst, FALSE);
2043 MMPLAYER_FSINK_UNLOCK(player);
2048 gst_element_set_locked_state(fakesink->gst, FALSE);
2050 MMPLAYER_FSINK_UNLOCK(player);
2056 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2058 GstPad *sinkpad = NULL;
2059 GstCaps* caps = NULL;
2060 GstElement* new_element = NULL;
2061 GstStructure* str = NULL;
2062 const gchar* name = NULL;
2064 mm_player_t* player = (mm_player_t*) data;
2068 MMPLAYER_RETURN_IF_FAIL(element && pad);
2069 MMPLAYER_RETURN_IF_FAIL(player &&
2071 player->pipeline->mainbin);
2074 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2075 * num_dynamic_pad will decreased after creating a sinkbin.
2077 player->num_dynamic_pad++;
2078 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2080 caps = gst_pad_query_caps(pad, NULL);
2082 MMPLAYER_CHECK_NULL(caps);
2084 /* clear previous result*/
2085 player->have_dynamic_pad = FALSE;
2087 str = gst_caps_get_structure(caps, 0);
2090 LOGE("cannot get structure from caps.\n");
2094 name = gst_structure_get_name(str);
2096 LOGE("cannot get mimetype from structure.\n");
2100 if (strstr(name, "video")) {
2102 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2104 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2105 if (player->v_stream_caps) {
2106 gst_caps_unref(player->v_stream_caps);
2107 player->v_stream_caps = NULL;
2110 new_element = gst_element_factory_make("fakesink", NULL);
2111 player->num_dynamic_pad--;
2116 /* clear previous result*/
2117 player->have_dynamic_pad = FALSE;
2119 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2120 LOGE("failed to autoplug for caps");
2124 /* check if there's dynamic pad*/
2125 if (player->have_dynamic_pad) {
2126 LOGE("using pad caps assums there's no dynamic pad !\n");
2130 gst_caps_unref(caps);
2135 /* excute new_element if created*/
2137 LOGD("adding new element to pipeline\n");
2139 /* set state to READY before add to bin */
2140 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2142 /* add new element to the pipeline */
2143 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2144 LOGE("failed to add autoplug element to bin\n");
2148 /* get pad from element */
2149 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2151 LOGE("failed to get sinkpad from autoplug element\n");
2156 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2157 LOGE("failed to link autoplug element\n");
2161 gst_object_unref(sinkpad);
2164 /* run. setting PLAYING here since streamming source is live source */
2165 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2172 STATE_CHANGE_FAILED:
2174 /* FIXIT : take care if new_element has already added to pipeline */
2176 gst_object_unref(GST_OBJECT(new_element));
2179 gst_object_unref(GST_OBJECT(sinkpad));
2182 gst_object_unref(GST_OBJECT(caps));
2184 /* FIXIT : how to inform this error to MSL ????? */
2185 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2186 * then post an error to application
2192 /* FIXIT : check indent */
2195 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2197 GstPad *sinkpad = NULL;
2198 GstCaps* caps = NULL;
2199 GstElement* new_element = NULL;
2200 enum MainElementID element_id = MMPLAYER_M_NUM;
2202 mm_player_t* player = (mm_player_t*) data;
2206 MMPLAYER_RETURN_IF_FAIL(element && pad);
2207 MMPLAYER_RETURN_IF_FAIL(player &&
2209 player->pipeline->mainbin);
2211 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2214 LOGD("using pad caps to autopluging instead of doing typefind\n");
2215 caps = gst_pad_query_caps(pad);
2216 MMPLAYER_CHECK_NULL(caps);
2217 /* clear previous result*/
2218 player->have_dynamic_pad = FALSE;
2219 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2221 LOGE("failed to create wfd rtp depay element\n");
2224 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2225 /* add new element to the pipeline */
2226 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2227 LOGD("failed to add autoplug element to bin\n");
2230 /* get pad from element */
2231 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2233 LOGD("failed to get sinkpad from autoplug element\n");
2237 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2238 LOGD("failed to link autoplug element\n");
2241 gst_object_unref(sinkpad);
2243 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2244 caps = gst_pad_query_caps(pad);
2245 MMPLAYER_CHECK_NULL(caps);
2246 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2247 /* create typefind */
2248 new_element = gst_element_factory_make("typefind", NULL);
2250 LOGD("failed to create typefind\n");
2254 MMPLAYER_SIGNAL_CONNECT(player,
2255 G_OBJECT(new_element),
2256 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2258 G_CALLBACK(__mmplayer_typefind_have_type),
2261 player->have_dynamic_pad = FALSE;
2264 /* excute new_element if created*/
2266 LOGD("adding new element to pipeline\n");
2268 /* set state to READY before add to bin */
2269 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2271 /* add new element to the pipeline */
2272 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2273 LOGD("failed to add autoplug element to bin\n");
2277 /* get pad from element */
2278 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2280 LOGD("failed to get sinkpad from autoplug element\n");
2285 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2286 LOGD("failed to link autoplug element\n");
2290 gst_object_unref(sinkpad);
2293 /* run. setting PLAYING here since streamming source is live source */
2294 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2297 /* store handle to futher manipulation */
2298 player->pipeline->mainbin[element_id].id = element_id;
2299 player->pipeline->mainbin[element_id].gst = new_element;
2305 STATE_CHANGE_FAILED:
2307 /* FIXIT : take care if new_element has already added to pipeline */
2309 gst_object_unref(GST_OBJECT(new_element));
2312 gst_object_unref(GST_OBJECT(sinkpad));
2315 gst_object_unref(GST_OBJECT(caps));
2317 /* FIXIT : how to inform this error to MSL ????? */
2318 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2319 * then post an error to application
2324 static GstPadProbeReturn
2325 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2327 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2328 return GST_PAD_PROBE_OK;
2331 static GstPadProbeReturn
2332 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2334 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2335 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2336 mm_player_t* player = (mm_player_t*)data;
2337 GstCaps* caps = NULL;
2338 GstStructure* str = NULL;
2339 const gchar* name = NULL;
2340 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2343 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2344 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2345 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2346 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2347 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2349 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2350 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2354 caps = gst_pad_query_caps(pad, NULL);
2356 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2360 str = gst_caps_get_structure(caps, 0);
2362 LOGE("failed to get structure from caps");
2366 name = gst_structure_get_name(str);
2368 LOGE("failed to get name from str");
2372 if (strstr(name, "audio")) {
2373 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2374 } else if (strstr(name, "video")) {
2375 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2377 /* text track is not supportable */
2378 LOGE("invalid name %s", name);
2382 switch (GST_EVENT_TYPE(event)) {
2385 /* in case of gapless, drop eos event not to send it to sink */
2386 if (player->gapless.reconfigure && !player->msg_posted) {
2387 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2388 ret = GST_PAD_PROBE_DROP;
2392 case GST_EVENT_STREAM_START:
2394 gint64 stop_running_time = 0;
2395 gint64 position_running_time = 0;
2396 gint64 position = 0;
2399 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2400 if ((player->gapless.update_segment[idx] == TRUE) ||
2401 !(player->selector[idx].event_probe_id)) {
2402 /* LOGW("[%d] skip", idx); */
2406 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2408 gst_segment_to_running_time(&player->gapless.segment[idx],
2409 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2410 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2412 gst_segment_to_running_time(&player->gapless.segment[idx],
2413 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2415 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2417 gst_segment_to_running_time(&player->gapless.segment[idx],
2418 GST_FORMAT_TIME, player->duration);
2421 position_running_time =
2422 gst_segment_to_running_time(&player->gapless.segment[idx],
2423 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2425 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2426 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2428 GST_TIME_ARGS(stop_running_time),
2429 GST_TIME_ARGS(position_running_time),
2430 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2431 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2433 position_running_time = MAX(position_running_time, stop_running_time);
2434 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2435 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2436 position_running_time = MAX(0, position_running_time);
2437 position = MAX(position, position_running_time);
2440 if (position != 0) {
2441 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2442 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2443 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2445 player->gapless.start_time[stream_type] += position;
2449 case GST_EVENT_FLUSH_STOP:
2451 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2452 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2453 player->gapless.start_time[stream_type] = 0;
2456 case GST_EVENT_SEGMENT:
2461 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2462 gst_event_copy_segment(event, &segment);
2464 if (segment.format == GST_FORMAT_TIME) {
2465 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2466 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2467 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2468 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2469 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2470 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2472 /* keep the all the segment ev to cover the seeking */
2473 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2474 player->gapless.update_segment[stream_type] = TRUE;
2476 if (!player->gapless.running)
2479 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2481 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2483 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2484 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2485 gst_event_unref(event);
2486 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2492 gdouble proportion = 0.0;
2493 GstClockTimeDiff diff = 0;
2494 GstClockTime timestamp = 0;
2495 gint64 running_time_diff = -1;
2496 GstQOSType type = 0;
2497 GstEvent *tmpev = NULL;
2499 running_time_diff = player->gapless.segment[stream_type].base;
2501 if (running_time_diff <= 0) /* don't need to adjust */
2504 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2505 gst_event_unref(event);
2507 if (timestamp < running_time_diff) {
2508 LOGW("QOS event from previous group");
2509 ret = GST_PAD_PROBE_DROP;
2513 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2514 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2515 stream_type, GST_TIME_ARGS(timestamp),
2516 GST_TIME_ARGS(running_time_diff),
2517 GST_TIME_ARGS(timestamp - running_time_diff));
2519 timestamp -= running_time_diff;
2521 /* That case is invalid for QoS events */
2522 if (diff < 0 && -diff > timestamp) {
2523 LOGW("QOS event from previous group");
2524 ret = GST_PAD_PROBE_DROP;
2528 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2529 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2539 gst_caps_unref(caps);
2544 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2546 mm_player_t* player = NULL;
2547 GstElement* pipeline = NULL;
2548 GstElement* selector = NULL;
2549 GstElement* fakesink = NULL;
2550 GstCaps* caps = NULL;
2551 GstStructure* str = NULL;
2552 const gchar* name = NULL;
2553 GstPad* sinkpad = NULL;
2554 GstPad* srcpad = NULL;
2555 gboolean first_track = FALSE;
2557 enum MainElementID elemId = MMPLAYER_M_NUM;
2558 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2561 player = (mm_player_t*)data;
2563 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2564 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2566 //LOGD("pad-added signal handling\n");
2568 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2570 /* get mimetype from caps */
2571 caps = gst_pad_query_caps(pad, NULL);
2573 LOGE("cannot get caps from pad.\n");
2577 str = gst_caps_get_structure(caps, 0);
2579 LOGE("cannot get structure from caps.\n");
2583 name = gst_structure_get_name(str);
2585 LOGE("cannot get mimetype from structure.\n");
2589 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2590 //LOGD("detected mimetype : %s\n", name);
2592 if (strstr(name, "video")) {
2594 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2596 /* don't make video because of not required, and not support multiple track */
2597 if (stype == MM_DISPLAY_SURFACE_NULL) {
2598 LOGD("no video sink by null surface");
2599 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
2600 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
2602 /* acquire resources for video playing */
2603 if (resource_state == RESOURCE_STATE_PREPARED) {
2604 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
2606 LOGE("could not acquire resources for video playing\n");
2607 _mmplayer_resource_manager_unprepare(&player->resource_manager);
2613 gchar *caps_str = gst_caps_to_string(caps);
2614 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
2615 player->set_mode.video_zc = TRUE;
2617 MMPLAYER_FREEIF(caps_str);
2619 if (player->v_stream_caps) {
2620 gst_caps_unref(player->v_stream_caps);
2621 player->v_stream_caps = NULL;
2624 LOGD("create fakesink instead of videobin");
2627 fakesink = gst_element_factory_make("fakesink", NULL);
2628 if (fakesink == NULL) {
2629 LOGE("ERROR : fakesink create error\n");
2633 if (player->ini.set_dump_element_flag)
2634 __mmplayer_add_dump_buffer_probe(player, fakesink);
2636 player->video_fakesink = fakesink;
2638 /* store it as it's sink element */
2639 __mmplayer_add_sink(player, player->video_fakesink);
2641 gst_bin_add(GST_BIN(pipeline), fakesink);
2644 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2646 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2647 LOGW("failed to link fakesink\n");
2648 gst_object_unref(GST_OBJECT(fakesink));
2652 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2653 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2654 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2657 if (player->set_mode.media_packet_video_stream) {
2658 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2660 MMPLAYER_SIGNAL_CONNECT(player,
2662 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2664 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2667 MMPLAYER_SIGNAL_CONNECT(player,
2669 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2671 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2675 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2676 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2680 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2681 __mmplayer_gst_decode_callback(elem, pad, player);
2685 LOGD("video selector \n");
2686 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2687 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2689 if (strstr(name, "audio")) {
2690 gint samplerate = 0;
2693 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2694 __mmplayer_gst_decode_callback(elem, pad, player);
2698 LOGD("audio selector \n");
2699 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2700 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2702 gst_structure_get_int(str, "rate", &samplerate);
2703 gst_structure_get_int(str, "channels", &channels);
2705 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2707 fakesink = gst_element_factory_make("fakesink", NULL);
2708 if (fakesink == NULL) {
2709 LOGE("ERROR : fakesink create error\n");
2713 gst_bin_add(GST_BIN(pipeline), fakesink);
2716 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2718 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2719 LOGW("failed to link fakesink\n");
2720 gst_object_unref(GST_OBJECT(fakesink));
2724 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2725 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2726 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2730 } else if (strstr(name, "text")) {
2731 LOGD("text selector \n");
2732 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2733 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2735 LOGE("wrong elem id \n");
2740 selector = player->pipeline->mainbin[elemId].gst;
2741 if (selector == NULL) {
2742 selector = gst_element_factory_make("input-selector", NULL);
2743 LOGD("Creating input-selector\n");
2744 if (selector == NULL) {
2745 LOGE("ERROR : input-selector create error\n");
2748 g_object_set(selector, "sync-streams", TRUE, NULL);
2750 player->pipeline->mainbin[elemId].id = elemId;
2751 player->pipeline->mainbin[elemId].gst = selector;
2754 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2756 srcpad = gst_element_get_static_pad(selector, "src");
2758 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2759 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2760 __mmplayer_gst_selector_blocked, NULL, NULL);
2761 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2762 __mmplayer_gst_selector_event_probe, player, NULL);
2764 gst_element_set_state(selector, GST_STATE_PAUSED);
2765 gst_bin_add(GST_BIN(pipeline), selector);
2767 LOGD("input-selector is already created.\n");
2770 LOGD("Calling request pad with selector %p \n", selector);
2771 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2773 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2775 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2776 LOGW("failed to link selector\n");
2777 gst_object_unref(GST_OBJECT(selector));
2782 LOGD("this is first track --> active track \n");
2783 g_object_set(selector, "active-pad", sinkpad, NULL);
2786 _mmplayer_track_update_info(player, stream_type, sinkpad);
2793 gst_caps_unref(caps);
2796 gst_object_unref(GST_OBJECT(sinkpad));
2801 gst_object_unref(GST_OBJECT(srcpad));
2808 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2810 GstPad* srcpad = NULL;
2811 MMHandleType attrs = 0;
2812 gint active_index = 0;
2814 // [link] input-selector :: textbin
2815 srcpad = gst_element_get_static_pad(text_selector, "src");
2817 LOGE("failed to get srcpad from selector\n");
2821 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2823 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2824 if ((active_index != DEFAULT_TRACK) &&
2825 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2826 LOGW("failed to change text track\n");
2827 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2830 player->no_more_pad = TRUE;
2831 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2833 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2834 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2835 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2836 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2839 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2841 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2842 player->has_closed_caption = TRUE;
2844 attrs = MMPLAYER_GET_ATTRS(player);
2846 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2847 if (mmf_attrs_commit(attrs))
2848 LOGE("failed to commit.\n");
2850 LOGE("cannot get content attribute");
2853 gst_object_unref(GST_OBJECT(srcpad));
2858 int _mmplayer_gst_set_audio_channel(MMHandleType hplayer, MMPlayerAudioChannel ch_idx)
2860 int result = MM_ERROR_NONE;
2862 mm_player_t* player = (mm_player_t*)hplayer;
2863 MMPlayerGstElement* mainbin = NULL;
2864 gchar* change_pad_name = NULL;
2865 GstPad* sinkpad = NULL;
2866 GstCaps* caps = NULL;
2870 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2872 LOGD("Change Audio mode to %d\n", ch_idx);
2873 player->use_deinterleave = TRUE;
2875 if ((!player->pipeline) || (!player->pipeline->mainbin)) {
2876 LOGD("pre setting : %d\n", ch_idx);
2878 player->audio_mode.active_pad_index = ch_idx;
2882 mainbin = player->pipeline->mainbin;
2884 if (mainbin[MMPLAYER_M_A_SELECTOR].gst == NULL) {
2885 if (player->max_audio_channels < 2) {
2886 LOGD("mono channel track only\n");
2890 LOGW("selector doesn't exist\n");
2891 return result; /* keep playing */
2894 LOGD("total_ch_num : %d\n", player->audio_mode.total_track_num);
2896 if (player->audio_mode.total_track_num < 2) {
2897 LOGW("there is no another audio path\n");
2898 return result; /* keep playing */
2901 if ((ch_idx < 0) || (ch_idx >= player->audio_mode.total_track_num)) {
2902 LOGW("Not a proper ch_idx : %d \n", ch_idx);
2903 return result; /* keep playing */
2906 /*To get the new pad from the selector*/
2907 change_pad_name = g_strdup_printf("sink%d", ch_idx);
2908 if (change_pad_name == NULL) {
2909 LOGW("Pad does not exists\n");
2910 goto ERROR; /* keep playing */
2913 LOGD("new active pad name: %s\n", change_pad_name);
2915 sinkpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_SELECTOR].gst, change_pad_name);
2916 if (sinkpad == NULL)
2917 //result = MM_ERROR_PLAYER_INTERNAL;
2918 goto ERROR; /* keep playing */
2920 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2921 g_object_set(mainbin[MMPLAYER_M_A_SELECTOR].gst, "active-pad", sinkpad, NULL);
2923 caps = gst_pad_get_current_caps(sinkpad);
2924 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2926 __mmplayer_set_audio_attrs(player, caps);
2927 player->audio_mode.active_pad_index = ch_idx;
2932 gst_object_unref(sinkpad);
2934 MMPLAYER_FREEIF(change_pad_name);
2943 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2945 mm_player_t* player = (mm_player_t*)data;
2946 GstElement* selector = NULL;
2947 GstElement* queue = NULL;
2949 GstPad* srcpad = NULL;
2950 GstPad* sinkpad = NULL;
2951 gchar* caps_str = NULL;
2954 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2956 caps_str = gst_caps_to_string(gst_pad_get_current_caps(pad));
2957 LOGD("deinterleave new caps : %s\n", caps_str);
2958 MMPLAYER_FREEIF(caps_str);
2960 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2961 LOGE("ERROR : queue create error\n");
2965 g_object_set(G_OBJECT(queue),
2966 "max-size-buffers", 10,
2967 "max-size-bytes", 0,
2968 "max-size-time", (guint64)0,
2971 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2974 LOGE("there is no audio channel selector.\n");
2978 srcpad = gst_element_get_static_pad(queue, "src");
2979 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2981 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2983 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2984 LOGW("failed to link deinterleave - selector\n");
2988 gst_element_set_state(queue, GST_STATE_PAUSED);
2989 player->audio_mode.total_track_num++;
2994 gst_object_unref(GST_OBJECT(srcpad));
2999 gst_object_unref(GST_OBJECT(sinkpad));
3008 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
3010 mm_player_t* player = NULL;
3011 GstElement* selector = NULL;
3012 GstPad* sinkpad = NULL;
3013 gint active_index = 0;
3014 gchar* change_pad_name = NULL;
3015 GstCaps* caps = NULL; // no need to unref
3016 gint default_audio_ch = 0;
3019 player = (mm_player_t*) data;
3021 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3024 LOGE("there is no audio channel selector.\n");
3028 active_index = player->audio_mode.active_pad_index;
3030 if (active_index != default_audio_ch) {
3031 gint audio_ch = default_audio_ch;
3033 /*To get the new pad from the selector*/
3034 change_pad_name = g_strdup_printf("sink%d", active_index);
3035 if (change_pad_name != NULL) {
3036 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3037 if (sinkpad != NULL) {
3038 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3039 g_object_set(selector, "active-pad", sinkpad, NULL);
3041 audio_ch = active_index;
3043 caps = gst_pad_get_current_caps(sinkpad);
3044 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3046 __mmplayer_set_audio_attrs(player, caps);
3048 MMPLAYER_FREEIF(change_pad_name);
3051 player->audio_mode.active_pad_index = audio_ch;
3052 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3058 gst_object_unref(sinkpad);
3065 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3067 mm_player_t* player = NULL;
3068 MMPlayerGstElement *mainbin = NULL;
3070 GstElement* tee = NULL;
3071 GstElement* stereo_queue = NULL;
3072 GstElement* mono_queue = NULL;
3073 GstElement* conv = NULL;
3074 GstElement* filter = NULL;
3075 GstElement* deinterleave = NULL;
3076 GstElement* selector = NULL;
3078 GstPad* srcpad = NULL;
3079 GstPad* selector_srcpad = NULL;
3080 GstPad* sinkpad = NULL;
3081 GstCaps* caps = NULL;
3082 gulong block_id = 0;
3087 player = (mm_player_t*) data;
3089 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3090 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3092 mainbin = player->pipeline->mainbin;
3095 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3096 LOGE("ERROR : tee create error\n");
3100 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3101 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3103 gst_element_set_state(tee, GST_STATE_PAUSED);
3106 srcpad = gst_element_get_request_pad(tee, "src_%u");
3107 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3108 LOGE("ERROR : stereo queue create error\n");
3112 g_object_set(G_OBJECT(stereo_queue),
3113 "max-size-buffers", 10,
3114 "max-size-bytes", 0,
3115 "max-size-time", (guint64)0,
3118 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3119 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3122 gst_object_unref(GST_OBJECT(srcpad));
3126 srcpad = gst_element_get_request_pad(tee, "src_%u");
3128 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3129 LOGE("ERROR : mono queue create error\n");
3133 g_object_set(G_OBJECT(mono_queue),
3134 "max-size-buffers", 10,
3135 "max-size-bytes", 0,
3136 "max-size-time", (guint64)0,
3139 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3140 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3142 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3143 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3146 srcpad = gst_element_get_static_pad(mono_queue, "src");
3147 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3148 LOGE("ERROR : audioconvert create error\n");
3152 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3153 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3157 gst_object_unref(GST_OBJECT(srcpad));
3160 srcpad = gst_element_get_static_pad(conv, "src");
3162 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3163 LOGE("ERROR : capsfilter create error\n");
3167 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3168 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3170 caps = gst_caps_from_string("audio/x-raw-int, "
3171 "width = (int) 16, "
3172 "depth = (int) 16, "
3173 "channels = (int) 2");
3175 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3176 gst_caps_unref(caps);
3178 gst_element_set_state(conv, GST_STATE_PAUSED);
3179 gst_element_set_state(filter, GST_STATE_PAUSED);
3183 gst_object_unref(GST_OBJECT(srcpad));
3186 srcpad = gst_element_get_static_pad(filter, "src");
3188 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3189 LOGE("ERROR : deinterleave create error\n");
3193 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3195 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3196 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3198 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3199 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3201 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3202 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3205 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3206 if (selector == NULL) {
3207 LOGE("ERROR : audio-selector create error\n");
3211 g_object_set(selector, "sync-streams", TRUE, NULL);
3212 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3214 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3215 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3217 selector_srcpad = gst_element_get_static_pad(selector, "src");
3219 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3221 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3222 __mmplayer_gst_selector_blocked, NULL, NULL);
3225 gst_object_unref(GST_OBJECT(srcpad));
3229 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3230 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3232 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3233 LOGW("failed to link queue_stereo - selector\n");
3237 player->audio_mode.total_track_num++;
3239 g_object_set(selector, "active-pad", sinkpad, NULL);
3240 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3241 gst_element_set_state(selector, GST_STATE_PAUSED);
3243 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3247 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3248 if (block_id != 0) {
3249 gst_pad_remove_probe(selector_srcpad, block_id);
3254 gst_object_unref(GST_OBJECT(sinkpad));
3259 gst_object_unref(GST_OBJECT(srcpad));
3263 if (selector_srcpad) {
3264 gst_object_unref(GST_OBJECT(selector_srcpad));
3265 selector_srcpad = NULL;
3273 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3275 mm_player_t* player = NULL;
3276 GstPad* srcpad = NULL;
3277 GstElement* video_selector = NULL;
3278 GstElement* audio_selector = NULL;
3279 GstElement* text_selector = NULL;
3280 MMHandleType attrs = 0;
3281 gint active_index = 0;
3282 gint64 dur_bytes = 0L;
3284 player = (mm_player_t*) data;
3286 LOGD("no-more-pad signal handling\n");
3288 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3289 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3290 LOGW("no need to go more");
3292 if (player->gapless.reconfigure) {
3293 player->gapless.reconfigure = FALSE;
3294 MMPLAYER_PLAYBACK_UNLOCK(player);
3300 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3301 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3302 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3303 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3304 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3306 if (NULL == player->streamer) {
3307 LOGW("invalid state for buffering");
3311 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
3312 guint buffer_bytes = init_buffering_time * ESTIMATED_BUFFER_UNIT;
3314 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3315 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d sec, buffer size : %d)\n", (gint)init_buffering_time, buffer_bytes);
3317 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3319 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3320 LOGE("fail to get duration.\n");
3322 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3323 // use file information was already set on Q2 when it was created.
3324 __mm_player_streaming_set_queue2(player->streamer,
3325 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3326 TRUE, // use_buffering
3328 init_buffering_time,
3330 player->ini.http_buffering_limit, // high percent
3331 MUXED_BUFFER_TYPE_MEM_QUEUE,
3333 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3336 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3337 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3338 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3339 if (video_selector) {
3340 // [link] input-selector :: videobin
3341 srcpad = gst_element_get_static_pad(video_selector, "src");
3343 LOGE("failed to get srcpad from video selector\n");
3347 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3348 if (!text_selector && !audio_selector)
3349 player->no_more_pad = TRUE;
3351 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3353 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3354 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3355 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3356 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3360 if (audio_selector) {
3361 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3362 if ((active_index != DEFAULT_TRACK) &&
3363 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3364 LOGW("failed to change audio track\n");
3365 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3368 // [link] input-selector :: audiobin
3369 srcpad = gst_element_get_static_pad(audio_selector, "src");
3371 LOGE("failed to get srcpad from selector\n");
3375 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3377 player->no_more_pad = TRUE;
3379 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3380 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3381 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3382 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3383 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3386 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3388 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3390 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3391 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3392 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3393 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3397 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3399 attrs = MMPLAYER_GET_ATTRS(player);
3401 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3402 if (mmf_attrs_commit(attrs))
3403 LOGE("failed to commit.\n");
3405 LOGE("cannot get content attribute");
3407 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3408 LOGD("There is no audio track : remove audiobin");
3410 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3411 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3413 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3414 MMPLAYER_FREEIF(player->pipeline->audiobin)
3417 if (player->num_dynamic_pad == 0)
3418 __mmplayer_pipeline_complete(NULL, player);
3421 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3423 __mmplayer_handle_text_decode_path(player, text_selector);
3430 gst_object_unref(GST_OBJECT(srcpad));
3434 if (player->gapless.reconfigure) {
3435 player->gapless.reconfigure = FALSE;
3436 MMPLAYER_PLAYBACK_UNLOCK(player);
3441 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data) // @
3443 mm_player_t* player = NULL;
3444 MMHandleType attrs = 0;
3445 GstElement* pipeline = NULL;
3446 GstCaps* caps = NULL;
3447 gchar* caps_str = NULL;
3448 GstStructure* str = NULL;
3449 const gchar* name = NULL;
3450 GstPad* sinkpad = NULL;
3451 GstElement* sinkbin = NULL;
3452 gboolean reusing = FALSE;
3453 GstElement *text_selector = NULL;
3454 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
3457 player = (mm_player_t*) data;
3459 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3460 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3462 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3464 attrs = MMPLAYER_GET_ATTRS(player);
3466 LOGE("cannot get content attribute\n");
3470 /* get mimetype from caps */
3471 caps = gst_pad_query_caps(pad, NULL);
3473 LOGE("cannot get caps from pad.\n");
3476 caps_str = gst_caps_to_string(caps);
3478 str = gst_caps_get_structure(caps, 0);
3480 LOGE("cannot get structure from caps.\n");
3484 name = gst_structure_get_name(str);
3486 LOGE("cannot get mimetype from structure.\n");
3490 //LOGD("detected mimetype : %s\n", name);
3492 if (strstr(name, "audio")) {
3493 if (player->pipeline->audiobin == NULL) {
3494 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3495 LOGE("failed to create audiobin. continuing without audio\n");
3499 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3500 LOGD("creating audiosink bin success\n");
3503 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3504 LOGD("reusing audiobin\n");
3505 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3508 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3509 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3511 player->audiosink_linked = 1;
3513 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3515 LOGE("failed to get pad from sinkbin\n");
3518 } else if (strstr(name, "video")) {
3519 if (strstr(caps_str, "ST12") || strstr(caps_str, "SN12"))
3520 player->set_mode.video_zc = TRUE;
3522 if (player->pipeline->videobin == NULL) {
3523 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3524 /* get video surface type */
3525 int surface_type = 0;
3526 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3527 LOGD("display_surface_type(%d)\n", surface_type);
3529 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3530 LOGD("not make videobin because it dose not want\n");
3534 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3535 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
3536 /* prepare resource manager for video overlay */
3537 if (resource_state >= RESOURCE_STATE_INITIALIZED) {
3538 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_OVERLAY)
3540 LOGE("could not prepare for video_overlay resource\n");
3547 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state)
3549 /* acquire resources for video playing */
3550 if (resource_state == RESOURCE_STATE_PREPARED) {
3551 if (_mmplayer_resource_manager_acquire(&player->resource_manager)
3553 LOGE("could not acquire resources for video playing\n");
3554 _mmplayer_resource_manager_unprepare(&player->resource_manager);
3560 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3561 LOGE("failed to create videobin. continuing without video\n");
3565 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3566 LOGD("creating videosink bin success\n");
3569 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3570 LOGD("re-using videobin\n");
3571 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3574 /* FIXIT : track number shouldn't be hardcoded */
3575 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3576 player->videosink_linked = 1;
3578 /* NOTE : intermediate code before doing H/W subtitle compositon */
3579 if (player->use_textoverlay && player->play_subtitle) {
3580 LOGD("using textoverlay for external subtitle");
3581 /* check text bin has created well */
3582 if (player->pipeline && player->pipeline->textbin) {
3583 /* get sinkpad from textoverlay */
3584 sinkpad = gst_element_get_static_pad(
3585 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3588 LOGE("failed to get sink pad from textoverlay");
3592 /* link new pad with textoverlay first */
3593 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3594 LOGE("failed to get pad from sinkbin\n");
3598 gst_object_unref(sinkpad);
3601 /* alright, override pad to textbin.src for futher link */
3602 pad = gst_element_get_static_pad(
3603 GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst),
3606 LOGE("failed to get sink pad from textoverlay");
3610 LOGE("should not reach here.");
3615 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3617 LOGE("failed to get pad from sinkbin\n");
3620 } else if (strstr(name, "text")) {
3621 if (player->pipeline->textbin == NULL) {
3622 MMPlayerGstElement* mainbin = NULL;
3624 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
3625 LOGE("failed to create textbin. continuing without text\n");
3629 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3630 LOGD("creating textsink bin success\n");
3632 /* FIXIT : track number shouldn't be hardcoded */
3633 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3635 player->textsink_linked = 1;
3636 LOGI("player->textsink_linked set to 1\n");
3638 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3640 LOGE("failed to get pad from sinkbin\n");
3644 mainbin = player->pipeline->mainbin;
3646 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3647 /* input selector */
3648 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3649 if (!text_selector) {
3650 LOGE("failed to create subtitle input selector element\n");
3653 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3655 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3656 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3659 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3660 LOGE("failed to set state(READY) to sinkbin\n");
3664 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3665 LOGW("failed to add subtitle input selector\n");
3669 LOGD("created element input-selector");
3672 LOGD("already having subtitle input selector");
3673 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3676 if (!player->textsink_linked) {
3677 LOGD("re-using textbin\n");
3680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3682 player->textsink_linked = 1;
3683 LOGI("player->textsink_linked set to 1\n");
3685 LOGD("ignoring internal subtutle since external subtitle is available");
3688 LOGW("unknown type of elementary stream!ignoring it...\n");
3695 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3696 LOGE("failed to set state(READY) to sinkbin\n");
3700 /* Added for multi audio support to avoid adding audio bin again*/
3702 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3703 LOGE("failed to add sinkbin to pipeline\n");
3709 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
3710 LOGE("failed to get pad from sinkbin\n");
3716 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3717 LOGE("failed to set state(PAUSED) to sinkbin\n");
3721 if (text_selector) {
3722 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3723 LOGE("failed to set state(PAUSED) to sinkbin\n");
3729 gst_object_unref(sinkpad);
3733 LOGD("linking sink bin success\n");
3735 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3736 * streaming task. if the task blocked, then buffer will not flow to the next element
3737 *(autoplugging element). so this is special hack for streaming. please try to remove it
3739 /* dec stream count. we can remove fakesink if it's zero */
3740 if (player->num_dynamic_pad)
3741 player->num_dynamic_pad--;
3743 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3745 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3746 __mmplayer_pipeline_complete(NULL, player);
3748 /* FIXIT : please leave a note why this code is needed */
3749 if (MMPLAYER_IS_WFD_STREAMING(player))
3750 player->no_more_pad = TRUE;
3754 MMPLAYER_FREEIF(caps_str);
3757 gst_caps_unref(caps);
3760 gst_object_unref(GST_OBJECT(sinkpad));
3762 /* flusing out new attributes */
3763 if (mmf_attrs_commit(attrs))
3764 LOGE("failed to comit attributes\n");
3770 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3772 int pro_value = 0; // in the case of expection, default will be returned.
3773 int dest_angle = rotation_angle;
3774 int rotation_type = -1;
3776 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3777 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3778 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3780 if (rotation_angle >= 360)
3781 dest_angle = rotation_angle - 360;
3783 /* chech if supported or not */
3784 if (dest_angle % 90) {
3785 LOGD("not supported rotation angle = %d", rotation_angle);
3791 * custom_convert - none (B)
3792 * videoflip - none (C)
3794 if (player->set_mode.video_zc) {
3795 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3796 rotation_type = ROTATION_USING_CUSTOM;
3798 rotation_type = ROTATION_USING_SINK;
3800 int surface_type = 0;
3801 rotation_type = ROTATION_USING_FLIP;
3803 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3804 LOGD("check display surface type attribute: %d", surface_type);
3806 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3807 rotation_type = ROTATION_USING_SINK;
3809 rotation_type = ROTATION_USING_FLIP; //C
3811 LOGD("using %d type for rotation", rotation_type);
3814 /* get property value for setting */
3815 switch (rotation_type) {
3816 case ROTATION_USING_SINK: // waylandsink
3818 switch (dest_angle) {
3822 pro_value = 3; // clockwise 90
3828 pro_value = 1; // counter-clockwise 90
3833 case ROTATION_USING_CUSTOM:
3835 gchar *ename = NULL;
3836 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3838 if (g_strrstr(ename, "fimcconvert")) {
3839 switch (dest_angle) {
3843 pro_value = 90; // clockwise 90
3849 pro_value = 270; // counter-clockwise 90
3855 case ROTATION_USING_FLIP: // videoflip
3857 switch (dest_angle) {
3861 pro_value = 1; // clockwise 90
3867 pro_value = 3; // counter-clockwise 90
3874 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3882 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3884 /* check video sinkbin is created */
3885 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3887 player->pipeline->videobin &&
3888 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3889 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3890 MM_ERROR_PLAYER_NOT_INITIALIZED);
3892 return MM_ERROR_NONE;
3896 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3898 int rotation_value = 0;
3899 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3903 /* check video sinkbin is created */
3904 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3907 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3909 /* get rotation value to set */
3910 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3911 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3912 LOGD("set video param : rotate %d", rotation_value);
3916 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3918 MMHandleType attrs = 0;
3922 /* check video sinkbin is created */
3923 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3926 attrs = MMPLAYER_GET_ATTRS(player);
3927 MMPLAYER_RETURN_IF_FAIL(attrs);
3929 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3930 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3931 LOGD("set video param : visible %d", visible);
3935 __mmplayer_video_param_set_display_method(mm_player_t* player)
3937 MMHandleType attrs = 0;
3938 int display_method = 0;
3941 /* check video sinkbin is created */
3942 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3945 attrs = MMPLAYER_GET_ATTRS(player);
3946 MMPLAYER_RETURN_IF_FAIL(attrs);
3948 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3949 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3950 LOGD("set video param : method %d", display_method);
3954 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3956 MMHandleType attrs = 0;
3957 int display_method = 0;
3958 void *handle = NULL;
3960 int wl_window_x = 0;
3961 int wl_window_y = 0;
3962 int wl_window_width = 0;
3963 int wl_window_height = 0;
3966 /* check video sinkbin is created */
3967 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3970 attrs = MMPLAYER_GET_ATTRS(player);
3971 MMPLAYER_RETURN_IF_FAIL(attrs);
3973 /* check roi mode is set */
3974 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3975 if (display_method != PLAYER_DISPLAY_MODE_DST_ROI) {
3976 LOGE("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle");
3979 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3982 /*It should be set after setting window*/
3983 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3984 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3985 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3986 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3988 /* After setting window handle, set render rectangle */
3989 gst_video_overlay_set_render_rectangle(
3990 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3991 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3992 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3993 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3998 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
4000 MMHandleType attrs = 0;
4001 void *handle = NULL;
4003 gboolean use_wl_surface = 0;
4004 void * wl_display = NULL;
4005 GstContext *context = NULL;
4007 /* check video sinkbin is created */
4008 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4011 attrs = MMPLAYER_GET_ATTRS(player);
4012 MMPLAYER_RETURN_IF_FAIL(attrs);
4014 /* common case if using overlay surface */
4015 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
4016 mm_attrs_get_int_by_name(attrs, "use_wl_surface", &use_wl_surface);
4018 if (handle && !use_wl_surface) {
4019 /* default is using wl_surface_id */
4020 unsigned int wl_surface_id = 0;
4021 wl_surface_id = *(int*)handle;
4022 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
4023 gst_video_overlay_set_wl_window_wl_surface_id(
4024 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4026 } else if (handle && use_wl_surface) {
4027 /* use wl_surface for legacy_player_test */
4028 mm_attrs_get_data_by_name(attrs, "wl_display", &wl_display);
4030 context = gst_wayland_display_handle_context_new(wl_display);
4032 gst_element_set_context(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), context);
4034 guintptr wl_surface = (guintptr)handle;
4035 LOGD("[use wl_surface for legacy_player_test] set video param : wayland surface %p", handle);
4036 gst_video_overlay_set_window_handle(
4037 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4040 /* FIXIT : is it error case? */
4041 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
4046 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
4048 bool update_all_param = FALSE;
4051 /* check video sinkbin is created */
4052 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4053 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4055 if (strcmp(player->ini.videosink_element_overlay, "waylandsink")) {
4056 LOGE("can not find waylandsink");
4057 return MM_ERROR_PLAYER_INTERNAL;
4060 LOGD("param_name : %s", param_name);
4061 if (!g_strcmp0(param_name, "update_all_param"))
4062 update_all_param = TRUE;
4064 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
4065 __mmplayer_video_param_set_display_overlay(player);
4066 if (update_all_param || !g_strcmp0(param_name, "display_method"))
4067 __mmplayer_video_param_set_display_method(player);
4068 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
4069 __mmplayer_video_param_set_render_rectangle(player);
4070 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
4071 __mmplayer_video_param_set_display_visible(player);
4072 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4073 __mmplayer_video_param_set_display_rotation(player);
4075 return MM_ERROR_NONE;
4079 _mmplayer_update_video_param(mm_player_t* player, char *param_name) // @
4081 MMHandleType attrs = 0;
4082 int surface_type = 0;
4083 int ret = MM_ERROR_NONE;
4087 /* check video sinkbin is created */
4088 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4089 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4091 attrs = MMPLAYER_GET_ATTRS(player);
4093 LOGE("cannot get content attribute");
4094 return MM_ERROR_PLAYER_INTERNAL;
4096 LOGD("param_name : %s", param_name);
4098 /* update display surface */
4099 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4100 LOGD("check display surface type attribute: %d", surface_type);
4102 /* configuring display */
4103 switch (surface_type) {
4104 case MM_DISPLAY_SURFACE_OVERLAY:
4106 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4107 if (ret != MM_ERROR_NONE)
4115 return MM_ERROR_NONE;
4119 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
4121 GList* bucket = element_bucket;
4122 MMPlayerGstElement* element = NULL;
4123 MMPlayerGstElement* prv_element = NULL;
4124 gint successful_link_count = 0;
4128 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4130 prv_element = (MMPlayerGstElement*)bucket->data;
4131 bucket = bucket->next;
4133 for (; bucket; bucket = bucket->next) {
4134 element = (MMPlayerGstElement*)bucket->data;
4136 if (element && element->gst) {
4137 /* If next element is audio appsrc then make a separate audio pipeline */
4138 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4139 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4140 prv_element = element;
4144 if (prv_element && prv_element->gst) {
4145 if (GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4146 LOGD("linking [%s] to [%s] success\n",
4147 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4148 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4149 successful_link_count++;
4151 LOGD("linking [%s] to [%s] failed\n",
4152 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4153 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4159 prv_element = element;
4164 return successful_link_count;
4168 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
4170 GList* bucket = element_bucket;
4171 MMPlayerGstElement* element = NULL;
4172 int successful_add_count = 0;
4176 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4177 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4179 for (; bucket; bucket = bucket->next) {
4180 element = (MMPlayerGstElement*)bucket->data;
4182 if (element && element->gst) {
4183 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4184 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4185 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4186 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4189 successful_add_count++;
4195 return successful_add_count;
4198 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4200 mm_player_t* player = (mm_player_t*) data;
4201 GstCaps *caps = NULL;
4202 GstStructure *str = NULL;
4207 MMPLAYER_RETURN_IF_FAIL(pad)
4208 MMPLAYER_RETURN_IF_FAIL(unused)
4209 MMPLAYER_RETURN_IF_FAIL(data)
4211 caps = gst_pad_get_current_caps(pad);
4215 str = gst_caps_get_structure(caps, 0);
4219 name = gst_structure_get_name(str);
4223 LOGD("name = %s\n", name);
4225 if (strstr(name, "audio")) {
4226 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4228 if (player->audio_stream_changed_cb) {
4229 LOGE("call the audio stream changed cb\n");
4230 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4232 } else if (strstr(name, "video")) {
4233 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4235 if (player->video_stream_changed_cb) {
4236 LOGE("call the video stream changed cb\n");
4237 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4244 gst_caps_unref(caps);
4254 * This function is to create audio pipeline for playing.
4256 * @param player [in] handle of player
4258 * @return This function returns zero on success.
4260 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4262 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
4263 x_bin[x_id].id = x_id;\
4264 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4265 if (!x_bin[x_id].gst) {\
4266 LOGE("failed to create %s \n", x_factory);\
4270 #define MMPLAYER_CREATE_ELEMENT_ADD_BIN(x_bin, x_id, x_factory, x_name, y_bin, x_player) \
4271 x_bin[x_id].id = x_id;\
4272 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4273 if (!x_bin[x_id].gst) {\
4274 LOGE("failed to create %s \n", x_factory);\
4277 if (x_player->ini.set_dump_element_flag)\
4278 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4280 if (!gst_bin_add(GST_BIN(y_bin), GST_ELEMENT(x_bin[x_id].gst))) { \
4281 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",\
4282 GST_ELEMENT_NAME(GST_ELEMENT(x_bin[x_id].gst)),\
4283 GST_ELEMENT_NAME(GST_ELEMENT(y_bin)));\
4287 /* macro for code readability. just for sinkbin-creation functions */
4288 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4290 x_bin[x_id].id = x_id;\
4291 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4292 if (!x_bin[x_id].gst) {\
4293 LOGE("failed to create %s \n", x_factory);\
4296 if (x_player->ini.set_dump_element_flag)\
4297 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4300 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4304 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4309 MMPLAYER_RETURN_IF_FAIL(player);
4311 if (player->audio_stream_buff_list) {
4312 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4313 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4316 LOGD("[%lld] send remained data.", tmp->channel_mask);
4317 __mmplayer_audio_stream_send_data(player, tmp);
4320 g_free(tmp->pcm_data);
4324 g_list_free(player->audio_stream_buff_list);
4325 player->audio_stream_buff_list = NULL;
4332 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4334 MMPlayerAudioStreamDataType audio_stream = { 0, };
4337 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4339 audio_stream.bitrate = a_buffer->bitrate;
4340 audio_stream.channel = a_buffer->channel;
4341 audio_stream.depth = a_buffer->depth;
4342 audio_stream.is_little_endian = a_buffer->is_little_endian;
4343 audio_stream.channel_mask = a_buffer->channel_mask;
4344 audio_stream.data_size = a_buffer->data_size;
4345 audio_stream.data = a_buffer->pcm_data;
4347 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4348 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4354 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4356 mm_player_t* player = (mm_player_t*) data;
4361 gint endianness = 0;
4362 guint64 channel_mask = 0;
4363 void *a_data = NULL;
4365 mm_player_audio_stream_buff_t *a_buffer = NULL;
4366 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4370 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4372 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4373 a_data = mapinfo.data;
4374 a_size = mapinfo.size;
4376 GstCaps *caps = gst_pad_get_current_caps(pad);
4377 GstStructure *structure = gst_caps_get_structure(caps, 0);
4379 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4380 gst_structure_get_int(structure, "rate", &rate);
4381 gst_structure_get_int(structure, "channels", &channel);
4382 gst_structure_get_int(structure, "depth", &depth);
4383 gst_structure_get_int(structure, "endianness", &endianness);
4384 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4385 gst_caps_unref(GST_CAPS(caps));
4387 /* In case of the sync is false, use buffer list. *
4388 * The num of buffer list depends on the num of audio channels */
4389 if (player->audio_stream_buff_list) {
4390 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4391 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4393 if (channel_mask == tmp->channel_mask) {
4394 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4395 if (tmp->data_size + a_size < tmp->buff_size) {
4396 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4397 tmp->data_size += a_size;
4399 /* send data to client */
4400 __mmplayer_audio_stream_send_data(player, tmp);
4402 if (a_size > tmp->buff_size) {
4403 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4404 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4405 if (tmp->pcm_data == NULL) {
4406 LOGE("failed to realloc data.");
4409 tmp->buff_size = a_size;
4411 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4412 memcpy(tmp->pcm_data, a_data, a_size);
4413 tmp->data_size = a_size;
4418 LOGE("data is empty in list.");
4424 /* create new audio stream data */
4425 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4426 if (a_buffer == NULL) {
4427 LOGE("failed to alloc data.");
4430 a_buffer->bitrate = rate;
4431 a_buffer->channel = channel;
4432 a_buffer->depth = depth;
4433 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4434 a_buffer->channel_mask = channel_mask;
4435 a_buffer->data_size = a_size;
4437 if (!player->audio_stream_sink_sync) {
4438 /* If sync is FALSE, use buffer list to reduce the IPC. */
4439 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4440 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4441 if (a_buffer->pcm_data == NULL) {
4442 LOGE("failed to alloc data.");
4446 memcpy(a_buffer->pcm_data, a_data, a_size);
4447 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4448 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4450 /* If sync is TRUE, send data directly. */
4451 a_buffer->pcm_data = a_data;
4452 __mmplayer_audio_stream_send_data(player, a_buffer);
4457 gst_buffer_unmap(buffer, &mapinfo);
4462 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4464 mm_player_t* player = (mm_player_t*)data;
4465 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4466 GstPad* sinkpad = NULL;
4467 GstElement *queue = NULL, *sink = NULL;
4470 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4472 queue = gst_element_factory_make("queue", NULL);
4473 if (queue == NULL) {
4474 LOGD("fail make queue\n");
4478 sink = gst_element_factory_make("fakesink", NULL);
4480 LOGD("fail make fakesink\n");
4484 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4486 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4487 LOGW("failed to link queue & sink\n");
4491 sinkpad = gst_element_get_static_pad(queue, "sink");
4493 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4494 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4498 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4500 gst_object_unref(sinkpad);
4501 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4502 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4504 gst_element_set_state(sink, GST_STATE_PAUSED);
4505 gst_element_set_state(queue, GST_STATE_PAUSED);
4507 MMPLAYER_SIGNAL_CONNECT(player,
4509 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4511 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4518 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4520 gst_object_unref(GST_OBJECT(queue));
4524 gst_object_unref(GST_OBJECT(sink));
4528 gst_object_unref(GST_OBJECT(sinkpad));
4535 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4537 #define MAX_PROPS_LEN 64
4538 gint latency_mode = 0;
4539 gchar *stream_type = NULL;
4540 gchar *latency = NULL;
4542 gchar stream_props[MAX_PROPS_LEN] = {0,};
4543 GstStructure *props = NULL;
4546 * It should be set after player creation through attribute.
4547 * But, it can not be changed during playing.
4550 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4551 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4554 LOGE("stream_type is null.\n");
4556 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_id);
4557 props = gst_structure_from_string(stream_props, NULL);
4558 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4559 LOGD("stream_id[%d], stream_type[%s], result[%s].\n", stream_id, stream_type, stream_props);
4562 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4564 switch (latency_mode) {
4565 case AUDIO_LATENCY_MODE_LOW:
4566 latency = g_strndup("low", 3);
4568 case AUDIO_LATENCY_MODE_MID:
4569 latency = g_strndup("mid", 3);
4571 case AUDIO_LATENCY_MODE_HIGH:
4572 latency = g_strndup("high", 4);
4576 #if 0 //need to check
4577 if (player->sound_focus.user_route_policy != 0)
4578 route_path = player->sound_focus.user_route_policy;
4580 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4581 "latency", latency_mode,
4584 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4585 volume_type, route_path, latency_mode);
4590 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4594 LOGD("audiosink property - latency=%s \n", latency);
4602 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4604 MMPlayerGstElement* first_element = NULL;
4605 MMPlayerGstElement* audiobin = NULL;
4606 MMHandleType attrs = 0;
4608 GstPad *ghostpad = NULL;
4609 GList* element_bucket = NULL;
4610 gboolean link_audio_sink_now = TRUE;
4615 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4618 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4620 LOGE("failed to allocate memory for audiobin\n");
4621 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4624 attrs = MMPLAYER_GET_ATTRS(player);
4627 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4628 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4629 if (!audiobin[MMPLAYER_A_BIN].gst) {
4630 LOGE("failed to create audiobin\n");
4635 player->pipeline->audiobin = audiobin;
4637 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4639 /* Adding audiotp plugin for reverse trickplay feature */
4640 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4646 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4648 if (player->set_mode.pcm_extraction) {
4649 // pcm extraction only and no sound output
4650 if (player->audio_stream_render_cb_ex) {
4651 char *caps_str = NULL;
4652 GstCaps* caps = NULL;
4653 gchar *format = NULL;
4656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4658 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4660 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4662 caps = gst_caps_new_simple("audio/x-raw",
4663 "format", G_TYPE_STRING, format,
4664 "rate", G_TYPE_INT, player->pcm_samplerate,
4665 "channels", G_TYPE_INT, player->pcm_channel,
4667 caps_str = gst_caps_to_string(caps);
4668 LOGD("new caps : %s\n", caps_str);
4670 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4673 gst_caps_unref(caps);
4674 MMPLAYER_FREEIF(caps_str);
4676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4678 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4679 /* raw pad handling signal */
4680 MMPLAYER_SIGNAL_CONNECT(player,
4681 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4682 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4683 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4685 int dst_samplerate = 0;
4686 int dst_channels = 0;
4688 char *caps_str = NULL;
4689 GstCaps* caps = NULL;
4691 /* get conf. values */
4692 mm_attrs_multiple_get(player->attrs,
4694 "pcm_extraction_samplerate", &dst_samplerate,
4695 "pcm_extraction_channels", &dst_channels,
4696 "pcm_extraction_depth", &dst_depth,
4700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4701 caps = gst_caps_new_simple("audio/x-raw",
4702 "rate", G_TYPE_INT, dst_samplerate,
4703 "channels", G_TYPE_INT, dst_channels,
4704 "depth", G_TYPE_INT, dst_depth,
4706 caps_str = gst_caps_to_string(caps);
4707 LOGD("new caps : %s\n", caps_str);
4709 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4712 gst_caps_unref(caps);
4713 MMPLAYER_FREEIF(caps_str);
4716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4723 //GstCaps* caps = NULL;
4726 /* for logical volume control */
4727 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4728 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4730 if (player->sound.mute) {
4731 LOGD("mute enabled\n");
4732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4737 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4738 caps = gst_caps_from_string("audio/x-raw-int, "
4739 "endianness = (int) LITTLE_ENDIAN, "
4740 "signed = (boolean) true, "
4741 "width = (int) 16, "
4742 "depth = (int) 16");
4743 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4744 gst_caps_unref(caps);
4747 /* chech if multi-chennels */
4748 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4749 GstPad *srcpad = NULL;
4750 GstCaps *caps = NULL;
4752 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4753 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4754 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4755 GstStructure *str = gst_caps_get_structure(caps, 0);
4757 gst_structure_get_int(str, "channels", &channels);
4758 gst_caps_unref(caps);
4760 gst_object_unref(srcpad);
4764 /* audio effect element. if audio effect is enabled */
4765 if ((strcmp(player->ini.audioeffect_element, ""))
4767 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4770 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4772 if ((!player->bypass_audio_effect)
4773 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4774 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4775 if (!_mmplayer_audio_effect_custom_apply(player))
4776 LOGI("apply audio effect(custom) setting success\n");
4780 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4781 && (player->set_mode.rich_audio))
4782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4784 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4785 if (player->set_mode.rich_audio && channels <= 2)
4786 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VSP, "audiovsp", "x-speed", TRUE, player);
4789 /* create audio sink */
4790 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4793 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4797 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4798 (player->videodec_linked && player->ini.use_system_clock)) {
4799 LOGD("system clock will be used.\n");
4800 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4803 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4804 __mmplayer_gst_set_audiosink_property(player, attrs);
4807 if (audiobin[MMPLAYER_A_SINK].gst) {
4808 GstPad *sink_pad = NULL;
4809 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4810 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4811 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4812 gst_object_unref(GST_OBJECT(sink_pad));
4815 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4817 /* adding created elements to bin */
4818 LOGD("adding created elements to bin\n");
4819 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4820 LOGE("failed to add elements\n");
4824 /* linking elements in the bucket by added order. */
4825 LOGD("Linking elements in the bucket by added order.\n");
4826 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4827 LOGE("failed to link elements\n");
4831 /* get first element's sinkpad for creating ghostpad */
4832 first_element = (MMPlayerGstElement *)element_bucket->data;
4833 if (!first_element) {
4834 LOGE("failed to get first elem\n");
4838 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4840 LOGE("failed to get pad from first element of audiobin\n");
4844 ghostpad = gst_ghost_pad_new("sink", pad);
4846 LOGE("failed to create ghostpad\n");
4850 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4851 LOGE("failed to add ghostpad to audiobin\n");
4855 gst_object_unref(pad);
4857 g_list_free(element_bucket);
4859 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4863 return MM_ERROR_NONE;
4867 LOGD("ERROR : releasing audiobin\n");
4870 gst_object_unref(GST_OBJECT(pad));
4873 gst_object_unref(GST_OBJECT(ghostpad));
4876 g_list_free(element_bucket);
4878 /* release element which are not added to bin */
4879 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4880 /* NOTE : skip bin */
4881 if (audiobin[i].gst) {
4882 GstObject* parent = NULL;
4883 parent = gst_element_get_parent(audiobin[i].gst);
4886 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4887 audiobin[i].gst = NULL;
4889 gst_object_unref(GST_OBJECT(parent));
4893 /* release audiobin with it's childs */
4894 if (audiobin[MMPLAYER_A_BIN].gst)
4895 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4897 MMPLAYER_FREEIF(audiobin);
4899 player->pipeline->audiobin = NULL;
4901 return MM_ERROR_PLAYER_INTERNAL;
4904 static GstPadProbeReturn
4905 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4907 mm_player_t* player = (mm_player_t*) u_data;
4908 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4909 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4911 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4913 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4914 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4916 return GST_PAD_PROBE_OK;
4919 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4921 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4924 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4926 int ret = MM_ERROR_NONE;
4928 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4929 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4931 MMPLAYER_VIDEO_BO_LOCK(player);
4933 if (player->video_bo_list) {
4934 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4935 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4936 if (tmp && tmp->bo == bo) {
4938 LOGD("release bo %p", bo);
4939 MMPLAYER_VIDEO_BO_UNLOCK(player);
4940 MMPLAYER_VIDEO_BO_SIGNAL(player);
4945 /* hw codec is running or the list was reset for DRC. */
4946 LOGW("there is no bo list.");
4948 MMPLAYER_VIDEO_BO_UNLOCK(player);
4950 LOGW("failed to find bo %p", bo);
4955 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4960 MMPLAYER_RETURN_IF_FAIL(player);
4962 MMPLAYER_VIDEO_BO_LOCK(player);
4963 if (player->video_bo_list) {
4964 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_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;
4969 tbm_bo_unref(tmp->bo);
4973 g_list_free(player->video_bo_list);
4974 player->video_bo_list = NULL;
4976 player->video_bo_size = 0;
4977 MMPLAYER_VIDEO_BO_UNLOCK(player);
4984 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4987 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4988 gboolean ret = TRUE;
4990 /* check DRC, if it is, destroy the prev bo list to create again */
4991 if (player->video_bo_size != size) {
4992 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4993 __mmplayer_video_stream_destroy_bo_list(player);
4994 player->video_bo_size = size;
4997 MMPLAYER_VIDEO_BO_LOCK(player);
4999 if ((!player->video_bo_list) ||
5000 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
5002 /* create bo list */
5004 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5006 if (player->video_bo_list) {
5007 /* if bo list did not created all, try it again. */
5008 idx = g_list_length(player->video_bo_list);
5009 LOGD("bo list exist(len: %d)", idx);
5012 for (; idx < player->ini.num_of_video_bo; idx++) {
5013 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5015 LOGE("Fail to alloc bo_info.");
5018 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5020 LOGE("Fail to tbm_bo_alloc.");
5024 bo_info->using = FALSE;
5025 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5028 /* update video num buffers */
5029 player->video_num_buffers = idx;
5030 if (idx == player->ini.num_of_video_bo)
5031 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5034 MMPLAYER_VIDEO_BO_UNLOCK(player);
5038 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5042 /* get bo from list*/
5043 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5044 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5045 if (tmp && (tmp->using == FALSE)) {
5046 LOGD("found bo %p to use", tmp->bo);
5048 MMPLAYER_VIDEO_BO_UNLOCK(player);
5053 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5054 MMPLAYER_VIDEO_BO_UNLOCK(player);
5058 if (player->ini.video_bo_timeout <= 0) {
5059 MMPLAYER_VIDEO_BO_WAIT(player);
5061 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5062 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5069 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5071 mm_player_t* player = (mm_player_t*)data;
5073 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5075 /* send prerolled pkt */
5076 player->video_stream_prerolled = FALSE;
5078 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5080 /* not to send prerolled pkt again */
5081 player->video_stream_prerolled = TRUE;
5085 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5087 mm_player_t* player = (mm_player_t*)data;
5088 GstCaps *caps = NULL;
5089 MMPlayerVideoStreamDataType stream;
5090 MMVideoBuffer *video_buffer = NULL;
5091 GstMemory *dataBlock = NULL;
5092 GstMemory *metaBlock = NULL;
5093 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5094 GstStructure *structure = NULL;
5095 const gchar *string_format = NULL;
5096 unsigned int fourcc = 0;
5099 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5101 if (player->video_stream_prerolled) {
5102 player->video_stream_prerolled = FALSE;
5103 LOGD("skip the prerolled pkt not to send it again");
5107 caps = gst_pad_get_current_caps(pad);
5109 LOGE("Caps is NULL.");
5113 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5115 /* clear stream data structure */
5116 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5118 structure = gst_caps_get_structure(caps, 0);
5119 gst_structure_get_int(structure, "width", & (stream.width));
5120 gst_structure_get_int(structure, "height", & (stream.height));
5121 string_format = gst_structure_get_string(structure, "format");
5123 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5124 stream.format = util_get_pixtype(fourcc);
5125 gst_caps_unref(caps);
5129 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5130 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5133 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5134 LOGE("Wrong condition!!");
5138 /* set size and timestamp */
5139 dataBlock = gst_buffer_peek_memory(buffer, 0);
5140 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5141 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5143 /* check zero-copy */
5144 if (player->set_mode.video_zc &&
5145 player->set_mode.media_packet_video_stream &&
5146 gst_buffer_n_memory(buffer) > 1) {
5147 metaBlock = gst_buffer_peek_memory(buffer, 1);
5148 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5149 video_buffer = (MMVideoBuffer *)mapinfo.data;
5152 if (video_buffer) { /* hw codec */
5154 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5155 /* copy pointer of tbm bo, stride, elevation */
5156 memcpy(stream.bo, video_buffer->handle.bo,
5157 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5158 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5159 /* FIXME: need to check this path */
5160 memcpy(stream.data, video_buffer->data,
5161 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5163 memcpy(stream.stride, video_buffer->stride_width,
5164 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5165 memcpy(stream.elevation, video_buffer->stride_height,
5166 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5167 /* set gst buffer */
5168 stream.internal_buffer = buffer;
5169 } else { /* sw codec */
5170 tbm_bo_handle thandle;
5171 int stride = GST_ROUND_UP_4(stream.width);
5172 int elevation = stream.height;
5176 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5178 LOGE("fail to gst_memory_map");
5182 stream.stride[0] = stride;
5183 stream.elevation[0] = elevation;
5184 if (stream.format == MM_PIXEL_FORMAT_I420) {
5185 stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5186 stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5187 size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5188 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5189 stream.stride[0] = stream.width * 4;
5190 size = stream.stride[0] * stream.height;
5192 LOGE("Not support format %d", stream.format);
5193 gst_memory_unmap(dataBlock, &mapinfo);
5196 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5197 if (!stream.bo[0]) {
5198 LOGE("Fail to tbm_bo_alloc!!");
5199 gst_memory_unmap(dataBlock, &mapinfo);
5202 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5203 if (thandle.ptr && mapinfo.data)
5204 memcpy(thandle.ptr, mapinfo.data, size);
5206 LOGE("data pointer is wrong. dest : %p, src : %p",
5207 thandle.ptr, mapinfo.data);
5208 tbm_bo_unmap(stream.bo[0]);
5211 if (player->video_stream_cb)
5212 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5215 gst_memory_unmap(metaBlock, &mapinfo);
5217 gst_memory_unmap(dataBlock, &mapinfo);
5223 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5225 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5226 gchar* video_csc = "videoconvert"; // default colorspace converter
5227 GList* element_bucket = *bucket;
5229 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5233 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5235 if (player->set_mode.video_zc) {
5236 video_csc = ""; /* videosinks don't use videoconvert normally */
5238 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5239 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5240 video_csc = "videoconvert";
5242 if (video_csc && (strcmp(video_csc, ""))) {
5243 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5244 LOGD("using video converter: %s", video_csc);
5247 /* set video rotator */
5248 if (!player->set_mode.video_zc)
5249 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5251 *bucket = element_bucket;
5253 return MM_ERROR_NONE;
5258 return MM_ERROR_PLAYER_INTERNAL;
5262 * This function is to create video pipeline.
5264 * @param player [in] handle of player
5265 * caps [in] src caps of decoder
5266 * surface_type [in] surface type for video rendering
5268 * @return This function returns zero on success.
5270 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5274 * - video overlay surface(arm/x86) : waylandsink
5277 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5281 GList*element_bucket = NULL;
5282 MMPlayerGstElement* first_element = NULL;
5283 MMPlayerGstElement* videobin = NULL;
5284 gchar *videosink_element = NULL;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5291 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5293 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5295 player->pipeline->videobin = videobin;
5297 attrs = MMPLAYER_GET_ATTRS(player);
5299 LOGE("cannot get content attribute");
5300 return MM_ERROR_PLAYER_INTERNAL;
5304 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5305 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5306 if (!videobin[MMPLAYER_V_BIN].gst) {
5307 LOGE("failed to create videobin");
5311 int enable_video_decoded_cb = 0;
5312 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5314 /* set video sink */
5315 switch (surface_type) {
5316 case MM_DISPLAY_SURFACE_OVERLAY:
5317 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5319 if (strlen(player->ini.videosink_element_overlay) > 0)
5320 videosink_element = player->ini.videosink_element_overlay;
5324 case MM_DISPLAY_SURFACE_NULL:
5325 if (strlen(player->ini.videosink_element_fake) > 0)
5326 videosink_element = player->ini.videosink_element_fake;
5330 case MM_DISPLAY_SURFACE_REMOTE:
5331 if (strlen(player->ini.videosink_element_fake) > 0)
5332 videosink_element = player->ini.videosink_element_fake;
5337 LOGE("unidentified surface type");
5340 LOGD("selected videosink name: %s", videosink_element);
5342 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5344 /* additional setting for sink plug-in */
5345 switch (surface_type) {
5346 case MM_DISPLAY_SURFACE_OVERLAY:
5348 bool use_tbm = player->set_mode.video_zc;
5350 LOGD("selected videosink name: %s", videosink_element);
5352 /* support shard memory with S/W codec on HawkP */
5353 if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5354 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5355 "use-tbm", use_tbm, NULL);
5361 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5364 LOGD("disable last-sample");
5365 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5369 if (player->set_mode.media_packet_video_stream) {
5371 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5373 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5375 MMPLAYER_SIGNAL_CONNECT(player,
5376 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5377 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5379 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5382 MMPLAYER_SIGNAL_CONNECT(player,
5383 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5384 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5386 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5391 case MM_DISPLAY_SURFACE_REMOTE:
5393 if (player->set_mode.media_packet_video_stream) {
5394 LOGE("add data probe at videosink");
5395 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5396 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5398 MMPLAYER_SIGNAL_CONNECT(player,
5399 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5400 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5402 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5405 MMPLAYER_SIGNAL_CONNECT(player,
5406 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5407 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5409 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5414 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5417 LOGD("disable last-sample");
5418 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5428 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5431 if (videobin[MMPLAYER_V_SINK].gst) {
5432 GstPad *sink_pad = NULL;
5433 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5435 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5436 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5437 gst_object_unref(GST_OBJECT(sink_pad));
5439 LOGW("failed to get sink pad from videosink\n");
5442 /* store it as it's sink element */
5443 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5445 /* adding created elements to bin */
5446 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5447 LOGE("failed to add elements\n");
5451 /* Linking elements in the bucket by added order */
5452 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5453 LOGE("failed to link elements\n");
5457 /* get first element's sinkpad for creating ghostpad */
5459 first_element = (MMPlayerGstElement *)element_bucket->data;
5460 if (!first_element) {
5461 LOGE("failed to get first element from bucket\n");
5465 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5467 LOGE("failed to get pad from first element\n");
5471 /* create ghostpad */
5472 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5473 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5474 LOGE("failed to add ghostpad to videobin\n");
5477 gst_object_unref(pad);
5479 /* done. free allocated variables */
5481 g_list_free(element_bucket);
5483 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
5487 return MM_ERROR_NONE;
5490 LOGE("ERROR : releasing videobin\n");
5492 g_list_free(element_bucket);
5495 gst_object_unref(GST_OBJECT(pad));
5497 /* release videobin with it's childs */
5498 if (videobin[MMPLAYER_V_BIN].gst)
5499 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5502 MMPLAYER_FREEIF(videobin);
5504 player->pipeline->videobin = NULL;
5506 return MM_ERROR_PLAYER_INTERNAL;
5509 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5511 GList *element_bucket = NULL;
5512 MMPlayerGstElement *textbin = player->pipeline->textbin;
5514 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5515 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5516 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5517 "signal-handoffs", FALSE,
5520 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5521 MMPLAYER_SIGNAL_CONNECT(player,
5522 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5523 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5525 G_CALLBACK(__mmplayer_update_subtitle),
5528 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5529 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5530 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5532 if (!player->play_subtitle) {
5533 LOGD("add textbin sink as sink element of whole pipeline.\n");
5534 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5537 /* adding created elements to bin */
5538 LOGD("adding created elements to bin\n");
5539 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5540 LOGE("failed to add elements\n");
5544 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5545 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5546 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5548 /* linking elements in the bucket by added order. */
5549 LOGD("Linking elements in the bucket by added order.\n");
5550 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5551 LOGE("failed to link elements\n");
5555 /* done. free allocated variables */
5556 g_list_free(element_bucket);
5558 if (textbin[MMPLAYER_T_QUEUE].gst) {
5560 GstPad *ghostpad = NULL;
5562 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5564 LOGE("failed to get video pad of textbin\n");
5565 return MM_ERROR_PLAYER_INTERNAL;
5568 ghostpad = gst_ghost_pad_new("text_sink", pad);
5569 gst_object_unref(pad);
5572 LOGE("failed to create ghostpad of textbin\n");
5576 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5577 LOGE("failed to add ghostpad to textbin\n");
5582 return MM_ERROR_NONE;
5585 g_list_free(element_bucket);
5587 return MM_ERROR_PLAYER_INTERNAL;
5590 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5592 MMPlayerGstElement *textbin = NULL;
5593 GList *element_bucket = NULL;
5598 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5601 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5603 LOGE("failed to allocate memory for textbin\n");
5604 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5608 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5609 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5610 if (!textbin[MMPLAYER_T_BIN].gst) {
5611 LOGE("failed to create textbin\n");
5616 player->pipeline->textbin = textbin;
5619 if (player->use_textoverlay) {
5620 LOGD("use textoverlay for displaying \n");
5622 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5624 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5626 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5628 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5630 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5631 LOGE("failed to link queue and converter\n");
5635 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5636 LOGE("failed to link queue and textoverlay\n");
5640 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5641 LOGE("failed to link queue and textoverlay\n");
5645 int surface_type = 0;
5647 LOGD("use subtitle message for displaying \n");
5649 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5651 switch (surface_type) {
5652 case MM_DISPLAY_SURFACE_OVERLAY:
5653 case MM_DISPLAY_SURFACE_NULL:
5654 case MM_DISPLAY_SURFACE_REMOTE:
5655 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5656 LOGE("failed to make plain text elements\n");
5668 return MM_ERROR_NONE;
5672 LOGD("ERROR : releasing textbin\n");
5674 g_list_free(element_bucket);
5676 /* release element which are not added to bin */
5677 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5678 /* NOTE : skip bin */
5679 if (textbin[i].gst) {
5680 GstObject* parent = NULL;
5681 parent = gst_element_get_parent(textbin[i].gst);
5684 gst_object_unref(GST_OBJECT(textbin[i].gst));
5685 textbin[i].gst = NULL;
5687 gst_object_unref(GST_OBJECT(parent));
5691 /* release textbin with it's childs */
5692 if (textbin[MMPLAYER_T_BIN].gst)
5693 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5695 MMPLAYER_FREEIF(textbin);
5697 player->pipeline->textbin = NULL;
5699 return MM_ERROR_PLAYER_INTERNAL;
5704 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5706 MMPlayerGstElement* mainbin = NULL;
5707 MMHandleType attrs = 0;
5708 GstElement *subsrc = NULL;
5709 GstElement *subparse = NULL;
5710 gchar *subtitle_uri = NULL;
5711 const gchar *charset = NULL;
5717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5719 mainbin = player->pipeline->mainbin;
5721 attrs = MMPLAYER_GET_ATTRS(player);
5723 LOGE("cannot get content attribute\n");
5724 return MM_ERROR_PLAYER_INTERNAL;
5727 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5728 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5729 LOGE("subtitle uri is not proper filepath.\n");
5730 return MM_ERROR_PLAYER_INVALID_URI;
5732 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5735 /* create the subtitle source */
5736 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5738 LOGE("failed to create filesrc element\n");
5741 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5743 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5744 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5746 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5747 LOGW("failed to add queue\n");
5752 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5754 LOGE("failed to create subparse element\n");
5758 charset = util_get_charset(subtitle_uri);
5760 LOGD("detected charset is %s\n", charset);
5761 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5764 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5765 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5767 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5768 LOGW("failed to add subparse\n");
5772 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5773 LOGW("failed to link subsrc and subparse\n");
5777 player->play_subtitle = TRUE;
5778 player->adjust_subtitle_pos = 0;
5780 LOGD("play subtitle using subtitle file\n");
5782 if (player->pipeline->textbin == NULL) {
5783 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
5784 LOGE("failed to create textbin. continuing without text\n");
5788 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5789 LOGW("failed to add textbin\n");
5793 LOGD("link text input selector and textbin ghost pad");
5795 player->textsink_linked = 1;
5796 player->external_text_idx = 0;
5797 LOGI("player->textsink_linked set to 1\n");
5799 LOGD("text bin has been created. reuse it.");
5800 player->external_text_idx = 1;
5803 if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5804 LOGW("failed to link subparse and textbin\n");
5808 pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5811 LOGE("failed to get sink pad from textsink to probe data");
5812 return MM_ERROR_PLAYER_INTERNAL;
5815 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5816 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5818 gst_object_unref(pad);
5821 /* create dot. for debugging */
5822 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5825 return MM_ERROR_NONE;
5828 player->textsink_linked = 0;
5829 return MM_ERROR_PLAYER_INTERNAL;
5833 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5835 mm_player_t* player = (mm_player_t*) data;
5836 MMMessageParamType msg = {0, };
5837 GstClockTime duration = 0;
5838 gpointer text = NULL;
5839 guint text_size = 0;
5840 gboolean ret = TRUE;
5841 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5845 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5846 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5848 if (player->is_subtitle_force_drop)
5850 LOGW("subtitle is dropped forcedly.");
5854 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5855 text = mapinfo.data;
5856 text_size = mapinfo.size;
5857 duration = GST_BUFFER_DURATION(buffer);
5859 if (player->set_mode.subtitle_off) {
5860 LOGD("subtitle is OFF.\n");
5864 if (!text || (text_size == 0)) {
5865 LOGD("There is no subtitle to be displayed.\n");
5869 msg.data = (void *) text;
5870 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5872 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5874 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5875 gst_buffer_unmap(buffer, &mapinfo);
5882 static GstPadProbeReturn
5883 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5886 mm_player_t *player = (mm_player_t *) u_data;
5887 GstClockTime cur_timestamp = 0;
5888 gint64 adjusted_timestamp = 0;
5889 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5891 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5893 if (player->set_mode.subtitle_off) {
5894 LOGD("subtitle is OFF.\n");
5898 if (player->adjust_subtitle_pos == 0) {
5899 LOGD("nothing to do");
5903 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5904 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5906 if (adjusted_timestamp < 0) {
5907 LOGD("adjusted_timestamp under zero");
5912 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5913 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5914 GST_TIME_ARGS(cur_timestamp),
5915 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5917 return GST_PAD_PROBE_OK;
5919 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5923 /* check player and subtitlebin are created */
5924 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5925 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5927 if (position == 0) {
5928 LOGD("nothing to do\n");
5930 return MM_ERROR_NONE;
5934 case MM_PLAYER_POS_FORMAT_TIME:
5936 /* check current postion */
5937 player->adjust_subtitle_pos = position;
5939 LOGD("save adjust_subtitle_pos in player") ;
5945 LOGW("invalid format.\n");
5947 return MM_ERROR_INVALID_ARGUMENT;
5953 return MM_ERROR_NONE;
5955 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5958 LOGD("adjusting video_pos in player") ;
5959 int current_pos = 0;
5960 /* check player and videobin are created */
5961 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5962 if (!player->pipeline->videobin ||
5963 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5964 LOGD("no video pipeline or sink is there");
5965 return MM_ERROR_PLAYER_INVALID_STATE ;
5968 LOGD("nothing to do\n");
5970 return MM_ERROR_NONE;
5972 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
5973 LOGD("failed to get current position");
5974 return MM_ERROR_PLAYER_INTERNAL;
5976 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5977 LOGD("enter video delay is valid");
5979 LOGD("enter video delay is crossing content boundary");
5980 return MM_ERROR_INVALID_ARGUMENT ;
5982 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5983 LOGD("video delay has been done");
5986 return MM_ERROR_NONE;
5990 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5992 GstElement *appsrc = element;
5993 tBuffer *buf = (tBuffer *)user_data;
5994 GstBuffer *buffer = NULL;
5995 GstFlowReturn ret = GST_FLOW_OK;
5998 MMPLAYER_RETURN_IF_FAIL(element);
5999 MMPLAYER_RETURN_IF_FAIL(buf);
6001 buffer = gst_buffer_new();
6003 if (buf->offset >= buf->len) {
6004 LOGD("call eos appsrc\n");
6005 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6009 if (buf->len - buf->offset < size)
6010 len = buf->len - buf->offset + buf->offset;
6012 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));
6013 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6014 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6016 //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6017 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6023 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6025 tBuffer *buf = (tBuffer *)user_data;
6027 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6029 buf->offset = (int)size;
6034 static GstBusSyncReply
6035 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6037 mm_player_t *player = (mm_player_t *)data;
6038 GstBusSyncReply reply = GST_BUS_DROP;
6040 if (!(player->pipeline && player->pipeline->mainbin)) {
6041 LOGE("player pipeline handle is null");
6042 return GST_BUS_PASS;
6045 if (!__mmplayer_check_useful_message(player, message)) {
6046 gst_message_unref(message);
6047 return GST_BUS_DROP;
6050 switch (GST_MESSAGE_TYPE(message)) {
6051 case GST_MESSAGE_STATE_CHANGED:
6052 /* post directly for fast launch */
6053 if (player->sync_handler) {
6054 __mmplayer_gst_callback(NULL, message, player);
6055 reply = GST_BUS_DROP;
6057 reply = GST_BUS_PASS;
6059 case GST_MESSAGE_TAG:
6060 __mmplayer_gst_extract_tag_from_msg(player, message);
6064 GstTagList *tags = NULL;
6066 gst_message_parse_tag(message, &tags);
6068 LOGE("TAGS received from element \"%s\".\n",
6069 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6071 gst_tag_list_foreach(tags, print_tag, NULL);
6072 gst_tag_list_free(tags);
6080 case GST_MESSAGE_DURATION_CHANGED:
6081 __mmplayer_gst_handle_duration(player, message);
6083 case GST_MESSAGE_ASYNC_DONE:
6084 /* NOTE:Don't call gst_callback directly
6085 * because previous frame can be showed even though this message is received for seek.
6088 reply = GST_BUS_PASS;
6092 if (reply == GST_BUS_DROP)
6093 gst_message_unref(message);
6099 __mmplayer_gst_create_decoder(mm_player_t *player,
6100 MMPlayerTrackType track,
6102 enum MainElementID elemId,
6105 gboolean ret = TRUE;
6106 GstPad *sinkpad = NULL;
6110 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6112 player->pipeline->mainbin, FALSE);
6113 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6114 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6115 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6117 GstElement *decodebin = NULL;
6118 GstCaps *dec_caps = NULL;
6120 /* create decodebin */
6121 decodebin = gst_element_factory_make("decodebin", name);
6124 LOGE("error : fail to create decodebin for %d decoder\n", track);
6129 /* raw pad handling signal */
6130 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6131 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6133 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6134 before looking for any elements that can handle that stream.*/
6135 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6136 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6138 /* This signal is emitted when a element is added to the bin.*/
6139 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6140 G_CALLBACK(__mmplayer_gst_element_added), player);
6142 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6143 LOGE("failed to add new decodebin\n");
6148 dec_caps = gst_pad_query_caps(srcpad, NULL);
6150 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6151 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6152 gst_caps_unref(dec_caps);
6155 player->pipeline->mainbin[elemId].id = elemId;
6156 player->pipeline->mainbin[elemId].gst = decodebin;
6158 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6160 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6161 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6162 gst_object_unref(GST_OBJECT(decodebin));
6165 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6166 LOGE("failed to sync second level decodebin state with parent\n");
6168 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6172 gst_object_unref(GST_OBJECT(sinkpad));
6181 * This function is to create audio or video pipeline for playing.
6183 * @param player [in] handle of player
6185 * @return This function returns zero on success.
6190 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6193 MMPlayerGstElement *mainbin = NULL;
6194 MMHandleType attrs = 0;
6195 GstElement* element = NULL;
6196 GstElement* elem_src_audio = NULL;
6197 GstElement* elem_src_subtitle = NULL;
6198 GstElement* es_video_queue = NULL;
6199 GstElement* es_audio_queue = NULL;
6200 GstElement* es_subtitle_queue = NULL;
6201 GList* element_bucket = NULL;
6202 gboolean need_state_holder = TRUE;
6204 #ifdef SW_CODEC_ONLY
6205 int surface_type = 0;
6209 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6211 /* get profile attribute */
6212 attrs = MMPLAYER_GET_ATTRS(player);
6214 LOGE("cannot get content attribute\n");
6218 /* create pipeline handles */
6219 if (player->pipeline) {
6220 LOGW("pipeline should be released before create new one\n");
6224 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6225 if (player->pipeline == NULL)
6228 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6231 /* create mainbin */
6232 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6233 if (mainbin == NULL)
6236 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6238 /* create pipeline */
6239 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6240 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6241 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6242 LOGE("failed to create pipeline\n");
6245 player->demux_pad_index = 0;
6246 player->subtitle_language_list = NULL;
6248 player->is_subtitle_force_drop = FALSE;
6249 player->last_multiwin_status = FALSE;
6251 _mmplayer_track_initialize(player);
6253 /* create source element */
6254 switch (player->profile.uri_type) {
6255 /* rtsp streamming */
6256 case MM_PLAYER_URI_TYPE_URL_RTSP:
6258 gint network_bandwidth;
6259 gchar *user_agent, *wap_profile;
6261 element = gst_element_factory_make("rtspsrc", "rtsp source");
6264 LOGE("failed to create streaming source element\n");
6269 network_bandwidth = 0;
6270 user_agent = wap_profile = NULL;
6273 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6274 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6275 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6277 SECURE_LOGD("user_agent : %s\n", user_agent);
6278 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6280 /* setting property to streaming source */
6281 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6283 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6285 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6287 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6288 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6289 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6290 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6292 player->use_decodebin = FALSE;
6297 case MM_PLAYER_URI_TYPE_URL_HTTP:
6299 gchar *user_agent, *proxy, *cookies, **cookie_list;
6300 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6301 user_agent = proxy = cookies = NULL;
6303 gint mode = MM_PLAYER_PD_MODE_NONE;
6305 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6307 player->pd_mode = mode;
6309 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6311 if (!MMPLAYER_IS_HTTP_PD(player)) {
6312 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6314 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6317 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6320 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6321 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6322 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6323 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6325 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6326 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6327 LOGD("get timeout from ini\n");
6328 http_timeout = player->ini.http_timeout;
6332 SECURE_LOGD("location : %s\n", player->profile.uri);
6333 SECURE_LOGD("cookies : %s\n", cookies);
6334 SECURE_LOGD("proxy : %s\n", proxy);
6335 SECURE_LOGD("user_agent : %s\n", user_agent);
6336 LOGD("timeout : %d\n", http_timeout);
6338 /* setting property to streaming source */
6339 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6340 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6341 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6343 /* check if prosy is vailid or not */
6344 if (util_check_valid_url(proxy))
6345 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6346 /* parsing cookies */
6347 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6348 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6350 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6352 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6353 LOGW("it's dash. and it's still experimental feature.");
6355 // progressive download
6356 gchar* location = NULL;
6358 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6361 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6363 MMPLAYER_FREEIF(player->pd_file_save_path);
6365 LOGD("PD Location : %s\n", path);
6368 player->pd_file_save_path = g_strdup(path);
6370 LOGE("can't find pd location so, it should be set \n");
6375 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6377 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6381 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6382 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6384 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6386 g_object_get(element, "location", &location, NULL);
6387 LOGD("PD_LOCATION [%s].\n", location);
6395 case MM_PLAYER_URI_TYPE_FILE:
6398 LOGD("using filesrc for 'file://' handler.\n");
6400 element = gst_element_factory_make("filesrc", "source");
6403 LOGE("failed to create filesrc\n");
6407 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6408 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
6412 case MM_PLAYER_URI_TYPE_SS:
6414 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6415 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6417 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6421 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6423 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6424 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6425 LOGD("get timeout from ini\n");
6426 http_timeout = player->ini.http_timeout;
6429 /* setting property to streaming source */
6430 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6431 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6434 case MM_PLAYER_URI_TYPE_MS_BUFF:
6436 LOGD("MS buff src is selected\n");
6438 if (player->v_stream_caps) {
6439 element = gst_element_factory_make("appsrc", "video_appsrc");
6441 LOGF("failed to create video app source element[appsrc].\n");
6445 if (player->a_stream_caps) {
6446 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6447 if (!elem_src_audio) {
6448 LOGF("failed to create audio app source element[appsrc].\n");
6452 } else if (player->a_stream_caps) {
6453 /* no video, only audio pipeline*/
6454 element = gst_element_factory_make("appsrc", "audio_appsrc");
6456 LOGF("failed to create audio app source element[appsrc].\n");
6461 if (player->s_stream_caps) {
6462 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6463 if (!elem_src_subtitle) {
6464 LOGF("failed to create subtitle app source element[appsrc].\n");
6469 LOGD("setting app sources properties.\n");
6470 LOGD("location : %s\n", player->profile.uri);
6472 if (player->v_stream_caps && element) {
6473 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6474 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6475 "caps", player->v_stream_caps, NULL);
6477 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6478 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6479 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6480 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6482 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6483 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6484 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6485 G_CALLBACK(__gst_seek_video_data), player);
6487 if (player->a_stream_caps && elem_src_audio) {
6488 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6489 "caps", player->a_stream_caps, NULL);
6491 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6492 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6493 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6494 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6496 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6497 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6498 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6499 G_CALLBACK(__gst_seek_audio_data), player);
6501 } else if (player->a_stream_caps && element) {
6502 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6503 "caps", player->a_stream_caps, NULL);
6505 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6506 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6507 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6508 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6510 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6511 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6512 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6513 G_CALLBACK(__gst_seek_audio_data), player);
6516 if (player->s_stream_caps && elem_src_subtitle) {
6517 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6518 "caps", player->s_stream_caps, NULL);
6520 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6521 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6522 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6523 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6525 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6527 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6528 G_CALLBACK(__gst_seek_subtitle_data), player);
6531 if (player->v_stream_caps && element) {
6532 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6533 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6534 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6535 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6537 if (player->a_stream_caps && elem_src_audio) {
6538 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6539 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6540 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6541 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6543 } else if (player->a_stream_caps && element) {
6544 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6545 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6546 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6547 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6550 if (player->s_stream_caps && elem_src_subtitle)
6551 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6552 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6554 need_state_holder = FALSE;
6556 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6557 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6558 LOGE("failed to commit\n");
6562 case MM_PLAYER_URI_TYPE_MEM:
6564 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6566 LOGD("mem src is selected\n");
6568 element = gst_element_factory_make("appsrc", "mem-source");
6570 LOGE("failed to create appsrc element\n");
6574 g_object_set(element, "stream-type", stream_type, NULL);
6575 g_object_set(element, "size", player->mem_buf.len, NULL);
6576 g_object_set(element, "blocksize", (guint64)20480, NULL);
6578 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6579 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6580 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6581 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6584 case MM_PLAYER_URI_TYPE_URL:
6587 case MM_PLAYER_URI_TYPE_TEMP:
6590 case MM_PLAYER_URI_TYPE_NONE:
6595 /* check source element is OK */
6597 LOGE("no source element was created.\n");
6601 /* take source element */
6602 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6603 mainbin[MMPLAYER_M_SRC].gst = element;
6604 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6606 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6607 player->streamer = __mm_player_streaming_create();
6608 __mm_player_streaming_initialize(player->streamer);
6611 if (MMPLAYER_IS_HTTP_PD(player)) {
6612 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6614 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6615 element = gst_element_factory_make("queue2", "queue2");
6617 LOGE("failed to create http streaming buffer element\n");
6622 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6623 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6624 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6626 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6628 __mm_player_streaming_set_queue2(player->streamer,
6631 player->ini.http_max_size_bytes,
6634 player->ini.http_buffering_limit,
6635 MUXED_BUFFER_TYPE_MEM_QUEUE,
6639 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6640 if (player->v_stream_caps) {
6641 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6642 if (!es_video_queue) {
6643 LOGE("create es_video_queue for es player failed\n");
6646 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6647 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6648 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6649 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6651 /* Adding audio appsrc to bucket */
6652 if (player->a_stream_caps && elem_src_audio) {
6653 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6654 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6655 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6657 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6658 if (!es_audio_queue) {
6659 LOGE("create es_audio_queue for es player failed\n");
6662 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6664 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6665 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6666 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6668 } else if (player->a_stream_caps) {
6669 /* Only audio stream, no video */
6670 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6671 if (!es_audio_queue) {
6672 LOGE("create es_audio_queue for es player failed\n");
6675 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6676 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6677 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6680 if (player->s_stream_caps && elem_src_subtitle) {
6681 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6682 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6683 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6685 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6686 if (!es_subtitle_queue) {
6687 LOGE("create es_subtitle_queue for es player failed\n");
6690 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6691 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6692 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6696 /* create autoplugging element if src element is not a rtsp src */
6697 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6698 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6699 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6701 enum MainElementID elemId = MMPLAYER_M_NUM;
6703 if ((player->use_decodebin) &&
6704 ((MMPLAYER_IS_HTTP_PD(player)) ||
6705 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6706 elemId = MMPLAYER_M_AUTOPLUG;
6707 element = __mmplayer_create_decodebin(player);
6709 /* default size of mq in decodebin is 2M
6710 * but it can cause blocking issue during seeking depends on content. */
6711 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6713 need_state_holder = FALSE;
6715 elemId = MMPLAYER_M_TYPEFIND;
6716 element = gst_element_factory_make("typefind", "typefinder");
6717 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6718 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6722 /* check autoplug element is OK */
6724 LOGE("can not create element(%d)\n", elemId);
6728 mainbin[elemId].id = elemId;
6729 mainbin[elemId].gst = element;
6731 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6734 /* add elements to pipeline */
6735 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6736 LOGE("Failed to add elements to pipeline\n");
6741 /* linking elements in the bucket by added order. */
6742 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6743 LOGE("Failed to link some elements\n");
6748 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6749 if (need_state_holder) {
6751 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6752 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6754 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6755 LOGE("fakesink element could not be created\n");
6758 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6760 /* take ownership of fakesink. we are reusing it */
6761 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6764 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6765 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6766 LOGE("failed to add fakesink to bin\n");
6771 /* now we have completed mainbin. take it */
6772 player->pipeline->mainbin = mainbin;
6774 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6775 GstPad *srcpad = NULL;
6777 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6778 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6780 __mmplayer_gst_create_decoder(player,
6781 MM_PLAYER_TRACK_TYPE_VIDEO,
6783 MMPLAYER_M_AUTOPLUG_V_DEC,
6786 gst_object_unref(GST_OBJECT(srcpad));
6791 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6792 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6794 __mmplayer_gst_create_decoder(player,
6795 MM_PLAYER_TRACK_TYPE_AUDIO,
6797 MMPLAYER_M_AUTOPLUG_A_DEC,
6800 gst_object_unref(GST_OBJECT(srcpad));
6805 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6806 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6809 /* connect bus callback */
6810 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6812 LOGE("cannot get bus from pipeline.\n");
6816 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6818 player->context.thread_default = g_main_context_get_thread_default();
6820 if (NULL == player->context.thread_default) {
6821 player->context.thread_default = g_main_context_default();
6822 LOGD("thread-default context is the global default context");
6824 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6826 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6827 if (__mmplayer_check_subtitle(player)) {
6828 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6829 LOGE("fail to create subtitle src\n");
6832 /* set sync handler to get tag synchronously */
6833 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6836 gst_object_unref(GST_OBJECT(bus));
6837 g_list_free(element_bucket);
6841 return MM_ERROR_NONE;
6845 __mmplayer_gst_destroy_pipeline(player);
6846 g_list_free(element_bucket);
6849 /* release element which are not added to bin */
6850 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6851 /* NOTE : skip pipeline */
6852 if (mainbin[i].gst) {
6853 GstObject* parent = NULL;
6854 parent = gst_element_get_parent(mainbin[i].gst);
6857 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6858 mainbin[i].gst = NULL;
6860 gst_object_unref(GST_OBJECT(parent));
6864 /* release pipeline with it's childs */
6865 if (mainbin[MMPLAYER_M_PIPE].gst)
6866 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6868 MMPLAYER_FREEIF(mainbin);
6871 MMPLAYER_FREEIF(player->pipeline);
6872 return MM_ERROR_PLAYER_INTERNAL;
6876 __mmplayer_reset_gapless_state(mm_player_t* player)
6879 MMPLAYER_RETURN_IF_FAIL(player
6881 && player->pipeline->audiobin
6882 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6884 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6891 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6894 int ret = MM_ERROR_NONE;
6898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6900 /* cleanup stuffs */
6901 MMPLAYER_FREEIF(player->type);
6902 player->have_dynamic_pad = FALSE;
6903 player->no_more_pad = FALSE;
6904 player->num_dynamic_pad = 0;
6905 player->demux_pad_index = 0;
6906 player->subtitle_language_list = NULL;
6907 player->use_deinterleave = FALSE;
6908 player->max_audio_channels = 0;
6909 player->video_share_api_delta = 0;
6910 player->video_share_clock_delta = 0;
6911 player->video_hub_download_mode = 0;
6912 __mmplayer_reset_gapless_state(player);
6914 if (player->streamer) {
6915 __mm_player_streaming_deinitialize(player->streamer);
6916 __mm_player_streaming_destroy(player->streamer);
6917 player->streamer = NULL;
6920 /* cleanup unlinked mime type */
6921 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6922 MMPLAYER_FREEIF(player->unlinked_video_mime);
6923 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6925 /* cleanup running stuffs */
6926 __mmplayer_cancel_eos_timer(player);
6928 /* cleanup gst stuffs */
6929 if (player->pipeline) {
6930 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6931 GstTagList* tag_list = player->pipeline->tag_list;
6933 /* first we need to disconnect all signal hander */
6934 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6936 /* disconnecting bus watch */
6937 if (player->bus_watcher)
6938 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6939 player->bus_watcher = 0;
6942 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6943 MMPlayerGstElement* videobin = player->pipeline->videobin;
6944 MMPlayerGstElement* textbin = player->pipeline->textbin;
6945 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6946 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6947 gst_object_unref(bus);
6949 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6950 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6951 if (ret != MM_ERROR_NONE) {
6952 LOGE("fail to change state to NULL\n");
6953 return MM_ERROR_PLAYER_INTERNAL;
6956 LOGW("succeeded in chaning state to NULL\n");
6958 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6961 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6962 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6964 /* free avsysaudiosink
6965 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6966 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6968 MMPLAYER_FREEIF(audiobin);
6969 MMPLAYER_FREEIF(videobin);
6970 MMPLAYER_FREEIF(textbin);
6971 MMPLAYER_FREEIF(mainbin);
6975 gst_tag_list_free(tag_list);
6977 MMPLAYER_FREEIF(player->pipeline);
6979 MMPLAYER_FREEIF(player->album_art);
6981 if (player->v_stream_caps) {
6982 gst_caps_unref(player->v_stream_caps);
6983 player->v_stream_caps = NULL;
6985 if (player->a_stream_caps) {
6986 gst_caps_unref(player->a_stream_caps);
6987 player->a_stream_caps = NULL;
6990 if (player->s_stream_caps) {
6991 gst_caps_unref(player->s_stream_caps);
6992 player->s_stream_caps = NULL;
6994 _mmplayer_track_destroy(player);
6996 if (player->sink_elements)
6997 g_list_free(player->sink_elements);
6998 player->sink_elements = NULL;
7000 if (player->bufmgr) {
7001 tbm_bufmgr_deinit(player->bufmgr);
7002 player->bufmgr = NULL;
7005 LOGW("finished destroy pipeline\n");
7012 static int __gst_realize(mm_player_t* player) // @
7015 int ret = MM_ERROR_NONE;
7019 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7021 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7023 ret = __mmplayer_gst_create_pipeline(player);
7025 LOGE("failed to create pipeline\n");
7029 /* set pipeline state to READY */
7030 /* NOTE : state change to READY must be performed sync. */
7031 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7032 ret = __mmplayer_gst_set_state(player,
7033 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7035 if (ret != MM_ERROR_NONE) {
7036 /* return error if failed to set state */
7037 LOGE("failed to set READY state");
7040 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7042 /* create dot before error-return. for debugging */
7043 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7050 static int __gst_unrealize(mm_player_t* player) // @
7052 int ret = MM_ERROR_NONE;
7056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7058 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7059 MMPLAYER_PRINT_STATE(player);
7061 /* release miscellaneous information */
7062 __mmplayer_release_misc(player);
7064 /* destroy pipeline */
7065 ret = __mmplayer_gst_destroy_pipeline(player);
7066 if (ret != MM_ERROR_NONE) {
7067 LOGE("failed to destory pipeline\n");
7071 /* release miscellaneous information.
7072 these info needs to be released after pipeline is destroyed. */
7073 __mmplayer_release_misc_post(player);
7075 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7082 static int __gst_pending_seek(mm_player_t* player)
7084 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7085 int ret = MM_ERROR_NONE;
7089 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7091 if (!player->pending_seek.is_pending) {
7092 LOGD("pending seek is not reserved. nothing to do.\n");
7096 /* check player state if player could pending seek or not. */
7097 current_state = MMPLAYER_CURRENT_STATE(player);
7099 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7100 LOGW("try to pending seek in %s state, try next time. \n",
7101 MMPLAYER_STATE_GET_NAME(current_state));
7105 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7107 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7109 if (MM_ERROR_NONE != ret)
7110 LOGE("failed to seek pending postion. just keep staying current position.\n");
7112 player->pending_seek.is_pending = FALSE;
7119 static int __gst_start(mm_player_t* player) // @
7121 gboolean sound_extraction = 0;
7122 int ret = MM_ERROR_NONE;
7123 gboolean async = FALSE;
7127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7129 /* get sound_extraction property */
7130 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7132 /* NOTE : if SetPosition was called before Start. do it now */
7133 /* streaming doesn't support it. so it should be always sync */
7134 /* !!create one more api to check if there is pending seek rather than checking variables */
7135 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7136 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7137 ret = __gst_pause(player, FALSE);
7138 if (ret != MM_ERROR_NONE) {
7139 LOGE("failed to set state to PAUSED for pending seek\n");
7143 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7145 if (sound_extraction) {
7146 LOGD("setting pcm extraction\n");
7148 ret = __mmplayer_set_pcm_extraction(player);
7149 if (MM_ERROR_NONE != ret) {
7150 LOGW("failed to set pcm extraction\n");
7154 if (MM_ERROR_NONE != __gst_pending_seek(player))
7155 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7159 LOGD("current state before doing transition");
7160 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7161 MMPLAYER_PRINT_STATE(player);
7163 /* set pipeline state to PLAYING */
7164 if (player->es_player_push_mode)
7166 /* set pipeline state to PLAYING */
7167 ret = __mmplayer_gst_set_state(player,
7168 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7170 if (ret == MM_ERROR_NONE) {
7171 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7173 LOGE("failed to set state to PLAYING");
7177 /* generating debug info before returning error */
7178 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7185 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7189 MMPLAYER_RETURN_IF_FAIL(player
7191 && player->pipeline->audiobin
7192 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7194 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7201 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7205 MMPLAYER_RETURN_IF_FAIL(player
7207 && player->pipeline->audiobin
7208 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7210 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7215 static int __gst_stop(mm_player_t* player) // @
7217 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7218 MMHandleType attrs = 0;
7219 gboolean fadedown = FALSE;
7220 gboolean rewind = FALSE;
7222 int ret = MM_ERROR_NONE;
7223 gboolean async = FALSE;
7227 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7230 LOGD("current state before doing transition");
7231 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7232 MMPLAYER_PRINT_STATE(player);
7234 attrs = MMPLAYER_GET_ATTRS(player);
7236 LOGE("cannot get content attribute\n");
7237 return MM_ERROR_PLAYER_INTERNAL;
7240 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7242 /* enable fadedown */
7243 if (fadedown || player->sound_focus.by_asm_cb)
7244 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7246 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7247 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7249 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7250 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7253 if (player->es_player_push_mode)
7256 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7258 /* disable fadeout */
7259 if (fadedown || player->sound_focus.by_asm_cb)
7260 __mmplayer_undo_sound_fadedown(player);
7262 /* return if set_state has failed */
7263 if (ret != MM_ERROR_NONE) {
7264 LOGE("failed to set state.\n");
7270 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7271 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7272 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7273 LOGW("failed to rewind\n");
7274 ret = MM_ERROR_PLAYER_SEEK;
7279 player->sent_bos = FALSE;
7281 if (player->es_player_push_mode) //for cloudgame
7284 /* wait for seek to complete */
7285 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7286 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7287 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7289 LOGE("fail to stop player.\n");
7290 ret = MM_ERROR_PLAYER_INTERNAL;
7291 __mmplayer_dump_pipeline_state(player);
7294 /* generate dot file if enabled */
7295 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7302 int __gst_pause(mm_player_t* player, gboolean async) // @
7304 int ret = MM_ERROR_NONE;
7308 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7309 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7311 LOGD("current state before doing transition");
7312 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7313 MMPLAYER_PRINT_STATE(player);
7315 /* set pipeline status to PAUSED */
7316 player->ignore_asyncdone = TRUE;
7318 ret = __mmplayer_gst_set_state(player,
7319 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7321 player->ignore_asyncdone = FALSE;
7323 if (FALSE == async) {
7324 if (ret != MM_ERROR_NONE) {
7325 GstMessage *msg = NULL;
7326 GTimer *timer = NULL;
7327 gdouble MAX_TIMEOUT_SEC = 3;
7329 LOGE("failed to set state to PAUSED");
7331 if (player->msg_posted) {
7332 LOGE("error msg is already posted.");
7336 timer = g_timer_new();
7337 g_timer_start(timer);
7339 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7342 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7344 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7345 GError *error = NULL;
7347 /* parse error code */
7348 gst_message_parse_error(msg, &error, NULL);
7350 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7351 /* Note : the streaming error from the streaming source is handled
7352 * using __mmplayer_handle_streaming_error.
7354 __mmplayer_handle_streaming_error(player, msg);
7357 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7359 if (error->domain == GST_STREAM_ERROR)
7360 ret = __gst_handle_stream_error(player, error, msg);
7361 else if (error->domain == GST_RESOURCE_ERROR)
7362 ret = __gst_handle_resource_error(player, error->code);
7363 else if (error->domain == GST_LIBRARY_ERROR)
7364 ret = __gst_handle_library_error(player, error->code);
7365 else if (error->domain == GST_CORE_ERROR)
7366 ret = __gst_handle_core_error(player, error->code);
7368 player->msg_posted = TRUE;
7370 gst_message_unref(msg);
7372 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7374 gst_object_unref(bus);
7375 g_timer_stop(timer);
7376 g_timer_destroy(timer);
7380 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7381 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7383 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7385 } else if (ret == MM_ERROR_NONE) {
7387 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7391 /* generate dot file before returning error */
7392 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7399 int __gst_resume(mm_player_t* player, gboolean async) // @
7401 int ret = MM_ERROR_NONE;
7406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7407 MM_ERROR_PLAYER_NOT_INITIALIZED);
7409 LOGD("current state before doing transition");
7410 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7411 MMPLAYER_PRINT_STATE(player);
7413 /* generate dot file before returning error */
7414 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7417 LOGD("do async state transition to PLAYING.\n");
7419 /* set pipeline state to PLAYING */
7420 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7422 ret = __mmplayer_gst_set_state(player,
7423 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7424 if (ret != MM_ERROR_NONE) {
7425 LOGE("failed to set state to PLAYING\n");
7428 if (async == FALSE) {
7429 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7430 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7431 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7435 /* generate dot file before returning error */
7436 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7444 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called) // @
7446 unsigned long dur_msec = 0;
7447 gint64 dur_nsec = 0;
7448 gint64 pos_nsec = 0;
7449 gboolean ret = TRUE;
7450 gboolean accurated = FALSE;
7451 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7455 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7457 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7458 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7461 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7462 /* check duration */
7463 /* NOTE : duration cannot be zero except live streaming.
7464 * Since some element could have some timing problemn with quering duration, try again.
7466 if (!player->duration) {
7467 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec))
7469 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7470 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7471 if ((MMPLAYER_IS_RTSP_STREAMING( player )) && (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7472 player->pending_seek.is_pending = TRUE;
7473 player->pending_seek.format = format;
7474 player->pending_seek.pos = position;
7475 player->doing_seek = FALSE;
7476 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
7477 return MM_ERROR_NONE;
7481 player->duration = dur_nsec;
7484 if (player->duration) {
7485 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7487 LOGE("could not get the duration. fail to seek.\n");
7491 LOGD("playback rate: %f\n", player->playback_rate);
7493 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7495 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7497 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7501 case MM_PLAYER_POS_FORMAT_TIME:
7503 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7504 /* check position is valid or not */
7505 if (position > dur_msec)
7508 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7510 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7511 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7512 This causes problem is position calculation during normal pause resume scenarios also.
7513 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7514 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7515 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7516 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7517 LOGW("getting current position failed in seek\n");
7519 player->last_position = pos_nsec;
7520 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7523 if (player->doing_seek) {
7524 LOGD("not completed seek");
7525 return MM_ERROR_PLAYER_DOING_SEEK;
7529 if (!internal_called)
7530 player->doing_seek = TRUE;
7532 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7534 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7535 gint64 cur_time = 0;
7537 /* get current position */
7538 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7541 GstEvent *event = gst_event_new_seek(1.0,
7543 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7544 GST_SEEK_TYPE_SET, cur_time,
7545 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7547 __gst_send_event_to_sink(player, event);
7549 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7550 __gst_pause(player, FALSE);
7553 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7554 that's why set position through property. */
7555 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7556 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7557 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7558 (!player->videodec_linked) && (!player->audiodec_linked)) {
7560 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7561 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7562 gst_element_get_name(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7563 player->doing_seek = FALSE;
7564 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7566 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7567 GST_FORMAT_TIME, seek_flags,
7568 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7572 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7578 case MM_PLAYER_POS_FORMAT_PERCENT:
7580 LOGD("seeking to(%lu)%% \n", position);
7582 if (player->doing_seek) {
7583 LOGD("not completed seek");
7584 return MM_ERROR_PLAYER_DOING_SEEK;
7587 if (!internal_called)
7588 player->doing_seek = TRUE;
7590 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7591 pos_nsec = (gint64)((position * player->duration) / 100);
7592 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7593 GST_FORMAT_TIME, seek_flags,
7594 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7596 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7606 /* NOTE : store last seeking point to overcome some bad operation
7607 * (returning zero when getting current position) of some elements
7609 player->last_position = pos_nsec;
7611 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7612 if (player->playback_rate > 1.0)
7613 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7616 return MM_ERROR_NONE;
7619 player->pending_seek.is_pending = TRUE;
7620 player->pending_seek.format = format;
7621 player->pending_seek.pos = position;
7623 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7624 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7626 return MM_ERROR_NONE;
7629 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7630 return MM_ERROR_INVALID_ARGUMENT;
7633 player->doing_seek = FALSE;
7634 return MM_ERROR_PLAYER_SEEK;
7637 #define TRICKPLAY_OFFSET GST_MSECOND
7640 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7642 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7643 gint64 pos_msec = 0;
7644 gboolean ret = TRUE;
7646 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7647 MM_ERROR_PLAYER_NOT_INITIALIZED);
7649 current_state = MMPLAYER_CURRENT_STATE(player);
7651 /* NOTE : query position except paused state to overcome some bad operation
7652 * please refer to below comments in details
7654 if (current_state != MM_PLAYER_STATE_PAUSED)
7655 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7657 /* NOTE : get last point to overcome some bad operation of some elements
7658 *(returning zero when getting current position in paused state
7659 * and when failed to get postion during seeking
7661 if ((current_state == MM_PLAYER_STATE_PAUSED)
7663 //|| (player->last_position != 0 && pos_msec == 0))
7664 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7666 if (player->playback_rate < 0.0)
7667 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7669 pos_msec = player->last_position;
7672 pos_msec = player->last_position;
7674 player->last_position = pos_msec;
7676 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7679 if (player->duration > 0 && pos_msec > player->duration)
7680 pos_msec = player->duration;
7682 if (player->sound_focus.keep_last_pos) {
7683 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7684 pos_msec = player->last_position;
7686 player->last_position = pos_msec;
7690 case MM_PLAYER_POS_FORMAT_TIME:
7691 *position = GST_TIME_AS_MSECONDS(pos_msec);
7694 case MM_PLAYER_POS_FORMAT_PERCENT:
7696 if (player->duration <= 0) {
7697 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7700 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7701 *position = pos_msec * 100 / player->duration;
7706 return MM_ERROR_PLAYER_INTERNAL;
7709 return MM_ERROR_NONE;
7713 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7715 #define STREAMING_IS_FINISHED 0
7716 #define BUFFERING_MAX_PER 100
7717 #define DEFAULT_PER_VALUE -1
7718 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7720 MMPlayerGstElement *mainbin = NULL;
7721 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7722 gint64 buffered_total = 0;
7723 unsigned long position = 0;
7724 gint buffered_sec = -1;
7725 GstBufferingMode mode = GST_BUFFERING_STREAM;
7726 gint64 content_size_time = player->duration;
7727 guint64 content_size_bytes = player->http_content_size;
7729 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7731 player->pipeline->mainbin,
7732 MM_ERROR_PLAYER_NOT_INITIALIZED);
7734 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7739 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7740 /* and rtsp is not ready yet. */
7741 LOGW("it's only used for http streaming case.\n");
7742 return MM_ERROR_PLAYER_NO_OP;
7745 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7746 LOGW("Time format is not supported yet.\n");
7747 return MM_ERROR_INVALID_ARGUMENT;
7750 if (content_size_time <= 0 || content_size_bytes <= 0) {
7751 LOGW("there is no content size.");
7752 return MM_ERROR_NONE;
7755 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7756 LOGW("fail to get current position.");
7757 return MM_ERROR_NONE;
7760 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7761 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7763 mainbin = player->pipeline->mainbin;
7764 start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7766 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7767 GstQuery *query = NULL;
7768 gint byte_in_rate = 0, byte_out_rate = 0;
7769 gint64 estimated_total = 0;
7771 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7772 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7773 LOGW("fail to get buffering query from queue2");
7775 gst_query_unref(query);
7776 return MM_ERROR_NONE;
7779 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7780 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7782 if (mode == GST_BUFFERING_STREAM) {
7783 /* using only queue in case of push mode(ts / mp3) */
7784 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7785 GST_FORMAT_BYTES, &buffered_total)) {
7786 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7787 stop_per = 100 * buffered_total / content_size_bytes;
7790 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7792 guint num_of_ranges = 0;
7793 gint64 start_byte = 0, stop_byte = 0;
7795 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7796 if (estimated_total != STREAMING_IS_FINISHED) {
7797 /* buffered size info from queue2 */
7798 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7799 for (idx = 0; idx < num_of_ranges; idx++) {
7800 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7801 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7803 buffered_total += (stop_byte - start_byte);
7806 stop_per = BUFFERING_MAX_PER;
7808 gst_query_unref(query);
7811 if (stop_per == DEFAULT_PER_VALUE) {
7812 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7814 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7816 /* buffered size info from multiqueue */
7817 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7818 guint curr_size_bytes = 0;
7819 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7820 "curr-size-bytes", &curr_size_bytes, NULL);
7821 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7822 buffered_total += curr_size_bytes;
7825 if (avg_byterate > 0)
7826 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7827 else if (player->total_maximum_bitrate > 0)
7828 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7829 else if (player->total_bitrate > 0)
7830 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7832 if (buffered_sec >= 0)
7833 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7837 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7838 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7840 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7841 buffered_total, buffered_sec, *start_pos, *stop_pos);
7843 return MM_ERROR_NONE;
7847 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7852 LOGW("set_message_callback is called with invalid player handle\n");
7853 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7856 player->msg_cb = callback;
7857 player->msg_cb_param = user_param;
7859 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7863 return MM_ERROR_NONE;
7866 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7868 int ret = MM_ERROR_PLAYER_INVALID_URI;
7873 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7874 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7875 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7877 memset(data, 0, sizeof(MMPlayerParseProfile));
7879 if ((path = strstr(uri, "es_buff://"))) {
7881 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7882 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7883 ret = MM_ERROR_NONE;
7885 } else if ((path = strstr(uri, "rtsp://"))) {
7887 if ((path = strstr(uri, "/wfd1.0/"))) {
7888 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7889 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7890 ret = MM_ERROR_NONE;
7891 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7893 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7894 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7895 ret = MM_ERROR_NONE;
7898 } else if ((path = strstr(uri, "http://"))) {
7900 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7902 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7903 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7904 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7906 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7908 ret = MM_ERROR_NONE;
7910 } else if ((path = strstr(uri, "https://"))) {
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, "rtspu://"))) {
7924 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7925 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7926 ret = MM_ERROR_NONE;
7928 } else if ((path = strstr(uri, "rtspr://"))) {
7929 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7930 char *separater = strstr(path, "*");
7934 char *urgent = separater + strlen("*");
7936 if ((urgent_len = strlen(urgent))) {
7937 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7938 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7939 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7940 ret = MM_ERROR_NONE;
7943 } else if ((path = strstr(uri, "mms://"))) {
7945 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7946 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7947 ret = MM_ERROR_NONE;
7949 } else if ((path = strstr(uri, "mem://"))) {
7952 char *buffer = NULL;
7953 char *seperator = strchr(path, ',');
7954 char ext[100] = {0,}, size[100] = {0,};
7957 if ((buffer = strstr(path, "ext="))) {
7958 buffer += strlen("ext=");
7960 if (strlen(buffer)) {
7961 strncpy(ext, buffer, 99);
7963 if ((seperator = strchr(ext, ','))
7964 || (seperator = strchr(ext, ' '))
7965 || (seperator = strchr(ext, '\0'))) {
7966 seperator[0] = '\0';
7971 if ((buffer = strstr(path, "size="))) {
7972 buffer += strlen("size=");
7974 if (strlen(buffer) > 0) {
7975 strncpy(size, buffer, 99);
7977 if ((seperator = strchr(size, ','))
7978 || (seperator = strchr(size, ' '))
7979 || (seperator = strchr(size, '\0'))) {
7980 seperator[0] = '\0';
7983 mem_size = atoi(size);
7988 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7989 if (mem_size && param) {
7991 data->mem_size = mem_size;
7992 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7993 ret = MM_ERROR_NONE;
7997 gchar *location = NULL;
8000 if ((path = strstr(uri, "file://"))) {
8002 location = g_filename_from_uri(uri, NULL, &err);
8004 if (!location || (err != NULL)) {
8005 LOGE("Invalid URI '%s' for filesrc: %s", path,
8006 (err != NULL) ? err->message : "unknown error");
8008 if (err) g_error_free(err);
8009 if (location) g_free(location);
8011 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8015 LOGD("path from uri: %s", location);
8018 path = (location != NULL) ? (location) : ((char*)uri);
8019 int file_stat = MM_ERROR_NONE;
8021 file_stat = util_exist_file_path(path);
8023 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8024 if (file_stat == MM_ERROR_NONE) {
8025 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8027 if (util_is_sdp_file(path)) {
8028 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8029 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8031 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8033 ret = MM_ERROR_NONE;
8034 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8035 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8037 LOGE("invalid uri, could not play..\n");
8038 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8041 if (location) g_free(location);
8045 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8046 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8047 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8048 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8050 /* dump parse result */
8051 SECURE_LOGW("incomming uri : %s\n", uri);
8052 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8053 data->uri_type, data->mem, data->mem_size, data->urgent);
8060 gboolean _asm_postmsg(gpointer *data)
8062 mm_player_t* player = (mm_player_t*)data;
8063 MMMessageParamType msg = {0, };
8066 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8067 LOGW("get notified");
8069 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8070 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8076 msg.union_type = MM_MSG_UNION_CODE;
8077 msg.code = player->sound_focus.focus_changed_msg;
8079 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8080 player->resume_event_id = 0;
8086 gboolean _asm_lazy_pause(gpointer *data)
8088 mm_player_t* player = (mm_player_t*)data;
8089 int ret = MM_ERROR_NONE;
8093 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8095 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8096 LOGD("Ready to proceed lazy pause\n");
8097 ret = _mmplayer_pause((MMHandleType)player);
8098 if (MM_ERROR_NONE != ret)
8099 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8101 LOGD("Invalid state to proceed lazy pause\n");
8104 if (player->pipeline && player->pipeline->audiobin)
8105 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8107 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8115 __mmplayer_can_do_interrupt(mm_player_t *player)
8117 if (!player || !player->pipeline || !player->attrs) {
8118 LOGW("not initialized");
8122 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8123 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8127 /* check if seeking */
8128 if (player->doing_seek) {
8129 MMMessageParamType msg_param;
8130 memset(&msg_param, 0, sizeof(MMMessageParamType));
8131 msg_param.code = MM_ERROR_PLAYER_SEEK;
8132 player->doing_seek = FALSE;
8133 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8137 /* check other thread */
8138 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8139 LOGW("locked already, cmd state : %d", player->cmd);
8141 /* check application command */
8142 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8143 LOGW("playing.. should wait cmd lock then, will be interrupted");
8145 /* lock will be released at mrp_resource_release_cb() */
8146 MMPLAYER_CMD_LOCK(player);
8149 LOGW("nothing to do");
8152 LOGW("can interrupt immediately");
8156 FAILED: /* with CMD UNLOCKED */
8159 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8163 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8165 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8167 int ret = MM_ERROR_NONE;
8168 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8170 if (strstr(reason_for_change, "alarm")) {
8171 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8173 } else if (strstr(reason_for_change, "notification")) {
8174 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8176 } else if (strstr(reason_for_change, "emergency")) {
8177 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8179 } else if (strstr(reason_for_change, "call-voice") ||
8180 strstr(reason_for_change, "call-video") ||
8181 strstr(reason_for_change, "voip") ||
8182 strstr(reason_for_change, "ringtone-voip") ||
8183 strstr(reason_for_change, "ringtone-call")) {
8184 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8186 } else if (strstr(reason_for_change, "media") ||
8187 strstr(reason_for_change, "radio") ||
8188 strstr(reason_for_change, "loopback") ||
8189 strstr(reason_for_change, "system") ||
8190 strstr(reason_for_change, "voice-information") ||
8191 strstr(reason_for_change, "voice-recognition")) {
8192 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8195 ret = MM_ERROR_INVALID_ARGUMENT;
8196 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8200 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8202 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8204 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8211 /* FIXME: will be updated with new funct */
8212 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8213 const char *reason_for_change, const char *additional_info, void *user_data)
8215 mm_player_t* player = (mm_player_t*) user_data;
8216 int result = MM_ERROR_NONE;
8217 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8219 LOGW("focus watch notified");
8221 if (!__mmplayer_can_do_interrupt(player)) {
8222 LOGW("no need to interrupt, so leave");
8223 goto EXIT_WITHOUT_UNLOCK;
8226 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8227 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8231 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8232 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8234 player->sound_focus.cb_pending = TRUE;
8235 player->sound_focus.by_asm_cb = TRUE;
8237 if (focus_state == FOCUS_IS_ACQUIRED) {
8238 LOGW("watch: FOCUS_IS_ACQUIRED");
8239 player->sound_focus.acquired = TRUE;
8241 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8242 player->sound_focus.focus_changed_msg = (int)msg;
8244 if (strstr(reason_for_change, "call") ||
8245 strstr(reason_for_change, "voip") || /* FIXME: to check */
8246 strstr(reason_for_change, "alarm") ||
8247 strstr(reason_for_change, "media")) {
8248 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8249 // hold 0.7 second to excute "fadedown mute" effect
8250 LOGW("do fade down->pause->undo fade down");
8252 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8254 result = _mmplayer_pause((MMHandleType)player);
8255 if (result != MM_ERROR_NONE) {
8256 LOGW("fail to set Pause state by asm");
8259 __mmplayer_undo_sound_fadedown(player);
8261 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8262 _mmplayer_unrealize((MMHandleType)player);
8264 LOGW("pause immediately");
8265 result = _mmplayer_pause((MMHandleType)player);
8266 if (result != MM_ERROR_NONE) {
8267 LOGW("fail to set Pause state by asm");
8271 } else if (focus_state == FOCUS_IS_RELEASED) {
8272 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8273 player->sound_focus.acquired = FALSE;
8274 player->sound_focus.antishock = TRUE;
8275 player->sound_focus.by_asm_cb = FALSE;
8277 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8278 player->sound_focus.focus_changed_msg = (int)msg;
8280 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8281 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8284 LOGW("unknown focus state %d", focus_state);
8287 player->sound_focus.by_asm_cb = FALSE;
8288 player->sound_focus.cb_pending = FALSE;
8291 MMPLAYER_CMD_UNLOCK(player);
8295 EXIT_WITHOUT_UNLOCK:
8301 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8302 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8304 mm_player_t* player = (mm_player_t*) user_data;
8305 int result = MM_ERROR_NONE;
8306 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8308 LOGW("get focus notified");
8310 if (!__mmplayer_can_do_interrupt(player)) {
8311 LOGW("no need to interrupt, so leave");
8312 goto EXIT_WITHOUT_UNLOCK;
8315 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8316 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8320 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8321 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8323 player->sound_focus.cb_pending = TRUE;
8324 player->sound_focus.by_asm_cb = TRUE;
8325 // player->sound_focus.event_src = event_src;
8327 if (focus_state == FOCUS_IS_RELEASED) {
8328 LOGW("FOCUS_IS_RELEASED");
8329 player->sound_focus.acquired = FALSE;
8331 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8332 player->sound_focus.focus_changed_msg = (int)msg;
8334 if (strstr(reason_for_change, "call") ||
8335 strstr(reason_for_change, "voip") || /* FIXME: to check */
8336 strstr(reason_for_change, "alarm") ||
8337 strstr(reason_for_change, "media")) {
8338 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8339 //hold 0.7 second to excute "fadedown mute" effect
8340 LOGW("do fade down->pause->undo fade down");
8342 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8344 result = _mmplayer_pause((MMHandleType)player);
8345 if (result != MM_ERROR_NONE) {
8346 LOGW("fail to set Pause state by asm");
8349 __mmplayer_undo_sound_fadedown(player);
8351 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8352 _mmplayer_unrealize((MMHandleType)player);
8354 LOGW("pause immediately");
8355 result = _mmplayer_pause((MMHandleType)player);
8356 if (result != MM_ERROR_NONE) {
8357 LOGW("fail to set Pause state by asm");
8361 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8362 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8363 player->sound_focus.acquired = TRUE;
8364 player->sound_focus.antishock = TRUE;
8365 player->sound_focus.by_asm_cb = FALSE;
8367 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8368 player->sound_focus.focus_changed_msg = (int)msg;
8370 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8371 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8374 LOGW("unknown focus state %d", focus_state);
8377 player->sound_focus.by_asm_cb = FALSE;
8378 player->sound_focus.cb_pending = FALSE;
8381 MMPLAYER_CMD_UNLOCK(player);
8385 EXIT_WITHOUT_UNLOCK:
8392 _mmplayer_create_player(MMHandleType handle) // @
8394 int ret = MM_ERROR_PLAYER_INTERNAL;
8395 mm_player_t* player = MM_PLAYER_CAST(handle);
8399 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8401 /* initialize player state */
8402 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8403 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8404 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8405 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8407 /* check current state */
8408 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8410 /* construct attributes */
8411 player->attrs = _mmplayer_construct_attribute(handle);
8413 if (!player->attrs) {
8414 LOGE("Failed to construct attributes\n");
8418 /* initialize gstreamer with configured parameter */
8419 if (!__mmplayer_init_gstreamer(player)) {
8420 LOGE("Initializing gstreamer failed\n");
8421 _mmplayer_deconstruct_attribute(handle);
8425 /* initialize factories if not using decodebin */
8426 if (player->factories == NULL)
8427 __mmplayer_init_factories(player);
8429 /* create lock. note that g_tread_init() has already called in gst_init() */
8430 g_mutex_init(&player->fsink_lock);
8432 /* create update tag lock */
8433 g_mutex_init(&player->update_tag_lock);
8435 /* create repeat mutex */
8436 g_mutex_init(&player->repeat_thread_mutex);
8438 /* create repeat cond */
8439 g_cond_init(&player->repeat_thread_cond);
8441 /* create repeat thread */
8442 player->repeat_thread =
8443 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8444 if (!player->repeat_thread) {
8445 LOGE("failed to create repeat_thread(%s)");
8446 g_mutex_clear(&player->repeat_thread_mutex);
8447 g_cond_clear(&player->repeat_thread_cond);
8448 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8452 /* create next play mutex */
8453 g_mutex_init(&player->next_play_thread_mutex);
8455 /* create next play cond */
8456 g_cond_init(&player->next_play_thread_cond);
8458 /* create next play thread */
8459 player->next_play_thread =
8460 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8461 if (!player->next_play_thread) {
8462 LOGE("failed to create next play thread");
8463 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8464 g_mutex_clear(&player->next_play_thread_mutex);
8465 g_cond_clear(&player->next_play_thread_cond);
8469 ret = _mmplayer_initialize_video_capture(player);
8470 if (ret != MM_ERROR_NONE) {
8471 LOGE("failed to initialize video capture\n");
8475 /* initialize resource manager */
8476 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8477 LOGE("failed to initialize resource manager\n");
8481 if (MMPLAYER_IS_HTTP_PD(player)) {
8482 player->pd_downloader = NULL;
8483 player->pd_file_save_path = NULL;
8486 /* create video bo lock and cond */
8487 g_mutex_init(&player->video_bo_mutex);
8488 g_cond_init(&player->video_bo_cond);
8490 /* create media stream callback mutex */
8491 g_mutex_init(&player->media_stream_cb_lock);
8493 player->streaming_type = STREAMING_SERVICE_NONE;
8495 /* give default value of audio effect setting */
8496 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8497 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8499 player->play_subtitle = FALSE;
8500 player->use_textoverlay = FALSE;
8501 player->play_count = 0;
8502 player->use_decodebin = TRUE;
8503 player->ignore_asyncdone = FALSE;
8504 player->use_deinterleave = FALSE;
8505 player->max_audio_channels = 0;
8506 player->video_share_api_delta = 0;
8507 player->video_share_clock_delta = 0;
8508 player->has_closed_caption = FALSE;
8509 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8510 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8511 player->pending_resume = FALSE;
8512 if (player->ini.dump_element_keyword[0][0] == '\0')
8513 player->ini.set_dump_element_flag = FALSE;
8515 player->ini.set_dump_element_flag = TRUE;
8517 /* set player state to null */
8518 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8519 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8521 return MM_ERROR_NONE;
8525 g_mutex_clear(&player->fsink_lock);
8527 /* free update tag lock */
8528 g_mutex_clear(&player->update_tag_lock);
8531 if (player->repeat_thread) {
8532 player->repeat_thread_exit = TRUE;
8533 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8535 g_thread_join(player->repeat_thread);
8536 player->repeat_thread = NULL;
8538 g_mutex_clear(&player->repeat_thread_mutex);
8539 g_cond_clear(&player->repeat_thread_cond);
8542 /* free next play thread */
8543 if (player->next_play_thread) {
8544 player->next_play_thread_exit = TRUE;
8545 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8547 g_thread_join(player->next_play_thread);
8548 player->next_play_thread = NULL;
8550 g_mutex_clear(&player->next_play_thread_mutex);
8551 g_cond_clear(&player->next_play_thread_cond);
8554 /* release attributes */
8555 _mmplayer_deconstruct_attribute(handle);
8563 __mmplayer_init_gstreamer(mm_player_t* player) // @
8565 static gboolean initialized = FALSE;
8566 static const int max_argc = 50;
8568 gchar** argv = NULL;
8569 gchar** argv2 = NULL;
8575 LOGD("gstreamer already initialized.\n");
8580 argc = malloc(sizeof(int));
8581 argv = malloc(sizeof(gchar*) * max_argc);
8582 argv2 = malloc(sizeof(gchar*) * max_argc);
8584 if (!argc || !argv || !argv2)
8587 memset(argv, 0, sizeof(gchar*) * max_argc);
8588 memset(argv2, 0, sizeof(gchar*) * max_argc);
8592 argv[0] = g_strdup("mmplayer");
8595 for (i = 0; i < 5; i++) {
8596 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8597 if (strlen(player->ini.gst_param[i]) > 0) {
8598 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8603 /* we would not do fork for scanning plugins */
8604 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8607 /* check disable registry scan */
8608 if (player->ini.skip_rescan) {
8609 argv[*argc] = g_strdup("--gst-disable-registry-update");
8613 /* check disable segtrap */
8614 if (player->ini.disable_segtrap) {
8615 argv[*argc] = g_strdup("--gst-disable-segtrap");
8619 LOGD("initializing gstreamer with following parameter\n");
8620 LOGD("argc : %d\n", *argc);
8623 for (i = 0; i < arg_count; i++) {
8625 LOGD("argv[%d] : %s\n", i, argv2[i]);
8629 /* initializing gstreamer */
8630 if (!gst_init_check(argc, &argv, &err)) {
8631 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8638 for (i = 0; i < arg_count; i++) {
8639 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8640 MMPLAYER_FREEIF(argv2[i]);
8643 MMPLAYER_FREEIF(argv);
8644 MMPLAYER_FREEIF(argv2);
8645 MMPLAYER_FREEIF(argc);
8655 for (i = 0; i < arg_count; i++) {
8656 LOGD("free[%d] : %s\n", i, argv2[i]);
8657 MMPLAYER_FREEIF(argv2[i]);
8660 MMPLAYER_FREEIF(argv);
8661 MMPLAYER_FREEIF(argv2);
8662 MMPLAYER_FREEIF(argc);
8668 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8672 if (player->pd_downloader) {
8673 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8674 MMPLAYER_FREEIF(player->pd_downloader);
8677 if (MMPLAYER_IS_HTTP_PD(player)) {
8678 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8679 MMPLAYER_FREEIF(player->pd_file_save_path);
8682 return MM_ERROR_NONE;
8686 __mmplayer_check_async_state_transition(mm_player_t* player)
8688 GstState element_state = GST_STATE_VOID_PENDING;
8689 GstState element_pending_state = GST_STATE_VOID_PENDING;
8690 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8691 GstElement * element = NULL;
8692 gboolean async = FALSE;
8694 /* check player handle */
8695 MMPLAYER_RETURN_IF_FAIL(player &&
8697 player->pipeline->mainbin &&
8698 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8701 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8703 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8704 LOGD("don't need to check the pipeline state");
8708 MMPLAYER_PRINT_STATE(player);
8710 /* wait for state transition */
8711 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8712 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8714 if (ret == GST_STATE_CHANGE_FAILURE) {
8715 LOGE(" [%s] state : %s pending : %s \n",
8716 GST_ELEMENT_NAME(element),
8717 gst_element_state_get_name(element_state),
8718 gst_element_state_get_name(element_pending_state));
8720 /* dump state of all element */
8721 __mmplayer_dump_pipeline_state(player);
8726 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8731 _mmplayer_destroy(MMHandleType handle) // @
8733 mm_player_t* player = MM_PLAYER_CAST(handle);
8737 /* check player handle */
8738 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8740 /* destroy can called at anytime */
8741 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8743 /* check async state transition */
8744 __mmplayer_check_async_state_transition(player);
8746 __mmplayer_destroy_streaming_ext(player);
8748 /* release repeat thread */
8749 if (player->repeat_thread) {
8750 player->repeat_thread_exit = TRUE;
8751 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8753 LOGD("waitting for repeat thread exit\n");
8754 g_thread_join(player->repeat_thread);
8755 g_mutex_clear(&player->repeat_thread_mutex);
8756 g_cond_clear(&player->repeat_thread_cond);
8757 LOGD("repeat thread released\n");
8760 /* release next play thread */
8761 if (player->next_play_thread) {
8762 player->next_play_thread_exit = TRUE;
8763 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8765 LOGD("waitting for next play thread exit\n");
8766 g_thread_join(player->next_play_thread);
8767 g_mutex_clear(&player->next_play_thread_mutex);
8768 g_cond_clear(&player->next_play_thread_cond);
8769 LOGD("next play thread released\n");
8772 _mmplayer_release_video_capture(player);
8774 /* flush any pending asm_cb */
8775 if (player->sound_focus.cb_pending) {
8776 /* set a flag for make sure asm_cb to be returned immediately */
8777 LOGW("asm cb has pending state");
8778 player->sound_focus.exit_cb = TRUE;
8780 /* make sure to release any pending asm_cb which locked by cmd_lock */
8781 MMPLAYER_CMD_UNLOCK(player);
8783 MMPLAYER_CMD_LOCK(player);
8787 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8788 LOGE("failed to deregister asm server\n");
8790 /* de-initialize resource manager */
8791 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8792 LOGE("failed to deinitialize resource manager\n");
8794 #ifdef USE_LAZY_PAUSE
8795 if (player->lazy_pause_event_id) {
8796 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8797 player->lazy_pause_event_id = 0;
8801 if (player->resume_event_id) {
8802 g_source_remove(player->resume_event_id);
8803 player->resume_event_id = 0;
8806 if (player->resumable_cancel_id) {
8807 g_source_remove(player->resumable_cancel_id);
8808 player->resumable_cancel_id = 0;
8811 /* release pipeline */
8812 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8813 LOGE("failed to destory pipeline\n");
8814 return MM_ERROR_PLAYER_INTERNAL;
8817 if (player->is_external_subtitle_present && player->subtitle_language_list) {
8818 g_list_free(player->subtitle_language_list);
8819 player->subtitle_language_list = NULL;
8822 __mmplayer_release_dump_list(player->dump_list);
8824 /* release miscellaneous information.
8825 these info needs to be released after pipeline is destroyed. */
8826 __mmplayer_release_misc_post(player);
8828 /* release attributes */
8829 _mmplayer_deconstruct_attribute(handle);
8831 /* release factories */
8832 __mmplayer_release_factories(player);
8835 g_mutex_clear(&player->fsink_lock);
8838 g_mutex_clear(&player->update_tag_lock);
8840 /* release video bo lock and cond */
8841 g_mutex_clear(&player->video_bo_mutex);
8842 g_cond_clear(&player->video_bo_cond);
8844 /* release media stream callback lock */
8845 g_mutex_clear(&player->media_stream_cb_lock);
8849 return MM_ERROR_NONE;
8853 __mmplayer_realize_streaming_ext(mm_player_t* player)
8855 int ret = MM_ERROR_NONE;
8858 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8860 if (MMPLAYER_IS_HTTP_PD(player)) {
8861 gboolean bret = FALSE;
8863 player->pd_downloader = _mmplayer_create_pd_downloader();
8864 if (!player->pd_downloader) {
8865 LOGE("Unable to create PD Downloader...");
8866 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8869 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8871 if (FALSE == bret) {
8872 LOGE("Unable to create PD Downloader...");
8873 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8882 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8884 mm_player_t* player = (mm_player_t*)hplayer;
8885 MMHandleType attrs = 0;
8886 int ret = MM_ERROR_NONE;
8888 attrs = MMPLAYER_GET_ATTRS(player);
8890 LOGE("fail to get attributes.\n");
8891 return MM_ERROR_PLAYER_INTERNAL;
8894 player->sound_focus.pid = pid;
8896 /* register to asm */
8897 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8898 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8899 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8901 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8902 LOGE("failed to register asm server\n");
8903 return MM_ERROR_POLICY_INTERNAL;
8909 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8911 mm_player_t* player = (mm_player_t*) hplayer;
8915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8917 *pid = player->sound_focus.pid;
8919 LOGD("registered pid[%d] %p", *pid, player);
8923 return MM_ERROR_NONE;
8927 _mmplayer_realize(MMHandleType hplayer) // @
8929 mm_player_t* player = (mm_player_t*)hplayer;
8932 gboolean update_registry = FALSE;
8933 MMHandleType attrs = 0;
8934 int ret = MM_ERROR_NONE;
8938 /* check player handle */
8939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8941 /* check current state */
8942 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8944 attrs = MMPLAYER_GET_ATTRS(player);
8946 LOGE("fail to get attributes.\n");
8947 return MM_ERROR_PLAYER_INTERNAL;
8949 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8950 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8952 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8953 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8955 if (ret != MM_ERROR_NONE) {
8956 LOGE("failed to parse profile\n");
8961 /* FIXIT : we can use thouse in player->profile directly */
8962 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8963 player->mem_buf.buf = (char *)player->profile.mem;
8964 player->mem_buf.len = player->profile.mem_size;
8965 player->mem_buf.offset = 0;
8968 if (uri && (strstr(uri, "es_buff://"))) {
8969 if (strstr(uri, "es_buff://push_mode"))
8970 player->es_player_push_mode = TRUE;
8972 player->es_player_push_mode = FALSE;
8975 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8976 LOGW("mms protocol is not supported format.\n");
8977 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8980 if (MMPLAYER_IS_STREAMING(player))
8981 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8983 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8985 player->smooth_streaming = FALSE;
8986 player->videodec_linked = 0;
8987 player->videosink_linked = 0;
8988 player->audiodec_linked = 0;
8989 player->audiosink_linked = 0;
8990 player->textsink_linked = 0;
8991 player->is_external_subtitle_present = FALSE;
8992 player->is_external_subtitle_added_now = FALSE;
8993 /* set the subtitle ON default */
8994 player->is_subtitle_off = FALSE;
8996 /* registry should be updated for downloadable codec */
8997 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
8999 if (update_registry) {
9000 LOGD("updating registry...\n");
9001 gst_update_registry();
9003 /* then we have to rebuild factories */
9004 __mmplayer_release_factories(player);
9005 __mmplayer_init_factories(player);
9008 /* realize pipeline */
9009 ret = __gst_realize(player);
9010 if (ret != MM_ERROR_NONE)
9011 LOGE("fail to realize the player.\n");
9013 ret = __mmplayer_realize_streaming_ext(player);
9021 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9026 /* destroy can called at anytime */
9027 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9028 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9029 MMPLAYER_FREEIF(player->pd_downloader);
9033 return MM_ERROR_NONE;
9037 _mmplayer_unrealize(MMHandleType hplayer)
9039 mm_player_t* player = (mm_player_t*)hplayer;
9040 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9041 int ret = MM_ERROR_NONE;
9045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9047 /* check current state */
9048 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9050 /* check async state transition */
9051 __mmplayer_check_async_state_transition(player);
9053 __mmplayer_unrealize_streaming_ext(player);
9055 /* unrealize pipeline */
9056 ret = __gst_unrealize(player);
9058 /* set asm stop if success */
9059 if (MM_ERROR_NONE == ret) {
9060 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9061 if (ret != MM_ERROR_NONE)
9062 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9064 if (!player->resource_manager.by_rm_cb &&
9065 _mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9066 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9067 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9068 if (ret != MM_ERROR_NONE)
9069 LOGE("failed to release resource, ret(0x%x)\n", ret);
9073 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9074 if (resource_state == RESOURCE_STATE_PREPARED) {
9075 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9076 if (ret != MM_ERROR_NONE)
9077 LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9081 LOGE("failed and don't change asm state to stop");
9089 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9091 mm_player_t* player = (mm_player_t*)hplayer;
9093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9095 return __gst_set_message_callback(player, callback, user_param);
9099 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9101 mm_player_t *player = (mm_player_t*)hplayer;
9103 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9105 *state = MMPLAYER_CURRENT_STATE(player);
9107 return MM_ERROR_NONE;
9112 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9114 mm_player_t* player = (mm_player_t*) hplayer;
9115 GstElement* vol_element = NULL;
9120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9122 LOGD("volume [L]=%f:[R]=%f\n",
9123 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9125 /* invalid factor range or not */
9126 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9127 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9128 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9129 return MM_ERROR_INVALID_ARGUMENT;
9133 /* not support to set other value into each channel */
9134 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9135 return MM_ERROR_INVALID_ARGUMENT;
9137 /* Save volume to handle. Currently the first array element will be saved. */
9138 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9140 /* check pipeline handle */
9141 if (!player->pipeline || !player->pipeline->audiobin) {
9142 LOGD("audiobin is not created yet\n");
9143 LOGD("but, current stored volume will be set when it's created.\n");
9145 /* NOTE : stored volume will be used in create_audiobin
9146 * returning MM_ERROR_NONE here makes application to able to
9147 * set volume at anytime.
9149 return MM_ERROR_NONE;
9152 /* setting volume to volume element */
9153 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9156 LOGD("volume is set [%f]\n", player->sound.volume);
9157 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9162 return MM_ERROR_NONE;
9167 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9169 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(volume, MM_ERROR_INVALID_ARGUMENT);
9177 /* returning stored volume */
9178 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9179 volume->level[i] = player->sound.volume;
9183 return MM_ERROR_NONE;
9189 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9191 mm_player_t* player = (mm_player_t*) hplayer;
9192 GstElement* vol_element = NULL;
9196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9198 /* mute value shoud 0 or 1 */
9199 if (mute != 0 && mute != 1) {
9200 LOGE("bad mute value\n");
9202 /* FIXIT : definitly, we need _BAD_PARAM error code */
9203 return MM_ERROR_INVALID_ARGUMENT;
9206 player->sound.mute = mute;
9208 /* just hold mute value if pipeline is not ready */
9209 if (!player->pipeline || !player->pipeline->audiobin) {
9210 LOGD("pipeline is not ready. holding mute value\n");
9211 return MM_ERROR_NONE;
9214 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9216 /* NOTE : volume will only created when the bt is enabled */
9218 LOGD("mute : %d\n", mute);
9219 g_object_set(vol_element, "mute", mute, NULL);
9221 LOGD("volume elemnet is not created. using volume in audiosink\n");
9225 return MM_ERROR_NONE;
9229 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9231 mm_player_t* player = (mm_player_t*) hplayer;
9235 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9236 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9238 /* just hold mute value if pipeline is not ready */
9239 if (!player->pipeline || !player->pipeline->audiobin) {
9240 LOGD("pipeline is not ready. returning stored value\n");
9241 *pmute = player->sound.mute;
9242 return MM_ERROR_NONE;
9245 *pmute = player->sound.mute;
9249 return MM_ERROR_NONE;
9253 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9255 mm_player_t* player = (mm_player_t*) hplayer;
9259 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9261 player->video_stream_changed_cb = callback;
9262 player->video_stream_changed_cb_user_param = user_param;
9263 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9267 return MM_ERROR_NONE;
9271 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9273 mm_player_t* player = (mm_player_t*) hplayer;
9277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9279 player->audio_stream_changed_cb = callback;
9280 player->audio_stream_changed_cb_user_param = user_param;
9281 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9285 return MM_ERROR_NONE;
9289 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param) // @
9291 mm_player_t* player = (mm_player_t*) hplayer;
9295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9297 player->audio_stream_render_cb_ex = callback;
9298 player->audio_stream_cb_user_param = user_param;
9299 player->audio_stream_sink_sync = sync;
9300 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);
9304 return MM_ERROR_NONE;
9308 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9310 mm_player_t* player = (mm_player_t*) hplayer;
9314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9316 if (callback && !player->bufmgr)
9317 player->bufmgr = tbm_bufmgr_init(-1);
9319 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9320 player->video_stream_cb = callback;
9321 player->video_stream_cb_user_param = user_param;
9323 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9327 return MM_ERROR_NONE;
9331 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9333 mm_player_t* player = (mm_player_t*) hplayer;
9337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9339 player->audio_stream_cb = callback;
9340 player->audio_stream_cb_user_param = user_param;
9341 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9345 return MM_ERROR_NONE;
9350 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9352 mm_player_t* player = (mm_player_t*) hplayer;
9356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9358 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9359 return MM_ERROR_PLAYER_INVALID_STATE;
9361 LOGD("pre buffer size : %d sec\n", second);
9364 LOGE("bad size value\n");
9365 return MM_ERROR_INVALID_ARGUMENT;
9368 if (player->streamer == NULL) {
9369 player->streamer = __mm_player_streaming_create();
9370 __mm_player_streaming_initialize(player->streamer);
9373 player->streamer->buffering_req.initial_second = second;
9377 return MM_ERROR_NONE;
9382 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9384 mm_player_t* player = (mm_player_t*) hplayer;
9388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9390 LOGD("mode %d\n", mode);
9392 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9393 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9394 return MM_ERROR_INVALID_ARGUMENT;
9396 if (player->streamer == NULL) {
9397 player->streamer = __mm_player_streaming_create();
9398 __mm_player_streaming_initialize(player->streamer);
9401 player->streamer->buffering_req.mode = mode;
9404 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9405 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9406 player->streamer->buffering_req.runtime_second = second;
9410 return MM_ERROR_NONE;
9414 __mmplayer_start_streaming_ext(mm_player_t *player)
9416 gint ret = MM_ERROR_NONE;
9419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9421 if (MMPLAYER_IS_HTTP_PD(player)) {
9422 if (!player->pd_downloader) {
9423 ret = __mmplayer_realize_streaming_ext(player);
9425 if (ret != MM_ERROR_NONE) {
9426 LOGE("failed to realize streaming ext\n");
9431 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9432 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9434 LOGE("ERROR while starting PD...\n");
9435 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9437 ret = MM_ERROR_NONE;
9446 _mmplayer_start(MMHandleType hplayer) // @
9448 mm_player_t* player = (mm_player_t*) hplayer;
9449 gint ret = MM_ERROR_NONE;
9453 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9455 /* check current state */
9456 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9458 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9459 if (ret != MM_ERROR_NONE) {
9460 LOGE("failed to acquire sound focus.\n");
9464 /* NOTE : we should check and create pipeline again if not created as we destroy
9465 * whole pipeline when stopping in streamming playback
9467 if (!player->pipeline) {
9468 ret = __gst_realize(player);
9469 if (MM_ERROR_NONE != ret) {
9470 LOGE("failed to realize before starting. only in streamming\n");
9476 ret = __mmplayer_start_streaming_ext(player);
9477 if (ret != MM_ERROR_NONE)
9478 LOGE("failed to start streaming ext \n");
9480 /* start pipeline */
9481 ret = __gst_start(player);
9482 if (ret != MM_ERROR_NONE)
9483 LOGE("failed to start player.\n");
9490 /* NOTE: post "not supported codec message" to application
9491 * when one codec is not found during AUTOPLUGGING in MSL.
9492 * So, it's separated with error of __mmplayer_gst_callback().
9493 * And, if any codec is not found, don't send message here.
9494 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9497 __mmplayer_handle_missed_plugin(mm_player_t* player)
9499 MMMessageParamType msg_param;
9500 memset(&msg_param, 0, sizeof(MMMessageParamType));
9501 gboolean post_msg_direct = FALSE;
9505 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9507 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9508 player->not_supported_codec, player->can_support_codec);
9510 if (player->not_found_demuxer) {
9511 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9512 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9514 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9515 MMPLAYER_FREEIF(msg_param.data);
9517 return MM_ERROR_NONE;
9520 if (player->not_supported_codec) {
9521 if (player->can_support_codec) {
9522 // There is one codec to play
9523 post_msg_direct = TRUE;
9525 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9526 post_msg_direct = TRUE;
9529 if (post_msg_direct) {
9530 MMMessageParamType msg_param;
9531 memset(&msg_param, 0, sizeof(MMMessageParamType));
9533 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9534 LOGW("not found AUDIO codec, posting error code to application.\n");
9536 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9537 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9538 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9539 LOGW("not found VIDEO codec, posting error code to application.\n");
9541 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9542 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9545 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9547 MMPLAYER_FREEIF(msg_param.data);
9549 return MM_ERROR_NONE;
9551 // no any supported codec case
9552 LOGW("not found any codec, posting error code to application.\n");
9554 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9555 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9556 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9558 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9559 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9562 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9564 MMPLAYER_FREEIF(msg_param.data);
9570 return MM_ERROR_NONE;
9573 static void __mmplayer_check_pipeline(mm_player_t* player)
9575 GstState element_state = GST_STATE_VOID_PENDING;
9576 GstState element_pending_state = GST_STATE_VOID_PENDING;
9578 int ret = MM_ERROR_NONE;
9580 if (player->gapless.reconfigure) {
9581 LOGW("pipeline is under construction.\n");
9583 MMPLAYER_PLAYBACK_LOCK(player);
9584 MMPLAYER_PLAYBACK_UNLOCK(player);
9586 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9588 /* wait for state transition */
9589 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9591 if (ret == GST_STATE_CHANGE_FAILURE)
9592 LOGE("failed to change pipeline state within %d sec\n", timeout);
9596 /* NOTE : it should be able to call 'stop' anytime*/
9598 _mmplayer_stop(MMHandleType hplayer) // @
9600 mm_player_t* player = (mm_player_t*)hplayer;
9601 int ret = MM_ERROR_NONE;
9605 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9607 /* check current state */
9608 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9610 /* check pipline building state */
9611 __mmplayer_check_pipeline(player);
9612 __mmplayer_reset_gapless_state(player);
9614 /* NOTE : application should not wait for EOS after calling STOP */
9615 __mmplayer_cancel_eos_timer(player);
9617 __mmplayer_unrealize_streaming_ext(player);
9620 player->doing_seek = FALSE;
9623 ret = __gst_stop(player);
9625 if (ret != MM_ERROR_NONE)
9626 LOGE("failed to stop player.\n");
9634 _mmplayer_pause(MMHandleType hplayer) // @
9636 mm_player_t* player = (mm_player_t*)hplayer;
9637 gint64 pos_msec = 0;
9638 gboolean async = FALSE;
9639 gint ret = MM_ERROR_NONE;
9643 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9645 /* check current state */
9646 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9648 /* check pipline building state */
9649 __mmplayer_check_pipeline(player);
9651 switch (MMPLAYER_CURRENT_STATE(player)) {
9652 case MM_PLAYER_STATE_READY:
9654 /* check prepare async or not.
9655 * In the case of streaming playback, it's recommned to avoid blocking wait.
9657 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9658 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9660 /* Changing back sync of rtspsrc to async */
9661 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9662 LOGD("async prepare working mode for rtsp");
9668 case MM_PLAYER_STATE_PLAYING:
9670 /* NOTE : store current point to overcome some bad operation
9671 *(returning zero when getting current position in paused state) of some
9674 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9675 LOGW("getting current position failed in paused\n");
9677 player->last_position = pos_msec;
9679 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9680 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9681 This causes problem is position calculation during normal pause resume scenarios also.
9682 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9683 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9684 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9685 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9691 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9692 LOGD("doing async pause in case of ms buff src");
9696 /* pause pipeline */
9697 ret = __gst_pause(player, async);
9699 if (ret != MM_ERROR_NONE)
9700 LOGE("failed to pause player. ret : 0x%x\n", ret);
9702 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9703 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9704 LOGE("failed to update display_rotation");
9713 _mmplayer_resume(MMHandleType hplayer)
9715 mm_player_t* player = (mm_player_t*)hplayer;
9716 int ret = MM_ERROR_NONE;
9717 gboolean async = FALSE;
9721 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9723 /* Changing back sync mode rtspsrc to async */
9724 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9725 LOGD("async resume for rtsp case");
9729 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9730 if (ret != MM_ERROR_NONE) {
9731 LOGE("failed to acquire sound focus.\n");
9735 /* check current state */
9736 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9738 ret = __gst_resume(player, async);
9740 if (ret != MM_ERROR_NONE)
9741 LOGE("failed to resume player.\n");
9749 __mmplayer_set_play_count(mm_player_t* player, gint count)
9751 MMHandleType attrs = 0;
9755 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9757 attrs = MMPLAYER_GET_ATTRS(player);
9759 LOGE("fail to get attributes.\n");
9760 return MM_ERROR_PLAYER_INTERNAL;
9763 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9764 if (mmf_attrs_commit(attrs)) /* return -1 if error */
9765 LOGE("failed to commit\n");
9769 return MM_ERROR_NONE;
9773 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9775 mm_player_t* player = (mm_player_t*)hplayer;
9776 gint64 start_pos = 0;
9782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9783 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9785 player->section_repeat = TRUE;
9786 player->section_repeat_start = start;
9787 player->section_repeat_end = end;
9789 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9790 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9792 __mmplayer_set_play_count(player, infinity);
9794 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9795 player->playback_rate,
9797 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9798 GST_SEEK_TYPE_SET, start_pos,
9799 GST_SEEK_TYPE_SET, end_pos))) {
9800 LOGE("failed to activate section repeat\n");
9802 return MM_ERROR_PLAYER_SEEK;
9805 LOGD("succeeded to set section repeat from %d to %d\n",
9806 player->section_repeat_start, player->section_repeat_end);
9810 return MM_ERROR_NONE;
9814 __mmplayer_set_pcm_extraction(mm_player_t* player)
9816 gint64 start_nsec = 0;
9817 gint64 end_nsec = 0;
9818 gint64 dur_nsec = 0;
9819 gint64 dur_msec = 0;
9820 int required_start = 0;
9821 int required_end = 0;
9826 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9828 mm_attrs_multiple_get(player->attrs,
9830 "pcm_extraction_start_msec", &required_start,
9831 "pcm_extraction_end_msec", &required_end,
9834 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9836 if (required_start == 0 && required_end == 0) {
9837 LOGD("extracting entire stream");
9838 return MM_ERROR_NONE;
9839 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9840 LOGD("invalid range for pcm extraction");
9841 return MM_ERROR_INVALID_ARGUMENT;
9845 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9847 LOGE("failed to get duration");
9848 return MM_ERROR_PLAYER_INTERNAL;
9850 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9852 if (dur_msec < required_end) {
9854 LOGD("invalid end pos for pcm extraction");
9855 return MM_ERROR_INVALID_ARGUMENT;
9858 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9859 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9861 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9864 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9865 GST_SEEK_TYPE_SET, start_nsec,
9866 GST_SEEK_TYPE_SET, end_nsec))) {
9867 LOGE("failed to seek for pcm extraction\n");
9869 return MM_ERROR_PLAYER_SEEK;
9872 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9876 return MM_ERROR_NONE;
9880 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9882 mm_player_t* player = (mm_player_t*)hplayer;
9888 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9890 player->section_repeat = FALSE;
9892 __mmplayer_set_play_count(player, onetime);
9894 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9896 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9899 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9900 GST_SEEK_TYPE_SET, cur_pos,
9901 GST_SEEK_TYPE_SET, player->duration))) {
9902 LOGE("failed to deactivate section repeat\n");
9904 return MM_ERROR_PLAYER_SEEK;
9909 return MM_ERROR_NONE;
9913 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9915 mm_player_t* player = (mm_player_t*)hplayer;
9916 gint64 pos_msec = 0;
9917 int ret = MM_ERROR_NONE;
9919 signed long long start = 0, stop = 0;
9920 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9924 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9926 /* The sound of video is not supported under 0.0 and over 2.0. */
9927 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9928 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9931 _mmplayer_set_mute(hplayer, mute);
9933 if (player->playback_rate == rate)
9934 return MM_ERROR_NONE;
9936 /* If the position is reached at start potion during fast backward, EOS is posted.
9937 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9939 player->playback_rate = rate;
9941 current_state = MMPLAYER_CURRENT_STATE(player);
9943 if (current_state != MM_PLAYER_STATE_PAUSED)
9944 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9946 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9948 if ((current_state == MM_PLAYER_STATE_PAUSED)
9949 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9950 LOGW("returning last point : %lld\n", player->last_position);
9951 pos_msec = player->last_position;
9957 stop = GST_CLOCK_TIME_NONE;
9959 start = GST_CLOCK_TIME_NONE;
9962 if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9965 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9966 GST_SEEK_TYPE_SET, start,
9967 GST_SEEK_TYPE_SET, stop))) {
9968 LOGE("failed to set speed playback\n");
9969 return MM_ERROR_PLAYER_SEEK;
9972 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9976 return MM_ERROR_NONE;;
9980 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
9982 mm_player_t* player = (mm_player_t*)hplayer;
9983 int ret = MM_ERROR_NONE;
9987 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9989 /* check pipline building state */
9990 __mmplayer_check_pipeline(player);
9992 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10000 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
10002 mm_player_t* player = (mm_player_t*)hplayer;
10003 int ret = MM_ERROR_NONE;
10005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10007 ret = __gst_get_position(player, format, position);
10013 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10015 mm_player_t* player = (mm_player_t*)hplayer;
10016 int ret = MM_ERROR_NONE;
10018 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10020 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10026 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10028 mm_player_t* player = (mm_player_t*)hplayer;
10029 int ret = MM_ERROR_NONE;
10033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10035 ret = __gst_adjust_subtitle_position(player, format, position);
10042 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10044 mm_player_t* player = (mm_player_t*)hplayer;
10045 int ret = MM_ERROR_NONE;
10049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10051 ret = __gst_adjust_video_position(player, offset);
10059 __mmplayer_is_midi_type(gchar* str_caps)
10061 if ((g_strrstr(str_caps, "audio/midi")) ||
10062 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10063 (g_strrstr(str_caps, "application/x-smaf")) ||
10064 (g_strrstr(str_caps, "audio/x-imelody")) ||
10065 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10066 (g_strrstr(str_caps, "audio/xmf")) ||
10067 (g_strrstr(str_caps, "audio/mxmf"))) {
10076 __mmplayer_is_only_mp3_type(gchar *str_caps)
10078 if (g_strrstr(str_caps, "application/x-id3") ||
10079 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10085 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10087 GstStructure* caps_structure = NULL;
10088 gint samplerate = 0;
10092 MMPLAYER_RETURN_IF_FAIL(player && caps);
10094 caps_structure = gst_caps_get_structure(caps, 0);
10096 /* set stream information */
10097 gst_structure_get_int(caps_structure, "rate", &samplerate);
10098 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10100 gst_structure_get_int(caps_structure, "channels", &channels);
10101 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10103 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10107 __mmplayer_update_content_type_info(mm_player_t* player)
10110 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10112 if (__mmplayer_is_midi_type(player->type)) {
10113 player->bypass_audio_effect = TRUE;
10114 } else if (g_strrstr(player->type, "application/x-hls")) {
10115 /* If it can't know exact type when it parses uri because of redirection case,
10116 * it will be fixed by typefinder or when doing autoplugging.
10118 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10119 if (player->streamer) {
10120 player->streamer->is_adaptive_streaming = TRUE;
10121 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10122 player->streamer->buffering_req.runtime_second = 5;
10124 } else if (g_strrstr(player->type, "application/dash+xml")) {
10125 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10132 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10133 GstCaps *caps, gpointer data)
10135 mm_player_t* player = (mm_player_t*)data;
10136 GstPad* pad = NULL;
10140 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10142 /* store type string */
10143 MMPLAYER_FREEIF(player->type);
10144 player->type = gst_caps_to_string(caps);
10146 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10148 if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10149 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10150 (g_strrstr(player->type, "audio/x-raw-int"))) {
10151 LOGE("not support media format\n");
10153 if (player->msg_posted == FALSE) {
10154 MMMessageParamType msg_param;
10155 memset(&msg_param, 0, sizeof(MMMessageParamType));
10157 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10158 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10160 /* don't post more if one was sent already */
10161 player->msg_posted = TRUE;
10166 __mmplayer_update_content_type_info(player);
10168 pad = gst_element_get_static_pad(tf, "src");
10170 LOGE("fail to get typefind src pad.\n");
10174 if (player->use_decodebin) {
10175 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10176 gboolean async = FALSE;
10177 LOGE("failed to autoplug %s\n", player->type);
10179 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10181 if (async && player->msg_posted == FALSE)
10182 __mmplayer_handle_missed_plugin(player);
10188 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10189 gboolean async = FALSE;
10190 LOGE("failed to autoplug %s\n", player->type);
10192 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10194 if (async && player->msg_posted == FALSE)
10195 __mmplayer_handle_missed_plugin(player);
10200 /* finish autopluging if no dynamic pad waiting */
10201 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10202 if (!MMPLAYER_IS_RTSP_STREAMING(player))
10203 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10208 gst_object_unref(GST_OBJECT(pad));
10215 static GstElement *
10216 __mmplayer_create_decodebin(mm_player_t* player)
10218 GstElement *decodebin = NULL;
10222 /* create decodebin */
10223 decodebin = gst_element_factory_make("decodebin", NULL);
10226 LOGE("fail to create decodebin\n");
10230 /* raw pad handling signal */
10231 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10232 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10234 /* no-more-pad pad handling signal */
10235 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10236 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10238 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10239 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10241 /* This signal is emitted when a pad for which there is no further possible
10242 decoding is added to the decodebin.*/
10243 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10244 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10246 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10247 before looking for any elements that can handle that stream.*/
10248 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10249 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10251 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10252 before looking for any elements that can handle that stream.*/
10253 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10254 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10256 /* This signal is emitted once decodebin has finished decoding all the data.*/
10257 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10258 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10260 /* This signal is emitted when a element is added to the bin.*/
10261 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10262 G_CALLBACK(__mmplayer_gst_element_added), player);
10269 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10271 MMPlayerGstElement* mainbin = NULL;
10272 GstElement* decodebin = NULL;
10273 GstElement* queue2 = NULL;
10274 GstPad* sinkpad = NULL;
10275 GstPad* qsrcpad = NULL;
10276 gchar *caps_str = NULL;
10277 gint64 dur_bytes = 0L;
10279 guint max_buffer_size_bytes = 0;
10280 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10285 mainbin = player->pipeline->mainbin;
10287 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10288 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10289 LOGD("creating http streaming buffering queue(queue2)\n");
10291 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10292 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10294 queue2 = gst_element_factory_make("queue2", "queue2");
10296 LOGE("failed to create buffering queue element\n");
10300 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10301 LOGE("failed to add buffering queue\n");
10305 sinkpad = gst_element_get_static_pad(queue2, "sink");
10306 qsrcpad = gst_element_get_static_pad(queue2, "src");
10308 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10309 LOGE("failed to link buffering queue\n");
10313 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10314 LOGE("fail to get duration.\n");
10316 LOGD("dur_bytes = %lld\n", dur_bytes);
10318 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10320 if (dur_bytes > 0) {
10321 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10322 type = MUXED_BUFFER_TYPE_FILE;
10324 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10325 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10331 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10332 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10333 if (!g_strrstr(player->type, "video/mpegts")) {
10334 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10335 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10337 __mm_player_streaming_set_queue2(player->streamer,
10340 max_buffer_size_bytes,
10341 player->ini.http_buffering_time,
10343 player->ini.http_buffering_limit, // no meaning
10345 player->http_file_buffering_path,
10346 (guint64)dur_bytes);
10349 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10350 LOGE("failed to sync queue2 state with parent\n");
10356 gst_object_unref(GST_OBJECT(sinkpad));
10358 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10359 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10363 /* create decodebin */
10364 decodebin = __mmplayer_create_decodebin(player);
10367 LOGE("can not create autoplug element\n");
10371 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10372 LOGE("failed to add decodebin\n");
10376 /* to force caps on the decodebin element and avoid reparsing stuff by
10377 * typefind. It also avoids a deadlock in the way typefind activates pads in
10378 * the state change */
10379 g_object_set(decodebin, "sink-caps", caps, NULL);
10381 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10383 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10384 LOGE("failed to link decodebin\n");
10388 gst_object_unref(GST_OBJECT(sinkpad));
10390 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10391 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10393 /* set decodebin property about buffer in streaming playback. *
10394 * in case of hls, it does not need to have big buffer *
10395 * because it is kind of adaptive streaming. */
10396 if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10397 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10398 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10399 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10400 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10402 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10403 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10404 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10407 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10408 "high-percent", (gint)player->ini.http_buffering_limit,
10409 "low-percent", 1, // 1%
10410 "max-size-bytes", max_size_bytes,
10411 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10412 "max-size-buffers", 0, NULL); // disable or automatic
10415 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10416 LOGE("failed to sync decodebin state with parent\n");
10426 MMPLAYER_FREEIF(caps_str);
10429 gst_object_unref(GST_OBJECT(sinkpad));
10432 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10433 * You need to explicitly set elements to the NULL state before
10434 * dropping the final reference, to allow them to clean up.
10436 gst_element_set_state(queue2, GST_STATE_NULL);
10438 /* And, it still has a parent "player".
10439 * You need to let the parent manage the object instead of unreffing the object directly.
10441 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10442 gst_object_unref(queue2);
10447 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10448 * You need to explicitly set elements to the NULL state before
10449 * dropping the final reference, to allow them to clean up.
10451 gst_element_set_state(decodebin, GST_STATE_NULL);
10453 /* And, it still has a parent "player".
10454 * You need to let the parent manage the object instead of unreffing the object directly.
10457 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10458 gst_object_unref(decodebin);
10465 /* it will return first created element */
10467 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10469 MMPlayerGstElement* mainbin = NULL;
10470 const char* mime = NULL;
10471 const GList* item = NULL;
10472 const gchar* klass = NULL;
10473 GstCaps* res = NULL;
10474 gboolean skip = FALSE;
10475 GstPad* queue_pad = NULL;
10476 GstElement* queue = NULL;
10477 GstElement *element = NULL;
10481 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10483 mainbin = player->pipeline->mainbin;
10485 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10487 /* return if we got raw output */
10488 if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10489 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10491 element = (GstElement*)gst_pad_get_parent(pad);
10492 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10493 * No queue will be added. I think it can caused breaking sound when playing raw audio
10494 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10495 * Anyway, currentely raw-queue seems not necessary.
10498 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10499 * has linked. if so, we need to add queue for quality of output. note that
10500 * decodebin also has same problem.
10502 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10504 /* add queue if needed */
10505 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10506 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) {
10507 LOGD("adding raw queue\n");
10509 queue = gst_element_factory_make("queue", NULL);
10511 LOGW("failed to create queue\n");
10516 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10517 LOGW("failed to set state READY to queue\n");
10521 /* add to pipeline */
10522 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10523 LOGW("failed to add queue\n");
10528 queue_pad = gst_element_get_static_pad(queue, "sink");
10530 if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10531 LOGW("failed to link queue\n");
10534 gst_object_unref(GST_OBJECT(queue_pad));
10538 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10539 LOGW("failed to set state PAUSED to queue\n");
10543 /* replace given pad to queue:src */
10544 pad = gst_element_get_static_pad(queue, "src");
10546 LOGW("failed to get pad from queue\n");
10551 /* check if player can do start continually */
10552 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10554 if (__mmplayer_link_sink(player, pad))
10555 __mmplayer_gst_decode_callback(element, pad, player);
10557 gst_object_unref(GST_OBJECT(element));
10563 item = player->factories;
10564 for (; item != NULL; item = item->next) {
10565 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10571 /* filtering exclude keyword */
10572 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10573 if (g_strrstr(GST_OBJECT_NAME(factory),
10574 player->ini.exclude_element_keyword[idx])) {
10575 LOGW("skipping [%s] by exculde keyword [%s]\n",
10576 GST_OBJECT_NAME(factory),
10577 player->ini.exclude_element_keyword[idx]);
10584 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10585 // omx decoder can not support mpeg4video data partitioned
10586 // rtsp streaming didn't know mpeg4video data partitioned format
10587 // so, if rtsp playback, player will skip omx_mpeg4dec.
10588 LOGW("skipping [%s] when rtsp streaming \n",
10589 GST_OBJECT_NAME(factory));
10594 if (skip) continue;
10596 /* check factory class for filtering */
10597 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10599 /*parsers are not required in case of external feeder*/
10600 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10603 /* NOTE : msl don't need to use image plugins.
10604 * So, those plugins should be skipped for error handling.
10606 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10607 LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10611 /* check pad compatability */
10612 for (pads = gst_element_factory_get_static_pad_templates(factory);
10613 pads != NULL; pads = pads->next) {
10614 GstStaticPadTemplate *temp1 = pads->data;
10615 GstCaps* static_caps = NULL;
10617 if (temp1->direction != GST_PAD_SINK
10618 || temp1->presence != GST_PAD_ALWAYS)
10621 /* using existing caps */
10622 if (GST_IS_CAPS(&temp1->static_caps.caps))
10623 static_caps = gst_caps_ref(temp1->static_caps.caps);
10626 static_caps = gst_caps_from_string(temp1->static_caps.string);
10628 res = gst_caps_intersect((GstCaps*)caps, static_caps);
10629 gst_caps_unref(static_caps);
10630 static_caps = NULL;
10632 if (res && !gst_caps_is_empty(res)) {
10633 GstElement *new_element;
10634 GList *elements = player->parsers;
10635 char *name_template = g_strdup(temp1->name_template);
10636 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10637 gst_caps_unref(res);
10639 /* check ALP Codec can be used or not */
10640 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10641 /* consider mp3 audio only */
10642 if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10643 /* try to use ALP decoder first instead of selected decoder */
10644 GstElement *element = NULL;
10645 GstElementFactory * element_facory;
10646 gchar *path = NULL;
10647 guint64 data_size = 0;
10648 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
10651 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10653 if (stat(path, &sb) == 0)
10654 data_size = (guint64)sb.st_size;
10655 LOGD("file size : %u", data_size);
10657 if (data_size > MIN_THRESHOLD_SIZE) {
10658 LOGD("checking if ALP can be used or not");
10659 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10661 /* check availability because multi-instance is not supported */
10662 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10664 if (ret != GST_STATE_CHANGE_SUCCESS) {
10665 // use just selected decoder
10666 gst_object_unref(element);
10667 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10668 // replace facotry to use omx
10670 gst_element_set_state(element, GST_STATE_NULL);
10671 gst_object_unref(element);
10673 element_facory = gst_element_factory_find("omx_mp3dec");
10674 /* replace, otherwise use selected thing instead */
10675 if (element_facory) {
10676 factory = element_facory;
10677 name_to_plug = GST_OBJECT_NAME(factory);
10683 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10684 if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10685 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10687 if (strncasecmp(env, "yes", 3) == 0) {
10688 LOGD("skipping [%s] by disabled\n", name_to_plug);
10689 MMPLAYER_FREEIF(name_template);
10696 LOGD("found %s to plug\n", name_to_plug);
10698 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10699 if (!new_element) {
10700 LOGE("failed to create element [%s]. continue with next.\n",
10701 GST_OBJECT_NAME(factory));
10703 MMPLAYER_FREEIF(name_template);
10708 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10709 * because parser can accept its own output as input.
10711 if (g_strrstr(klass, "Parser")) {
10712 gchar *selected = NULL;
10714 for (; elements; elements = g_list_next(elements)) {
10715 gchar *element_name = elements->data;
10717 if (g_strrstr(element_name, name_to_plug)) {
10718 LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10724 MMPLAYER_FREEIF(name_template);
10728 selected = g_strdup(name_to_plug);
10729 player->parsers = g_list_append(player->parsers, selected);
10732 /* store specific handles for futher control */
10733 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10734 /* FIXIT : first value will be overwritten if there's more
10735 * than 1 demuxer/parser
10737 LOGD("plugged element is demuxer. take it\n");
10738 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10739 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10741 /*Added for multi audio support */
10742 if (g_strrstr(klass, "Demux")) {
10743 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10744 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10746 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10747 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10748 this code should be removed after mpegtsdemux is fixed */
10749 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10750 LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10751 player->no_more_pad = TRUE;
10754 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10755 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10756 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10757 if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10758 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10759 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10760 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10761 } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10762 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10763 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10764 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10766 /* NOTE : IF one codec is found, add it to supported_codec and remove from
10767 * missing plugin. Both of them are used to check what's supported codec
10768 * before returning result of play start. And, missing plugin should be
10769 * updated here for multi track files.
10771 if (g_str_has_prefix(mime, "video")) {
10772 GstPad *src_pad = NULL;
10773 GstPadTemplate *pad_templ = NULL;
10774 GstCaps *caps = NULL;
10775 gchar *caps_str = NULL;
10777 LOGD("found VIDEO decoder\n");
10778 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10779 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10781 src_pad = gst_element_get_static_pad(new_element, "src");
10782 pad_templ = gst_pad_get_pad_template(src_pad);
10783 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10785 caps_str = gst_caps_to_string(caps);
10788 MMPLAYER_FREEIF(caps_str);
10789 gst_object_unref(src_pad);
10790 } else if (g_str_has_prefix(mime, "audio")) {
10791 LOGD("found AUDIO decoder\n");
10792 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10793 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10797 if (!__mmplayer_close_link(player, pad, new_element,
10798 name_template, gst_element_factory_get_static_pad_templates(factory))) {
10799 MMPLAYER_FREEIF(name_template);
10800 if (player->keep_detecting_vcodec)
10803 /* Link is failed even though a supportable codec is found. */
10804 __mmplayer_check_not_supported_codec(player, klass, mime);
10806 LOGE("failed to call _close_link\n");
10810 MMPLAYER_FREEIF(name_template);
10814 gst_caps_unref(res);
10819 /* There is no available codec. */
10820 __mmplayer_check_not_supported_codec(player, klass, mime);
10828 gst_object_unref(queue);
10831 gst_object_unref(queue_pad);
10834 gst_object_unref(element);
10841 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10845 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10846 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10848 LOGD("class : %s, mime : %s \n", factory_class, mime);
10850 /* add missing plugin */
10851 /* NOTE : msl should check missing plugin for image mime type.
10852 * Some motion jpeg clips can have playable audio track.
10853 * So, msl have to play audio after displaying popup written video format not supported.
10855 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10856 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10857 LOGD("not found demuxer\n");
10858 player->not_found_demuxer = TRUE;
10859 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10865 if (!g_strrstr(factory_class, "Demuxer")) {
10866 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10867 LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10868 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10870 /* check that clip have multi tracks or not */
10871 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10872 LOGD("video plugin is already linked\n");
10874 LOGW("add VIDEO to missing plugin\n");
10875 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10877 } else if (g_str_has_prefix(mime, "audio")) {
10878 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10879 LOGD("audio plugin is already linked\n");
10881 LOGW("add AUDIO to missing plugin\n");
10882 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10890 return MM_ERROR_NONE;
10895 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10897 mm_player_t* player = (mm_player_t*)data;
10901 MMPLAYER_RETURN_IF_FAIL(player);
10903 /* remove fakesink. */
10904 if (!__mmplayer_gst_remove_fakesink(player,
10905 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10906 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10907 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10908 * source element are not same. To overcome this situation, this function will called
10909 * several places and several times. Therefore, this is not an error case.
10914 LOGD("pipeline has completely constructed\n");
10916 if ((player->ini.async_start) &&
10917 (player->msg_posted == FALSE) &&
10918 (player->cmd >= MMPLAYER_COMMAND_START))
10919 __mmplayer_handle_missed_plugin(player);
10921 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10925 __mmplayer_verify_next_play_path(mm_player_t *player)
10927 MMHandleType attrs = 0;
10928 MMPlayerParseProfile profile;
10929 gint uri_idx = 0, check_cnt = 0;
10931 gint mode = MM_PLAYER_PD_MODE_NONE;
10935 guint num_of_list = 0;
10936 static int profile_tv = -1;
10940 LOGD("checking for gapless play");
10942 if (player->pipeline->textbin) {
10943 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10947 attrs = MMPLAYER_GET_ATTRS(player);
10949 LOGE("fail to get attributes.\n");
10953 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10955 if (__builtin_expect(profile_tv == -1, 0)) {
10957 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10958 switch (*profileName) {
10968 /* gapless playback is not supported in case of video at TV profile. */
10969 if (profile_tv && video) {
10970 LOGW("not support video gapless playback");
10974 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10975 if (mode == TRUE) {
10981 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10982 LOGE("can not get play count\n");
10984 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10985 LOGE("can not get gapless mode\n");
10987 if (video && !gapless) {
10988 LOGW("not enabled video gapless playback");
10992 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10996 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
11000 num_of_list = g_list_length(player->uri_info.uri_list);
11002 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11004 if (num_of_list == 0) {
11005 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11006 LOGE("can not get profile_uri\n");
11011 LOGE("uri list is empty.\n");
11015 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11016 LOGD("add original path : %s ", uri);
11022 uri_idx = player->uri_info.uri_idx;
11027 if (check_cnt > num_of_list) {
11028 LOGE("there is no valid uri.");
11032 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11034 if (uri_idx < num_of_list-1) {
11037 if ((count <= 1) && (count != -1)) {
11038 LOGD("no repeat.");
11040 } else if (count > 1) {
11041 /* decrease play count */
11042 /* we succeeded to rewind. update play count and then wait for next EOS */
11045 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11047 /* commit attribute */
11048 if (mmf_attrs_commit(attrs))
11049 LOGE("failed to commit attribute\n");
11052 /* count < 0 : repeat continually */
11056 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11057 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11060 LOGW("next uri does not exist\n");
11064 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11065 LOGE("failed to parse profile\n");
11069 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11070 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11071 LOGW("uri type is not supported(%d).", profile.uri_type);
11078 player->uri_info.uri_idx = uri_idx;
11079 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11081 if (mmf_attrs_commit(player->attrs)) {
11082 LOGE("failed to commit.\n");
11086 LOGD("next uri %s(%d)\n", uri, uri_idx);
11092 LOGE("unable to play next path. EOS will be posted soon.\n");
11097 __mmplayer_initialize_next_play(mm_player_t *player)
11103 player->smooth_streaming = FALSE;
11104 player->videodec_linked = 0;
11105 player->audiodec_linked = 0;
11106 player->videosink_linked = 0;
11107 player->audiosink_linked = 0;
11108 player->textsink_linked = 0;
11109 player->is_external_subtitle_present = FALSE;
11110 player->is_external_subtitle_added_now = FALSE;
11111 player->not_supported_codec = MISSING_PLUGIN_NONE;
11112 player->can_support_codec = FOUND_PLUGIN_NONE;
11113 player->pending_seek.is_pending = FALSE;
11114 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11115 player->pending_seek.pos = 0;
11116 player->msg_posted = FALSE;
11117 player->has_many_types = FALSE;
11118 player->no_more_pad = FALSE;
11119 player->not_found_demuxer = 0;
11120 player->doing_seek = FALSE;
11121 player->max_audio_channels = 0;
11122 player->is_subtitle_force_drop = FALSE;
11123 player->play_subtitle = FALSE;
11124 player->use_textoverlay = FALSE;
11125 player->adjust_subtitle_pos = 0;
11127 player->updated_bitrate_count = 0;
11128 player->total_bitrate = 0;
11129 player->updated_maximum_bitrate_count = 0;
11130 player->total_maximum_bitrate = 0;
11132 _mmplayer_track_initialize(player);
11134 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11135 player->bitrate[i] = 0;
11136 player->maximum_bitrate[i] = 0;
11139 if (player->v_stream_caps) {
11140 gst_caps_unref(player->v_stream_caps);
11141 player->v_stream_caps = NULL;
11144 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11145 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11147 /* clean found parsers */
11148 if (player->parsers) {
11149 GList *parsers = player->parsers;
11150 for (; parsers; parsers = g_list_next(parsers)) {
11151 gchar *name = parsers->data;
11152 MMPLAYER_FREEIF(name);
11154 g_list_free(player->parsers);
11155 player->parsers = NULL;
11158 /* clean found audio decoders */
11159 if (player->audio_decoders) {
11160 GList *a_dec = player->audio_decoders;
11161 for (; a_dec; a_dec = g_list_next(a_dec)) {
11162 gchar *name = a_dec->data;
11163 MMPLAYER_FREEIF(name);
11165 g_list_free(player->audio_decoders);
11166 player->audio_decoders = NULL;
11173 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11175 MMPlayerGstElement *mainbin = NULL;
11176 MMMessageParamType msg_param = {0,};
11177 GstElement *element = NULL;
11178 MMHandleType attrs = 0;
11180 enum MainElementID elemId = MMPLAYER_M_NUM;
11184 if ((player == NULL) ||
11185 (player->pipeline == NULL) ||
11186 (player->pipeline->mainbin == NULL)) {
11187 LOGE("player is null.\n");
11191 mainbin = player->pipeline->mainbin;
11192 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11194 attrs = MMPLAYER_GET_ATTRS(player);
11196 LOGE("fail to get attributes.\n");
11200 /* Initialize Player values */
11201 __mmplayer_initialize_next_play(player);
11203 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11205 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11206 LOGE("failed to parse profile\n");
11207 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11211 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11212 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11213 LOGE("it's dash or hls. not support.");
11214 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11219 switch (player->profile.uri_type) {
11221 case MM_PLAYER_URI_TYPE_FILE:
11223 LOGD("using filesrc for 'file://' handler.\n");
11225 element = gst_element_factory_make("filesrc", "source");
11228 LOGE("failed to create filesrc\n");
11232 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11235 case MM_PLAYER_URI_TYPE_URL_HTTP:
11237 gchar *user_agent, *proxy, *cookies, **cookie_list;
11238 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11239 user_agent = proxy = cookies = NULL;
11240 cookie_list = NULL;
11242 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11244 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11247 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11249 /* get attribute */
11250 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11251 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11252 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11253 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11255 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11256 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11257 LOGD("get timeout from ini\n");
11258 http_timeout = player->ini.http_timeout;
11261 /* get attribute */
11262 SECURE_LOGD("location : %s\n", player->profile.uri);
11263 SECURE_LOGD("cookies : %s\n", cookies);
11264 SECURE_LOGD("proxy : %s\n", proxy);
11265 SECURE_LOGD("user_agent : %s\n", user_agent);
11266 LOGD("timeout : %d\n", http_timeout);
11268 /* setting property to streaming source */
11269 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11270 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11271 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11273 /* check if prosy is vailid or not */
11274 if (util_check_valid_url(proxy))
11275 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11276 /* parsing cookies */
11277 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11278 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11280 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11284 LOGE("not support uri type %d\n", player->profile.uri_type);
11289 LOGE("no source element was created.\n");
11293 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11294 LOGE("failed to add source element to pipeline\n");
11295 gst_object_unref(GST_OBJECT(element));
11300 /* take source element */
11301 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11302 mainbin[MMPLAYER_M_SRC].gst = element;
11306 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11307 if (player->streamer == NULL) {
11308 player->streamer = __mm_player_streaming_create();
11309 __mm_player_streaming_initialize(player->streamer);
11312 elemId = MMPLAYER_M_TYPEFIND;
11313 element = gst_element_factory_make("typefind", "typefinder");
11314 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11315 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11317 elemId = MMPLAYER_M_AUTOPLUG;
11318 element = __mmplayer_create_decodebin(player);
11321 /* check autoplug element is OK */
11323 LOGE("can not create element(%d)\n", elemId);
11327 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11328 LOGE("failed to add sinkbin to pipeline\n");
11329 gst_object_unref(GST_OBJECT(element));
11334 mainbin[elemId].id = elemId;
11335 mainbin[elemId].gst = element;
11337 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11338 LOGE("Failed to link src - autoplug(or typefind)\n");
11342 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11343 LOGE("Failed to change state of src element\n");
11347 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11348 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11349 LOGE("Failed to change state of decodebin\n");
11353 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11354 LOGE("Failed to change state of src element\n");
11359 player->gapless.stream_changed = TRUE;
11360 player->gapless.running = TRUE;
11366 MMPLAYER_PLAYBACK_UNLOCK(player);
11368 if (!player->msg_posted) {
11369 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11370 player->msg_posted = TRUE;
11377 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11379 mm_player_selector_t *selector = &player->selector[type];
11380 MMPlayerGstElement *sinkbin = NULL;
11381 enum MainElementID selectorId = MMPLAYER_M_NUM;
11382 enum MainElementID sinkId = MMPLAYER_M_NUM;
11383 GstPad *srcpad = NULL;
11384 GstPad *sinkpad = NULL;
11385 gboolean send_notice = FALSE;
11388 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11390 LOGD("type %d", type);
11393 case MM_PLAYER_TRACK_TYPE_AUDIO:
11394 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11395 sinkId = MMPLAYER_A_BIN;
11396 sinkbin = player->pipeline->audiobin;
11398 case MM_PLAYER_TRACK_TYPE_VIDEO:
11399 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11400 sinkId = MMPLAYER_V_BIN;
11401 sinkbin = player->pipeline->videobin;
11402 send_notice = TRUE;
11404 case MM_PLAYER_TRACK_TYPE_TEXT:
11405 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11406 sinkId = MMPLAYER_T_BIN;
11407 sinkbin = player->pipeline->textbin;
11410 LOGE("requested type is not supportable");
11415 if (player->pipeline->mainbin[selectorId].gst) {
11418 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11420 if (selector->event_probe_id != 0)
11421 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11422 selector->event_probe_id = 0;
11424 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11425 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11427 if (srcpad && sinkpad) {
11428 /* after getting drained signal there is no data flows, so no need to do pad_block */
11429 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11430 gst_pad_unlink(srcpad, sinkpad);
11432 /* send custom event to sink pad to handle it at video sink */
11434 LOGD("send custom event to sinkpad");
11435 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11436 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11437 gst_pad_send_event(sinkpad, event);
11441 gst_object_unref(sinkpad);
11444 gst_object_unref(srcpad);
11447 LOGD("selector release");
11449 /* release and unref requests pad from the selector */
11450 for (n = 0; n < selector->channels->len; n++) {
11451 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11452 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11454 g_ptr_array_set_size(selector->channels, 0);
11456 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11457 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11459 player->pipeline->mainbin[selectorId].gst = NULL;
11467 __mmplayer_deactivate_old_path(mm_player_t *player)
11470 MMPLAYER_RETURN_IF_FAIL(player);
11472 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11473 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11474 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11475 LOGE("deactivate selector error");
11479 _mmplayer_track_destroy(player);
11480 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11482 if (player->streamer) {
11483 __mm_player_streaming_deinitialize(player->streamer);
11484 __mm_player_streaming_destroy(player->streamer);
11485 player->streamer = NULL;
11488 MMPLAYER_PLAYBACK_LOCK(player);
11489 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11496 if (!player->msg_posted) {
11497 MMMessageParamType msg = {0,};
11500 msg.code = MM_ERROR_PLAYER_INTERNAL;
11501 LOGE("next_uri_play> deactivate error");
11503 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11504 player->msg_posted = TRUE;
11509 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11511 int result = MM_ERROR_NONE;
11512 mm_player_t* player = (mm_player_t*) hplayer;
11515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11518 player->http_file_buffering_path = (gchar*)file_path;
11519 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11525 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11527 int result = MM_ERROR_NONE;
11528 mm_player_t* player = (mm_player_t*) hplayer;
11531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11533 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11534 if (mmf_attrs_commit(player->attrs)) {
11535 LOGE("failed to commit the original uri.\n");
11536 result = MM_ERROR_PLAYER_INTERNAL;
11538 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11539 LOGE("failed to add the original uri in the uri list.\n");
11546 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11548 mm_player_t* player = (mm_player_t*) hplayer;
11549 guint num_of_list = 0;
11553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11554 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11556 if (player->pipeline && player->pipeline->textbin) {
11557 LOGE("subtitle path is enabled.\n");
11558 return MM_ERROR_PLAYER_INVALID_STATE;
11561 num_of_list = g_list_length(player->uri_info.uri_list);
11563 if (is_first_path == TRUE) {
11564 if (num_of_list == 0) {
11565 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11566 LOGD("add original path : %s", uri);
11568 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11569 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11571 LOGD("change original path : %s", uri);
11574 MMHandleType attrs = 0;
11575 attrs = MMPLAYER_GET_ATTRS(player);
11577 if (num_of_list == 0) {
11578 char *original_uri = NULL;
11581 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11583 if (!original_uri) {
11584 LOGE("there is no original uri.");
11585 return MM_ERROR_PLAYER_INVALID_STATE;
11588 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11589 player->uri_info.uri_idx = 0;
11591 LOGD("add original path at first : %s(%d)", original_uri);
11595 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11596 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11600 return MM_ERROR_NONE;
11603 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11605 mm_player_t* player = (mm_player_t*) hplayer;
11606 char *next_uri = NULL;
11607 guint num_of_list = 0;
11610 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11612 num_of_list = g_list_length(player->uri_info.uri_list);
11614 if (num_of_list > 0) {
11615 gint uri_idx = player->uri_info.uri_idx;
11617 if (uri_idx < num_of_list-1)
11622 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11623 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11625 *uri = g_strdup(next_uri);
11629 return MM_ERROR_NONE;
11633 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11634 GstCaps *caps, gpointer data)
11636 mm_player_t* player = (mm_player_t*)data;
11637 const gchar* klass = NULL;
11638 const gchar* mime = NULL;
11639 gchar* caps_str = NULL;
11641 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11642 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11643 caps_str = gst_caps_to_string(caps);
11645 LOGW("unknown type of caps : %s from %s",
11646 caps_str, GST_ELEMENT_NAME(elem));
11648 MMPLAYER_FREEIF(caps_str);
11650 /* There is no available codec. */
11651 __mmplayer_check_not_supported_codec(player, klass, mime);
11655 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11656 GstCaps * caps, gpointer data)
11658 mm_player_t* player = (mm_player_t*)data;
11659 const char* mime = NULL;
11660 gboolean ret = TRUE;
11662 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11663 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11665 if (g_str_has_prefix(mime, "audio")) {
11666 GstStructure* caps_structure = NULL;
11667 gint samplerate = 0;
11669 gchar *caps_str = NULL;
11671 caps_structure = gst_caps_get_structure(caps, 0);
11672 gst_structure_get_int(caps_structure, "rate", &samplerate);
11673 gst_structure_get_int(caps_structure, "channels", &channels);
11675 if ((channels > 0 && samplerate == 0)) {
11676 LOGD("exclude audio...");
11680 caps_str = gst_caps_to_string(caps);
11681 /* set it directly because not sent by TAG */
11682 if (g_strrstr(caps_str, "mobile-xmf"))
11683 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11684 MMPLAYER_FREEIF(caps_str);
11685 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11686 MMMessageParamType msg_param;
11687 memset(&msg_param, 0, sizeof(MMMessageParamType));
11688 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11689 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11690 LOGD("video file is not supported on this device");
11692 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11693 LOGD("already video linked");
11696 LOGD("found new stream");
11703 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11704 GstCaps* caps, GstElementFactory* factory, gpointer data)
11706 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11707 We are defining our own and will be removed when it actually exposed */
11709 GST_AUTOPLUG_SELECT_TRY,
11710 GST_AUTOPLUG_SELECT_EXPOSE,
11711 GST_AUTOPLUG_SELECT_SKIP
11712 } GstAutoplugSelectResult;
11714 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11715 mm_player_t* player = (mm_player_t*)data;
11717 gchar* factory_name = NULL;
11718 gchar* caps_str = NULL;
11719 const gchar* klass = NULL;
11721 int surface_type = 0;
11723 factory_name = GST_OBJECT_NAME(factory);
11724 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11725 caps_str = gst_caps_to_string(caps);
11727 LOGD("found new element [%s] to link", factory_name);
11729 /* store type string */
11730 if (player->type == NULL) {
11731 player->type = gst_caps_to_string(caps);
11732 __mmplayer_update_content_type_info(player);
11735 mm_attrs_get_int_by_name(player->attrs,
11736 "display_surface_type", &surface_type);
11737 LOGD("check display surface type attribute: %d", surface_type);
11739 /* filtering exclude keyword */
11740 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11741 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11742 LOGW("skipping [%s] by exculde keyword [%s]\n",
11743 factory_name, player->ini.exclude_element_keyword[idx]);
11745 // NOTE : does we need to check n_value against the number of item selected?
11746 result = GST_AUTOPLUG_SELECT_SKIP;
11751 /* exclude webm format */
11752 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11753 * because webm format is not supportable.
11754 * If webm is disabled in "autoplug-continue", there is no state change
11755 * failure or error because the decodebin will expose the pad directly.
11756 * It make MSL invoke _prepare_async_callback.
11757 * So, we need to disable webm format in "autoplug-select" */
11758 if (caps_str && strstr(caps_str, "webm")) {
11759 LOGW("webm is not supported");
11760 result = GST_AUTOPLUG_SELECT_SKIP;
11764 /* check factory class for filtering */
11765 /* NOTE : msl don't need to use image plugins.
11766 * So, those plugins should be skipped for error handling.
11768 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11769 LOGD("skipping [%s] by not required\n", factory_name);
11770 result = GST_AUTOPLUG_SELECT_SKIP;
11774 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11775 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11776 // TO CHECK : subtitle if needed, add subparse exception.
11777 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11778 result = GST_AUTOPLUG_SELECT_SKIP;
11782 if (g_strrstr(factory_name, "mpegpsdemux")) {
11783 LOGD("skipping PS container - not support\n");
11784 result = GST_AUTOPLUG_SELECT_SKIP;
11788 if (g_strrstr(factory_name, "mssdemux"))
11789 player->smooth_streaming = TRUE;
11791 /* check ALP Codec can be used or not */
11792 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11793 GstStructure* str = NULL;
11796 str = gst_caps_get_structure(caps, 0);
11798 gst_structure_get_int(str, "channels", &channels);
11800 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11801 if (player->max_audio_channels < channels)
11802 player->max_audio_channels = channels;
11804 /* set stream information */
11805 if (!player->audiodec_linked)
11806 __mmplayer_set_audio_attrs(player, caps);
11807 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11808 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11809 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11810 /* prepare resource manager for video decoder */
11811 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11813 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11814 /* prepare resource manager for video decoder */
11815 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11816 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11817 != MM_ERROR_NONE) {
11818 LOGW("could not prepare for video_decoder resource, skip it.");
11819 result = GST_AUTOPLUG_SELECT_SKIP;
11827 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11828 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11831 GstStructure *str = NULL;
11832 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11834 /* don't make video because of not required */
11835 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11836 (player->set_mode.media_packet_video_stream == FALSE)) {
11837 LOGD("no video because it's not required. -> return expose");
11838 result = GST_AUTOPLUG_SELECT_EXPOSE;
11842 /* get w/h for omx state-tune */
11843 str = gst_caps_get_structure(caps, 0);
11844 gst_structure_get_int(str, "width", &width);
11847 if (player->v_stream_caps) {
11848 gst_caps_unref(player->v_stream_caps);
11849 player->v_stream_caps = NULL;
11852 player->v_stream_caps = gst_caps_copy(caps);
11853 LOGD("take caps for video state tune");
11854 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11858 if (g_strrstr(klass, "Decoder")) {
11859 const char* mime = NULL;
11860 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11862 if (g_str_has_prefix(mime, "video")) {
11863 // __mmplayer_check_video_zero_cpoy(player, factory);
11865 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11866 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11868 player->videodec_linked = 1;
11869 } else if (g_str_has_prefix(mime, "audio")) {
11870 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11871 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11873 player->audiodec_linked = 1;
11878 MMPLAYER_FREEIF(caps_str);
11885 static GValueArray*
11886 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
11887 GstCaps * caps, gpointer data)
11889 //mm_player_t* player = (mm_player_t*)data;
11891 LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11892 gst_caps_to_string(caps),
11893 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11900 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11901 gpointer data) // @
11903 //mm_player_t* player = (mm_player_t*)data;
11904 GstCaps* caps = NULL;
11906 LOGD("[Decodebin2] pad-removed signal\n");
11908 caps = gst_pad_query_caps(new_pad, NULL);
11910 gchar* caps_str = NULL;
11911 caps_str = gst_caps_to_string(caps);
11913 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11915 MMPLAYER_FREEIF(caps_str);
11920 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11922 mm_player_t* player = (mm_player_t*)data;
11923 GstIterator *iter = NULL;
11924 GValue item = { 0, };
11925 GstPad *pad = NULL;
11926 gboolean done = FALSE;
11927 gboolean is_all_drained = TRUE;
11930 MMPLAYER_RETURN_IF_FAIL(player);
11932 LOGD("__mmplayer_gst_decode_drained");
11934 if (player->use_deinterleave == TRUE) {
11935 LOGD("group playing mode.");
11939 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11940 LOGW("Fail to get cmd lock");
11944 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11945 !__mmplayer_verify_next_play_path(player)) {
11946 LOGD("decoding is finished.");
11947 __mmplayer_reset_gapless_state(player);
11948 MMPLAYER_CMD_UNLOCK(player);
11952 player->gapless.reconfigure = TRUE;
11954 /* check decodebin src pads whether they received EOS or not */
11955 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11958 switch (gst_iterator_next(iter, &item)) {
11959 case GST_ITERATOR_OK:
11960 pad = g_value_get_object(&item);
11961 if (!GST_PAD_IS_EOS(pad)) {
11962 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11963 is_all_drained = FALSE;
11966 g_value_reset(&item);
11968 case GST_ITERATOR_RESYNC:
11969 gst_iterator_resync(iter);
11971 case GST_ITERATOR_ERROR:
11972 case GST_ITERATOR_DONE:
11977 g_value_unset(&item);
11978 gst_iterator_free(iter);
11980 if (!is_all_drained) {
11981 LOGD("Wait util the all pads get EOS.");
11982 MMPLAYER_CMD_UNLOCK(player);
11987 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11988 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11990 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11991 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11992 __mmplayer_deactivate_old_path(player);
11993 MMPLAYER_CMD_UNLOCK(player);
11999 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
12001 mm_player_t* player = (mm_player_t*)data;
12002 const gchar* klass = NULL;
12003 gchar* factory_name = NULL;
12005 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12006 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12008 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12010 if (__mmplayer_add_dump_buffer_probe(player, element))
12011 LOGD("add buffer probe");
12014 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12015 gchar* selected = NULL;
12016 selected = g_strdup(GST_ELEMENT_NAME(element));
12017 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12021 if (g_strrstr(klass, "Parser")) {
12022 gchar* selected = NULL;
12024 selected = g_strdup(factory_name);
12025 player->parsers = g_list_append(player->parsers, selected);
12028 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
12029 /* FIXIT : first value will be overwritten if there's more
12030 * than 1 demuxer/parser
12033 //LOGD("plugged element is demuxer. take it\n");
12034 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12035 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12037 /*Added for multi audio support */ // Q. del?
12038 if (g_strrstr(klass, "Demux")) {
12039 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12040 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12044 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12045 int surface_type = 0;
12047 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12050 // to support trust-zone only
12051 if (g_strrstr(factory_name, "asfdemux")) {
12052 LOGD("set file-location %s\n", player->profile.uri);
12053 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12055 if (player->video_hub_download_mode == TRUE)
12056 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12057 } else if (g_strrstr(factory_name, "legacyh264parse")) {
12058 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12059 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12060 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12061 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12062 (__mmplayer_is_only_mp3_type(player->type))) {
12063 LOGD("[mpegaudioparse] set streaming pull mode.");
12064 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12066 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12067 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12070 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12071 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12072 LOGD("plugged element is multiqueue. take it\n");
12074 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12075 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12077 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12078 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12079 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12080 __mm_player_streaming_set_multiqueue(player->streamer,
12083 player->ini.http_buffering_time,
12085 player->ini.http_buffering_limit);
12087 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12094 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12097 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12099 if (MMPLAYER_IS_STREAMING(player))
12102 /* This callback can be set to music player only. */
12103 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12104 LOGW("audio callback is not supported for video");
12108 if (player->audio_stream_cb) {
12109 GstPad *pad = NULL;
12111 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12114 LOGE("failed to get sink pad from audiosink to probe data\n");
12117 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12118 __mmplayer_audio_stream_probe, player, NULL);
12120 gst_object_unref(pad);
12124 LOGE("There is no audio callback to configure.\n");
12134 __mmplayer_init_factories(mm_player_t* player) // @
12136 MMPLAYER_RETURN_IF_FAIL(player);
12138 player->factories = gst_registry_feature_filter(gst_registry_get(),
12139 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12140 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12144 __mmplayer_release_factories(mm_player_t* player) // @
12147 MMPLAYER_RETURN_IF_FAIL(player);
12149 if (player->factories) {
12150 gst_plugin_feature_list_free(player->factories);
12151 player->factories = NULL;
12158 __mmplayer_release_misc(mm_player_t* player)
12161 gboolean cur_mode = player->set_mode.rich_audio;
12164 MMPLAYER_RETURN_IF_FAIL(player);
12166 player->video_stream_cb = NULL;
12167 player->video_stream_cb_user_param = NULL;
12168 player->video_stream_prerolled = FALSE;
12170 player->audio_stream_cb = NULL;
12171 player->audio_stream_render_cb_ex = NULL;
12172 player->audio_stream_cb_user_param = NULL;
12173 player->audio_stream_sink_sync = false;
12175 player->video_stream_changed_cb = NULL;
12176 player->video_stream_changed_cb_user_param = NULL;
12178 player->audio_stream_changed_cb = NULL;
12179 player->audio_stream_changed_cb_user_param = NULL;
12181 player->sent_bos = FALSE;
12182 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12184 player->doing_seek = FALSE;
12186 player->updated_bitrate_count = 0;
12187 player->total_bitrate = 0;
12188 player->updated_maximum_bitrate_count = 0;
12189 player->total_maximum_bitrate = 0;
12191 player->not_found_demuxer = 0;
12193 player->last_position = 0;
12194 player->duration = 0;
12195 player->http_content_size = 0;
12196 player->not_supported_codec = MISSING_PLUGIN_NONE;
12197 player->can_support_codec = FOUND_PLUGIN_NONE;
12198 player->pending_seek.is_pending = FALSE;
12199 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12200 player->pending_seek.pos = 0;
12201 player->msg_posted = FALSE;
12202 player->has_many_types = FALSE;
12203 player->max_audio_channels = 0;
12204 player->video_share_api_delta = 0;
12205 player->video_share_clock_delta = 0;
12206 player->sound_focus.keep_last_pos = FALSE;
12207 player->sound_focus.acquired = FALSE;
12208 player->is_subtitle_force_drop = FALSE;
12209 player->play_subtitle = FALSE;
12210 player->use_textoverlay = FALSE;
12211 player->adjust_subtitle_pos = 0;
12212 player->last_multiwin_status = FALSE;
12213 player->has_closed_caption = FALSE;
12214 player->set_mode.media_packet_video_stream = FALSE;
12215 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12216 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12218 player->set_mode.rich_audio = cur_mode;
12220 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12221 player->bitrate[i] = 0;
12222 player->maximum_bitrate[i] = 0;
12225 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12227 /* remove media stream cb(appsrc cb) */
12228 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12229 player->media_stream_buffer_status_cb[i] = NULL;
12230 player->media_stream_seek_data_cb[i] = NULL;
12232 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12234 /* free memory related to audio effect */
12235 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12237 if (player->state_tune_caps) {
12238 gst_caps_unref(player->state_tune_caps);
12239 player->state_tune_caps = NULL;
12246 __mmplayer_release_misc_post(mm_player_t* player)
12248 char *original_uri = NULL;
12251 /* player->pipeline is already released before. */
12253 MMPLAYER_RETURN_IF_FAIL(player);
12255 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12256 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12258 /* clean found parsers */
12259 if (player->parsers) {
12260 GList *parsers = player->parsers;
12261 for (; parsers; parsers = g_list_next(parsers)) {
12262 gchar *name = parsers->data;
12263 MMPLAYER_FREEIF(name);
12265 g_list_free(player->parsers);
12266 player->parsers = NULL;
12269 /* clean found audio decoders */
12270 if (player->audio_decoders) {
12271 GList *a_dec = player->audio_decoders;
12272 for (; a_dec; a_dec = g_list_next(a_dec)) {
12273 gchar *name = a_dec->data;
12274 MMPLAYER_FREEIF(name);
12276 g_list_free(player->audio_decoders);
12277 player->audio_decoders = NULL;
12280 /* clean the uri list except original uri */
12281 if (player->uri_info.uri_list) {
12282 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12284 if (player->attrs) {
12285 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12286 LOGD("restore original uri = %s\n", original_uri);
12288 if (mmf_attrs_commit(player->attrs))
12289 LOGE("failed to commit the original uri.\n");
12292 GList *uri_list = player->uri_info.uri_list;
12293 for (; uri_list; uri_list = g_list_next(uri_list)) {
12294 gchar *uri = uri_list->data;
12295 MMPLAYER_FREEIF(uri);
12297 g_list_free(player->uri_info.uri_list);
12298 player->uri_info.uri_list = NULL;
12301 /* clear the audio stream buffer list */
12302 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12304 /* clear the video stream bo list */
12305 __mmplayer_video_stream_destroy_bo_list(player);
12307 player->uri_info.uri_idx = 0;
12311 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12313 GstElement *element = NULL;
12316 LOGD("creating %s to plug\n", name);
12318 element = gst_element_factory_make(name, NULL);
12320 LOGE("failed to create queue\n");
12324 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12325 LOGE("failed to set state READY to %s\n", name);
12326 gst_object_unref(element);
12330 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12331 LOGE("failed to add %s\n", name);
12332 gst_object_unref(element);
12336 sinkpad = gst_element_get_static_pad(element, "sink");
12338 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12339 LOGE("failed to link %s\n", name);
12340 gst_object_unref(sinkpad);
12341 gst_object_unref(element);
12345 LOGD("linked %s to pipeline successfully\n", name);
12347 gst_object_unref(sinkpad);
12353 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12354 const char *padname, const GList *templlist)
12356 GstPad *pad = NULL;
12357 gboolean has_dynamic_pads = FALSE;
12358 gboolean has_many_types = FALSE;
12359 const char *klass = NULL;
12360 GstStaticPadTemplate *padtemplate = NULL;
12361 GstElementFactory *factory = NULL;
12362 GstElement* queue = NULL;
12363 GstElement* parser = NULL;
12364 GstPad *pssrcpad = NULL;
12365 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12366 MMPlayerGstElement *mainbin = NULL;
12367 GstStructure* str = NULL;
12368 GstCaps* srccaps = NULL;
12369 GstState target_state = GST_STATE_READY;
12370 gboolean isvideo_decoder = FALSE;
12371 guint q_max_size_time = 0;
12375 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12376 player->pipeline &&
12377 player->pipeline->mainbin,
12380 mainbin = player->pipeline->mainbin;
12382 LOGD("plugging pad %s:%s to newly create %s:%s\n",
12383 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12384 GST_PAD_NAME(srcpad),
12385 GST_ELEMENT_NAME(sinkelement),
12388 factory = gst_element_get_factory(sinkelement);
12389 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12391 /* check if player can do start continually */
12392 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12394 /* need it to warm up omx before linking to pipeline */
12395 if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12396 LOGD("get demux caps.\n");
12397 if (player->state_tune_caps) {
12398 gst_caps_unref(player->state_tune_caps);
12399 player->state_tune_caps = NULL;
12401 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12404 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12405 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12406 if (player->state_tune_caps != NULL) {
12407 LOGD("set demux's caps to omx codec if resource is available");
12408 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12409 target_state = GST_STATE_PAUSED;
12410 isvideo_decoder = TRUE;
12411 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12413 LOGW("failed to set caps for state tuning");
12415 gst_caps_unref(player->state_tune_caps);
12416 player->state_tune_caps = NULL;
12419 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12420 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12421 if (isvideo_decoder) {
12422 gst_element_set_state(sinkelement, GST_STATE_NULL);
12423 gst_object_unref(G_OBJECT(sinkelement));
12424 player->keep_detecting_vcodec = TRUE;
12429 /* add to pipeline */
12430 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12431 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12435 LOGD("element klass : %s\n", klass);
12437 /* added to support multi track files */
12438 /* only decoder case and any of the video/audio still need to link*/
12439 if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12440 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12442 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12443 gchar *src_demux_caps_str = NULL;
12444 gchar *needed_parser = NULL;
12445 GstCaps *src_demux_caps = NULL;
12446 gboolean smooth_streaming = FALSE;
12448 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12449 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12451 gst_caps_unref(src_demux_caps);
12453 if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12454 if (g_strrstr(name, "mssdemux")) {
12455 needed_parser = g_strdup("legacyh264parse");
12456 smooth_streaming = TRUE;
12458 needed_parser = g_strdup("h264parse");
12459 } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12460 needed_parser = g_strdup("mpeg4videoparse");
12462 MMPLAYER_FREEIF(src_demux_caps_str);
12464 if (needed_parser) {
12465 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12466 MMPLAYER_FREEIF(needed_parser);
12469 LOGE("failed to create parser\n");
12471 if (smooth_streaming)
12472 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12474 /* update srcpad if parser is created */
12475 pssrcpad = gst_element_get_static_pad(parser, "src");
12480 MMPLAYER_FREEIF(name);
12482 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12484 LOGE("failed to create queue\n");
12488 /* update srcpad to link with decoder */
12489 qsrcpad = gst_element_get_static_pad(queue, "src");
12492 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12494 /* assigning queue handle for futher manipulation purpose */
12495 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12496 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12497 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12498 mainbin[MMPLAYER_M_Q1].gst = queue;
12500 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12501 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12502 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12503 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12505 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12506 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12508 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12509 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12510 mainbin[MMPLAYER_M_Q2].gst = queue;
12512 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12513 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12514 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12515 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12517 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12518 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12521 LOGE("Not supporting more then two elementary stream\n");
12525 pad = gst_element_get_static_pad(sinkelement, padname);
12528 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12529 padname, GST_ELEMENT_NAME(sinkelement));
12531 pad = gst_element_get_static_pad(sinkelement, "sink");
12533 LOGE("failed to get pad(sink) from %s. \n",
12534 GST_ELEMENT_NAME(sinkelement));
12539 /* to check the video/audio type set the proper flag*/
12540 const gchar *mime_type = NULL;
12541 srccaps = gst_pad_query_caps(srcpad, NULL);
12544 str = gst_caps_get_structure(srccaps, 0);
12547 mime_type = gst_structure_get_name(str);
12551 /* link queue and decoder. so, it will be queue - decoder. */
12552 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12553 gst_object_unref(GST_OBJECT(pad));
12554 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12556 /* reconstitute supportable codec */
12557 if (strstr(mime_type, "video"))
12558 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12559 else if (strstr(mime_type, "audio"))
12560 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12564 if (strstr(mime_type, "video")) {
12565 player->videodec_linked = 1;
12566 LOGI("player->videodec_linked set to 1\n");
12568 } else if (strstr(mime_type, "audio")) {
12569 player->audiodec_linked = 1;
12570 LOGI("player->auddiodec_linked set to 1\n");
12573 gst_object_unref(GST_OBJECT(pad));
12574 gst_caps_unref(GST_CAPS(srccaps));
12578 if (!MMPLAYER_IS_HTTP_PD(player)) {
12579 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12580 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12581 gint64 dur_bytes = 0L;
12582 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12584 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12585 LOGD("creating http streaming buffering queue\n");
12587 queue = gst_element_factory_make("queue2", "queue2");
12589 LOGE("failed to create buffering queue element\n");
12593 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12594 LOGE("failed to set state READY to buffering queue\n");
12598 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12599 LOGE("failed to add buffering queue\n");
12603 qsinkpad = gst_element_get_static_pad(queue, "sink");
12604 qsrcpad = gst_element_get_static_pad(queue, "src");
12606 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12607 LOGE("failed to link buffering queue\n");
12613 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12614 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12616 if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12617 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12618 LOGE("fail to get duration.\n");
12620 if (dur_bytes > 0) {
12621 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12622 type = MUXED_BUFFER_TYPE_FILE;
12624 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12625 if (player->streamer)
12626 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12633 /* NOTE : we cannot get any duration info from ts container in case of streaming */
12634 if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12635 __mm_player_streaming_set_queue2(player->streamer,
12638 player->ini.http_max_size_bytes,
12639 player->ini.http_buffering_time,
12641 player->ini.http_buffering_limit,
12643 player->http_file_buffering_path,
12644 (guint64)dur_bytes);
12650 /* if it is not decoder or */
12651 /* in decoder case any of the video/audio still need to link*/
12652 if (!g_strrstr(klass, "Decoder")) {
12653 pad = gst_element_get_static_pad(sinkelement, padname);
12655 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12656 padname, GST_ELEMENT_NAME(sinkelement));
12658 pad = gst_element_get_static_pad(sinkelement, "sink");
12661 LOGE("failed to get pad(sink) from %s. \n",
12662 GST_ELEMENT_NAME(sinkelement));
12667 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12668 gst_object_unref(GST_OBJECT(pad));
12669 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12673 gst_object_unref(GST_OBJECT(pad));
12676 for (; templlist != NULL; templlist = templlist->next) {
12677 padtemplate = templlist->data;
12679 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12681 if (padtemplate->direction != GST_PAD_SRC ||
12682 padtemplate->presence == GST_PAD_REQUEST)
12685 switch (padtemplate->presence) {
12686 case GST_PAD_ALWAYS:
12688 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12689 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12691 /* Check whether caps has many types */
12692 if (!gst_caps_is_fixed(caps)) {
12693 LOGD("always pad but, caps has many types");
12694 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12695 has_many_types = TRUE;
12699 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12700 gst_object_unref(GST_OBJECT(srcpad));
12701 gst_caps_unref(GST_CAPS(caps));
12703 LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12707 gst_caps_unref(GST_CAPS(caps));
12708 gst_object_unref(GST_OBJECT(srcpad));
12714 case GST_PAD_SOMETIMES:
12715 has_dynamic_pads = TRUE;
12723 /* check if player can do start continually */
12724 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12726 if (has_dynamic_pads) {
12727 player->have_dynamic_pad = TRUE;
12728 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12729 G_CALLBACK(__mmplayer_add_new_pad), player);
12731 /* for streaming, more then one typefind will used for each elementary stream
12732 * so this doesn't mean the whole pipeline completion
12734 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12735 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12736 G_CALLBACK(__mmplayer_pipeline_complete), player);
12740 if (has_many_types) {
12741 GstPad *pad = NULL;
12743 player->has_many_types = has_many_types;
12745 pad = gst_element_get_static_pad(sinkelement, "src");
12746 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12747 gst_object_unref(GST_OBJECT(pad));
12751 /* check if player can do start continually */
12752 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12754 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12755 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12760 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12761 LOGE("failed to set state PAUSED to queue\n");
12767 gst_object_unref(GST_OBJECT(qsrcpad));
12772 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12773 LOGE("failed to set state PAUSED to queue\n");
12779 gst_object_unref(GST_OBJECT(pssrcpad));
12790 gst_object_unref(GST_OBJECT(qsrcpad));
12792 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12793 * You need to explicitly set elements to the NULL state before
12794 * dropping the final reference, to allow them to clean up.
12796 gst_element_set_state(queue, GST_STATE_NULL);
12797 /* And, it still has a parent "player".
12798 * You need to let the parent manage the object instead of unreffing the object directly.
12801 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12802 //gst_object_unref(queue);
12806 gst_caps_unref(GST_CAPS(srccaps));
12811 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12813 const gchar *klass;
12815 /* we only care about element factories */
12816 if (!GST_IS_ELEMENT_FACTORY(feature))
12819 /* only parsers, demuxers and decoders */
12820 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12822 if (g_strrstr(klass, "Demux") == NULL &&
12823 g_strrstr(klass, "Codec/Decoder") == NULL &&
12824 g_strrstr(klass, "Depayloader") == NULL &&
12825 g_strrstr(klass, "Parse") == NULL)
12831 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12833 mm_player_t* player = (mm_player_t*) data;
12834 GstCaps *caps = NULL;
12835 GstStructure *str = NULL;
12840 MMPLAYER_RETURN_IF_FAIL(pad)
12841 MMPLAYER_RETURN_IF_FAIL(unused)
12842 MMPLAYER_RETURN_IF_FAIL(data)
12844 caps = gst_pad_query_caps(pad, NULL);
12848 str = gst_caps_get_structure(caps, 0);
12852 name = gst_structure_get_name(str);
12855 LOGD("name=%s\n", name);
12857 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12858 LOGE("failed to autoplug for type(%s)\n", name);
12859 gst_caps_unref(caps);
12863 gst_caps_unref(caps);
12865 __mmplayer_pipeline_complete(NULL, (gpointer)player);
12872 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12876 const char *stream_type;
12877 gchar *version_field = NULL;
12881 MMPLAYER_RETURN_IF_FAIL(player);
12882 MMPLAYER_RETURN_IF_FAIL(caps);
12884 str = gst_caps_get_structure(caps, 0);
12888 stream_type = gst_structure_get_name(str);
12893 /* set unlinked mime type for downloadable codec */
12894 if (g_str_has_prefix(stream_type, "video/")) {
12895 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12896 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12897 version_field = MM_PLAYER_MPEG_VNAME;
12898 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12899 gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12900 version_field = MM_PLAYER_WMV_VNAME;
12902 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12903 gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12904 version_field = MM_PLAYER_DIVX_VNAME;
12908 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12910 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12911 } else if (g_str_has_prefix(stream_type, "audio/")) {
12912 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12914 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12915 version_field = MM_PLAYER_MPEG_VNAME;
12916 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12917 gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12918 version_field = MM_PLAYER_WMA_VNAME;
12922 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12924 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12930 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12932 mm_player_t* player = (mm_player_t*) data;
12933 GstCaps *caps = NULL;
12934 GstStructure *str = NULL;
12938 MMPLAYER_RETURN_IF_FAIL(player);
12939 MMPLAYER_RETURN_IF_FAIL(pad);
12941 GST_OBJECT_LOCK(pad);
12942 if ((caps = gst_pad_get_current_caps(pad)))
12943 gst_caps_ref(caps);
12944 GST_OBJECT_UNLOCK(pad);
12946 if (NULL == caps) {
12947 caps = gst_pad_query_caps(pad, NULL);
12951 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12953 str = gst_caps_get_structure(caps, 0);
12957 name = gst_structure_get_name(str);
12961 player->num_dynamic_pad++;
12962 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12964 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12965 * If want to play it, remove this code.
12967 if (g_strrstr(name, "application")) {
12968 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12969 /* If id3/ape tag comes, keep going */
12970 LOGD("application mime exception : id3/ape tag");
12972 /* Otherwise, we assume that this stream is subtile. */
12973 LOGD(" application mime type pad is closed.");
12976 } else if (g_strrstr(name, "audio")) {
12977 gint samplerate = 0, channels = 0;
12979 if (player->audiodec_linked) {
12980 gst_caps_unref(caps);
12981 LOGD("multi tracks. skip to plug");
12985 /* set stream information */
12986 /* if possible, set it here because the caps is not distrubed by resampler. */
12987 gst_structure_get_int(str, "rate", &samplerate);
12988 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12990 gst_structure_get_int(str, "channels", &channels);
12991 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12993 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
12994 } else if (g_strrstr(name, "video")) {
12996 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
12998 /* don't make video because of not required */
12999 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
13000 LOGD("no video because it's not required");
13004 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13007 if (!__mmplayer_try_to_plug(player, pad, caps)) {
13008 LOGE("failed to autoplug for type(%s)", name);
13010 __mmplayer_set_unlinked_mime_type(player, caps);
13013 gst_caps_unref(caps);
13020 __mmplayer_check_subtitle(mm_player_t* player)
13022 MMHandleType attrs = 0;
13023 char *subtitle_uri = NULL;
13027 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13029 /* get subtitle attribute */
13030 attrs = MMPLAYER_GET_ATTRS(player);
13034 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13035 if (!subtitle_uri || !strlen(subtitle_uri))
13038 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13039 player->is_external_subtitle_present = TRUE;
13047 __mmplayer_can_extract_pcm(mm_player_t* player)
13049 MMHandleType attrs = 0;
13050 gboolean sound_extraction = FALSE;
13052 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13054 attrs = MMPLAYER_GET_ATTRS(player);
13056 LOGE("fail to get attributes.");
13060 /* get sound_extraction property */
13061 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13063 if (!sound_extraction) {
13064 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13072 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13075 MMMessageParamType msg_param;
13076 gchar *msg_src_element = NULL;
13077 GstStructure *s = NULL;
13078 guint error_id = 0;
13079 gchar *error_string = NULL;
13083 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13084 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13086 s = malloc(sizeof(GstStructure));
13087 memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13089 if (!gst_structure_get_uint(s, "error_id", &error_id))
13090 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13092 switch (error_id) {
13093 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13094 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13096 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13097 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13099 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13100 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13102 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13103 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13105 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13106 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13108 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13109 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13111 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13112 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13114 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13115 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13117 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13118 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13120 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13121 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13123 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13124 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13126 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13127 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13129 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13130 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13132 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13133 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13135 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13136 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13138 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13139 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13141 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13142 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13144 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13145 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13147 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13148 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13150 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13151 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13153 case MMPLAYER_STREAMING_ERROR_GONE:
13154 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13156 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13157 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13159 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13160 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13162 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13163 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13165 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13166 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13168 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13169 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13171 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13172 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13174 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13175 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13177 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13178 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13180 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13181 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13183 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13184 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13186 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13187 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13189 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13190 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13192 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13193 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13195 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13196 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13198 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13199 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13201 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13202 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13204 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13205 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13207 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13208 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13210 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13211 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13213 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13214 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13216 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13217 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13219 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13220 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13222 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13223 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13225 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13226 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13230 MMPLAYER_FREEIF(s);
13231 return MM_ERROR_PLAYER_STREAMING_FAIL;
13235 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13237 msg_param.data = (void *) error_string;
13239 if (message->src) {
13240 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13242 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13243 msg_src_element, msg_param.code, (char*)msg_param.data);
13246 /* post error to application */
13247 if (!player->msg_posted) {
13248 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13250 /* don't post more if one was sent already */
13251 player->msg_posted = TRUE;
13253 LOGD("skip error post because it's sent already.\n");
13255 MMPLAYER_FREEIF(s);
13257 g_free(error_string);
13264 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13266 MMPLAYER_RETURN_IF_FAIL(player);
13269 /* post now if delay is zero */
13270 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13271 LOGD("eos delay is zero. posting EOS now\n");
13272 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13274 if (player->set_mode.pcm_extraction)
13275 __mmplayer_cancel_eos_timer(player);
13280 /* cancel if existing */
13281 __mmplayer_cancel_eos_timer(player);
13283 /* init new timeout */
13284 /* NOTE : consider give high priority to this timer */
13285 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13287 player->eos_timer = g_timeout_add(delay_in_ms,
13288 __mmplayer_eos_timer_cb, player);
13290 player->context.global_default = g_main_context_default();
13291 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13293 /* check timer is valid. if not, send EOS now */
13294 if (player->eos_timer == 0) {
13295 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13296 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13301 __mmplayer_cancel_eos_timer(mm_player_t* player)
13303 MMPLAYER_RETURN_IF_FAIL(player);
13305 if (player->eos_timer) {
13306 LOGD("cancel eos timer");
13307 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13308 player->eos_timer = 0;
13315 __mmplayer_eos_timer_cb(gpointer u_data)
13317 mm_player_t* player = NULL;
13318 player = (mm_player_t*) u_data;
13320 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13322 if (player->play_count > 1) {
13323 gint ret_value = 0;
13324 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13325 if (ret_value == MM_ERROR_NONE) {
13326 MMHandleType attrs = 0;
13327 attrs = MMPLAYER_GET_ATTRS(player);
13329 /* we successeded to rewind. update play count and then wait for next EOS */
13330 player->play_count--;
13332 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13333 mmf_attrs_commit(attrs);
13335 LOGE("seeking to 0 failed in repeat play");
13338 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13340 /* we are returning FALSE as we need only one posting */
13345 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13347 const gchar* name = NULL;
13348 GstStructure* str = NULL;
13349 GstCaps* srccaps = NULL;
13353 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13354 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13356 /* to check any of the decoder(video/audio) need to be linked to parser*/
13357 srccaps = gst_pad_query_caps(srcpad, NULL);
13361 str = gst_caps_get_structure(srccaps, 0);
13365 name = gst_structure_get_name(str);
13369 if (strstr(name, "video")) {
13370 if (player->videodec_linked) {
13371 LOGI("Video decoder already linked\n");
13375 if (strstr(name, "audio")) {
13376 if (player->audiodec_linked) {
13377 LOGI("Audio decoder already linked\n");
13382 gst_caps_unref(srccaps);
13390 gst_caps_unref(srccaps);
13396 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13398 const gchar* name = NULL;
13399 GstStructure* str = NULL;
13400 GstCaps* srccaps = NULL;
13404 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13405 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13407 /* to check any of the decoder(video/audio) need to be linked to parser*/
13408 srccaps = gst_pad_query_caps(srcpad, NULL);
13412 str = gst_caps_get_structure(srccaps, 0);
13416 name = gst_structure_get_name(str);
13420 if (strstr(name, "video")) {
13421 if (player->videosink_linked) {
13422 LOGI("Video Sink already linked\n");
13426 if (strstr(name, "audio")) {
13427 if (player->audiosink_linked) {
13428 LOGI("Audio Sink already linked\n");
13432 if (strstr(name, "text")) {
13433 if (player->textsink_linked) {
13434 LOGI("Text Sink already linked\n");
13439 gst_caps_unref(srccaps);
13443 //return (!player->videosink_linked || !player->audiosink_linked);
13448 gst_caps_unref(srccaps);
13454 /* sending event to one of sinkelements */
13456 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13458 GstEvent * event2 = NULL;
13459 GList *sinks = NULL;
13460 gboolean res = FALSE;
13463 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13464 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13466 /* While adding subtitles in live feeds seek is getting called.
13467 Adding defensive check in framework layer.*/
13468 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13469 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13470 LOGE ("Should not send seek event during live playback");
13475 if (player->play_subtitle && !player->use_textoverlay)
13476 event2 = gst_event_copy((const GstEvent *)event);
13478 sinks = player->sink_elements;
13480 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13482 if (GST_IS_ELEMENT(sink)) {
13483 /* keep ref to the event */
13484 gst_event_ref(event);
13486 if ((res = gst_element_send_event(sink, event))) {
13487 LOGD("sending event[%s] to sink element [%s] success!\n",
13488 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13490 /* rtsp case, asyn_done is not called after seek during pause state */
13491 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13492 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13493 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13494 LOGD("RTSP seek completed, after pause state..\n");
13495 player->doing_seek = FALSE;
13496 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13502 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13503 sinks = g_list_next(sinks);
13509 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13510 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13513 sinks = g_list_next(sinks);
13518 request pad name = sink0;
13520 request pad name = sink1; // external
13523 /* Note : Textbin is not linked to the video or audio bin.
13524 * It needs to send the event to the text sink seperatelly.
13526 if (player->play_subtitle && !player->use_textoverlay) {
13527 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13529 if (GST_IS_ELEMENT(text_sink)) {
13530 /* keep ref to the event */
13531 gst_event_ref(event2);
13533 if ((res = gst_element_send_event(text_sink, event2)))
13534 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13535 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13537 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13538 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13540 gst_event_unref(event2);
13544 gst_event_unref(event);
13552 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13556 MMPLAYER_RETURN_IF_FAIL(player);
13557 MMPLAYER_RETURN_IF_FAIL(sink);
13559 player->sink_elements =
13560 g_list_append(player->sink_elements, sink);
13566 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13570 MMPLAYER_RETURN_IF_FAIL(player);
13571 MMPLAYER_RETURN_IF_FAIL(sink);
13573 player->sink_elements =
13574 g_list_remove(player->sink_elements, sink);
13580 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13581 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13582 gint64 cur, GstSeekType stop_type, gint64 stop)
13584 GstEvent* event = NULL;
13585 gboolean result = FALSE;
13589 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13591 if (player->pipeline && player->pipeline->textbin)
13592 __mmplayer_drop_subtitle(player, FALSE);
13594 event = gst_event_new_seek(rate, format, flags, cur_type,
13595 cur, stop_type, stop);
13597 result = __gst_send_event_to_sink(player, event);
13604 /* NOTE : be careful with calling this api. please refer to below glib comment
13605 * glib comment : Note that there is a bug in GObject that makes this function much
13606 * less useful than it might seem otherwise. Once gobject is disposed, the callback
13607 * will no longer be called, but, the signal handler is not currently disconnected.
13608 * If the instance is itself being freed at the same time than this doesn't matter,
13609 * since the signal will automatically be removed, but if instance persists,
13610 * then the signal handler will leak. You should not remove the signal yourself
13611 * because in a future versions of GObject, the handler will automatically be
13614 * It's possible to work around this problem in a way that will continue to work
13615 * with future versions of GObject by checking that the signal handler is still
13616 * connected before disconnected it:
13618 * if (g_signal_handler_is_connected(instance, id))
13619 * g_signal_handler_disconnect(instance, id);
13622 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13624 GList* sig_list = NULL;
13625 MMPlayerSignalItem* item = NULL;
13629 MMPLAYER_RETURN_IF_FAIL(player);
13631 LOGD("release signals type : %d", type);
13633 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13634 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13635 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13636 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13637 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13638 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13642 sig_list = player->signals[type];
13644 for (; sig_list; sig_list = sig_list->next) {
13645 item = sig_list->data;
13647 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13648 if (g_signal_handler_is_connected(item->obj, item->sig))
13649 g_signal_handler_disconnect(item->obj, item->sig);
13652 MMPLAYER_FREEIF(item);
13655 g_list_free(player->signals[type]);
13656 player->signals[type] = NULL;
13663 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13665 mm_player_t* player = 0;
13666 int prev_display_surface_type = 0;
13667 void *prev_display_overlay = NULL;
13668 const gchar *klass = NULL;
13669 gchar *cur_videosink_name = NULL;
13672 int num_of_dec = 2; /* DEC1, DEC2 */
13676 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13677 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13679 player = MM_PLAYER_CAST(handle);
13681 if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13682 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13684 return MM_ERROR_INVALID_ARGUMENT;
13687 /* load previous attributes */
13688 if (player->attrs) {
13689 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13690 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13691 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13692 if (prev_display_surface_type == surface_type) {
13693 LOGD("incoming display surface type is same as previous one, do nothing..");
13695 return MM_ERROR_NONE;
13698 LOGE("failed to load attributes");
13700 return MM_ERROR_PLAYER_INTERNAL;
13703 /* check videosink element is created */
13704 if (!player->pipeline || !player->pipeline->videobin ||
13705 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13706 LOGD("videosink element is not yet ready");
13708 /* videobin is not created yet, so we just set attributes related to display surface */
13709 LOGD("store display attribute for given surface type(%d)", surface_type);
13710 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13711 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13712 if (mmf_attrs_commit(player->attrs)) {
13713 LOGE("failed to commit attribute");
13715 return MM_ERROR_PLAYER_INTERNAL;
13718 return MM_ERROR_NONE;
13720 /* get player command status */
13721 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13722 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13724 return MM_ERROR_PLAYER_INVALID_STATE;
13727 /* surface change */
13728 for (i = 0 ; i < num_of_dec ; i++) {
13729 if (player->pipeline->mainbin &&
13730 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13731 GstElementFactory *decfactory;
13732 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13734 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13735 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13736 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13737 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13741 LOGW("success to changing display surface(%d)", surface_type);
13743 return MM_ERROR_NONE;
13745 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13746 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13750 LOGW("success to changing display surface(%d)", surface_type);
13752 return MM_ERROR_NONE;
13755 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13756 ret = MM_ERROR_PLAYER_INTERNAL;
13765 /* rollback to previous attributes */
13766 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13767 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13768 if (mmf_attrs_commit(player->attrs)) {
13769 LOGE("failed to commit attributes to rollback");
13771 return MM_ERROR_PLAYER_INTERNAL;
13777 /* NOTE : It does not support some use cases, eg using colorspace converter */
13779 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13781 GstPad *src_pad_dec = NULL;
13782 GstPad *sink_pad_videosink = NULL;
13783 GstPad *sink_pad_videobin = NULL;
13784 GstClock *clock = NULL;
13785 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13786 int ret = MM_ERROR_NONE;
13787 gboolean is_audiobin_created = TRUE;
13791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13792 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13793 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13795 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13796 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13798 /* get information whether if audiobin is created */
13799 if (!player->pipeline->audiobin ||
13800 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13801 LOGW("audiobin is null, this video content may not have audio data");
13802 is_audiobin_created = FALSE;
13805 /* get current state of player */
13806 previous_state = MMPLAYER_CURRENT_STATE(player);
13807 LOGD("previous state(%d)", previous_state);
13810 /* get src pad of decoder and block it */
13811 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13812 if (!src_pad_dec) {
13813 LOGE("failed to get src pad from decode in mainbin");
13814 return MM_ERROR_PLAYER_INTERNAL;
13817 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13818 LOGW("trying to block pad(video)");
13819 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13820 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13823 LOGE("failed to set block pad(video)");
13824 return MM_ERROR_PLAYER_INTERNAL;
13826 LOGW("pad is blocked(video)");
13828 /* no data flows, so no need to do pad_block */
13829 if (player->doing_seek)
13830 LOGW("not completed seek(%d), do nothing", player->doing_seek);
13832 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13836 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13837 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13838 LOGE("failed to remove previous ghost_pad for videobin");
13839 return MM_ERROR_PLAYER_INTERNAL;
13842 /* change state of videobin to NULL */
13843 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13844 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13845 if (ret != GST_STATE_CHANGE_SUCCESS) {
13846 LOGE("failed to change state of videobin to NULL");
13847 return MM_ERROR_PLAYER_INTERNAL;
13850 /* unlink between decoder and videobin and remove previous videosink from videobin */
13851 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13852 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13853 LOGE("failed to remove former videosink from videobin");
13854 return MM_ERROR_PLAYER_INTERNAL;
13857 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13859 /* create a new videosink and add it to videobin */
13860 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13861 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13862 LOGE("failed to create videosink element\n");
13864 return MM_ERROR_PLAYER_INTERNAL;
13866 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13867 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13868 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13870 /* save attributes */
13871 if (player->attrs) {
13872 /* set a new display surface type */
13873 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13874 /* set a new diplay overlay */
13875 switch (surface_type) {
13876 case MM_DISPLAY_SURFACE_OVERLAY:
13877 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13878 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13881 LOGE("invalid type(%d) for changing display surface", surface_type);
13883 return MM_ERROR_INVALID_ARGUMENT;
13885 if (mmf_attrs_commit(player->attrs)) {
13886 LOGE("failed to commit");
13888 return MM_ERROR_PLAYER_INTERNAL;
13891 LOGE("player->attrs is null, failed to save attributes");
13893 return MM_ERROR_PLAYER_INTERNAL;
13896 /* update video param */
13897 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13898 LOGE("failed to update video param");
13899 return MM_ERROR_PLAYER_INTERNAL;
13902 /* change state of videobin to READY */
13903 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13904 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13905 if (ret != GST_STATE_CHANGE_SUCCESS) {
13906 LOGE("failed to change state of videobin to READY");
13907 return MM_ERROR_PLAYER_INTERNAL;
13910 /* change ghostpad */
13911 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13912 if (!sink_pad_videosink) {
13913 LOGE("failed to get sink pad from videosink element");
13914 return MM_ERROR_PLAYER_INTERNAL;
13916 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13917 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13918 LOGE("failed to set active to ghost_pad");
13919 return MM_ERROR_PLAYER_INTERNAL;
13921 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13922 LOGE("failed to change ghostpad for videobin");
13923 return MM_ERROR_PLAYER_INTERNAL;
13925 gst_object_unref(sink_pad_videosink);
13927 /* link decoder with videobin */
13928 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13929 if (!sink_pad_videobin) {
13930 LOGE("failed to get sink pad from videobin");
13931 return MM_ERROR_PLAYER_INTERNAL;
13933 if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13934 LOGE("failed to link");
13935 return MM_ERROR_PLAYER_INTERNAL;
13937 gst_object_unref(sink_pad_videobin);
13939 /* clock setting for a new videosink plugin */
13940 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13941 so we set it from audiosink plugin or pipeline(system clock) */
13942 if (!is_audiobin_created) {
13943 LOGW("audiobin is not created, get clock from pipeline..");
13944 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13946 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13950 GstClockTime base_time;
13951 LOGD("set the clock to videosink");
13952 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13953 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13955 LOGD("got clock of videosink");
13956 now = gst_clock_get_time(clock);
13957 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13958 LOGD("at time %" GST_TIME_FORMAT ", base %"
13959 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13961 LOGE("failed to get clock of videosink after setting clock");
13962 return MM_ERROR_PLAYER_INTERNAL;
13965 LOGW("failed to get clock, maybe it is the time before first playing");
13967 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13968 /* change state of videobin to PAUSED */
13969 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13970 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13971 if (ret != GST_STATE_CHANGE_FAILURE) {
13972 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13974 LOGE("failed to change state of videobin to PLAYING");
13975 return MM_ERROR_PLAYER_INTERNAL;
13978 /* release blocked and unref src pad of video decoder */
13980 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13981 LOGE("failed to set pad blocked FALSE(video)");
13982 return MM_ERROR_PLAYER_INTERNAL;
13985 LOGW("pad is unblocked(video)");
13987 if (player->doing_seek)
13988 LOGW("not completed seek(%d)", player->doing_seek);
13989 /* change state of videobin to PAUSED */
13990 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13991 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13992 if (ret != GST_STATE_CHANGE_FAILURE) {
13993 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13995 LOGE("failed to change state of videobin to PLAYING");
13996 return MM_ERROR_PLAYER_INTERNAL;
13999 /* already skipped pad block */
14000 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14003 /* do get/set position for new videosink plugin */
14005 unsigned long position = 0;
14006 gint64 pos_msec = 0;
14008 LOGD("do get/set position for new videosink plugin");
14009 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14010 LOGE("failed to get position");
14011 return MM_ERROR_PLAYER_INTERNAL;
14013 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14014 /* accurate seek */
14015 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14016 LOGE("failed to set position");
14017 return MM_ERROR_PLAYER_INTERNAL;
14020 /* key unit seek */
14021 pos_msec = position * G_GINT64_CONSTANT(1000000);
14022 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14023 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14024 GST_SEEK_TYPE_SET, pos_msec,
14025 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14027 LOGE("failed to set position");
14028 return MM_ERROR_PLAYER_INTERNAL;
14034 gst_object_unref(src_pad_dec);
14035 LOGD("success to change sink");
14039 return MM_ERROR_NONE;
14043 /* Note : if silent is true, then subtitle would not be displayed. :*/
14044 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14046 mm_player_t* player = (mm_player_t*) hplayer;
14050 /* check player handle */
14051 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14053 player->set_mode.subtitle_off = silent;
14055 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14059 return MM_ERROR_NONE;
14062 int _mmplayer_remove_audio_parser_decoder(mm_player_t* player, GstPad *inpad)
14064 int result = MM_ERROR_NONE;
14065 GstPad *peer = NULL, *pad = NULL;
14066 GstElement *Element = NULL;
14067 MMPlayerGstElement* mainbin = NULL;
14068 mainbin = player->pipeline->mainbin;
14071 if (!gst_pad_set_blocked(inpad, TRUE)) {
14072 result = MM_ERROR_PLAYER_INTERNAL;
14076 gst_pad_add_probe(inpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
14079 /*Getting pad connected to demuxer audio pad */
14080 peer = gst_pad_get_peer(inpad);
14081 /* Disconnecting Demuxer and its peer plugin [audio] */
14083 if (!gst_pad_unlink(inpad, peer)) {
14084 result = MM_ERROR_PLAYER_INTERNAL;
14088 result = MM_ERROR_PLAYER_INTERNAL;
14091 /*Removing elements between Demuxer and audiobin*/
14092 while (peer != NULL) {
14093 gchar *Element_name = NULL;
14094 gchar *factory_name = NULL;
14095 GList *elements = NULL;
14096 GstElementFactory *factory = NULL;
14097 /*Getting peer element*/
14098 Element = gst_pad_get_parent_element(peer);
14099 if (Element == NULL) {
14100 gst_object_unref(peer);
14101 result = MM_ERROR_PLAYER_INTERNAL;
14105 Element_name = gst_element_get_name(Element);
14106 factory = gst_element_get_factory(Element);
14107 /*checking the element is audio bin*/
14108 if (!strcmp(Element_name, "audiobin")) {
14109 gst_object_unref(peer);
14110 result = MM_ERROR_NONE;
14111 g_free(Element_name);
14114 factory_name = GST_OBJECT_NAME(factory);
14115 pad = gst_element_get_static_pad(Element, "src");
14117 result = MM_ERROR_PLAYER_INTERNAL;
14118 g_free(Element_name);
14121 gst_object_unref(peer);
14122 peer = gst_pad_get_peer(pad);
14124 if (!gst_pad_unlink(pad, peer)) {
14125 gst_object_unref(peer);
14126 gst_object_unref(pad);
14127 result = MM_ERROR_PLAYER_INTERNAL;
14128 g_free(Element_name);
14132 elements = player->parsers;
14133 /* Removing the element form the list*/
14134 for (; elements; elements = g_list_next(elements)) {
14135 Element_name = elements->data;
14136 if (g_strrstr(Element_name, factory_name))
14137 player->parsers = g_list_remove(player->parsers, elements->data);
14139 gst_element_set_state(Element, GST_STATE_NULL);
14140 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), Element);
14141 gst_object_unref(pad);
14142 if (Element == mainbin[MMPLAYER_M_Q1].gst)
14143 mainbin[MMPLAYER_M_Q1].gst = NULL;
14144 else if (Element == mainbin[MMPLAYER_M_Q2].gst)
14145 mainbin[MMPLAYER_M_Q2].gst = NULL;
14146 else if (Element == mainbin[MMPLAYER_M_DEC1].gst)
14147 mainbin[MMPLAYER_M_DEC1].gst = NULL;
14148 else if (Element == mainbin[MMPLAYER_M_DEC2].gst)
14149 mainbin[MMPLAYER_M_DEC2].gst = NULL;
14151 gst_object_unref(Element);
14157 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14159 MMPlayerGstElement* mainbin = NULL;
14160 MMPlayerGstElement* textbin = NULL;
14161 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14162 GstState current_state = GST_STATE_VOID_PENDING;
14163 GstState element_state = GST_STATE_VOID_PENDING;
14164 GstState element_pending_state = GST_STATE_VOID_PENDING;
14166 GstEvent *event = NULL;
14167 int result = MM_ERROR_NONE;
14169 GstClock *curr_clock = NULL;
14170 GstClockTime base_time, start_time, curr_time;
14175 /* check player handle */
14176 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14178 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14179 LOGE("Pipeline is not in proper state\n");
14180 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14184 mainbin = player->pipeline->mainbin;
14185 textbin = player->pipeline->textbin;
14187 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14189 // sync clock with current pipeline
14190 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14191 curr_time = gst_clock_get_time(curr_clock);
14193 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14194 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14196 LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14197 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14199 if (current_state > GST_STATE_READY) {
14200 // sync state with current pipeline
14201 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14202 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14203 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14205 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14206 if (GST_STATE_CHANGE_FAILURE == ret)
14207 LOGE("fail to state change.\n");
14210 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14211 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14214 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14215 gst_object_unref(curr_clock);
14218 // seek to current position
14219 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14220 result = MM_ERROR_PLAYER_INVALID_STATE;
14221 LOGE("gst_element_query_position failed, invalid state\n");
14225 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14226 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
14228 __gst_send_event_to_sink(player, event);
14230 result = MM_ERROR_PLAYER_INTERNAL;
14231 LOGE("gst_event_new_seek failed\n");
14235 // sync state with current pipeline
14236 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14237 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14238 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14245 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14247 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14248 GstState current_state = GST_STATE_VOID_PENDING;
14250 MMHandleType attrs = 0;
14251 MMPlayerGstElement* mainbin = NULL;
14252 MMPlayerGstElement* textbin = NULL;
14254 gchar* subtitle_uri = NULL;
14255 int result = MM_ERROR_NONE;
14256 const gchar *charset = NULL;
14260 /* check player handle */
14261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14262 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14264 if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14265 result = MM_ERROR_PLAYER_INVALID_STATE;
14266 LOGE("Pipeline is not in proper state\n");
14270 mainbin = player->pipeline->mainbin;
14271 textbin = player->pipeline->textbin;
14273 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14274 if (current_state < GST_STATE_READY) {
14275 result = MM_ERROR_PLAYER_INVALID_STATE;
14276 LOGE("Pipeline is not in proper state\n");
14280 attrs = MMPLAYER_GET_ATTRS(player);
14282 LOGE("cannot get content attribute\n");
14283 result = MM_ERROR_PLAYER_INTERNAL;
14287 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14288 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14289 LOGE("subtitle uri is not proper filepath\n");
14290 result = MM_ERROR_PLAYER_INVALID_URI;
14294 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14295 LOGD("new subtitle file path is [%s]\n", filepath);
14297 if (!strcmp(filepath, subtitle_uri)) {
14298 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14301 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14302 if (mmf_attrs_commit(player->attrs)) {
14303 LOGE("failed to commit.\n");
14308 //gst_pad_set_blocked_async(src-srcpad, TRUE)
14310 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14311 if (ret != GST_STATE_CHANGE_SUCCESS) {
14312 LOGE("failed to change state of textbin to READY");
14313 result = MM_ERROR_PLAYER_INTERNAL;
14317 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14318 if (ret != GST_STATE_CHANGE_SUCCESS) {
14319 LOGE("failed to change state of subparse to READY");
14320 result = MM_ERROR_PLAYER_INTERNAL;
14324 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14325 if (ret != GST_STATE_CHANGE_SUCCESS) {
14326 LOGE("failed to change state of filesrc to READY");
14327 result = MM_ERROR_PLAYER_INTERNAL;
14331 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14333 charset = util_get_charset(filepath);
14335 LOGD("detected charset is %s\n", charset);
14336 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14339 result = _mmplayer_sync_subtitle_pipeline(player);
14346 /* API to switch between external subtitles */
14347 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14349 int result = MM_ERROR_NONE;
14350 mm_player_t* player = (mm_player_t*)hplayer;
14354 /* check player handle */
14355 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14357 if (!player->pipeline) {
14359 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14360 if (mmf_attrs_commit(player->attrs)) {
14361 LOGE("failed to commit.\n");
14362 result = MM_ERROR_PLAYER_INTERNAL;
14365 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14366 if (filepath == NULL)
14367 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14369 if (!__mmplayer_check_subtitle(player)) {
14370 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14371 if (mmf_attrs_commit(player->attrs)) {
14372 LOGE("failed to commit.\n");
14373 result = MM_ERROR_PLAYER_INTERNAL;
14376 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14377 LOGE("fail to create subtitle src\n");
14379 result = _mmplayer_sync_subtitle_pipeline(player);
14381 result = __mmplayer_change_external_subtitle_language(player, filepath);
14383 player->is_external_subtitle_added_now = TRUE;
14391 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14393 int result = MM_ERROR_NONE;
14394 gchar* change_pad_name = NULL;
14395 GstPad* sinkpad = NULL;
14396 MMPlayerGstElement* mainbin = NULL;
14397 enum MainElementID elemId = MMPLAYER_M_NUM;
14398 GstCaps* caps = NULL;
14399 gint total_track_num = 0;
14403 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14404 MM_ERROR_PLAYER_NOT_INITIALIZED);
14406 LOGD("Change Track(%d) to %d\n", type, index);
14408 mainbin = player->pipeline->mainbin;
14410 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14411 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14412 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14413 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14415 /* Changing Video Track is not supported. */
14416 LOGE("Track Type Error\n");
14420 if (mainbin[elemId].gst == NULL) {
14421 result = MM_ERROR_PLAYER_NO_OP;
14422 LOGD("Req track doesn't exist\n");
14426 total_track_num = player->selector[type].total_track_num;
14427 if (total_track_num <= 0) {
14428 result = MM_ERROR_PLAYER_NO_OP;
14429 LOGD("Language list is not available \n");
14433 if ((index < 0) || (index >= total_track_num)) {
14434 result = MM_ERROR_INVALID_ARGUMENT;
14435 LOGD("Not a proper index : %d \n", index);
14439 /*To get the new pad from the selector*/
14440 change_pad_name = g_strdup_printf("sink_%u", index);
14441 if (change_pad_name == NULL) {
14442 result = MM_ERROR_PLAYER_INTERNAL;
14443 LOGD("Pad does not exists\n");
14447 LOGD("new active pad name: %s\n", change_pad_name);
14449 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14450 if (sinkpad == NULL) {
14451 LOGD("sinkpad is NULL");
14452 result = MM_ERROR_PLAYER_INTERNAL;
14456 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14457 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14459 caps = gst_pad_get_current_caps(sinkpad);
14460 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14463 gst_object_unref(sinkpad);
14465 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14466 __mmplayer_set_audio_attrs(player, caps);
14470 MMPLAYER_FREEIF(change_pad_name);
14474 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14476 int result = MM_ERROR_NONE;
14477 mm_player_t* player = NULL;
14478 MMPlayerGstElement* mainbin = NULL;
14480 gint current_active_index = 0;
14482 GstState current_state = GST_STATE_VOID_PENDING;
14483 GstEvent* event = NULL;
14488 player = (mm_player_t*)hplayer;
14489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14491 if (!player->pipeline) {
14492 LOGE("Track %d pre setting -> %d\n", type, index);
14494 player->selector[type].active_pad_index = index;
14498 mainbin = player->pipeline->mainbin;
14500 current_active_index = player->selector[type].active_pad_index;
14502 /*If index is same as running index no need to change the pad*/
14503 if (current_active_index == index)
14506 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14507 result = MM_ERROR_PLAYER_INVALID_STATE;
14511 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14512 if (current_state < GST_STATE_PAUSED) {
14513 result = MM_ERROR_PLAYER_INVALID_STATE;
14514 LOGW("Pipeline not in porper state\n");
14518 result = __mmplayer_change_selector_pad(player, type, index);
14519 if (result != MM_ERROR_NONE) {
14520 LOGE("change selector pad error\n");
14524 player->selector[type].active_pad_index = index;
14526 if (current_state == GST_STATE_PLAYING) {
14527 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
14529 __gst_send_event_to_sink(player, event);
14531 result = MM_ERROR_PLAYER_INTERNAL;
14540 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14542 mm_player_t* player = (mm_player_t*) hplayer;
14546 /* check player handle */
14547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14549 *silent = player->set_mode.subtitle_off;
14551 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14555 return MM_ERROR_NONE;
14559 __is_ms_buff_src(mm_player_t* player)
14561 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14563 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14567 __has_suffix(mm_player_t* player, const gchar* suffix)
14569 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14570 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14572 gboolean ret = FALSE;
14573 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14574 gchar* t_suffix = g_ascii_strdown(suffix, -1);
14576 if (g_str_has_suffix(player->profile.uri, suffix))
14579 MMPLAYER_FREEIF(t_url);
14580 MMPLAYER_FREEIF(t_suffix);
14586 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14588 mm_player_t* player = (mm_player_t*) hplayer;
14590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14592 MMPLAYER_VIDEO_SINK_CHECK(player);
14594 LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14596 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14598 return MM_ERROR_NONE;
14601 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14604 mm_player_t* player = (mm_player_t*) hplayer;
14605 float _level = 0.0;
14609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14611 MMPLAYER_VIDEO_SINK_CHECK(player);
14613 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14615 LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14621 return MM_ERROR_NONE;
14625 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14627 mm_player_t* player = (mm_player_t*) hplayer;
14629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14631 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14632 MMPLAYER_PRINT_STATE(player);
14633 LOGE("wrong-state : can't set the download mode to parse");
14634 return MM_ERROR_PLAYER_INVALID_STATE;
14637 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14638 player->video_hub_download_mode = mode;
14640 return MM_ERROR_NONE;
14644 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14646 mm_player_t* player = (mm_player_t*) hplayer;
14648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14650 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14651 player->sync_handler = enable;
14653 return MM_ERROR_NONE;
14657 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14659 long long clock_delta,
14660 long long video_time,
14661 long long media_clock,
14662 long long audio_time)
14664 mm_player_t* player = (mm_player_t*) hplayer;
14665 MMPlayerGstElement* mainbin = NULL;
14666 GstClockTime start_time_audio = 0, start_time_video = 0;
14667 GstClockTimeDiff base_time = 0, new_base_time = 0;
14668 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14669 gint64 api_delta = 0;
14670 gint64 position = 0, position_delta = 0;
14671 gint64 adj_base_time = 0;
14672 GstClock *curr_clock = NULL;
14673 GstClockTime curr_time = 0;
14674 gboolean query_ret = TRUE;
14675 int result = MM_ERROR_NONE;
14679 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14680 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14681 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14683 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14685 if ((video_time < 0) || (player->doing_seek)) {
14686 LOGD("skip setting master clock. %lld", video_time);
14690 mainbin = player->pipeline->mainbin;
14692 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14693 curr_time = gst_clock_get_time(curr_clock);
14695 current_state = MMPLAYER_CURRENT_STATE(player);
14697 if (current_state == MM_PLAYER_STATE_PLAYING)
14698 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14700 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14702 position = player->last_position;
14703 LOGD("query fail. %lld", position);
14706 clock *= GST_USECOND;
14707 clock_delta *= GST_USECOND;
14709 api_delta = clock - curr_time;
14710 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14711 player->video_share_api_delta = api_delta;
14713 clock_delta += (api_delta - player->video_share_api_delta);
14715 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14716 player->video_share_clock_delta = (gint64)clock_delta;
14718 position_delta = (position/GST_USECOND) - video_time;
14719 position_delta *= GST_USECOND;
14721 adj_base_time = position_delta;
14722 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14725 gint64 new_play_time = 0;
14726 gint64 network_delay = 0;
14728 video_time *= GST_USECOND;
14730 network_delay = clock_delta - player->video_share_clock_delta;
14731 new_play_time = video_time + network_delay;
14733 adj_base_time = position - new_play_time;
14735 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14736 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14739 /* Adjust Current Stream Time with base_time of sink
14740 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14741 * 2. Set new base time
14742 * if adj_base_time is positive value, the stream time will be decreased.
14743 * 3. If seek event is occurred, the start time will be reset. */
14744 if ((player->pipeline->audiobin) &&
14745 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14746 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14748 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14749 LOGD("audio sink : gst_element_set_start_time -> NONE");
14750 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14753 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14756 if ((player->pipeline->videobin) &&
14757 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14758 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14760 if (start_time_video != GST_CLOCK_TIME_NONE) {
14761 LOGD("video sink : gst_element_set_start_time -> NONE");
14762 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14765 // if videobin exist, get base_time from videobin.
14766 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14769 new_base_time = base_time + adj_base_time;
14771 if ((player->pipeline->audiobin) &&
14772 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14773 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14775 if ((player->pipeline->videobin) &&
14776 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14777 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14786 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14787 long long *video_time,
14788 long long *media_clock,
14789 long long *audio_time)
14791 mm_player_t* player = (mm_player_t*) hplayer;
14792 MMPlayerGstElement* mainbin = NULL;
14793 GstClock *curr_clock = NULL;
14794 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14795 gint64 position = 0;
14796 gboolean query_ret = TRUE;
14800 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14801 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14802 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14804 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14805 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14806 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14808 mainbin = player->pipeline->mainbin;
14810 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14812 current_state = MMPLAYER_CURRENT_STATE(player);
14814 if (current_state != MM_PLAYER_STATE_PAUSED)
14815 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14817 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14819 position = player->last_position;
14821 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14823 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14826 gst_object_unref(curr_clock);
14830 return MM_ERROR_NONE;
14834 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14836 mm_player_t* player = (mm_player_t*) hplayer;
14841 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14842 MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14844 if (player->v_stream_caps) {
14845 GstStructure *str = NULL;
14847 str = gst_caps_get_structure(player->v_stream_caps, 0);
14848 if (!gst_structure_get_int(str, "orientation", &org_angle))
14849 LOGD("missing 'orientation' field in video caps");
14852 LOGD("orientation: %d", org_angle);
14853 *angle = org_angle;
14856 return MM_ERROR_NONE;
14860 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14862 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14863 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14865 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14866 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14870 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14871 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14872 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14873 mm_player_dump_t *dump_s;
14874 dump_s = g_malloc(sizeof(mm_player_dump_t));
14876 if (dump_s == NULL) {
14877 LOGE("malloc fail");
14881 dump_s->dump_element_file = NULL;
14882 dump_s->dump_pad = NULL;
14883 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14885 if (dump_s->dump_pad) {
14886 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14887 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]);
14888 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14889 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);
14890 /* add list for removed buffer probe and close FILE */
14891 player->dump_list = g_list_append(player->dump_list, dump_s);
14892 LOGD("%s sink pad added buffer probe for dump", factory_name);
14897 LOGE("failed to get %s sink pad added", factory_name);
14906 static GstPadProbeReturn
14907 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
14909 FILE *dump_data = (FILE *) u_data;
14910 // int written = 0;
14911 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14912 GstMapInfo probe_info = GST_MAP_INFO_INIT;
14914 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14916 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14918 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14920 fwrite(probe_info.data, 1, probe_info.size , dump_data);
14922 return GST_PAD_PROBE_OK;
14926 __mmplayer_release_dump_list(GList *dump_list)
14929 GList *d_list = dump_list;
14930 for (; d_list; d_list = g_list_next(d_list)) {
14931 mm_player_dump_t *dump_s = d_list->data;
14932 if (dump_s->dump_pad) {
14933 if (dump_s->probe_handle_id)
14934 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14936 if (dump_s->dump_element_file) {
14937 fclose(dump_s->dump_element_file);
14938 dump_s->dump_element_file = NULL;
14940 MMPLAYER_FREEIF(dump_s);
14942 g_list_free(dump_list);
14948 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14950 mm_player_t* player = (mm_player_t*) hplayer;
14954 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14955 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14957 *exist = player->has_closed_caption;
14961 return MM_ERROR_NONE;
14964 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14968 /* increase ref count of gst buffer */
14970 ret = gst_buffer_ref((GstBuffer *)buffer);
14976 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14980 gst_buffer_unref((GstBuffer *)buffer);
14987 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14989 mm_player_t *player = (mm_player_t*)user_data;
14990 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14991 guint64 current_level_bytes = 0;
14993 MMPLAYER_RETURN_IF_FAIL(player);
14995 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14997 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14998 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15000 if (player->media_stream_buffer_status_cb[type])
15001 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15002 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15007 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
15009 mm_player_t *player = (mm_player_t*)user_data;
15010 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15011 guint64 current_level_bytes = 0;
15013 MMPLAYER_RETURN_IF_FAIL(player);
15015 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15017 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
15019 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15020 if (player->media_stream_buffer_status_cb[type])
15021 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15022 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15026 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
15028 mm_player_t *player = (mm_player_t*)user_data;
15029 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15030 guint64 current_level_bytes = 0;
15032 MMPLAYER_RETURN_IF_FAIL(player);
15034 LOGI("app-src: feed subtitle\n");
15036 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15038 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15039 if (player->media_stream_buffer_status_cb[type])
15040 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
15042 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15046 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
15048 mm_player_t *player = (mm_player_t*)user_data;
15049 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15050 guint64 current_level_bytes = 0;
15052 MMPLAYER_RETURN_IF_FAIL(player);
15054 LOGI("app-src: audio buffer is full.\n");
15056 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15058 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15060 if (player->media_stream_buffer_status_cb[type])
15061 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15063 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15067 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
15069 mm_player_t *player = (mm_player_t*)user_data;
15070 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15071 guint64 current_level_bytes = 0;
15073 MMPLAYER_RETURN_IF_FAIL(player);
15075 LOGI("app-src: video buffer is full.\n");
15077 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
15079 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15080 if (player->media_stream_buffer_status_cb[type])
15081 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15083 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15087 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15089 mm_player_t *player = (mm_player_t*)user_data;
15090 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15092 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15094 LOGD("app-src: seek audio data %llu\n", position);
15095 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15097 if (player->media_stream_seek_data_cb[type])
15098 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15099 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15105 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15107 mm_player_t *player = (mm_player_t*)user_data;
15108 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15110 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15112 LOGD("app-src: seek video data %llu\n", position);
15113 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15114 if (player->media_stream_seek_data_cb[type])
15115 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15116 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15122 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15124 mm_player_t *player = (mm_player_t*)user_data;
15125 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15127 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15129 LOGD("app-src: seek subtitle data\n");
15130 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15132 if (player->media_stream_seek_data_cb[type])
15133 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15134 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15140 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15142 mm_player_t* player = (mm_player_t*) hplayer;
15146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15148 player->pcm_samplerate = samplerate;
15149 player->pcm_channel = channel;
15152 return MM_ERROR_NONE;
15155 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15157 mm_player_t* player = (mm_player_t*) hplayer;
15161 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15162 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15164 if (MMPLAYER_IS_STREAMING(player))
15165 *timeout = player->ini.live_state_change_timeout;
15167 *timeout = player->ini.localplayback_state_change_timeout;
15169 LOGD("timeout = %d\n", *timeout);
15172 return MM_ERROR_NONE;
15175 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15177 mm_player_t* player = (mm_player_t*) hplayer;
15181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15182 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15184 *num = player->video_num_buffers;
15185 *extra_num = player->video_extra_num_buffers;
15187 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15190 return MM_ERROR_NONE;