4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/wayland/wayland.h>
33 #include <gst/audio/gstaudiobasesink.h>
43 #include <mm_attrs_private.h>
45 #include <mm_sound_focus.h>
47 #include "mm_player_priv.h"
48 #include "mm_player_ini.h"
49 #include "mm_player_attrs.h"
50 #include "mm_player_capture.h"
51 #include "mm_player_utils.h"
52 #include "mm_player_tracks.h"
54 /*===========================================================================================
56 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
58 ========================================================================================== */
60 /*---------------------------------------------------------------------------
61 | GLOBAL CONSTANT DEFINITIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
65 | IMPORTED VARIABLE DECLARATIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED FUNCTION DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
74 ---------------------------------------------------------------------------*/
75 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
76 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
78 #define MM_VOLUME_FACTOR_DEFAULT 1.0
79 #define MM_VOLUME_FACTOR_MIN 0
80 #define MM_VOLUME_FACTOR_MAX 1.0
82 /* Don't need to sleep for sound fadeout
83 * fadeout related fucntion will be deleted(Deprecated)
85 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
87 #define MM_PLAYER_MPEG_VNAME "mpegversion"
88 #define MM_PLAYER_DIVX_VNAME "divxversion"
89 #define MM_PLAYER_WMV_VNAME "wmvversion"
90 #define MM_PLAYER_WMA_VNAME "wmaversion"
92 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYBACK_RATE_EX_AUDIO_MIN 0.5
94 #define PLAYBACK_RATE_EX_AUDIO_MAX 2.0
95 #define PLAYBACK_RATE_EX_VIDEO_MIN 0.5
96 #define PLAYBACK_RATE_EX_VIDEO_MAX 1.5
97 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
99 #define GST_QUEUE_DEFAULT_TIME 4
100 #define GST_QUEUE_HLS_TIME 8
102 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
103 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
104 (player->ini.http_use_file_buffer) && \
105 (player->http_file_buffering_path) && \
106 (strlen(player->http_file_buffering_path) > 0))
107 #define MM_PLAYER_NAME "mmplayer"
109 #define PLAYER_DISPLAY_MODE_DST_ROI 5
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | GLOBAL VARIABLE DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------
124 | LOCAL VARIABLE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | LOCAL FUNCTION PROTOTYPES: |
129 ---------------------------------------------------------------------------*/
130 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
131 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
132 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_create_subtitle_src(mm_player_t* player);
134 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
138 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
139 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
140 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
141 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
142 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
143 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
144 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
145 //static GValueArray* __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
147 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
148 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
149 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
150 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
154 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
155 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
156 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
157 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
158 //static void __mmplayer_check_video_zero_cpoy(mm_player_t* player, GstElementFactory* factory);
160 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
161 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
162 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
164 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
165 //static void __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
166 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
167 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player);
168 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
171 static void __mmplayer_init_factories(mm_player_t* player);
172 static void __mmplayer_release_factories(mm_player_t* player);
173 static void __mmplayer_release_misc(mm_player_t* player);
174 static void __mmplayer_release_misc_post(mm_player_t* player);
175 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
176 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
177 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
179 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
180 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
182 int __mmplayer_switch_audio_sink(mm_player_t* player);
183 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
184 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
185 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
186 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
187 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
188 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
190 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
191 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
192 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
193 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
194 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
195 static gboolean __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad);
196 static gboolean __mmplayer_link_sink(mm_player_t* player, GstPad *srcpad);
197 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
198 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
199 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
200 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
201 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
202 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
203 static gpointer __mmplayer_next_play_thread(gpointer data);
204 static gpointer __mmplayer_repeat_thread(gpointer data);
205 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
208 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
209 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
210 static void __mmplayer_release_dump_list(GList *dump_list);
212 static int __gst_realize(mm_player_t* player);
213 static int __gst_unrealize(mm_player_t* player);
214 static int __gst_start(mm_player_t* player);
215 static int __gst_stop(mm_player_t* player);
216 static int __gst_pause(mm_player_t* player, gboolean async);
217 static int __gst_resume(mm_player_t* player, gboolean async);
218 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
219 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
220 gint64 cur, GstSeekType stop_type, gint64 stop);
221 static int __gst_pending_seek(mm_player_t* player);
223 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
224 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
225 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
226 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
227 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
229 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
231 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
232 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
235 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
236 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
238 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
239 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
242 static gboolean __is_ms_buff_src(mm_player_t* player);
243 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
245 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
246 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
247 static int __mmplayer_start_streaming_ext(mm_player_t *player);
248 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
249 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
251 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
252 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
253 static void __mmplayer_check_pipeline(mm_player_t* player);
254 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
255 static void __mmplayer_deactivate_old_path(mm_player_t *player);
256 #if 0 // We'll need this in future.
257 static int __mmplayer_gst_switching_element(mm_player_t *player, GstElement *search_from, const gchar *removal_name, const gchar *new_element_name);
260 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
261 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
263 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
264 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
265 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
266 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
267 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
268 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
269 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
270 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
271 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
272 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
273 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
274 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
275 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
276 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
278 /*===========================================================================================
280 | FUNCTION DEFINITIONS |
282 ========================================================================================== */
286 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
290 count = gst_tag_list_get_tag_size(list, tag);
292 LOGD("count = %d", count);
294 for (i = 0; i < count; i++) {
297 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
298 if (!gst_tag_list_get_string_index(list, tag, i, &str))
299 g_assert_not_reached();
301 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
304 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
306 g_print(" : %s\n", str);
313 /* This function should be called after the pipeline goes PAUSED or higher
316 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag) // @
318 static gboolean has_duration = FALSE;
319 static gboolean has_video_attrs = FALSE;
320 static gboolean has_audio_attrs = FALSE;
321 static gboolean has_bitrate = FALSE;
322 gboolean missing_only = FALSE;
323 gboolean all = FALSE;
325 GstStructure* p = NULL;
326 MMHandleType attrs = 0;
328 gint stream_service_type = STREAMING_SERVICE_NONE;
333 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
335 /* check player state here */
336 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
337 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
338 /* give warning now only */
339 LOGW("be careful. content attributes may not available in this state ");
342 /* get content attribute first */
343 attrs = MMPLAYER_GET_ATTRS(player);
345 LOGE("cannot get content attribute");
349 /* get update flag */
351 if (flag & ATTR_MISSING_ONLY) {
353 LOGD("updating missed attr only");
356 if (flag & ATTR_ALL) {
358 has_duration = FALSE;
359 has_video_attrs = FALSE;
360 has_audio_attrs = FALSE;
363 LOGD("updating all attrs");
366 if (missing_only && all) {
367 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
368 missing_only = FALSE;
371 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
372 LOGD("try to update duration");
373 has_duration = FALSE;
375 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
376 player->duration = dur_nsec;
377 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
380 if (player->duration < 0) {
381 LOGW("duration : %lld is Non-Initialized !!! \n",player->duration);
382 player->duration = 0;
385 /* try to get streaming service type */
386 stream_service_type = __mmplayer_get_stream_service_type(player);
387 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
389 /* check duration is OK */
390 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
391 /* FIXIT : find another way to get duration here. */
392 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
395 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
400 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
401 /* update audio params
402 NOTE : We need original audio params and it can be only obtained from src pad of audio
403 decoder. Below code only valid when we are not using 'resampler' just before
406 LOGD("try to update audio attrs");
407 has_audio_attrs = FALSE;
409 if (player->pipeline->audiobin &&
410 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
411 GstCaps *caps_a = NULL;
413 gint samplerate = 0, channels = 0;
415 pad = gst_element_get_static_pad(
416 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
419 caps_a = gst_pad_get_current_caps(pad);
422 p = gst_caps_get_structure(caps_a, 0);
424 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
426 gst_structure_get_int(p, "rate", &samplerate);
427 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
429 gst_structure_get_int(p, "channels", &channels);
430 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
432 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
434 gst_caps_unref(caps_a);
437 has_audio_attrs = TRUE;
439 LOGW("not ready to get audio caps");
441 gst_object_unref(pad);
443 LOGW("failed to get pad from audiosink");
447 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
448 LOGD("try to update video attrs");
449 has_video_attrs = FALSE;
451 if (player->pipeline->videobin &&
452 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
453 GstCaps *caps_v = NULL;
458 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
460 caps_v = gst_pad_get_current_caps(pad);
462 /* Use v_stream_caps, if fail to get video_sink sink pad*/
463 if (!caps_v && player->v_stream_caps) {
464 caps_v = player->v_stream_caps;
465 gst_caps_ref(caps_v);
469 p = gst_caps_get_structure(caps_v, 0);
470 gst_structure_get_int(p, "width", &width);
471 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
473 gst_structure_get_int(p, "height", &height);
474 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
476 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
478 SECURE_LOGD("width : %d height : %d", width, height);
480 gst_caps_unref(caps_v);
484 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
485 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
488 has_video_attrs = TRUE;
490 LOGD("no negitiated caps from videosink");
491 gst_object_unref(pad);
494 LOGD("no videosink sink pad");
499 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
502 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
503 if (player->duration) {
504 guint64 data_size = 0;
506 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
507 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
509 if (stat(path, &sb) == 0)
510 data_size = (guint64)sb.st_size;
511 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
512 data_size = player->http_content_size;
513 LOGD("try to update bitrate : data_size = %lld", data_size);
517 guint64 msec_dur = 0;
519 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
520 bitrate = data_size * 8 * 1000 / msec_dur;
521 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
522 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
527 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
528 if (player->total_bitrate) {
529 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
537 if (mmf_attrs_commit(attrs)) {
538 LOGE("failed to update attributes\n");
547 static gboolean __mmplayer_get_stream_service_type(mm_player_t* player)
549 gint streaming_type = STREAMING_SERVICE_NONE;
553 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
555 player->pipeline->mainbin &&
556 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
559 /* streaming service type if streaming */
560 if (!MMPLAYER_IS_STREAMING(player))
561 return STREAMING_SERVICE_NONE;
563 if (MMPLAYER_IS_HTTP_STREAMING(player))
564 streaming_type = (player->duration == 0) ?
565 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
567 switch (streaming_type) {
568 case STREAMING_SERVICE_LIVE:
569 LOGD("it's live streaming");
571 case STREAMING_SERVICE_VOD:
572 LOGD("it's vod streaming");
575 LOGE("should not get here");
578 player->streaming_type = streaming_type;
581 return streaming_type;
585 /* this function sets the player state and also report
586 * it to applicaton by calling callback function
589 __mmplayer_set_state(mm_player_t* player, int state) // @
591 MMMessageParamType msg = {0, };
592 int sound_result = MM_ERROR_NONE;
593 gboolean post_bos = FALSE;
594 gboolean interrupted_by_focus = FALSE;
595 gboolean interrupted_by_resource = FALSE;
597 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
599 if (MMPLAYER_CURRENT_STATE(player) == state) {
600 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
601 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
602 return MM_ERROR_NONE;
605 /* update player states */
606 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
607 MMPLAYER_CURRENT_STATE(player) = state;
609 /* FIXIT : it's better to do like below code
610 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_TARGET_STATE(player))
611 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
612 and add more code to handling PENDING_STATE.
614 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
615 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
618 MMPLAYER_PRINT_STATE(player);
620 /* do some FSM stuffs before posting new state to application */
621 interrupted_by_focus = player->sound_focus.by_asm_cb;
622 interrupted_by_resource = player->resource_manager.by_rm_cb;
624 switch (MMPLAYER_CURRENT_STATE(player)) {
625 case MM_PLAYER_STATE_NULL:
626 case MM_PLAYER_STATE_READY:
628 if (player->cmd == MMPLAYER_COMMAND_STOP) {
629 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
630 if (sound_result != MM_ERROR_NONE) {
631 LOGE("failed to release sound focus\n");
632 return MM_ERROR_POLICY_INTERNAL;
638 case MM_PLAYER_STATE_PAUSED:
640 if (!player->sent_bos) {
642 #define MMPLAYER_MAX_SOUND_PRIORITY 3
644 /* rtsp case, get content attrs by GstMessage */
645 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
646 /* it's first time to update all content attrs. */
647 _mmplayer_update_content_attrs( player, ATTR_ALL );
650 /* set max sound priority to keep own sound and not to mute other's one */
651 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
653 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
655 LOGD("set max audio priority");
656 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
662 /* add audio callback probe if condition is satisfied */
663 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
664 __mmplayer_configure_audio_callback(player);
665 /* FIXIT : handle return value */
667 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
668 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
669 if (sound_result != MM_ERROR_NONE) {
670 LOGE("failed to release sound focus\n");
671 return MM_ERROR_POLICY_INTERNAL;
677 case MM_PLAYER_STATE_PLAYING:
679 /* try to get content metadata */
680 if (!player->sent_bos) {
681 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
682 * c-api since c-api doesn't use _start() anymore. It may not work propery with
683 * legacy mmfw-player api */
684 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
687 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
688 if (!player->sent_bos)
689 __mmplayer_handle_missed_plugin(player);
690 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
691 if (sound_result != MM_ERROR_NONE) {
692 // FIXME : need to check history
693 if (player->pipeline->videobin) {
694 MMMessageParamType msg = {0, };
696 LOGE("failed to go ahead because of video conflict\n");
698 msg.union_type = MM_MSG_UNION_CODE;
699 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
700 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
702 _mmplayer_unrealize((MMHandleType)player);
704 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
705 _mmplayer_pause((MMHandleType)player);
708 return MM_ERROR_POLICY_INTERNAL;
712 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
713 /* initialize because auto resume is done well. */
714 player->resumed_by_rewind = FALSE;
715 player->playback_rate = 1.0;
718 if (!player->sent_bos) {
719 /* check audio codec field is set or not
720 * we can get it from typefinder or codec's caps.
722 gchar *audio_codec = NULL;
723 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
725 /* The codec format can't be sent for audio only case like amr, mid etc.
726 * Because, parser don't make related TAG.
727 * So, if it's not set yet, fill it with found data.
730 if (g_strrstr(player->type, "audio/midi"))
731 audio_codec = g_strdup("MIDI");
732 else if (g_strrstr(player->type, "audio/x-amr"))
733 audio_codec = g_strdup("AMR");
734 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
735 audio_codec = g_strdup("AAC");
737 audio_codec = g_strdup("unknown");
738 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
740 MMPLAYER_FREEIF(audio_codec);
741 mmf_attrs_commit(player->attrs);
742 LOGD("set audio codec type with caps\n");
750 case MM_PLAYER_STATE_NONE:
752 LOGW("invalid target state, there is nothing to do.\n");
757 /* post message to application */
758 if (MMPLAYER_TARGET_STATE(player) == state) {
759 /* fill the message with state of player */
760 msg.union_type = MM_MSG_UNION_STATE;
761 msg.state.previous = MMPLAYER_PREV_STATE(player);
762 msg.state.current = MMPLAYER_CURRENT_STATE(player);
764 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
766 /* state changed by focus or resource callback */
767 if (interrupted_by_focus || interrupted_by_resource) {
768 if (interrupted_by_focus)
769 msg.state.code = player->sound_focus.focus_changed_msg;
770 else if (interrupted_by_resource)
771 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
772 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
773 } else { /* state changed by usecase */
774 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
777 LOGD("intermediate state, do nothing.\n");
778 MMPLAYER_PRINT_STATE(player);
779 return MM_ERROR_NONE;
783 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
784 player->sent_bos = TRUE;
787 return MM_ERROR_NONE;
790 static gpointer __mmplayer_next_play_thread(gpointer data)
792 mm_player_t* player = (mm_player_t*) data;
793 MMPlayerGstElement *mainbin = NULL;
795 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
797 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
798 while (!player->next_play_thread_exit) {
799 LOGD("next play thread started. waiting for signal.\n");
800 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
802 LOGD("reconfigure pipeline for gapless play.\n");
804 if (player->next_play_thread_exit) {
805 if (player->gapless.reconfigure) {
806 player->gapless.reconfigure = false;
807 MMPLAYER_PLAYBACK_UNLOCK(player);
809 LOGD("exiting gapless play thread\n");
813 mainbin = player->pipeline->mainbin;
815 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
816 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
817 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
818 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
819 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
821 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
823 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
828 static gpointer __mmplayer_repeat_thread(gpointer data)
830 mm_player_t* player = (mm_player_t*) data;
831 gboolean ret_value = FALSE;
832 MMHandleType attrs = 0;
835 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
837 MMPLAYER_REPEAT_THREAD_LOCK(player);
838 while (!player->repeat_thread_exit) {
839 LOGD("repeat thread started. waiting for signal.\n");
840 MMPLAYER_REPEAT_THREAD_WAIT(player);
842 if (player->repeat_thread_exit) {
843 LOGD("exiting repeat thread\n");
849 MMPLAYER_CMD_LOCK(player);
851 attrs = MMPLAYER_GET_ATTRS(player);
853 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
854 LOGE("can not get play count\n");
855 MMPLAYER_CMD_UNLOCK(player);
859 if (player->section_repeat) {
860 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
862 if (player->playback_rate < 0.0) {
863 player->resumed_by_rewind = TRUE;
864 _mmplayer_set_mute((MMHandleType)player, 0);
865 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
868 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
869 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
870 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
873 player->sent_bos = FALSE;
877 LOGE("failed to set position to zero for rewind\n");
878 MMPLAYER_CMD_UNLOCK(player);
882 /* decrease play count */
884 /* we successeded to rewind. update play count and then wait for next EOS */
887 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
889 /* commit attribute */
890 if (mmf_attrs_commit(attrs))
891 LOGE("failed to commit attribute\n");
895 MMPLAYER_CMD_UNLOCK(player);
898 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
903 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
905 MMHandleType attrs = 0;
906 guint64 data_size = 0;
908 unsigned long pos_msec = 0;
911 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
913 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
915 attrs = MMPLAYER_GET_ATTRS(player);
917 LOGE("fail to get attributes.\n");
921 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
922 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
924 if (stat(path, &sb) == 0)
925 data_size = (guint64)sb.st_size;
926 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
927 data_size = player->http_content_size;
929 __mm_player_streaming_buffering(player->streamer,
932 player->last_position,
935 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
941 __mmplayer_handle_buffering_message(mm_player_t* player)
943 int ret = MM_ERROR_NONE;
944 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
945 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
946 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
947 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
949 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
950 LOGW("do nothing for buffering msg\n");
951 ret = MM_ERROR_PLAYER_INVALID_STATE;
955 prev_state = MMPLAYER_PREV_STATE(player);
956 current_state = MMPLAYER_CURRENT_STATE(player);
957 target_state = MMPLAYER_TARGET_STATE(player);
958 pending_state = MMPLAYER_PENDING_STATE(player);
960 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
961 MMPLAYER_STATE_GET_NAME(prev_state),
962 MMPLAYER_STATE_GET_NAME(current_state),
963 MMPLAYER_STATE_GET_NAME(pending_state),
964 MMPLAYER_STATE_GET_NAME(target_state),
965 player->streamer->is_buffering);
967 if (!player->streamer->is_buffering) {
968 /* NOTE : if buffering has done, player has to go to target state. */
969 switch (target_state) {
970 case MM_PLAYER_STATE_PAUSED:
972 switch (pending_state) {
973 case MM_PLAYER_STATE_PLAYING:
974 __gst_pause(player, TRUE);
977 case MM_PLAYER_STATE_PAUSED:
978 LOGD("player is already going to paused state, there is nothing to do.\n");
981 case MM_PLAYER_STATE_NONE:
982 case MM_PLAYER_STATE_NULL:
983 case MM_PLAYER_STATE_READY:
985 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
991 case MM_PLAYER_STATE_PLAYING:
993 switch (pending_state) {
994 case MM_PLAYER_STATE_NONE:
996 if (current_state != MM_PLAYER_STATE_PLAYING)
997 __gst_resume(player, TRUE);
1001 case MM_PLAYER_STATE_PAUSED:
1002 /* NOTE: It should be worked as asynchronously.
1003 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1005 __gst_resume(player, TRUE);
1008 case MM_PLAYER_STATE_PLAYING:
1009 LOGD("player is already going to playing state, there is nothing to do.\n");
1012 case MM_PLAYER_STATE_NULL:
1013 case MM_PLAYER_STATE_READY:
1015 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1021 case MM_PLAYER_STATE_NULL:
1022 case MM_PLAYER_STATE_READY:
1023 case MM_PLAYER_STATE_NONE:
1025 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1029 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1030 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1032 switch (pending_state) {
1033 case MM_PLAYER_STATE_NONE:
1035 if (current_state != MM_PLAYER_STATE_PAUSED) {
1036 /* rtsp streaming pause makes rtsp server stop sending data. */
1037 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1038 LOGD("set pause state during buffering\n");
1039 __gst_pause( player, TRUE );
1045 case MM_PLAYER_STATE_PLAYING:
1046 /* rtsp streaming pause makes rtsp server stop sending data. */
1047 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1048 __gst_pause ( player, TRUE );
1052 case MM_PLAYER_STATE_PAUSED:
1055 case MM_PLAYER_STATE_NULL:
1056 case MM_PLAYER_STATE_READY:
1058 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1068 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1070 MMPlayerGstElement *textbin;
1073 MMPLAYER_RETURN_IF_FAIL(player &&
1075 player->pipeline->textbin);
1077 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1079 textbin = player->pipeline->textbin;
1082 LOGD("Drop subtitle text after getting EOS\n");
1084 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1085 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1087 player->is_subtitle_force_drop = TRUE;
1089 if (player->is_subtitle_force_drop == TRUE) {
1090 LOGD("Enable subtitle data path without drop\n");
1092 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1093 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1095 LOGD("non-connected with external display");
1097 player->is_subtitle_force_drop = FALSE;
1103 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1105 mm_player_t* player = (mm_player_t*) data;
1106 gboolean ret = TRUE;
1107 static gboolean async_done = FALSE;
1109 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1110 MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
1112 switch (GST_MESSAGE_TYPE(msg)) {
1113 case GST_MESSAGE_UNKNOWN:
1114 LOGD("unknown message received\n");
1117 case GST_MESSAGE_EOS:
1119 MMHandleType attrs = 0;
1122 LOGD("GST_MESSAGE_EOS received\n");
1124 /* NOTE : EOS event is comming multiple time. watch out it */
1125 /* check state. we only process EOS when pipeline state goes to PLAYING */
1126 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1127 LOGD("EOS received on non-playing state. ignoring it\n");
1131 if (player->pipeline) {
1132 if (player->pipeline->textbin)
1133 __mmplayer_drop_subtitle(player, TRUE);
1135 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1138 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1140 LOGD("release audio callback\n");
1142 /* release audio callback */
1143 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1144 player->audio_cb_probe_id = 0;
1145 /* audio callback should be free because it can be called even though probe remove.*/
1146 player->audio_stream_cb = NULL;
1147 player->audio_stream_cb_user_param = NULL;
1151 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1152 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1154 /* rewind if repeat count is greater then zero */
1155 /* get play count */
1156 attrs = MMPLAYER_GET_ATTRS(player);
1159 gboolean smooth_repeat = FALSE;
1161 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1162 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1164 player->play_count = count;
1166 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1168 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1169 if (smooth_repeat) {
1170 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1172 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1178 if (player->section_repeat) {
1179 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1181 if (player->playback_rate < 0.0) {
1182 player->resumed_by_rewind = TRUE;
1183 _mmplayer_set_mute((MMHandleType)player, 0);
1184 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1187 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1190 player->sent_bos = FALSE;
1193 if (MM_ERROR_NONE != ret_value)
1194 LOGE("failed to set position to zero for rewind\n");
1196 /* not posting eos when repeating */
1202 if (player->pipeline)
1203 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1205 /* post eos message to application */
1206 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1208 /* reset last position */
1209 player->last_position = 0;
1213 case GST_MESSAGE_ERROR:
1215 GError *error = NULL;
1216 gchar* debug = NULL;
1218 /* generating debug info before returning error */
1219 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1221 /* get error code */
1222 gst_message_parse_error(msg, &error, &debug);
1224 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1225 /* Note : the streaming error from the streaming source is handled
1226 * using __mmplayer_handle_streaming_error.
1228 __mmplayer_handle_streaming_error(player, msg);
1230 /* dump state of all element */
1231 __mmplayer_dump_pipeline_state(player);
1233 /* traslate gst error code to msl error code. then post it
1234 * to application if needed
1236 __mmplayer_handle_gst_error(player, msg, error);
1239 LOGE("error debug : %s", debug);
1242 if (MMPLAYER_IS_HTTP_PD(player))
1243 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1245 MMPLAYER_FREEIF(debug);
1246 g_error_free(error);
1250 case GST_MESSAGE_WARNING:
1253 GError* error = NULL;
1255 gst_message_parse_warning(msg, &error, &debug);
1257 LOGD("warning : %s\n", error->message);
1258 LOGD("debug : %s\n", debug);
1260 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1262 MMPLAYER_FREEIF(debug);
1263 g_error_free(error);
1267 case GST_MESSAGE_TAG:
1269 LOGD("GST_MESSAGE_TAG\n");
1270 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1271 LOGW("failed to extract tags from gstmessage\n");
1275 case GST_MESSAGE_BUFFERING:
1277 MMMessageParamType msg_param = {0, };
1278 int bRet = MM_ERROR_NONE;
1280 if (!MMPLAYER_IS_STREAMING(player))
1283 /* ignore the prev buffering message */
1284 if ((player->streamer) && (player->streamer->is_buffering == FALSE) && (player->streamer->is_buffering_done == TRUE)) {
1285 gint buffer_percent = 0;
1287 gst_message_parse_buffering(msg, &buffer_percent);
1289 if (buffer_percent == MAX_BUFFER_PERCENT) {
1290 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1291 player->streamer->is_buffering_done = FALSE;
1297 MMPLAYER_CMD_LOCK(player);
1298 __mmplayer_update_buffer_setting(player, msg);
1300 bRet = __mmplayer_handle_buffering_message(player);
1302 if (bRet == MM_ERROR_NONE) {
1303 msg_param.connection.buffering = player->streamer->buffering_percent;
1304 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1306 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1307 player->pending_resume &&
1308 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1310 player->is_external_subtitle_added_now = FALSE;
1311 player->pending_resume = FALSE;
1312 _mmplayer_resume((MMHandleType)player);
1315 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1316 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1318 if (player->doing_seek) {
1319 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1320 player->doing_seek = FALSE;
1321 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1322 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1327 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1328 if (!player->streamer) {
1329 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1330 MMPLAYER_CMD_UNLOCK(player);
1334 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1336 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1337 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1339 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1340 msg_param.connection.buffering = player->streamer->buffering_percent;
1341 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1343 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1346 msg_param.connection.buffering = player->streamer->buffering_percent;
1347 MMPLAYER_POST_MSG( player, MM_MESSAGE_BUFFERING, &msg_param );
1350 MMPLAYER_CMD_UNLOCK(player);
1354 case GST_MESSAGE_STATE_CHANGED:
1356 MMPlayerGstElement *mainbin;
1357 const GValue *voldstate, *vnewstate, *vpending;
1358 GstState oldstate = GST_STATE_NULL;
1359 GstState newstate = GST_STATE_NULL;
1360 GstState pending = GST_STATE_NULL;
1362 if (!(player->pipeline && player->pipeline->mainbin)) {
1363 LOGE("player pipeline handle is null");
1367 mainbin = player->pipeline->mainbin;
1369 /* we only handle messages from pipeline */
1370 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1373 /* get state info from msg */
1374 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1375 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1376 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1378 if (!voldstate || !vnewstate) {
1379 LOGE("received msg has wrong format.");
1383 oldstate = (GstState)voldstate->data[0].v_int;
1384 newstate = (GstState)vnewstate->data[0].v_int;
1386 pending = (GstState)vpending->data[0].v_int;
1388 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1389 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1390 gst_element_state_get_name((GstState)oldstate),
1391 gst_element_state_get_name((GstState)newstate),
1392 gst_element_state_get_name((GstState)pending));
1394 if (newstate == GST_STATE_PLAYING) {
1395 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1397 int retVal = MM_ERROR_NONE;
1398 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1400 retVal = __gst_set_position( player, player->pending_seek.format, player->pending_seek.pos, TRUE );
1402 if (MM_ERROR_NONE != retVal)
1403 LOGE("failed to seek pending postion. just keep staying current position.\n");
1405 player->pending_seek.is_pending = FALSE;
1409 if (oldstate == newstate) {
1410 LOGD("pipeline reports state transition to old state");
1415 case GST_STATE_VOID_PENDING:
1418 case GST_STATE_NULL:
1421 case GST_STATE_READY:
1424 case GST_STATE_PAUSED:
1426 gboolean prepare_async = FALSE;
1428 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1429 __mmplayer_configure_audio_callback(player);
1431 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1432 // managed prepare async case
1433 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1434 LOGD("checking prepare mode for async transition - %d", prepare_async);
1437 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1438 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1440 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1441 __mm_player_streaming_set_content_bitrate(player->streamer,
1442 player->total_maximum_bitrate, player->total_bitrate);
1447 case GST_STATE_PLAYING:
1449 if (MMPLAYER_IS_STREAMING(player)) {
1450 // managed prepare async case when buffering is completed
1451 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1452 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1453 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1454 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1456 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1458 LOGD("Current Buffering Percent = %d",player->streamer->buffering_percent);
1459 if (player->streamer->buffering_percent < 100) {
1461 MMMessageParamType msg_param = {0, };
1462 LOGW("Posting Buffering Completed Message to Application !!!");
1464 msg_param.connection.buffering = 100;
1465 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1470 if (player->gapless.stream_changed) {
1471 _mmplayer_update_content_attrs(player, ATTR_ALL);
1472 player->gapless.stream_changed = FALSE;
1475 if (player->doing_seek && async_done) {
1476 player->doing_seek = FALSE;
1478 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1489 case GST_MESSAGE_CLOCK_LOST:
1491 GstClock *clock = NULL;
1492 gboolean need_new_clock = FALSE;
1494 gst_message_parse_clock_lost(msg, &clock);
1495 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1497 if (!player->videodec_linked)
1498 need_new_clock = TRUE;
1499 else if (!player->ini.use_system_clock)
1500 need_new_clock = TRUE;
1502 if (need_new_clock) {
1503 LOGD("Provide clock is TRUE, do pause->resume\n");
1504 __gst_pause(player, FALSE);
1505 __gst_resume(player, FALSE);
1510 case GST_MESSAGE_NEW_CLOCK:
1512 GstClock *clock = NULL;
1513 gst_message_parse_new_clock(msg, &clock);
1514 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1518 case GST_MESSAGE_ELEMENT:
1520 const gchar *structure_name;
1522 MMHandleType attrs = 0;
1524 attrs = MMPLAYER_GET_ATTRS(player);
1526 LOGE("cannot get content attribute");
1531 if (gst_message_get_structure(msg) == NULL)
1534 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1535 if (!structure_name)
1538 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1539 gint num_buffers = 0;
1540 gint extra_num_buffers = 0;
1542 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1543 player->video_num_buffers = num_buffers;
1544 LOGD("video_num_buffers : %d", player->video_num_buffers);
1547 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1548 player->video_extra_num_buffers = extra_num_buffers;
1549 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1554 if (!strcmp(structure_name, "Language_list")) {
1555 const GValue *lang_list = NULL;
1556 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1557 if (lang_list != NULL) {
1558 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1560 LOGD("Total audio tracks(from parser) = %d \n", count);
1564 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1565 const GValue *lang_list = NULL;
1566 MMPlayerLangStruct *temp = NULL;
1568 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1569 if (lang_list != NULL) {
1570 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1572 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1573 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1574 if (mmf_attrs_commit(attrs))
1575 LOGE("failed to commit.\n");
1576 LOGD("Total subtitle tracks = %d \n", count);
1579 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1581 LOGD("value of lang_key is %s and lang_code is %s",
1582 temp->language_key, temp->language_code);
1588 /* custom message */
1589 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1590 MMMessageParamType msg_param = {0,};
1591 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1592 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1595 /* custom message for RTSP attribute :
1596 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1597 sdp which has contents info is received when rtsp connection is opened.
1598 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1599 if (!strcmp(structure_name, "rtspsrc_properties")) {
1601 gchar *audio_codec = NULL;
1602 gchar *video_codec = NULL;
1603 gchar *video_frame_size = NULL;
1605 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1606 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1607 __mmplayer_get_stream_service_type(player);
1608 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1610 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1611 LOGD("rtsp_audio_codec : %s", audio_codec);
1613 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1615 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1616 LOGD("rtsp_video_codec : %s", video_codec);
1618 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1620 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1621 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1622 if (video_frame_size) {
1624 char *seperator = strchr(video_frame_size, '-');
1627 char video_width[10]={0,};
1628 int frame_size_len = strlen(video_frame_size);
1629 int separtor_len = strlen(seperator);
1631 strncpy(video_width,video_frame_size,(frame_size_len-separtor_len));
1632 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1635 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1639 if (mmf_attrs_commit(attrs))
1640 LOGE("failed to commit.\n");
1645 case GST_MESSAGE_DURATION_CHANGED:
1647 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1648 ret = __mmplayer_gst_handle_duration(player, msg);
1650 LOGW("failed to update duration");
1655 case GST_MESSAGE_ASYNC_START:
1656 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1659 case GST_MESSAGE_ASYNC_DONE:
1661 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1663 /* we only handle messages from pipeline */
1664 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1667 if (player->doing_seek) {
1668 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1669 player->doing_seek = FALSE;
1670 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1671 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1672 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1673 (player->streamer) &&
1674 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1675 (player->streamer->is_buffering == FALSE)) {
1676 GstQuery *query = NULL;
1677 gboolean busy = FALSE;
1680 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1681 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1682 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1683 gst_query_parse_buffering_percent(query, &busy, &percent);
1684 gst_query_unref(query);
1686 LOGD("buffered percent(%s): %d\n",
1687 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1690 if (percent >= 100) {
1691 player->streamer->is_buffering = FALSE;
1692 __mmplayer_handle_buffering_message(player);
1702 #if 0 /* delete unnecessary logs */
1703 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1704 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1705 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1706 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1707 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1708 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1709 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1710 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1711 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1712 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1713 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1714 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1715 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1716 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1717 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1724 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1725 * gst_element_post_message api takes ownership of the message.
1727 //gst_message_unref(msg);
1733 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1739 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1740 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1742 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1743 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1744 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1746 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1747 LOGD("data total size of http content: %lld", bytes);
1748 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1751 /* handling audio clip which has vbr. means duration is keep changing */
1752 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1761 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1764 /* macro for better code readability */
1765 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1766 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1767 if (string != NULL) {\
1768 SECURE_LOGD("update tag string : %s\n", string); \
1769 mm_attrs_set_string_by_name(attribute, playertag, string); \
1775 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1776 GstSample *sample = NULL;\
1777 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1778 GstMapInfo info = GST_MAP_INFO_INIT;\
1779 buffer = gst_sample_get_buffer(sample);\
1780 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1781 LOGD("failed to get image data from tag");\
1784 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1785 MMPLAYER_FREEIF(player->album_art);\
1786 player->album_art = (gchar *)g_malloc(info.size);\
1787 if (player->album_art) {\
1788 memcpy(player->album_art, info.data, info.size);\
1789 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1790 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1791 msg_param.data = (void *)player->album_art;\
1792 msg_param.size = info.size;\
1793 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1794 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1797 gst_buffer_unmap(buffer, &info);\
1800 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1801 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) {\
1803 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) {\
1804 if (player->updated_bitrate_count == 0) \
1805 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1806 if (player->updated_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1807 player->bitrate[player->updated_bitrate_count] = v_uint;\
1808 player->total_bitrate += player->bitrate[player->updated_bitrate_count]; \
1809 player->updated_bitrate_count++; \
1810 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1811 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1814 else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) {\
1815 if (player->updated_maximum_bitrate_count < MM_PLAYER_STREAM_COUNT_MAX) {\
1816 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1817 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1818 player->updated_maximum_bitrate_count++; \
1819 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1820 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1823 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1828 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1829 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1830 if (date != NULL) {\
1831 string = g_strdup_printf("%d", g_date_get_year(date));\
1832 mm_attrs_set_string_by_name(attribute, playertag, string);\
1833 SECURE_LOGD("metainfo year : %s\n", string);\
1834 MMPLAYER_FREEIF(string);\
1839 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1840 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1841 if (datetime != NULL) {\
1842 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1843 mm_attrs_set_string_by_name(attribute, playertag, string);\
1844 SECURE_LOGD("metainfo year : %s\n", string);\
1845 MMPLAYER_FREEIF(string);\
1846 gst_date_time_unref(datetime);\
1850 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1851 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1853 /* FIXIT : don't know how to store date */\
1859 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1860 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1862 /* FIXIT : don't know how to store date */\
1868 /* function start */
1869 GstTagList* tag_list = NULL;
1871 MMHandleType attrs = 0;
1873 char *string = NULL;
1876 GstDateTime *datetime = NULL;
1878 GstBuffer *buffer = NULL;
1880 MMMessageParamType msg_param = {0, };
1882 /* currently not used. but those are needed for above macro */
1883 //guint64 v_uint64 = 0;
1884 //gdouble v_double = 0;
1886 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1888 attrs = MMPLAYER_GET_ATTRS(player);
1890 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1892 /* get tag list from gst message */
1893 gst_message_parse_tag(msg, &tag_list);
1895 /* store tags to player attributes */
1896 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1897 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1898 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1899 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1900 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1901 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1902 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1903 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1904 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1905 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1906 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1907 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1908 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1909 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1910 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1911 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1912 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1913 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1915 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1916 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1917 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1918 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1919 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1920 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1923 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1924 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1925 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1926 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1927 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1928 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1929 MMPLAYER_UPDATE_TAG_LOCK(player);
1930 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1931 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1932 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1933 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1934 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1940 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1941 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1942 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1943 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1944 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1946 if (mmf_attrs_commit(attrs))
1947 LOGE("failed to commit.\n");
1949 gst_tag_list_free(tag_list);
1955 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) // @
1957 mm_player_t* player = (mm_player_t*) data;
1961 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1962 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1963 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1964 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1966 * [1] audio and video will be dumped with filesink.
1967 * [2] autoplugging is done by just using pad caps.
1968 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1969 * and the video will be dumped via filesink.
1971 if (player->num_dynamic_pad == 0) {
1972 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1974 if (!__mmplayer_gst_remove_fakesink(player,
1975 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1976 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1977 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1978 * source element are not same. To overcome this situation, this function will called
1979 * several places and several times. Therefore, this is not an error case.
1984 /* create dot before error-return. for debugging */
1985 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1987 player->no_more_pad = TRUE;
1993 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1995 GstElement* parent = NULL;
1997 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1999 /* if we have no fakesink. this meas we are using decodebin which doesn'
2000 t need to add extra fakesink */
2001 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2004 MMPLAYER_FSINK_LOCK(player);
2009 /* get parent of fakesink */
2010 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2012 LOGD("fakesink already removed\n");
2016 gst_element_set_locked_state(fakesink->gst, TRUE);
2018 /* setting the state to NULL never returns async
2019 * so no need to wait for completion of state transiton
2021 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2022 LOGE("fakesink state change failure!\n");
2023 /* FIXIT : should I return here? or try to proceed to next? */
2026 /* remove fakesink from it's parent */
2027 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2028 LOGE("failed to remove fakesink\n");
2030 gst_object_unref(parent);
2035 gst_object_unref(parent);
2037 LOGD("state-holder removed\n");
2039 gst_element_set_locked_state(fakesink->gst, FALSE);
2041 MMPLAYER_FSINK_UNLOCK(player);
2046 gst_element_set_locked_state(fakesink->gst, FALSE);
2048 MMPLAYER_FSINK_UNLOCK(player);
2054 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2056 GstPad *sinkpad = NULL;
2057 GstCaps* caps = NULL;
2058 GstElement* new_element = NULL;
2059 GstStructure* str = NULL;
2060 const gchar* name = NULL;
2062 mm_player_t* player = (mm_player_t*) data;
2066 MMPLAYER_RETURN_IF_FAIL(element && pad);
2067 MMPLAYER_RETURN_IF_FAIL(player &&
2069 player->pipeline->mainbin);
2072 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2073 * num_dynamic_pad will decreased after creating a sinkbin.
2075 player->num_dynamic_pad++;
2076 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2078 caps = gst_pad_query_caps(pad, NULL);
2080 MMPLAYER_CHECK_NULL(caps);
2082 /* clear previous result*/
2083 player->have_dynamic_pad = FALSE;
2085 str = gst_caps_get_structure(caps, 0);
2088 LOGE("cannot get structure from caps.\n");
2092 name = gst_structure_get_name(str);
2094 LOGE("cannot get mimetype from structure.\n");
2098 if (strstr(name, "video")) {
2100 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2102 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2103 if (player->v_stream_caps) {
2104 gst_caps_unref(player->v_stream_caps);
2105 player->v_stream_caps = NULL;
2108 new_element = gst_element_factory_make("fakesink", NULL);
2109 player->num_dynamic_pad--;
2114 /* clear previous result*/
2115 player->have_dynamic_pad = FALSE;
2117 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2118 LOGE("failed to autoplug for caps");
2122 /* check if there's dynamic pad*/
2123 if (player->have_dynamic_pad) {
2124 LOGE("using pad caps assums there's no dynamic pad !\n");
2128 gst_caps_unref(caps);
2133 /* excute new_element if created*/
2135 LOGD("adding new element to pipeline\n");
2137 /* set state to READY before add to bin */
2138 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2140 /* add new element to the pipeline */
2141 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2142 LOGE("failed to add autoplug element to bin\n");
2146 /* get pad from element */
2147 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2149 LOGE("failed to get sinkpad from autoplug element\n");
2154 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2155 LOGE("failed to link autoplug element\n");
2159 gst_object_unref(sinkpad);
2162 /* run. setting PLAYING here since streamming source is live source */
2163 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2170 STATE_CHANGE_FAILED:
2172 /* FIXIT : take care if new_element has already added to pipeline */
2174 gst_object_unref(GST_OBJECT(new_element));
2177 gst_object_unref(GST_OBJECT(sinkpad));
2180 gst_object_unref(GST_OBJECT(caps));
2182 /* FIXIT : how to inform this error to MSL ????? */
2183 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2184 * then post an error to application
2190 /* FIXIT : check indent */
2193 __mmplayer_gst_wfd_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) // @
2195 GstPad *sinkpad = NULL;
2196 GstCaps* caps = NULL;
2197 GstElement* new_element = NULL;
2198 enum MainElementID element_id = MMPLAYER_M_NUM;
2200 mm_player_t* player = (mm_player_t*) data;
2204 MMPLAYER_RETURN_IF_FAIL(element && pad);
2205 MMPLAYER_RETURN_IF_FAIL(player &&
2207 player->pipeline->mainbin);
2209 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2212 LOGD("using pad caps to autopluging instead of doing typefind\n");
2213 caps = gst_pad_query_caps(pad);
2214 MMPLAYER_CHECK_NULL(caps);
2215 /* clear previous result*/
2216 player->have_dynamic_pad = FALSE;
2217 new_element = gst_element_factory_make("rtpmp2tdepay", "wfd_rtp_depay");
2219 LOGE("failed to create wfd rtp depay element\n");
2222 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2223 /* add new element to the pipeline */
2224 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2225 LOGD("failed to add autoplug element to bin\n");
2228 /* get pad from element */
2229 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2231 LOGD("failed to get sinkpad from autoplug element\n");
2235 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2236 LOGD("failed to link autoplug element\n");
2239 gst_object_unref(sinkpad);
2241 pad = gst_element_get_static_pad(GST_ELEMENT(new_element), "src");
2242 caps = gst_pad_query_caps(pad);
2243 MMPLAYER_CHECK_NULL(caps);
2244 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2245 /* create typefind */
2246 new_element = gst_element_factory_make("typefind", NULL);
2248 LOGD("failed to create typefind\n");
2252 MMPLAYER_SIGNAL_CONNECT(player,
2253 G_OBJECT(new_element),
2254 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG,
2256 G_CALLBACK(__mmplayer_typefind_have_type),
2259 player->have_dynamic_pad = FALSE;
2262 /* excute new_element if created*/
2264 LOGD("adding new element to pipeline\n");
2266 /* set state to READY before add to bin */
2267 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2269 /* add new element to the pipeline */
2270 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2271 LOGD("failed to add autoplug element to bin\n");
2275 /* get pad from element */
2276 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2278 LOGD("failed to get sinkpad from autoplug element\n");
2283 if (GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad)) {
2284 LOGD("failed to link autoplug element\n");
2288 gst_object_unref(sinkpad);
2291 /* run. setting PLAYING here since streamming source is live source */
2292 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2295 /* store handle to futher manipulation */
2296 player->pipeline->mainbin[element_id].id = element_id;
2297 player->pipeline->mainbin[element_id].gst = new_element;
2303 STATE_CHANGE_FAILED:
2305 /* FIXIT : take care if new_element has already added to pipeline */
2307 gst_object_unref(GST_OBJECT(new_element));
2310 gst_object_unref(GST_OBJECT(sinkpad));
2313 gst_object_unref(GST_OBJECT(caps));
2315 /* FIXIT : how to inform this error to MSL ????? */
2316 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2317 * then post an error to application
2322 static GstPadProbeReturn
2323 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2325 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2326 return GST_PAD_PROBE_OK;
2329 static GstPadProbeReturn
2330 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2332 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2333 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2334 mm_player_t* player = (mm_player_t*)data;
2335 GstCaps* caps = NULL;
2336 GstStructure* str = NULL;
2337 const gchar* name = NULL;
2338 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2341 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2342 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2343 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2344 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2345 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2347 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2348 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2352 caps = gst_pad_query_caps(pad, NULL);
2354 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2358 str = gst_caps_get_structure(caps, 0);
2360 LOGE("failed to get structure from caps");
2364 name = gst_structure_get_name(str);
2366 LOGE("failed to get name from str");
2370 if (strstr(name, "audio")) {
2371 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2372 } else if (strstr(name, "video")) {
2373 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2375 /* text track is not supportable */
2376 LOGE("invalid name %s", name);
2380 switch (GST_EVENT_TYPE(event)) {
2383 /* in case of gapless, drop eos event not to send it to sink */
2384 if (player->gapless.reconfigure && !player->msg_posted) {
2385 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2386 ret = GST_PAD_PROBE_DROP;
2390 case GST_EVENT_STREAM_START:
2392 gint64 stop_running_time = 0;
2393 gint64 position_running_time = 0;
2394 gint64 position = 0;
2397 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2398 if ((player->gapless.update_segment[idx] == TRUE) ||
2399 !(player->selector[idx].event_probe_id)) {
2400 /* LOGW("[%d] skip", idx); */
2404 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2406 gst_segment_to_running_time(&player->gapless.segment[idx],
2407 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2408 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2410 gst_segment_to_running_time(&player->gapless.segment[idx],
2411 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2413 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2415 gst_segment_to_running_time(&player->gapless.segment[idx],
2416 GST_FORMAT_TIME, player->duration);
2419 position_running_time =
2420 gst_segment_to_running_time(&player->gapless.segment[idx],
2421 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2423 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2424 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2426 GST_TIME_ARGS(stop_running_time),
2427 GST_TIME_ARGS(position_running_time),
2428 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2429 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2431 position_running_time = MAX(position_running_time, stop_running_time);
2432 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2433 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2434 position_running_time = MAX(0, position_running_time);
2435 position = MAX(position, position_running_time);
2438 if (position != 0) {
2439 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2440 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2441 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2443 player->gapless.start_time[stream_type] += position;
2447 case GST_EVENT_FLUSH_STOP:
2449 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2450 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2451 player->gapless.start_time[stream_type] = 0;
2454 case GST_EVENT_SEGMENT:
2459 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2460 gst_event_copy_segment(event, &segment);
2462 if (segment.format == GST_FORMAT_TIME) {
2463 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2464 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2465 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2466 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2467 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2468 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2470 /* keep the all the segment ev to cover the seeking */
2471 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2472 player->gapless.update_segment[stream_type] = TRUE;
2474 if (!player->gapless.running)
2477 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2479 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2481 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2482 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2483 gst_event_unref(event);
2484 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2490 gdouble proportion = 0.0;
2491 GstClockTimeDiff diff = 0;
2492 GstClockTime timestamp = 0;
2493 gint64 running_time_diff = -1;
2494 GstQOSType type = 0;
2495 GstEvent *tmpev = NULL;
2497 running_time_diff = player->gapless.segment[stream_type].base;
2499 if (running_time_diff <= 0) /* don't need to adjust */
2502 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2503 gst_event_unref(event);
2505 if (timestamp < running_time_diff) {
2506 LOGW("QOS event from previous group");
2507 ret = GST_PAD_PROBE_DROP;
2511 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2512 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2513 stream_type, GST_TIME_ARGS(timestamp),
2514 GST_TIME_ARGS(running_time_diff),
2515 GST_TIME_ARGS(timestamp - running_time_diff));
2517 timestamp -= running_time_diff;
2519 /* That case is invalid for QoS events */
2520 if (diff < 0 && -diff > timestamp) {
2521 LOGW("QOS event from previous group");
2522 ret = GST_PAD_PROBE_DROP;
2526 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2527 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2537 gst_caps_unref(caps);
2542 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2544 mm_player_t* player = NULL;
2545 GstElement* pipeline = NULL;
2546 GstElement* selector = NULL;
2547 GstElement* fakesink = NULL;
2548 GstCaps* caps = NULL;
2549 GstStructure* str = NULL;
2550 const gchar* name = NULL;
2551 GstPad* sinkpad = NULL;
2552 GstPad* srcpad = NULL;
2553 gboolean first_track = FALSE;
2555 enum MainElementID elemId = MMPLAYER_M_NUM;
2556 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2559 player = (mm_player_t*)data;
2561 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2562 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2564 //LOGD("pad-added signal handling\n");
2566 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2568 /* get mimetype from caps */
2569 caps = gst_pad_query_caps(pad, NULL);
2571 LOGE("cannot get caps from pad.\n");
2575 str = gst_caps_get_structure(caps, 0);
2577 LOGE("cannot get structure from caps.\n");
2581 name = gst_structure_get_name(str);
2583 LOGE("cannot get mimetype from structure.\n");
2587 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2588 //LOGD("detected mimetype : %s\n", name);
2590 if (strstr(name, "video")) {
2593 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
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 (caps_str && (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 (caps_str && (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 128
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 if (player->sound_focus.focus_id)
4557 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4558 stream_type, stream_id, player->sound_focus.focus_id);
4560 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4561 stream_type, stream_id);
4562 props = gst_structure_from_string(stream_props, NULL);
4563 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4564 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n", stream_type, stream_id, player->sound_focus.focus_id, stream_props);
4567 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4569 switch (latency_mode) {
4570 case AUDIO_LATENCY_MODE_LOW:
4571 latency = g_strndup("low", 3);
4573 case AUDIO_LATENCY_MODE_MID:
4574 latency = g_strndup("mid", 3);
4576 case AUDIO_LATENCY_MODE_HIGH:
4577 latency = g_strndup("high", 4);
4581 #if 0 //need to check
4582 if (player->sound_focus.user_route_policy != 0)
4583 route_path = player->sound_focus.user_route_policy;
4585 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4586 "latency", latency_mode,
4589 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4590 volume_type, route_path, latency_mode);
4595 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4599 LOGD("audiosink property - latency=%s \n", latency);
4607 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4609 MMPlayerGstElement* first_element = NULL;
4610 MMPlayerGstElement* audiobin = NULL;
4611 MMHandleType attrs = 0;
4613 GstPad *ghostpad = NULL;
4614 GList* element_bucket = NULL;
4615 gboolean link_audio_sink_now = TRUE;
4620 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4623 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4625 LOGE("failed to allocate memory for audiobin\n");
4626 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4629 attrs = MMPLAYER_GET_ATTRS(player);
4632 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4633 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4634 if (!audiobin[MMPLAYER_A_BIN].gst) {
4635 LOGE("failed to create audiobin\n");
4640 player->pipeline->audiobin = audiobin;
4642 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4644 /* Adding audiotp plugin for reverse trickplay feature */
4645 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4648 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4653 if (player->set_mode.pcm_extraction) {
4654 // pcm extraction only and no sound output
4655 if (player->audio_stream_render_cb_ex) {
4656 char *caps_str = NULL;
4657 GstCaps* caps = NULL;
4658 gchar *format = NULL;
4661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4663 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4665 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4667 caps = gst_caps_new_simple("audio/x-raw",
4668 "format", G_TYPE_STRING, format,
4669 "rate", G_TYPE_INT, player->pcm_samplerate,
4670 "channels", G_TYPE_INT, player->pcm_channel,
4672 caps_str = gst_caps_to_string(caps);
4673 LOGD("new caps : %s\n", caps_str);
4675 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4678 gst_caps_unref(caps);
4679 MMPLAYER_FREEIF(caps_str);
4681 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4683 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4684 /* raw pad handling signal */
4685 MMPLAYER_SIGNAL_CONNECT(player,
4686 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4687 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4688 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4690 int dst_samplerate = 0;
4691 int dst_channels = 0;
4693 char *caps_str = NULL;
4694 GstCaps* caps = NULL;
4696 /* get conf. values */
4697 mm_attrs_multiple_get(player->attrs,
4699 "pcm_extraction_samplerate", &dst_samplerate,
4700 "pcm_extraction_channels", &dst_channels,
4701 "pcm_extraction_depth", &dst_depth,
4705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4706 caps = gst_caps_new_simple("audio/x-raw",
4707 "rate", G_TYPE_INT, dst_samplerate,
4708 "channels", G_TYPE_INT, dst_channels,
4709 "depth", G_TYPE_INT, dst_depth,
4711 caps_str = gst_caps_to_string(caps);
4712 LOGD("new caps : %s\n", caps_str);
4714 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4717 gst_caps_unref(caps);
4718 MMPLAYER_FREEIF(caps_str);
4721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4728 //GstCaps* caps = NULL;
4731 /* for logical volume control */
4732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4735 if (player->sound.mute) {
4736 LOGD("mute enabled\n");
4737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4743 caps = gst_caps_from_string("audio/x-raw-int, "
4744 "endianness = (int) LITTLE_ENDIAN, "
4745 "signed = (boolean) true, "
4746 "width = (int) 16, "
4747 "depth = (int) 16");
4748 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4749 gst_caps_unref(caps);
4752 /* chech if multi-chennels */
4753 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4754 GstPad *srcpad = NULL;
4755 GstCaps *caps = NULL;
4757 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4758 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4759 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4760 GstStructure *str = gst_caps_get_structure(caps, 0);
4762 gst_structure_get_int(str, "channels", &channels);
4763 gst_caps_unref(caps);
4765 gst_object_unref(srcpad);
4769 /* audio effect element. if audio effect is enabled */
4770 if ((strcmp(player->ini.audioeffect_element, ""))
4772 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4775 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4777 if ((!player->bypass_audio_effect)
4778 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4779 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4780 if (!_mmplayer_audio_effect_custom_apply(player))
4781 LOGI("apply audio effect(custom) setting success\n");
4785 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4786 && (player->set_mode.rich_audio))
4787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4790 /* create audio sink */
4791 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4795 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4798 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4799 (player->videodec_linked && player->ini.use_system_clock)) {
4800 LOGD("system clock will be used.\n");
4801 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4804 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4805 __mmplayer_gst_set_audiosink_property(player, attrs);
4808 if (audiobin[MMPLAYER_A_SINK].gst) {
4809 GstPad *sink_pad = NULL;
4810 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4811 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4812 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4813 gst_object_unref(GST_OBJECT(sink_pad));
4816 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4818 /* adding created elements to bin */
4819 LOGD("adding created elements to bin\n");
4820 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4821 LOGE("failed to add elements\n");
4825 /* linking elements in the bucket by added order. */
4826 LOGD("Linking elements in the bucket by added order.\n");
4827 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4828 LOGE("failed to link elements\n");
4832 /* get first element's sinkpad for creating ghostpad */
4833 first_element = (MMPlayerGstElement *)element_bucket->data;
4834 if (!first_element) {
4835 LOGE("failed to get first elem\n");
4839 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4841 LOGE("failed to get pad from first element of audiobin\n");
4845 ghostpad = gst_ghost_pad_new("sink", pad);
4847 LOGE("failed to create ghostpad\n");
4851 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4852 LOGE("failed to add ghostpad to audiobin\n");
4856 gst_object_unref(pad);
4858 g_list_free(element_bucket);
4860 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4864 return MM_ERROR_NONE;
4868 LOGD("ERROR : releasing audiobin\n");
4871 gst_object_unref(GST_OBJECT(pad));
4874 gst_object_unref(GST_OBJECT(ghostpad));
4877 g_list_free(element_bucket);
4879 /* release element which are not added to bin */
4880 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4881 /* NOTE : skip bin */
4882 if (audiobin[i].gst) {
4883 GstObject* parent = NULL;
4884 parent = gst_element_get_parent(audiobin[i].gst);
4887 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4888 audiobin[i].gst = NULL;
4890 gst_object_unref(GST_OBJECT(parent));
4894 /* release audiobin with it's childs */
4895 if (audiobin[MMPLAYER_A_BIN].gst)
4896 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4898 MMPLAYER_FREEIF(audiobin);
4900 player->pipeline->audiobin = NULL;
4902 return MM_ERROR_PLAYER_INTERNAL;
4905 static GstPadProbeReturn
4906 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4908 mm_player_t* player = (mm_player_t*) u_data;
4909 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4910 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4912 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4914 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4915 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4917 return GST_PAD_PROBE_OK;
4920 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4922 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4925 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4927 int ret = MM_ERROR_NONE;
4929 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4930 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4932 MMPLAYER_VIDEO_BO_LOCK(player);
4934 if (player->video_bo_list) {
4935 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4936 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4937 if (tmp && tmp->bo == bo) {
4939 LOGD("release bo %p", bo);
4940 MMPLAYER_VIDEO_BO_UNLOCK(player);
4941 MMPLAYER_VIDEO_BO_SIGNAL(player);
4946 /* hw codec is running or the list was reset for DRC. */
4947 LOGW("there is no bo list.");
4949 MMPLAYER_VIDEO_BO_UNLOCK(player);
4951 LOGW("failed to find bo %p", bo);
4956 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4961 MMPLAYER_RETURN_IF_FAIL(player);
4963 MMPLAYER_VIDEO_BO_LOCK(player);
4964 if (player->video_bo_list) {
4965 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4966 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4967 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4970 tbm_bo_unref(tmp->bo);
4974 g_list_free(player->video_bo_list);
4975 player->video_bo_list = NULL;
4977 player->video_bo_size = 0;
4978 MMPLAYER_VIDEO_BO_UNLOCK(player);
4985 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4988 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4989 gboolean ret = TRUE;
4991 /* check DRC, if it is, destroy the prev bo list to create again */
4992 if (player->video_bo_size != size) {
4993 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4994 __mmplayer_video_stream_destroy_bo_list(player);
4995 player->video_bo_size = size;
4998 MMPLAYER_VIDEO_BO_LOCK(player);
5000 if ((!player->video_bo_list) ||
5001 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
5003 /* create bo list */
5005 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5007 if (player->video_bo_list) {
5008 /* if bo list did not created all, try it again. */
5009 idx = g_list_length(player->video_bo_list);
5010 LOGD("bo list exist(len: %d)", idx);
5013 for (; idx < player->ini.num_of_video_bo; idx++) {
5014 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5016 LOGE("Fail to alloc bo_info.");
5019 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5021 LOGE("Fail to tbm_bo_alloc.");
5025 bo_info->using = FALSE;
5026 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5029 /* update video num buffers */
5030 player->video_num_buffers = idx;
5031 if (idx == player->ini.num_of_video_bo)
5032 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5035 MMPLAYER_VIDEO_BO_UNLOCK(player);
5039 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5043 /* get bo from list*/
5044 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5045 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5046 if (tmp && (tmp->using == FALSE)) {
5047 LOGD("found bo %p to use", tmp->bo);
5049 MMPLAYER_VIDEO_BO_UNLOCK(player);
5054 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5055 MMPLAYER_VIDEO_BO_UNLOCK(player);
5059 if (player->ini.video_bo_timeout <= 0) {
5060 MMPLAYER_VIDEO_BO_WAIT(player);
5062 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5063 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5070 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5072 mm_player_t* player = (mm_player_t*)data;
5074 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5076 /* send prerolled pkt */
5077 player->video_stream_prerolled = FALSE;
5079 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5081 /* not to send prerolled pkt again */
5082 player->video_stream_prerolled = TRUE;
5086 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5088 mm_player_t* player = (mm_player_t*)data;
5089 GstCaps *caps = NULL;
5090 MMPlayerVideoStreamDataType stream;
5091 MMVideoBuffer *video_buffer = NULL;
5092 GstMemory *dataBlock = NULL;
5093 GstMemory *metaBlock = NULL;
5094 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5095 GstStructure *structure = NULL;
5096 const gchar *string_format = NULL;
5097 unsigned int fourcc = 0;
5100 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5102 if (player->video_stream_prerolled) {
5103 player->video_stream_prerolled = FALSE;
5104 LOGD("skip the prerolled pkt not to send it again");
5108 caps = gst_pad_get_current_caps(pad);
5110 LOGE("Caps is NULL.");
5114 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5116 /* clear stream data structure */
5117 memset(&stream, 0x0, sizeof(MMPlayerVideoStreamDataType));
5119 structure = gst_caps_get_structure(caps, 0);
5120 gst_structure_get_int(structure, "width", & (stream.width));
5121 gst_structure_get_int(structure, "height", & (stream.height));
5122 string_format = gst_structure_get_string(structure, "format");
5124 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5125 stream.format = util_get_pixtype(fourcc);
5126 gst_caps_unref(caps);
5130 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5131 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5134 if (stream.width == 0 || stream.height == 0 || stream.format == MM_PIXEL_FORMAT_INVALID) {
5135 LOGE("Wrong condition!!");
5139 /* set size and timestamp */
5140 dataBlock = gst_buffer_peek_memory(buffer, 0);
5141 stream.length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5142 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5144 /* check zero-copy */
5145 if (player->set_mode.video_zc &&
5146 player->set_mode.media_packet_video_stream &&
5147 gst_buffer_n_memory(buffer) > 1) {
5148 metaBlock = gst_buffer_peek_memory(buffer, 1);
5149 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5150 video_buffer = (MMVideoBuffer *)mapinfo.data;
5153 if (video_buffer) { /* hw codec */
5155 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5156 /* copy pointer of tbm bo, stride, elevation */
5157 memcpy(stream.bo, video_buffer->handle.bo,
5158 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5159 } else if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
5160 /* FIXME: need to check this path */
5161 memcpy(stream.data, video_buffer->data,
5162 sizeof(void *) * MM_VIDEO_BUFFER_PLANE_MAX);
5164 memcpy(stream.stride, video_buffer->stride_width,
5165 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5166 memcpy(stream.elevation, video_buffer->stride_height,
5167 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5168 /* set gst buffer */
5169 stream.internal_buffer = buffer;
5170 } else { /* sw codec */
5171 tbm_bo_handle thandle;
5172 int stride = GST_ROUND_UP_4(stream.width);
5173 int elevation = stream.height;
5177 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5179 LOGE("fail to gst_memory_map");
5183 stream.stride[0] = stride;
5184 stream.elevation[0] = elevation;
5185 if (stream.format == MM_PIXEL_FORMAT_I420) {
5186 stream.stride[1] = stream.stride[2] = GST_ROUND_UP_4(GST_ROUND_UP_2(stream.width) / 2);
5187 stream.elevation[1] = stream.elevation[2] = stream.height / 2;
5188 size = stream.stride[0] * stream.elevation[0] + stream.stride[1] * stream.elevation[1] + stream.stride[2] * stream.elevation[2];
5189 } else if (stream.format == MM_PIXEL_FORMAT_RGBA) {
5190 stream.stride[0] = stream.width * 4;
5191 size = stream.stride[0] * stream.height;
5193 LOGE("Not support format %d", stream.format);
5194 gst_memory_unmap(dataBlock, &mapinfo);
5197 stream.bo[0] = __mmplayer_video_stream_get_bo(player, size);
5198 if (!stream.bo[0]) {
5199 LOGE("Fail to tbm_bo_alloc!!");
5200 gst_memory_unmap(dataBlock, &mapinfo);
5203 thandle = tbm_bo_map(stream.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5204 if (thandle.ptr && mapinfo.data)
5205 memcpy(thandle.ptr, mapinfo.data, size);
5207 LOGE("data pointer is wrong. dest : %p, src : %p",
5208 thandle.ptr, mapinfo.data);
5209 tbm_bo_unmap(stream.bo[0]);
5212 if (player->video_stream_cb)
5213 player->video_stream_cb(&stream, player->video_stream_cb_user_param);
5216 gst_memory_unmap(metaBlock, &mapinfo);
5218 gst_memory_unmap(dataBlock, &mapinfo);
5224 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5226 MMDisplaySurfaceType surface_type = MM_DISPLAY_SURFACE_NULL;
5227 gchar* video_csc = "videoconvert"; // default colorspace converter
5228 GList* element_bucket = *bucket;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5234 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", (int *)&surface_type);
5236 if (player->set_mode.video_zc) {
5237 video_csc = ""; /* videosinks don't use videoconvert normally */
5239 /* sw codec, if player use libav, waylandsink need videoconvert to render shm wl-buffer which support RGB only */
5240 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (!strncmp(player->ini.videosink_element_overlay, "waylandsink", strlen(player->ini.videosink_element_overlay))))
5241 video_csc = "videoconvert";
5243 if (video_csc && (strcmp(video_csc, ""))) {
5244 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5245 LOGD("using video converter: %s", video_csc);
5248 /* set video rotator */
5249 if (!player->set_mode.video_zc)
5250 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5252 *bucket = element_bucket;
5254 return MM_ERROR_NONE;
5259 return MM_ERROR_PLAYER_INTERNAL;
5263 * This function is to create video pipeline.
5265 * @param player [in] handle of player
5266 * caps [in] src caps of decoder
5267 * surface_type [in] surface type for video rendering
5269 * @return This function returns zero on success.
5271 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5275 * - video overlay surface(arm/x86) : waylandsink
5278 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5282 GList*element_bucket = NULL;
5283 MMPlayerGstElement* first_element = NULL;
5284 MMPlayerGstElement* videobin = NULL;
5285 gchar *videosink_element = NULL;
5289 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5294 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5296 player->pipeline->videobin = videobin;
5298 attrs = MMPLAYER_GET_ATTRS(player);
5300 LOGE("cannot get content attribute");
5301 return MM_ERROR_PLAYER_INTERNAL;
5305 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5306 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5307 if (!videobin[MMPLAYER_V_BIN].gst) {
5308 LOGE("failed to create videobin");
5312 int enable_video_decoded_cb = 0;
5313 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5315 /* set video sink */
5316 switch (surface_type) {
5317 case MM_DISPLAY_SURFACE_OVERLAY:
5318 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5320 if (strlen(player->ini.videosink_element_overlay) > 0)
5321 videosink_element = player->ini.videosink_element_overlay;
5325 case MM_DISPLAY_SURFACE_NULL:
5326 if (strlen(player->ini.videosink_element_fake) > 0)
5327 videosink_element = player->ini.videosink_element_fake;
5331 case MM_DISPLAY_SURFACE_REMOTE:
5332 if (strlen(player->ini.videosink_element_fake) > 0)
5333 videosink_element = player->ini.videosink_element_fake;
5338 LOGE("unidentified surface type");
5341 LOGD("selected videosink name: %s", videosink_element);
5343 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5345 /* additional setting for sink plug-in */
5346 switch (surface_type) {
5347 case MM_DISPLAY_SURFACE_OVERLAY:
5349 bool use_tbm = player->set_mode.video_zc;
5351 LOGD("selected videosink name: %s", videosink_element);
5353 /* support shard memory with S/W codec on HawkP */
5354 if (strncmp(videosink_element, "waylandsink", strlen(videosink_element)) == 0) {
5355 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5356 "use-tbm", use_tbm, NULL);
5362 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5365 LOGD("disable last-sample");
5366 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5370 if (player->set_mode.media_packet_video_stream) {
5372 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5374 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5376 MMPLAYER_SIGNAL_CONNECT(player,
5377 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5378 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5380 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5383 MMPLAYER_SIGNAL_CONNECT(player,
5384 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5385 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5387 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5392 case MM_DISPLAY_SURFACE_REMOTE:
5394 if (player->set_mode.media_packet_video_stream) {
5395 LOGE("add data probe at videosink");
5396 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5397 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5399 MMPLAYER_SIGNAL_CONNECT(player,
5400 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5401 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5403 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5406 MMPLAYER_SIGNAL_CONNECT(player,
5407 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5408 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5410 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5419 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5422 if (videobin[MMPLAYER_V_SINK].gst) {
5423 GstPad *sink_pad = NULL;
5424 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5426 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5427 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5428 gst_object_unref(GST_OBJECT(sink_pad));
5430 LOGW("failed to get sink pad from videosink\n");
5433 /* store it as it's sink element */
5434 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5436 /* adding created elements to bin */
5437 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5438 LOGE("failed to add elements\n");
5442 /* Linking elements in the bucket by added order */
5443 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5444 LOGE("failed to link elements\n");
5448 /* get first element's sinkpad for creating ghostpad */
5450 first_element = (MMPlayerGstElement *)element_bucket->data;
5451 if (!first_element) {
5452 LOGE("failed to get first element from bucket\n");
5456 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5458 LOGE("failed to get pad from first element\n");
5462 /* create ghostpad */
5463 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5464 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5465 LOGE("failed to add ghostpad to videobin\n");
5468 gst_object_unref(pad);
5470 /* done. free allocated variables */
5472 g_list_free(element_bucket);
5476 return MM_ERROR_NONE;
5479 LOGE("ERROR : releasing videobin\n");
5481 g_list_free(element_bucket);
5484 gst_object_unref(GST_OBJECT(pad));
5486 /* release videobin with it's childs */
5487 if (videobin[MMPLAYER_V_BIN].gst)
5488 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5491 MMPLAYER_FREEIF(videobin);
5493 player->pipeline->videobin = NULL;
5495 return MM_ERROR_PLAYER_INTERNAL;
5498 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5500 GList *element_bucket = NULL;
5501 MMPlayerGstElement *textbin = player->pipeline->textbin;
5503 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5504 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5505 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5506 "signal-handoffs", FALSE,
5509 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5510 MMPLAYER_SIGNAL_CONNECT(player,
5511 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5512 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5514 G_CALLBACK(__mmplayer_update_subtitle),
5517 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5518 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5519 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5521 if (!player->play_subtitle) {
5522 LOGD("add textbin sink as sink element of whole pipeline.\n");
5523 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5526 /* adding created elements to bin */
5527 LOGD("adding created elements to bin\n");
5528 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5529 LOGE("failed to add elements\n");
5533 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5534 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5535 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5537 /* linking elements in the bucket by added order. */
5538 LOGD("Linking elements in the bucket by added order.\n");
5539 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5540 LOGE("failed to link elements\n");
5544 /* done. free allocated variables */
5545 g_list_free(element_bucket);
5547 if (textbin[MMPLAYER_T_QUEUE].gst) {
5549 GstPad *ghostpad = NULL;
5551 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5553 LOGE("failed to get video pad of textbin\n");
5554 return MM_ERROR_PLAYER_INTERNAL;
5557 ghostpad = gst_ghost_pad_new("text_sink", pad);
5558 gst_object_unref(pad);
5561 LOGE("failed to create ghostpad of textbin\n");
5565 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5566 LOGE("failed to add ghostpad to textbin\n");
5571 return MM_ERROR_NONE;
5574 g_list_free(element_bucket);
5576 return MM_ERROR_PLAYER_INTERNAL;
5579 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5581 MMPlayerGstElement *textbin = NULL;
5582 GList *element_bucket = NULL;
5587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5590 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5592 LOGE("failed to allocate memory for textbin\n");
5593 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5597 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5598 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5599 if (!textbin[MMPLAYER_T_BIN].gst) {
5600 LOGE("failed to create textbin\n");
5605 player->pipeline->textbin = textbin;
5608 if (player->use_textoverlay) {
5609 LOGD("use textoverlay for displaying \n");
5611 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_QUEUE, "queue", "text_t_queue", textbin[MMPLAYER_T_BIN].gst, player);
5613 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_QUEUE, "queue", "text_v_queue", textbin[MMPLAYER_T_BIN].gst, player);
5615 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_VIDEO_CONVERTER, "fimcconvert", "text_v_converter", textbin[MMPLAYER_T_BIN].gst, player);
5617 MMPLAYER_CREATE_ELEMENT_ADD_BIN(textbin, MMPLAYER_T_OVERLAY, "textoverlay", "text_overlay", textbin[MMPLAYER_T_BIN].gst, player);
5619 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_QUEUE].gst, "src", textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "sink")) {
5620 LOGE("failed to link queue and converter\n");
5624 if (!gst_element_link_pads(textbin[MMPLAYER_T_VIDEO_CONVERTER].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "video_sink")) {
5625 LOGE("failed to link queue and textoverlay\n");
5629 if (!gst_element_link_pads(textbin[MMPLAYER_T_QUEUE].gst, "src", textbin[MMPLAYER_T_OVERLAY].gst, "text_sink")) {
5630 LOGE("failed to link queue and textoverlay\n");
5634 int surface_type = 0;
5636 LOGD("use subtitle message for displaying \n");
5638 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5640 switch (surface_type) {
5641 case MM_DISPLAY_SURFACE_OVERLAY:
5642 case MM_DISPLAY_SURFACE_NULL:
5643 case MM_DISPLAY_SURFACE_REMOTE:
5644 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5645 LOGE("failed to make plain text elements\n");
5657 return MM_ERROR_NONE;
5661 LOGD("ERROR : releasing textbin\n");
5663 g_list_free(element_bucket);
5665 /* release element which are not added to bin */
5666 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5667 /* NOTE : skip bin */
5668 if (textbin[i].gst) {
5669 GstObject* parent = NULL;
5670 parent = gst_element_get_parent(textbin[i].gst);
5673 gst_object_unref(GST_OBJECT(textbin[i].gst));
5674 textbin[i].gst = NULL;
5676 gst_object_unref(GST_OBJECT(parent));
5680 /* release textbin with it's childs */
5681 if (textbin[MMPLAYER_T_BIN].gst)
5682 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5684 MMPLAYER_FREEIF(textbin);
5686 player->pipeline->textbin = NULL;
5688 return MM_ERROR_PLAYER_INTERNAL;
5693 __mmplayer_gst_create_subtitle_src(mm_player_t* player)
5695 MMPlayerGstElement* mainbin = NULL;
5696 MMHandleType attrs = 0;
5697 GstElement *subsrc = NULL;
5698 GstElement *subparse = NULL;
5699 gchar *subtitle_uri = NULL;
5700 const gchar *charset = NULL;
5706 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5708 mainbin = player->pipeline->mainbin;
5710 attrs = MMPLAYER_GET_ATTRS(player);
5712 LOGE("cannot get content attribute\n");
5713 return MM_ERROR_PLAYER_INTERNAL;
5716 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5717 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5718 LOGE("subtitle uri is not proper filepath.\n");
5719 return MM_ERROR_PLAYER_INVALID_URI;
5722 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5723 LOGE("failed to get storage info of subtitle path");
5724 return MM_ERROR_PLAYER_INVALID_URI;
5727 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5729 /* create the subtitle source */
5730 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5732 LOGE("failed to create filesrc element\n");
5735 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5737 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5738 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5740 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5741 LOGW("failed to add queue\n");
5746 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5748 LOGE("failed to create subparse element\n");
5752 charset = util_get_charset(subtitle_uri);
5754 LOGD("detected charset is %s\n", charset);
5755 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5758 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5759 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5761 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5762 LOGW("failed to add subparse\n");
5766 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5767 LOGW("failed to link subsrc and subparse\n");
5771 player->play_subtitle = TRUE;
5772 player->adjust_subtitle_pos = 0;
5774 LOGD("play subtitle using subtitle file\n");
5776 if (player->pipeline->textbin == NULL) {
5777 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
5778 LOGE("failed to create textbin. continuing without text\n");
5782 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(player->pipeline->textbin[MMPLAYER_T_BIN].gst))) {
5783 LOGW("failed to add textbin\n");
5787 LOGD("link text input selector and textbin ghost pad");
5789 player->textsink_linked = 1;
5790 player->external_text_idx = 0;
5791 LOGI("player->textsink_linked set to 1\n");
5793 LOGD("text bin has been created. reuse it.");
5794 player->external_text_idx = 1;
5797 if (!gst_element_link_pads(subparse, "src", player->pipeline->textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5798 LOGW("failed to link subparse and textbin\n");
5802 pad = gst_element_get_static_pad(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5805 LOGE("failed to get sink pad from textsink to probe data");
5806 return MM_ERROR_PLAYER_INTERNAL;
5809 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5810 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5812 gst_object_unref(pad);
5815 /* create dot. for debugging */
5816 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5819 return MM_ERROR_NONE;
5822 player->textsink_linked = 0;
5823 return MM_ERROR_PLAYER_INTERNAL;
5827 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5829 mm_player_t* player = (mm_player_t*) data;
5830 MMMessageParamType msg = {0, };
5831 GstClockTime duration = 0;
5832 gpointer text = NULL;
5833 guint text_size = 0;
5834 gboolean ret = TRUE;
5835 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5839 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5840 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5842 if (player->is_subtitle_force_drop)
5844 LOGW("subtitle is dropped forcedly.");
5848 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5849 text = mapinfo.data;
5850 text_size = mapinfo.size;
5851 duration = GST_BUFFER_DURATION(buffer);
5853 if (player->set_mode.subtitle_off) {
5854 LOGD("subtitle is OFF.\n");
5858 if (!text || (text_size == 0)) {
5859 LOGD("There is no subtitle to be displayed.\n");
5863 msg.data = (void *) text;
5864 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5866 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5868 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5869 gst_buffer_unmap(buffer, &mapinfo);
5876 static GstPadProbeReturn
5877 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5880 mm_player_t *player = (mm_player_t *) u_data;
5881 GstClockTime cur_timestamp = 0;
5882 gint64 adjusted_timestamp = 0;
5883 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5885 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5887 if (player->set_mode.subtitle_off) {
5888 LOGD("subtitle is OFF.\n");
5892 if (player->adjust_subtitle_pos == 0) {
5893 LOGD("nothing to do");
5897 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5898 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5900 if (adjusted_timestamp < 0) {
5901 LOGD("adjusted_timestamp under zero");
5906 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5907 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5908 GST_TIME_ARGS(cur_timestamp),
5909 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5911 return GST_PAD_PROBE_OK;
5913 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5917 /* check player and subtitlebin are created */
5918 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5919 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5921 if (position == 0) {
5922 LOGD("nothing to do\n");
5924 return MM_ERROR_NONE;
5928 case MM_PLAYER_POS_FORMAT_TIME:
5930 /* check current postion */
5931 player->adjust_subtitle_pos = position;
5933 LOGD("save adjust_subtitle_pos in player") ;
5939 LOGW("invalid format.\n");
5941 return MM_ERROR_INVALID_ARGUMENT;
5947 return MM_ERROR_NONE;
5949 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5952 LOGD("adjusting video_pos in player") ;
5953 int current_pos = 0;
5954 /* check player and videobin are created */
5955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5956 if (!player->pipeline->videobin ||
5957 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5958 LOGD("no video pipeline or sink is there");
5959 return MM_ERROR_PLAYER_INVALID_STATE ;
5962 LOGD("nothing to do\n");
5964 return MM_ERROR_NONE;
5966 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
5967 LOGD("failed to get current position");
5968 return MM_ERROR_PLAYER_INTERNAL;
5970 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
5971 LOGD("enter video delay is valid");
5973 LOGD("enter video delay is crossing content boundary");
5974 return MM_ERROR_INVALID_ARGUMENT ;
5976 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
5977 LOGD("video delay has been done");
5980 return MM_ERROR_NONE;
5984 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
5986 GstElement *appsrc = element;
5987 tBuffer *buf = (tBuffer *)user_data;
5988 GstBuffer *buffer = NULL;
5989 GstFlowReturn ret = GST_FLOW_OK;
5992 MMPLAYER_RETURN_IF_FAIL(element);
5993 MMPLAYER_RETURN_IF_FAIL(buf);
5995 buffer = gst_buffer_new();
5997 if (buf->offset >= buf->len) {
5998 LOGD("call eos appsrc\n");
5999 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6003 if (buf->len - buf->offset < size)
6004 len = buf->len - buf->offset + buf->offset;
6006 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));
6007 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6008 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6010 //LOGD("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
6011 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6017 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
6019 tBuffer *buf = (tBuffer *)user_data;
6021 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6023 buf->offset = (int)size;
6028 static GstBusSyncReply
6029 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6031 mm_player_t *player = (mm_player_t *)data;
6032 GstBusSyncReply reply = GST_BUS_DROP;
6034 if (!(player->pipeline && player->pipeline->mainbin)) {
6035 LOGE("player pipeline handle is null");
6036 return GST_BUS_PASS;
6039 if (!__mmplayer_check_useful_message(player, message)) {
6040 gst_message_unref(message);
6041 return GST_BUS_DROP;
6044 switch (GST_MESSAGE_TYPE(message)) {
6045 case GST_MESSAGE_STATE_CHANGED:
6046 /* post directly for fast launch */
6047 if (player->sync_handler) {
6048 __mmplayer_gst_callback(NULL, message, player);
6049 reply = GST_BUS_DROP;
6051 reply = GST_BUS_PASS;
6053 case GST_MESSAGE_TAG:
6054 __mmplayer_gst_extract_tag_from_msg(player, message);
6058 GstTagList *tags = NULL;
6060 gst_message_parse_tag(message, &tags);
6062 LOGE("TAGS received from element \"%s\".\n",
6063 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6065 gst_tag_list_foreach(tags, print_tag, NULL);
6066 gst_tag_list_free(tags);
6074 case GST_MESSAGE_DURATION_CHANGED:
6075 __mmplayer_gst_handle_duration(player, message);
6077 case GST_MESSAGE_ASYNC_DONE:
6078 /* NOTE:Don't call gst_callback directly
6079 * because previous frame can be showed even though this message is received for seek.
6082 reply = GST_BUS_PASS;
6086 if (reply == GST_BUS_DROP)
6087 gst_message_unref(message);
6093 __mmplayer_gst_create_decoder(mm_player_t *player,
6094 MMPlayerTrackType track,
6096 enum MainElementID elemId,
6099 gboolean ret = TRUE;
6100 GstPad *sinkpad = NULL;
6104 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6106 player->pipeline->mainbin, FALSE);
6107 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6108 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6109 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6111 GstElement *decodebin = NULL;
6112 GstCaps *dec_caps = NULL;
6114 /* create decodebin */
6115 decodebin = gst_element_factory_make("decodebin", name);
6118 LOGE("error : fail to create decodebin for %d decoder\n", track);
6123 /* raw pad handling signal */
6124 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6125 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6127 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6128 before looking for any elements that can handle that stream.*/
6129 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6130 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6132 /* This signal is emitted when a element is added to the bin.*/
6133 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6134 G_CALLBACK(__mmplayer_gst_element_added), player);
6136 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6137 LOGE("failed to add new decodebin\n");
6142 dec_caps = gst_pad_query_caps(srcpad, NULL);
6144 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6145 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6146 gst_caps_unref(dec_caps);
6149 player->pipeline->mainbin[elemId].id = elemId;
6150 player->pipeline->mainbin[elemId].gst = decodebin;
6152 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6154 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6155 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6156 gst_object_unref(GST_OBJECT(decodebin));
6159 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6160 LOGE("failed to sync second level decodebin state with parent\n");
6162 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6166 gst_object_unref(GST_OBJECT(sinkpad));
6175 * This function is to create audio or video pipeline for playing.
6177 * @param player [in] handle of player
6179 * @return This function returns zero on success.
6184 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
6187 MMPlayerGstElement *mainbin = NULL;
6188 MMHandleType attrs = 0;
6189 GstElement* element = NULL;
6190 GstElement* elem_src_audio = NULL;
6191 GstElement* elem_src_subtitle = NULL;
6192 GstElement* es_video_queue = NULL;
6193 GstElement* es_audio_queue = NULL;
6194 GstElement* es_subtitle_queue = NULL;
6195 GList* element_bucket = NULL;
6196 gboolean need_state_holder = TRUE;
6198 #ifdef SW_CODEC_ONLY
6199 int surface_type = 0;
6203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6205 /* get profile attribute */
6206 attrs = MMPLAYER_GET_ATTRS(player);
6208 LOGE("cannot get content attribute\n");
6212 /* create pipeline handles */
6213 if (player->pipeline) {
6214 LOGW("pipeline should be released before create new one\n");
6218 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6219 if (player->pipeline == NULL)
6222 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo));
6225 /* create mainbin */
6226 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6227 if (mainbin == NULL)
6230 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6232 /* create pipeline */
6233 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6234 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6235 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6236 LOGE("failed to create pipeline\n");
6239 player->demux_pad_index = 0;
6240 player->subtitle_language_list = NULL;
6242 player->is_subtitle_force_drop = FALSE;
6243 player->last_multiwin_status = FALSE;
6245 _mmplayer_track_initialize(player);
6246 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6248 /* create source element */
6249 switch (player->profile.uri_type) {
6250 /* rtsp streamming */
6251 case MM_PLAYER_URI_TYPE_URL_RTSP:
6253 gint network_bandwidth;
6254 gchar *user_agent, *wap_profile;
6256 element = gst_element_factory_make("rtspsrc", "rtsp source");
6259 LOGE("failed to create streaming source element\n");
6264 network_bandwidth = 0;
6265 user_agent = wap_profile = NULL;
6268 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6269 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6270 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6272 SECURE_LOGD("user_agent : %s\n", user_agent);
6273 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6275 /* setting property to streaming source */
6276 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6278 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6280 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6282 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6283 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6284 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6285 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6287 player->use_decodebin = FALSE;
6292 case MM_PLAYER_URI_TYPE_URL_HTTP:
6294 gchar *user_agent, *proxy, *cookies, **cookie_list;
6295 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6296 user_agent = proxy = cookies = NULL;
6298 gint mode = MM_PLAYER_PD_MODE_NONE;
6300 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6302 player->pd_mode = mode;
6304 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6306 if (!MMPLAYER_IS_HTTP_PD(player)) {
6307 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6309 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6312 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6315 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6316 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6317 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6318 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6320 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6321 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6322 LOGD("get timeout from ini\n");
6323 http_timeout = player->ini.http_timeout;
6327 SECURE_LOGD("location : %s\n", player->profile.uri);
6328 SECURE_LOGD("cookies : %s\n", cookies);
6329 SECURE_LOGD("proxy : %s\n", proxy);
6330 SECURE_LOGD("user_agent : %s\n", user_agent);
6331 LOGD("timeout : %d\n", http_timeout);
6333 /* setting property to streaming source */
6334 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6335 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6336 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6338 /* check if prosy is vailid or not */
6339 if (util_check_valid_url(proxy))
6340 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6341 /* parsing cookies */
6342 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
6343 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6345 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6347 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6348 LOGW("it's dash. and it's still experimental feature.");
6350 // progressive download
6351 gchar* location = NULL;
6353 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6356 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6358 MMPLAYER_FREEIF(player->pd_file_save_path);
6360 LOGD("PD Location : %s\n", path);
6363 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6364 LOGE("failed to get storage info");
6367 player->pd_file_save_path = g_strdup(path);
6369 LOGE("can't find pd location so, it should be set \n");
6374 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6376 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6380 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6381 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6383 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6384 g_object_get(element, "location", &location, NULL);
6385 LOGD("PD_LOCATION [%s].\n", location);
6393 case MM_PLAYER_URI_TYPE_FILE:
6395 LOGD("using filesrc for 'file://' handler.\n");
6396 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6397 LOGE("failed to get storage info");
6401 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:// */
6411 case MM_PLAYER_URI_TYPE_SS:
6413 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6414 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6416 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6420 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6422 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6423 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6424 LOGD("get timeout from ini\n");
6425 http_timeout = player->ini.http_timeout;
6428 /* setting property to streaming source */
6429 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6430 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6433 case MM_PLAYER_URI_TYPE_MS_BUFF:
6435 LOGD("MS buff src is selected\n");
6437 if (player->v_stream_caps) {
6438 element = gst_element_factory_make("appsrc", "video_appsrc");
6440 LOGF("failed to create video app source element[appsrc].\n");
6444 if (player->a_stream_caps) {
6445 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6446 if (!elem_src_audio) {
6447 LOGF("failed to create audio app source element[appsrc].\n");
6451 } else if (player->a_stream_caps) {
6452 /* no video, only audio pipeline*/
6453 element = gst_element_factory_make("appsrc", "audio_appsrc");
6455 LOGF("failed to create audio app source element[appsrc].\n");
6460 if (player->s_stream_caps) {
6461 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6462 if (!elem_src_subtitle) {
6463 LOGF("failed to create subtitle app source element[appsrc].\n");
6468 LOGD("setting app sources properties.\n");
6469 LOGD("location : %s\n", player->profile.uri);
6471 if (player->v_stream_caps && element) {
6472 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6473 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6474 "caps", player->v_stream_caps, NULL);
6476 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6477 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6478 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6479 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6481 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6482 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6483 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6484 G_CALLBACK(__gst_seek_video_data), player);
6486 if (player->a_stream_caps && elem_src_audio) {
6487 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6488 "caps", player->a_stream_caps, NULL);
6490 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6491 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6492 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6493 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6495 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6496 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6497 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6498 G_CALLBACK(__gst_seek_audio_data), player);
6500 } else if (player->a_stream_caps && element) {
6501 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6502 "caps", player->a_stream_caps, NULL);
6504 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6505 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6506 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6507 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6509 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6510 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6511 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6512 G_CALLBACK(__gst_seek_audio_data), player);
6515 if (player->s_stream_caps && elem_src_subtitle) {
6516 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6517 "caps", player->s_stream_caps, NULL);
6519 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6520 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6521 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6522 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6524 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6526 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6527 G_CALLBACK(__gst_seek_subtitle_data), player);
6530 if (player->v_stream_caps && element) {
6531 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6532 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6533 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6534 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6536 if (player->a_stream_caps && elem_src_audio) {
6537 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6538 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6539 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6540 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6542 } else if (player->a_stream_caps && element) {
6543 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6544 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6545 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6546 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6549 if (player->s_stream_caps && elem_src_subtitle)
6550 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6551 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6553 need_state_holder = FALSE;
6555 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6556 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6557 LOGE("failed to commit\n");
6561 case MM_PLAYER_URI_TYPE_MEM:
6563 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6565 LOGD("mem src is selected\n");
6567 element = gst_element_factory_make("appsrc", "mem-source");
6569 LOGE("failed to create appsrc element\n");
6573 g_object_set(element, "stream-type", stream_type, NULL);
6574 g_object_set(element, "size", player->mem_buf.len, NULL);
6575 g_object_set(element, "blocksize", (guint64)20480, NULL);
6577 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6578 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6579 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6580 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6583 case MM_PLAYER_URI_TYPE_URL:
6586 case MM_PLAYER_URI_TYPE_TEMP:
6589 case MM_PLAYER_URI_TYPE_NONE:
6594 /* check source element is OK */
6596 LOGE("no source element was created.\n");
6600 /* take source element */
6601 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6602 mainbin[MMPLAYER_M_SRC].gst = element;
6603 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6605 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6606 player->streamer = __mm_player_streaming_create();
6607 __mm_player_streaming_initialize(player->streamer);
6610 if (MMPLAYER_IS_HTTP_PD(player)) {
6611 gdouble pre_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
6613 LOGD("Picked queue2 element(pre buffer : %d sec)....\n", pre_buffering_time);
6614 element = gst_element_factory_make("queue2", "queue2");
6616 LOGE("failed to create http streaming buffer element\n");
6621 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6622 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6623 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6625 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6627 __mm_player_streaming_set_queue2(player->streamer,
6630 player->ini.http_max_size_bytes,
6633 player->ini.http_buffering_limit,
6634 MUXED_BUFFER_TYPE_MEM_QUEUE,
6638 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6639 if (player->v_stream_caps) {
6640 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6641 if (!es_video_queue) {
6642 LOGE("create es_video_queue for es player failed\n");
6645 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6646 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6647 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6648 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6650 /* Adding audio appsrc to bucket */
6651 if (player->a_stream_caps && elem_src_audio) {
6652 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6653 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6654 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6656 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6657 if (!es_audio_queue) {
6658 LOGE("create es_audio_queue for es player failed\n");
6661 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6663 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6664 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6665 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6667 } else if (player->a_stream_caps) {
6668 /* Only audio stream, no video */
6669 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6670 if (!es_audio_queue) {
6671 LOGE("create es_audio_queue for es player failed\n");
6674 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6675 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6676 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6679 if (player->s_stream_caps && elem_src_subtitle) {
6680 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6681 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6682 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6684 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6685 if (!es_subtitle_queue) {
6686 LOGE("create es_subtitle_queue for es player failed\n");
6689 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6690 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6691 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6695 /* create autoplugging element if src element is not a rtsp src */
6696 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6697 (player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_WFD) &&
6698 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6700 enum MainElementID elemId = MMPLAYER_M_NUM;
6702 if ((player->use_decodebin) &&
6703 ((MMPLAYER_IS_HTTP_PD(player)) ||
6704 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6705 elemId = MMPLAYER_M_AUTOPLUG;
6706 element = __mmplayer_create_decodebin(player);
6708 /* default size of mq in decodebin is 2M
6709 * but it can cause blocking issue during seeking depends on content. */
6710 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6712 need_state_holder = FALSE;
6714 elemId = MMPLAYER_M_TYPEFIND;
6715 element = gst_element_factory_make("typefind", "typefinder");
6716 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6717 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6721 /* check autoplug element is OK */
6723 LOGE("can not create element(%d)\n", elemId);
6727 mainbin[elemId].id = elemId;
6728 mainbin[elemId].gst = element;
6730 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6733 /* add elements to pipeline */
6734 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6735 LOGE("Failed to add elements to pipeline\n");
6740 /* linking elements in the bucket by added order. */
6741 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6742 LOGE("Failed to link some elements\n");
6747 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6748 if (need_state_holder) {
6750 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6751 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6753 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6754 LOGE("fakesink element could not be created\n");
6757 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6759 /* take ownership of fakesink. we are reusing it */
6760 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6763 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6764 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6765 LOGE("failed to add fakesink to bin\n");
6770 /* now we have completed mainbin. take it */
6771 player->pipeline->mainbin = mainbin;
6773 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6774 GstPad *srcpad = NULL;
6776 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6777 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6779 __mmplayer_gst_create_decoder(player,
6780 MM_PLAYER_TRACK_TYPE_VIDEO,
6782 MMPLAYER_M_AUTOPLUG_V_DEC,
6785 gst_object_unref(GST_OBJECT(srcpad));
6790 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6791 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6793 __mmplayer_gst_create_decoder(player,
6794 MM_PLAYER_TRACK_TYPE_AUDIO,
6796 MMPLAYER_M_AUTOPLUG_A_DEC,
6799 gst_object_unref(GST_OBJECT(srcpad));
6804 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6805 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6808 /* connect bus callback */
6809 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6811 LOGE("cannot get bus from pipeline.\n");
6815 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
6817 player->context.thread_default = g_main_context_get_thread_default();
6819 if (NULL == player->context.thread_default) {
6820 player->context.thread_default = g_main_context_default();
6821 LOGD("thread-default context is the global default context");
6823 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6825 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6826 if (__mmplayer_check_subtitle(player)) {
6827 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
6828 LOGE("fail to create subtitle src\n");
6831 /* set sync handler to get tag synchronously */
6832 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6835 gst_object_unref(GST_OBJECT(bus));
6836 g_list_free(element_bucket);
6840 return MM_ERROR_NONE;
6844 __mmplayer_gst_destroy_pipeline(player);
6845 g_list_free(element_bucket);
6848 /* release element which are not added to bin */
6849 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6850 /* NOTE : skip pipeline */
6851 if (mainbin[i].gst) {
6852 GstObject* parent = NULL;
6853 parent = gst_element_get_parent(mainbin[i].gst);
6856 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6857 mainbin[i].gst = NULL;
6859 gst_object_unref(GST_OBJECT(parent));
6863 /* release pipeline with it's childs */
6864 if (mainbin[MMPLAYER_M_PIPE].gst)
6865 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6867 MMPLAYER_FREEIF(mainbin);
6870 MMPLAYER_FREEIF(player->pipeline);
6871 return MM_ERROR_PLAYER_INTERNAL;
6875 __mmplayer_reset_gapless_state(mm_player_t* player)
6878 MMPLAYER_RETURN_IF_FAIL(player
6880 && player->pipeline->audiobin
6881 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6883 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6890 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
6893 int ret = MM_ERROR_NONE;
6897 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6899 /* cleanup stuffs */
6900 MMPLAYER_FREEIF(player->type);
6901 player->have_dynamic_pad = FALSE;
6902 player->no_more_pad = FALSE;
6903 player->num_dynamic_pad = 0;
6904 player->demux_pad_index = 0;
6905 player->subtitle_language_list = NULL;
6906 player->use_deinterleave = FALSE;
6907 player->max_audio_channels = 0;
6908 player->video_share_api_delta = 0;
6909 player->video_share_clock_delta = 0;
6910 player->video_hub_download_mode = 0;
6911 __mmplayer_reset_gapless_state(player);
6913 if (player->streamer) {
6914 __mm_player_streaming_deinitialize(player->streamer);
6915 __mm_player_streaming_destroy(player->streamer);
6916 player->streamer = NULL;
6919 /* cleanup unlinked mime type */
6920 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6921 MMPLAYER_FREEIF(player->unlinked_video_mime);
6922 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6924 /* cleanup running stuffs */
6925 __mmplayer_cancel_eos_timer(player);
6927 /* cleanup gst stuffs */
6928 if (player->pipeline) {
6929 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6930 GstTagList* tag_list = player->pipeline->tag_list;
6932 /* first we need to disconnect all signal hander */
6933 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6935 /* disconnecting bus watch */
6936 if (player->bus_watcher)
6937 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6938 player->bus_watcher = 0;
6941 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6942 MMPlayerGstElement* videobin = player->pipeline->videobin;
6943 MMPlayerGstElement* textbin = player->pipeline->textbin;
6944 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6945 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6946 gst_object_unref(bus);
6948 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6949 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6950 if (ret != MM_ERROR_NONE) {
6951 LOGE("fail to change state to NULL\n");
6952 return MM_ERROR_PLAYER_INTERNAL;
6955 LOGW("succeeded in chaning state to NULL\n");
6957 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6960 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6961 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6963 /* free avsysaudiosink
6964 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6965 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6967 MMPLAYER_FREEIF(audiobin);
6968 MMPLAYER_FREEIF(videobin);
6969 MMPLAYER_FREEIF(textbin);
6970 MMPLAYER_FREEIF(mainbin);
6974 gst_tag_list_free(tag_list);
6976 MMPLAYER_FREEIF(player->pipeline);
6978 MMPLAYER_FREEIF(player->album_art);
6980 if (player->v_stream_caps) {
6981 gst_caps_unref(player->v_stream_caps);
6982 player->v_stream_caps = NULL;
6984 if (player->a_stream_caps) {
6985 gst_caps_unref(player->a_stream_caps);
6986 player->a_stream_caps = NULL;
6989 if (player->s_stream_caps) {
6990 gst_caps_unref(player->s_stream_caps);
6991 player->s_stream_caps = NULL;
6993 _mmplayer_track_destroy(player);
6995 if (player->sink_elements)
6996 g_list_free(player->sink_elements);
6997 player->sink_elements = NULL;
6999 if (player->bufmgr) {
7000 tbm_bufmgr_deinit(player->bufmgr);
7001 player->bufmgr = NULL;
7004 LOGW("finished destroy pipeline\n");
7011 static int __gst_realize(mm_player_t* player) // @
7014 int ret = MM_ERROR_NONE;
7018 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7020 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7022 ret = __mmplayer_gst_create_pipeline(player);
7024 LOGE("failed to create pipeline\n");
7028 /* set pipeline state to READY */
7029 /* NOTE : state change to READY must be performed sync. */
7030 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7031 ret = __mmplayer_gst_set_state(player,
7032 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7034 if (ret != MM_ERROR_NONE) {
7035 /* return error if failed to set state */
7036 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, NULL);
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;
7482 player->duration = dur_nsec;
7485 if (player->duration) {
7486 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7488 LOGE("could not get the duration. fail to seek.\n");
7492 LOGD("playback rate: %f\n", player->playback_rate);
7494 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7496 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7498 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7502 case MM_PLAYER_POS_FORMAT_TIME:
7504 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7505 GstQuery *query = NULL;
7506 gboolean seekable = FALSE;
7508 /* check position is valid or not */
7509 if (position > dur_msec)
7512 query = gst_query_new_seeking (GST_FORMAT_TIME);
7513 if (gst_element_query (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7514 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
7515 gst_query_unref (query);
7518 LOGW("non-seekable content");
7519 player->doing_seek = FALSE;
7520 return MM_ERROR_PLAYER_NO_OP;
7523 LOGW("failed to get seeking query");
7524 gst_query_unref (query); /* keep seeking operation */
7527 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7529 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7530 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7531 This causes problem is position calculation during normal pause resume scenarios also.
7532 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7533 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
7534 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
7535 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7536 LOGW("getting current position failed in seek\n");
7538 player->last_position = pos_nsec;
7539 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
7542 if (player->doing_seek) {
7543 LOGD("not completed seek");
7544 return MM_ERROR_PLAYER_DOING_SEEK;
7548 if (!internal_called)
7549 player->doing_seek = TRUE;
7551 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7553 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7554 gint64 cur_time = 0;
7556 /* get current position */
7557 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7560 GstEvent *event = gst_event_new_seek(1.0,
7562 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7563 GST_SEEK_TYPE_SET, cur_time,
7564 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7566 __gst_send_event_to_sink(player, event);
7568 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7569 __gst_pause(player, FALSE);
7572 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7573 that's why set position through property. */
7574 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7575 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7576 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7577 (!player->videodec_linked) && (!player->audiodec_linked)) {
7579 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7580 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7581 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7582 player->doing_seek = FALSE;
7583 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7585 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7586 GST_FORMAT_TIME, seek_flags,
7587 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7591 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7597 case MM_PLAYER_POS_FORMAT_PERCENT:
7599 LOGD("seeking to(%lu)%% \n", position);
7601 if (player->doing_seek) {
7602 LOGD("not completed seek");
7603 return MM_ERROR_PLAYER_DOING_SEEK;
7606 if (!internal_called)
7607 player->doing_seek = TRUE;
7609 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7610 pos_nsec = (gint64)((position * player->duration) / 100);
7611 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7612 GST_FORMAT_TIME, seek_flags,
7613 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7615 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7625 /* NOTE : store last seeking point to overcome some bad operation
7626 * (returning zero when getting current position) of some elements
7628 player->last_position = pos_nsec;
7630 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7631 if (player->playback_rate > 1.0)
7632 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7635 return MM_ERROR_NONE;
7638 player->pending_seek.is_pending = TRUE;
7639 player->pending_seek.format = format;
7640 player->pending_seek.pos = position;
7642 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7643 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7645 return MM_ERROR_NONE;
7648 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7649 return MM_ERROR_INVALID_ARGUMENT;
7652 player->doing_seek = FALSE;
7653 return MM_ERROR_PLAYER_SEEK;
7656 #define TRICKPLAY_OFFSET GST_MSECOND
7659 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
7661 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7662 gint64 pos_msec = 0;
7663 gboolean ret = TRUE;
7665 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7666 MM_ERROR_PLAYER_NOT_INITIALIZED);
7668 current_state = MMPLAYER_CURRENT_STATE(player);
7670 /* NOTE : query position except paused state to overcome some bad operation
7671 * please refer to below comments in details
7673 if (current_state != MM_PLAYER_STATE_PAUSED)
7674 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7676 /* NOTE : get last point to overcome some bad operation of some elements
7677 *(returning zero when getting current position in paused state
7678 * and when failed to get postion during seeking
7680 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7681 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7683 if (player->playback_rate < 0.0)
7684 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7686 pos_msec = player->last_position;
7689 pos_msec = player->last_position;
7691 player->last_position = pos_msec;
7693 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7696 if (player->duration > 0 && pos_msec > player->duration)
7697 pos_msec = player->duration;
7699 if (player->sound_focus.keep_last_pos) {
7700 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7701 pos_msec = player->last_position;
7703 player->last_position = pos_msec;
7708 case MM_PLAYER_POS_FORMAT_TIME:
7709 *position = GST_TIME_AS_MSECONDS(pos_msec);
7712 case MM_PLAYER_POS_FORMAT_PERCENT:
7714 if (player->duration <= 0) {
7715 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7718 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7719 *position = pos_msec * 100 / player->duration;
7724 return MM_ERROR_PLAYER_INTERNAL;
7727 return MM_ERROR_NONE;
7731 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7733 #define STREAMING_IS_FINISHED 0
7734 #define BUFFERING_MAX_PER 100
7735 #define DEFAULT_PER_VALUE -1
7736 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7738 MMPlayerGstElement *mainbin = NULL;
7739 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7740 gint64 buffered_total = 0;
7741 unsigned long position = 0;
7742 gint buffered_sec = -1;
7743 GstBufferingMode mode = GST_BUFFERING_STREAM;
7744 gint64 content_size_time = player->duration;
7745 guint64 content_size_bytes = player->http_content_size;
7747 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7749 player->pipeline->mainbin,
7750 MM_ERROR_PLAYER_NOT_INITIALIZED);
7752 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7757 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7758 /* and rtsp is not ready yet. */
7759 LOGW("it's only used for http streaming case.\n");
7760 return MM_ERROR_PLAYER_NO_OP;
7763 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7764 LOGW("Time format is not supported yet.\n");
7765 return MM_ERROR_INVALID_ARGUMENT;
7768 if (content_size_time <= 0 || content_size_bytes <= 0) {
7769 LOGW("there is no content size.");
7770 return MM_ERROR_NONE;
7773 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7774 LOGW("fail to get current position.");
7775 return MM_ERROR_NONE;
7778 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7779 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7781 mainbin = player->pipeline->mainbin;
7782 start_per = ceil(100 *(position*GST_MSECOND) / content_size_time);
7784 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7785 GstQuery *query = NULL;
7786 gint byte_in_rate = 0, byte_out_rate = 0;
7787 gint64 estimated_total = 0;
7789 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7790 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7791 LOGW("fail to get buffering query from queue2");
7793 gst_query_unref(query);
7794 return MM_ERROR_NONE;
7797 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7798 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7800 if (mode == GST_BUFFERING_STREAM) {
7801 /* using only queue in case of push mode(ts / mp3) */
7802 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7803 GST_FORMAT_BYTES, &buffered_total)) {
7804 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7805 stop_per = 100 * buffered_total / content_size_bytes;
7808 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7810 guint num_of_ranges = 0;
7811 gint64 start_byte = 0, stop_byte = 0;
7813 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7814 if (estimated_total != STREAMING_IS_FINISHED) {
7815 /* buffered size info from queue2 */
7816 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7817 for (idx = 0; idx < num_of_ranges; idx++) {
7818 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7819 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7821 buffered_total += (stop_byte - start_byte);
7824 stop_per = BUFFERING_MAX_PER;
7826 gst_query_unref(query);
7829 if (stop_per == DEFAULT_PER_VALUE) {
7830 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7832 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7834 /* buffered size info from multiqueue */
7835 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7836 guint curr_size_bytes = 0;
7837 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7838 "curr-size-bytes", &curr_size_bytes, NULL);
7839 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7840 buffered_total += curr_size_bytes;
7843 if (avg_byterate > 0)
7844 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7845 else if (player->total_maximum_bitrate > 0)
7846 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7847 else if (player->total_bitrate > 0)
7848 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7850 if (buffered_sec >= 0)
7851 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7855 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7856 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7858 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7859 buffered_total, buffered_sec, *start_pos, *stop_pos);
7861 return MM_ERROR_NONE;
7865 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
7870 LOGW("set_message_callback is called with invalid player handle\n");
7871 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7874 player->msg_cb = callback;
7875 player->msg_cb_param = user_param;
7877 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7881 return MM_ERROR_NONE;
7884 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
7886 int ret = MM_ERROR_PLAYER_INVALID_URI;
7891 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7892 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7893 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7895 memset(data, 0, sizeof(MMPlayerParseProfile));
7897 if ((path = strstr(uri, "es_buff://"))) {
7899 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7900 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7901 ret = MM_ERROR_NONE;
7903 } else if ((path = strstr(uri, "rtsp://"))) {
7905 if ((path = strstr(uri, "/wfd1.0/"))) {
7906 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7907 data->uri_type = MM_PLAYER_URI_TYPE_URL_WFD;
7908 ret = MM_ERROR_NONE;
7909 LOGD("uri is actually a wfd client path. giving it to wfdrtspsrc\n");
7911 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7912 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7913 ret = MM_ERROR_NONE;
7916 } else if ((path = strstr(uri, "http://"))) {
7918 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7920 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7921 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7922 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7924 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7926 ret = MM_ERROR_NONE;
7928 } else if ((path = strstr(uri, "https://"))) {
7930 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7932 if (g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".ism/manifest") ||
7933 g_str_has_suffix(g_ascii_strdown(uri, strlen(uri)), ".isml/manifest"))
7934 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7936 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7938 ret = MM_ERROR_NONE;
7940 } else if ((path = strstr(uri, "rtspu://"))) {
7942 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7943 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7944 ret = MM_ERROR_NONE;
7946 } else if ((path = strstr(uri, "rtspr://"))) {
7947 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7948 char *separater = strstr(path, "*");
7952 char *urgent = separater + strlen("*");
7954 if ((urgent_len = strlen(urgent))) {
7955 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7956 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7957 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958 ret = MM_ERROR_NONE;
7961 } else if ((path = strstr(uri, "mms://"))) {
7963 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7964 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7965 ret = MM_ERROR_NONE;
7967 } else if ((path = strstr(uri, "mem://"))) {
7970 char *buffer = NULL;
7971 char *seperator = strchr(path, ',');
7972 char ext[100] = {0,}, size[100] = {0,};
7975 if ((buffer = strstr(path, "ext="))) {
7976 buffer += strlen("ext=");
7978 if (strlen(buffer)) {
7979 strncpy(ext, buffer, 99);
7981 if ((seperator = strchr(ext, ','))
7982 || (seperator = strchr(ext, ' '))
7983 || (seperator = strchr(ext, '\0'))) {
7984 seperator[0] = '\0';
7989 if ((buffer = strstr(path, "size="))) {
7990 buffer += strlen("size=");
7992 if (strlen(buffer) > 0) {
7993 strncpy(size, buffer, 99);
7995 if ((seperator = strchr(size, ','))
7996 || (seperator = strchr(size, ' '))
7997 || (seperator = strchr(size, '\0'))) {
7998 seperator[0] = '\0';
8001 mem_size = atoi(size);
8006 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8007 if (mem_size && param) {
8009 data->mem_size = mem_size;
8010 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8011 ret = MM_ERROR_NONE;
8015 gchar *location = NULL;
8018 if ((path = strstr(uri, "file://"))) {
8020 location = g_filename_from_uri(uri, NULL, &err);
8022 if (!location || (err != NULL)) {
8023 LOGE("Invalid URI '%s' for filesrc: %s", path,
8024 (err != NULL) ? err->message : "unknown error");
8026 if (err) g_error_free(err);
8027 if (location) g_free(location);
8029 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8033 LOGD("path from uri: %s", location);
8036 path = (location != NULL) ? (location) : ((char*)uri);
8037 int file_stat = MM_ERROR_NONE;
8039 file_stat = util_exist_file_path(path);
8041 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8042 if (file_stat == MM_ERROR_NONE) {
8043 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8045 if (util_is_sdp_file(path)) {
8046 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8047 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8049 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8051 ret = MM_ERROR_NONE;
8052 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8053 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8055 LOGE("invalid uri, could not play..\n");
8056 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8059 if (location) g_free(location);
8063 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8064 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8065 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8066 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8068 /* dump parse result */
8069 SECURE_LOGW("incomming uri : %s\n", uri);
8070 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8071 data->uri_type, data->mem, data->mem_size, data->urgent);
8078 gboolean _asm_postmsg(gpointer *data)
8080 mm_player_t* player = (mm_player_t*)data;
8081 MMMessageParamType msg = {0, };
8084 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8085 LOGW("get notified");
8087 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8088 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8094 msg.union_type = MM_MSG_UNION_CODE;
8095 msg.code = player->sound_focus.focus_changed_msg;
8097 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8098 player->resume_event_id = 0;
8104 gboolean _asm_lazy_pause(gpointer *data)
8106 mm_player_t* player = (mm_player_t*)data;
8107 int ret = MM_ERROR_NONE;
8111 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8113 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8114 LOGD("Ready to proceed lazy pause\n");
8115 ret = _mmplayer_pause((MMHandleType)player);
8116 if (MM_ERROR_NONE != ret)
8117 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8119 LOGD("Invalid state to proceed lazy pause\n");
8122 if (player->pipeline && player->pipeline->audiobin)
8123 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8125 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8133 __mmplayer_can_do_interrupt(mm_player_t *player)
8135 if (!player || !player->pipeline || !player->attrs) {
8136 LOGW("not initialized");
8140 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8141 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8145 /* check if seeking */
8146 if (player->doing_seek) {
8147 MMMessageParamType msg_param;
8148 memset(&msg_param, 0, sizeof(MMMessageParamType));
8149 msg_param.code = MM_ERROR_PLAYER_SEEK;
8150 player->doing_seek = FALSE;
8151 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8155 /* check other thread */
8156 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8157 LOGW("locked already, cmd state : %d", player->cmd);
8159 /* check application command */
8160 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8161 LOGW("playing.. should wait cmd lock then, will be interrupted");
8163 /* lock will be released at mrp_resource_release_cb() */
8164 MMPLAYER_CMD_LOCK(player);
8167 LOGW("nothing to do");
8170 LOGW("can interrupt immediately");
8174 FAILED: /* with CMD UNLOCKED */
8177 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8181 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8183 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8185 int ret = MM_ERROR_NONE;
8186 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8188 if (strstr(reason_for_change, "alarm")) {
8189 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8191 } else if (strstr(reason_for_change, "notification")) {
8192 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8194 } else if (strstr(reason_for_change, "emergency")) {
8195 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8197 } else if (strstr(reason_for_change, "call-voice") ||
8198 strstr(reason_for_change, "call-video") ||
8199 strstr(reason_for_change, "voip") ||
8200 strstr(reason_for_change, "ringtone-voip") ||
8201 strstr(reason_for_change, "ringtone-call")) {
8202 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8204 } else if (strstr(reason_for_change, "media") ||
8205 strstr(reason_for_change, "radio") ||
8206 strstr(reason_for_change, "loopback") ||
8207 strstr(reason_for_change, "system") ||
8208 strstr(reason_for_change, "voice-information") ||
8209 strstr(reason_for_change, "voice-recognition")) {
8210 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8213 ret = MM_ERROR_INVALID_ARGUMENT;
8214 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8218 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8220 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8222 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8229 /* FIXME: will be updated with new funct */
8230 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8231 const char *reason_for_change, const char *additional_info, void *user_data)
8233 mm_player_t* player = (mm_player_t*) user_data;
8234 int result = MM_ERROR_NONE;
8235 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8237 LOGW("focus watch notified");
8239 if (!__mmplayer_can_do_interrupt(player)) {
8240 LOGW("no need to interrupt, so leave");
8241 goto EXIT_WITHOUT_UNLOCK;
8244 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8245 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8249 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8250 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8252 player->sound_focus.cb_pending = TRUE;
8253 player->sound_focus.by_asm_cb = TRUE;
8255 if (focus_state == FOCUS_IS_ACQUIRED) {
8256 LOGW("watch: FOCUS_IS_ACQUIRED");
8257 player->sound_focus.acquired = TRUE;
8259 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8260 player->sound_focus.focus_changed_msg = (int)msg;
8262 if (strstr(reason_for_change, "call") ||
8263 strstr(reason_for_change, "voip") || /* FIXME: to check */
8264 strstr(reason_for_change, "alarm") ||
8265 strstr(reason_for_change, "media")) {
8266 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8267 // hold 0.7 second to excute "fadedown mute" effect
8268 LOGW("do fade down->pause->undo fade down");
8270 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8272 result = _mmplayer_pause((MMHandleType)player);
8273 if (result != MM_ERROR_NONE) {
8274 LOGW("fail to set Pause state by asm");
8277 __mmplayer_undo_sound_fadedown(player);
8279 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8280 _mmplayer_unrealize((MMHandleType)player);
8282 LOGW("pause immediately");
8283 result = _mmplayer_pause((MMHandleType)player);
8284 if (result != MM_ERROR_NONE) {
8285 LOGW("fail to set Pause state by asm");
8289 } else if (focus_state == FOCUS_IS_RELEASED) {
8290 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8291 player->sound_focus.acquired = FALSE;
8292 player->sound_focus.antishock = TRUE;
8293 player->sound_focus.by_asm_cb = FALSE;
8295 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8296 player->sound_focus.focus_changed_msg = (int)msg;
8298 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8299 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8302 LOGW("unknown focus state %d", focus_state);
8305 player->sound_focus.by_asm_cb = FALSE;
8306 player->sound_focus.cb_pending = FALSE;
8309 MMPLAYER_CMD_UNLOCK(player);
8313 EXIT_WITHOUT_UNLOCK:
8319 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8320 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8322 mm_player_t* player = (mm_player_t*) user_data;
8323 int result = MM_ERROR_NONE;
8324 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8326 LOGW("get focus notified");
8328 if (!__mmplayer_can_do_interrupt(player)) {
8329 LOGW("no need to interrupt, so leave");
8330 goto EXIT_WITHOUT_UNLOCK;
8333 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8334 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8338 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8339 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8341 player->sound_focus.cb_pending = TRUE;
8342 player->sound_focus.by_asm_cb = TRUE;
8343 // player->sound_focus.event_src = event_src;
8345 if (focus_state == FOCUS_IS_RELEASED) {
8346 LOGW("FOCUS_IS_RELEASED");
8347 player->sound_focus.acquired = FALSE;
8349 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8350 player->sound_focus.focus_changed_msg = (int)msg;
8352 if (strstr(reason_for_change, "call") ||
8353 strstr(reason_for_change, "voip") || /* FIXME: to check */
8354 strstr(reason_for_change, "alarm") ||
8355 strstr(reason_for_change, "media")) {
8356 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8357 //hold 0.7 second to excute "fadedown mute" effect
8358 LOGW("do fade down->pause->undo fade down");
8360 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8362 result = _mmplayer_pause((MMHandleType)player);
8363 if (result != MM_ERROR_NONE) {
8364 LOGW("fail to set Pause state by asm");
8367 __mmplayer_undo_sound_fadedown(player);
8369 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8370 _mmplayer_unrealize((MMHandleType)player);
8372 LOGW("pause immediately");
8373 result = _mmplayer_pause((MMHandleType)player);
8374 if (result != MM_ERROR_NONE) {
8375 LOGW("fail to set Pause state by asm");
8379 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8380 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8381 player->sound_focus.antishock = TRUE;
8382 player->sound_focus.by_asm_cb = FALSE;
8384 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8385 player->sound_focus.focus_changed_msg = (int)msg;
8387 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8388 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8391 LOGW("unknown focus state %d", focus_state);
8394 player->sound_focus.by_asm_cb = FALSE;
8395 player->sound_focus.cb_pending = FALSE;
8398 if (mm_sound_update_focus_status(id, 0))
8399 LOGE("failed to update focus status\n");
8400 MMPLAYER_CMD_UNLOCK(player);
8404 EXIT_WITHOUT_UNLOCK:
8411 _mmplayer_create_player(MMHandleType handle) // @
8413 int ret = MM_ERROR_PLAYER_INTERNAL;
8414 mm_player_t* player = MM_PLAYER_CAST(handle);
8418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8420 /* initialize player state */
8421 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8422 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8423 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8426 /* check current state */
8427 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8429 /* construct attributes */
8430 player->attrs = _mmplayer_construct_attribute(handle);
8432 if (!player->attrs) {
8433 LOGE("Failed to construct attributes\n");
8437 /* initialize gstreamer with configured parameter */
8438 if (!__mmplayer_init_gstreamer(player)) {
8439 LOGE("Initializing gstreamer failed\n");
8440 _mmplayer_deconstruct_attribute(handle);
8444 /* initialize factories if not using decodebin */
8445 if (player->factories == NULL)
8446 __mmplayer_init_factories(player);
8448 /* create lock. note that g_tread_init() has already called in gst_init() */
8449 g_mutex_init(&player->fsink_lock);
8451 /* create update tag lock */
8452 g_mutex_init(&player->update_tag_lock);
8454 /* create repeat mutex */
8455 g_mutex_init(&player->repeat_thread_mutex);
8457 /* create repeat cond */
8458 g_cond_init(&player->repeat_thread_cond);
8460 /* create repeat thread */
8461 player->repeat_thread =
8462 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8463 if (!player->repeat_thread) {
8464 LOGE("failed to create repeat_thread(%s)");
8465 g_mutex_clear(&player->repeat_thread_mutex);
8466 g_cond_clear(&player->repeat_thread_cond);
8467 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8471 /* create next play mutex */
8472 g_mutex_init(&player->next_play_thread_mutex);
8474 /* create next play cond */
8475 g_cond_init(&player->next_play_thread_cond);
8477 /* create next play thread */
8478 player->next_play_thread =
8479 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8480 if (!player->next_play_thread) {
8481 LOGE("failed to create next play thread");
8482 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8483 g_mutex_clear(&player->next_play_thread_mutex);
8484 g_cond_clear(&player->next_play_thread_cond);
8488 ret = _mmplayer_initialize_video_capture(player);
8489 if (ret != MM_ERROR_NONE) {
8490 LOGE("failed to initialize video capture\n");
8494 /* initialize resource manager */
8495 if (MM_ERROR_NONE != _mmplayer_resource_manager_init(&player->resource_manager, player)) {
8496 LOGE("failed to initialize resource manager\n");
8500 if (MMPLAYER_IS_HTTP_PD(player)) {
8501 player->pd_downloader = NULL;
8502 player->pd_file_save_path = NULL;
8505 /* create video bo lock and cond */
8506 g_mutex_init(&player->video_bo_mutex);
8507 g_cond_init(&player->video_bo_cond);
8509 /* create media stream callback mutex */
8510 g_mutex_init(&player->media_stream_cb_lock);
8512 player->streaming_type = STREAMING_SERVICE_NONE;
8514 /* give default value of audio effect setting */
8515 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8516 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8518 player->play_subtitle = FALSE;
8519 player->use_textoverlay = FALSE;
8520 player->play_count = 0;
8521 player->use_decodebin = TRUE;
8522 player->ignore_asyncdone = FALSE;
8523 player->use_deinterleave = FALSE;
8524 player->max_audio_channels = 0;
8525 player->video_share_api_delta = 0;
8526 player->video_share_clock_delta = 0;
8527 player->has_closed_caption = FALSE;
8528 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8529 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8530 player->pending_resume = FALSE;
8531 if (player->ini.dump_element_keyword[0][0] == '\0')
8532 player->ini.set_dump_element_flag = FALSE;
8534 player->ini.set_dump_element_flag = TRUE;
8536 /* set player state to null */
8537 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8538 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8540 return MM_ERROR_NONE;
8544 g_mutex_clear(&player->fsink_lock);
8546 /* free update tag lock */
8547 g_mutex_clear(&player->update_tag_lock);
8550 if (player->repeat_thread) {
8551 player->repeat_thread_exit = TRUE;
8552 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8554 g_thread_join(player->repeat_thread);
8555 player->repeat_thread = NULL;
8557 g_mutex_clear(&player->repeat_thread_mutex);
8558 g_cond_clear(&player->repeat_thread_cond);
8561 /* free next play thread */
8562 if (player->next_play_thread) {
8563 player->next_play_thread_exit = TRUE;
8564 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8566 g_thread_join(player->next_play_thread);
8567 player->next_play_thread = NULL;
8569 g_mutex_clear(&player->next_play_thread_mutex);
8570 g_cond_clear(&player->next_play_thread_cond);
8573 /* release attributes */
8574 _mmplayer_deconstruct_attribute(handle);
8582 __mmplayer_init_gstreamer(mm_player_t* player) // @
8584 static gboolean initialized = FALSE;
8585 static const int max_argc = 50;
8587 gchar** argv = NULL;
8588 gchar** argv2 = NULL;
8594 LOGD("gstreamer already initialized.\n");
8599 argc = malloc(sizeof(int));
8600 argv = malloc(sizeof(gchar*) * max_argc);
8601 argv2 = malloc(sizeof(gchar*) * max_argc);
8603 if (!argc || !argv || !argv2)
8606 memset(argv, 0, sizeof(gchar*) * max_argc);
8607 memset(argv2, 0, sizeof(gchar*) * max_argc);
8611 argv[0] = g_strdup("mmplayer");
8614 for (i = 0; i < 5; i++) {
8615 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8616 if (strlen(player->ini.gst_param[i]) > 0) {
8617 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8622 /* we would not do fork for scanning plugins */
8623 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8626 /* check disable registry scan */
8627 if (player->ini.skip_rescan) {
8628 argv[*argc] = g_strdup("--gst-disable-registry-update");
8632 /* check disable segtrap */
8633 if (player->ini.disable_segtrap) {
8634 argv[*argc] = g_strdup("--gst-disable-segtrap");
8638 LOGD("initializing gstreamer with following parameter\n");
8639 LOGD("argc : %d\n", *argc);
8642 for (i = 0; i < arg_count; i++) {
8644 LOGD("argv[%d] : %s\n", i, argv2[i]);
8648 /* initializing gstreamer */
8649 if (!gst_init_check(argc, &argv, &err)) {
8650 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8657 for (i = 0; i < arg_count; i++) {
8658 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8659 MMPLAYER_FREEIF(argv2[i]);
8662 MMPLAYER_FREEIF(argv);
8663 MMPLAYER_FREEIF(argv2);
8664 MMPLAYER_FREEIF(argc);
8674 for (i = 0; i < arg_count; i++) {
8675 LOGD("free[%d] : %s\n", i, argv2[i]);
8676 MMPLAYER_FREEIF(argv2[i]);
8679 MMPLAYER_FREEIF(argv);
8680 MMPLAYER_FREEIF(argv2);
8681 MMPLAYER_FREEIF(argc);
8687 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8691 if (player->pd_downloader) {
8692 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8693 MMPLAYER_FREEIF(player->pd_downloader);
8696 if (MMPLAYER_IS_HTTP_PD(player)) {
8697 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8698 MMPLAYER_FREEIF(player->pd_file_save_path);
8701 return MM_ERROR_NONE;
8705 __mmplayer_check_async_state_transition(mm_player_t* player)
8707 GstState element_state = GST_STATE_VOID_PENDING;
8708 GstState element_pending_state = GST_STATE_VOID_PENDING;
8709 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8710 GstElement * element = NULL;
8711 gboolean async = FALSE;
8713 /* check player handle */
8714 MMPLAYER_RETURN_IF_FAIL(player &&
8716 player->pipeline->mainbin &&
8717 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8720 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8722 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8723 LOGD("don't need to check the pipeline state");
8727 MMPLAYER_PRINT_STATE(player);
8729 /* wait for state transition */
8730 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8731 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8733 if (ret == GST_STATE_CHANGE_FAILURE) {
8734 LOGE(" [%s] state : %s pending : %s \n",
8735 GST_ELEMENT_NAME(element),
8736 gst_element_state_get_name(element_state),
8737 gst_element_state_get_name(element_pending_state));
8739 /* dump state of all element */
8740 __mmplayer_dump_pipeline_state(player);
8745 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8750 _mmplayer_destroy(MMHandleType handle) // @
8752 mm_player_t* player = MM_PLAYER_CAST(handle);
8756 /* check player handle */
8757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8759 /* destroy can called at anytime */
8760 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8762 /* check async state transition */
8763 __mmplayer_check_async_state_transition(player);
8765 __mmplayer_destroy_streaming_ext(player);
8767 /* release repeat thread */
8768 if (player->repeat_thread) {
8769 player->repeat_thread_exit = TRUE;
8770 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8772 LOGD("waitting for repeat thread exit\n");
8773 g_thread_join(player->repeat_thread);
8774 g_mutex_clear(&player->repeat_thread_mutex);
8775 g_cond_clear(&player->repeat_thread_cond);
8776 LOGD("repeat thread released\n");
8779 /* release next play thread */
8780 if (player->next_play_thread) {
8781 player->next_play_thread_exit = TRUE;
8782 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8784 LOGD("waitting for next play thread exit\n");
8785 g_thread_join(player->next_play_thread);
8786 g_mutex_clear(&player->next_play_thread_mutex);
8787 g_cond_clear(&player->next_play_thread_cond);
8788 LOGD("next play thread released\n");
8791 _mmplayer_release_video_capture(player);
8793 /* flush any pending asm_cb */
8794 if (player->sound_focus.cb_pending) {
8795 /* set a flag for make sure asm_cb to be returned immediately */
8796 LOGW("asm cb has pending state");
8797 player->sound_focus.exit_cb = TRUE;
8799 /* make sure to release any pending asm_cb which locked by cmd_lock */
8800 MMPLAYER_CMD_UNLOCK(player);
8802 MMPLAYER_CMD_LOCK(player);
8806 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
8807 LOGE("failed to deregister asm server\n");
8809 /* de-initialize resource manager */
8810 if (MM_ERROR_NONE != _mmplayer_resource_manager_deinit(&player->resource_manager))
8811 LOGE("failed to deinitialize resource manager\n");
8813 #ifdef USE_LAZY_PAUSE
8814 if (player->lazy_pause_event_id) {
8815 __mmplayer_remove_g_source_from_context(player->context.global_default, player->lazy_pause_event_id);
8816 player->lazy_pause_event_id = 0;
8820 if (player->resume_event_id) {
8821 g_source_remove(player->resume_event_id);
8822 player->resume_event_id = 0;
8825 if (player->resumable_cancel_id) {
8826 g_source_remove(player->resumable_cancel_id);
8827 player->resumable_cancel_id = 0;
8830 /* release pipeline */
8831 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8832 LOGE("failed to destory pipeline\n");
8833 return MM_ERROR_PLAYER_INTERNAL;
8836 if (player->is_external_subtitle_present && player->subtitle_language_list) {
8837 g_list_free(player->subtitle_language_list);
8838 player->subtitle_language_list = NULL;
8841 __mmplayer_release_dump_list(player->dump_list);
8843 /* release miscellaneous information.
8844 these info needs to be released after pipeline is destroyed. */
8845 __mmplayer_release_misc_post(player);
8847 /* release attributes */
8848 _mmplayer_deconstruct_attribute(handle);
8850 /* release factories */
8851 __mmplayer_release_factories(player);
8854 g_mutex_clear(&player->fsink_lock);
8857 g_mutex_clear(&player->update_tag_lock);
8859 /* release video bo lock and cond */
8860 g_mutex_clear(&player->video_bo_mutex);
8861 g_cond_clear(&player->video_bo_cond);
8863 /* release media stream callback lock */
8864 g_mutex_clear(&player->media_stream_cb_lock);
8868 return MM_ERROR_NONE;
8872 __mmplayer_realize_streaming_ext(mm_player_t* player)
8874 int ret = MM_ERROR_NONE;
8877 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8879 if (MMPLAYER_IS_HTTP_PD(player)) {
8880 gboolean bret = FALSE;
8882 player->pd_downloader = _mmplayer_create_pd_downloader();
8883 if (!player->pd_downloader) {
8884 LOGE("Unable to create PD Downloader...");
8885 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8888 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8890 if (FALSE == bret) {
8891 LOGE("Unable to create PD Downloader...");
8892 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8901 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid) // @
8903 mm_player_t* player = (mm_player_t*)hplayer;
8904 MMHandleType attrs = 0;
8905 int ret = MM_ERROR_NONE;
8907 attrs = MMPLAYER_GET_ATTRS(player);
8909 LOGE("fail to get attributes.\n");
8910 return MM_ERROR_PLAYER_INTERNAL;
8913 player->sound_focus.pid = pid;
8915 /* register to asm */
8916 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
8917 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
8918 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
8920 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
8921 LOGE("failed to register asm server\n");
8922 return MM_ERROR_POLICY_INTERNAL;
8928 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
8930 mm_player_t* player = (mm_player_t*) hplayer;
8934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8936 *pid = player->sound_focus.pid;
8938 LOGD("registered pid[%d] %p", *pid, player);
8942 return MM_ERROR_NONE;
8946 _mmplayer_realize(MMHandleType hplayer) // @
8948 mm_player_t* player = (mm_player_t*)hplayer;
8951 gboolean update_registry = FALSE;
8952 MMHandleType attrs = 0;
8953 int ret = MM_ERROR_NONE;
8957 /* check player handle */
8958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8960 /* check current state */
8961 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8963 attrs = MMPLAYER_GET_ATTRS(player);
8965 LOGE("fail to get attributes.\n");
8966 return MM_ERROR_PLAYER_INTERNAL;
8968 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8969 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8971 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8972 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8974 if (ret != MM_ERROR_NONE) {
8975 LOGE("failed to parse profile\n");
8980 /* FIXIT : we can use thouse in player->profile directly */
8981 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
8982 player->mem_buf.buf = (char *)player->profile.mem;
8983 player->mem_buf.len = player->profile.mem_size;
8984 player->mem_buf.offset = 0;
8987 if (uri && (strstr(uri, "es_buff://"))) {
8988 if (strstr(uri, "es_buff://push_mode"))
8989 player->es_player_push_mode = TRUE;
8991 player->es_player_push_mode = FALSE;
8994 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8995 LOGW("mms protocol is not supported format.\n");
8996 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8999 if (MMPLAYER_IS_STREAMING(player))
9000 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9002 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9004 player->smooth_streaming = FALSE;
9005 player->videodec_linked = 0;
9006 player->videosink_linked = 0;
9007 player->audiodec_linked = 0;
9008 player->audiosink_linked = 0;
9009 player->textsink_linked = 0;
9010 player->is_external_subtitle_present = FALSE;
9011 player->is_external_subtitle_added_now = FALSE;
9012 /* set the subtitle ON default */
9013 player->is_subtitle_off = FALSE;
9015 /* registry should be updated for downloadable codec */
9016 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9018 if (update_registry) {
9019 LOGD("updating registry...\n");
9020 gst_update_registry();
9022 /* then we have to rebuild factories */
9023 __mmplayer_release_factories(player);
9024 __mmplayer_init_factories(player);
9027 /* realize pipeline */
9028 ret = __gst_realize(player);
9029 if (ret != MM_ERROR_NONE)
9030 LOGE("fail to realize the player.\n");
9032 ret = __mmplayer_realize_streaming_ext(player);
9040 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9043 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9045 /* destroy can called at anytime */
9046 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player)) {
9047 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9048 MMPLAYER_FREEIF(player->pd_downloader);
9052 return MM_ERROR_NONE;
9056 _mmplayer_unrealize(MMHandleType hplayer)
9058 mm_player_t* player = (mm_player_t*)hplayer;
9059 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
9060 int ret = MM_ERROR_NONE;
9064 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9066 /* check current state */
9067 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9069 /* check async state transition */
9070 __mmplayer_check_async_state_transition(player);
9072 __mmplayer_unrealize_streaming_ext(player);
9074 /* unrealize pipeline */
9075 ret = __gst_unrealize(player);
9077 /* set asm stop if success */
9078 if (MM_ERROR_NONE == ret) {
9079 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9080 if (ret != MM_ERROR_NONE)
9081 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9083 if (!player->resource_manager.by_rm_cb && /* is being released */
9084 _mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9085 if (resource_state >= RESOURCE_STATE_ACQUIRED) {
9086 ret = _mmplayer_resource_manager_release(&player->resource_manager);
9087 if (ret != MM_ERROR_NONE)
9088 LOGE("failed to release resource, ret(0x%x)\n", ret);
9092 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
9093 if (resource_state == RESOURCE_STATE_PREPARED) {
9094 ret = _mmplayer_resource_manager_unprepare(&player->resource_manager);
9095 if (ret != MM_ERROR_NONE)
9096 LOGE("failed to unprepare resource, ret(0x%x)\n", ret);
9100 LOGE("failed and don't change asm state to stop");
9108 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
9110 mm_player_t* player = (mm_player_t*)hplayer;
9112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114 return __gst_set_message_callback(player, callback, user_param);
9118 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
9120 mm_player_t *player = (mm_player_t*)hplayer;
9122 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9124 *state = MMPLAYER_CURRENT_STATE(player);
9126 return MM_ERROR_NONE;
9131 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
9133 mm_player_t* player = (mm_player_t*) hplayer;
9134 GstElement* vol_element = NULL;
9139 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9141 LOGD("volume [L]=%f:[R]=%f\n",
9142 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9144 /* invalid factor range or not */
9145 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9146 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9147 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9148 return MM_ERROR_INVALID_ARGUMENT;
9152 /* not support to set other value into each channel */
9153 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9154 return MM_ERROR_INVALID_ARGUMENT;
9156 /* Save volume to handle. Currently the first array element will be saved. */
9157 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9159 /* check pipeline handle */
9160 if (!player->pipeline || !player->pipeline->audiobin) {
9161 LOGD("audiobin is not created yet\n");
9162 LOGD("but, current stored volume will be set when it's created.\n");
9164 /* NOTE : stored volume will be used in create_audiobin
9165 * returning MM_ERROR_NONE here makes application to able to
9166 * set volume at anytime.
9168 return MM_ERROR_NONE;
9171 /* setting volume to volume element */
9172 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9175 LOGD("volume is set [%f]\n", player->sound.volume);
9176 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9181 return MM_ERROR_NONE;
9186 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9188 mm_player_t* player = (mm_player_t*) hplayer;
9193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9194 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9196 /* returning stored volume */
9197 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9198 volume->level[i] = player->sound.volume;
9202 return MM_ERROR_NONE;
9208 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
9210 mm_player_t* player = (mm_player_t*) hplayer;
9211 GstElement* vol_element = NULL;
9215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9217 /* mute value shoud 0 or 1 */
9218 if (mute != 0 && mute != 1) {
9219 LOGE("bad mute value\n");
9221 /* FIXIT : definitly, we need _BAD_PARAM error code */
9222 return MM_ERROR_INVALID_ARGUMENT;
9225 player->sound.mute = mute;
9227 /* just hold mute value if pipeline is not ready */
9228 if (!player->pipeline || !player->pipeline->audiobin) {
9229 LOGD("pipeline is not ready. holding mute value\n");
9230 return MM_ERROR_NONE;
9233 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9235 /* NOTE : volume will only created when the bt is enabled */
9237 LOGD("mute : %d\n", mute);
9238 g_object_set(vol_element, "mute", mute, NULL);
9240 LOGD("volume elemnet is not created. using volume in audiosink\n");
9244 return MM_ERROR_NONE;
9248 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
9250 mm_player_t* player = (mm_player_t*) hplayer;
9254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9255 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9257 /* just hold mute value if pipeline is not ready */
9258 if (!player->pipeline || !player->pipeline->audiobin) {
9259 LOGD("pipeline is not ready. returning stored value\n");
9260 *pmute = player->sound.mute;
9261 return MM_ERROR_NONE;
9264 *pmute = player->sound.mute;
9268 return MM_ERROR_NONE;
9272 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9274 mm_player_t* player = (mm_player_t*) hplayer;
9278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9280 player->video_stream_changed_cb = callback;
9281 player->video_stream_changed_cb_user_param = user_param;
9282 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9286 return MM_ERROR_NONE;
9290 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9292 mm_player_t* player = (mm_player_t*) hplayer;
9296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9298 player->audio_stream_changed_cb = callback;
9299 player->audio_stream_changed_cb_user_param = user_param;
9300 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9304 return MM_ERROR_NONE;
9308 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex 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 player->audio_stream_render_cb_ex = callback;
9317 player->audio_stream_cb_user_param = user_param;
9318 player->audio_stream_sink_sync = sync;
9319 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);
9323 return MM_ERROR_NONE;
9327 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
9329 mm_player_t* player = (mm_player_t*) hplayer;
9333 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9335 if (callback && !player->bufmgr)
9336 player->bufmgr = tbm_bufmgr_init(-1);
9338 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9339 player->video_stream_cb = callback;
9340 player->video_stream_cb_user_param = user_param;
9342 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9346 return MM_ERROR_NONE;
9350 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
9352 mm_player_t* player = (mm_player_t*) hplayer;
9356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9358 player->audio_stream_cb = callback;
9359 player->audio_stream_cb_user_param = user_param;
9360 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9364 return MM_ERROR_NONE;
9369 _mmplayer_set_prepare_buffering_time(MMHandleType hplayer, int second)
9371 mm_player_t* player = (mm_player_t*) hplayer;
9375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9377 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9378 return MM_ERROR_PLAYER_INVALID_STATE;
9380 LOGD("pre buffer size : %d sec\n", second);
9383 LOGE("bad size value\n");
9384 return MM_ERROR_INVALID_ARGUMENT;
9387 if (player->streamer == NULL) {
9388 player->streamer = __mm_player_streaming_create();
9389 __mm_player_streaming_initialize(player->streamer);
9392 player->streamer->buffering_req.initial_second = second;
9396 return MM_ERROR_NONE;
9401 _mmplayer_set_runtime_buffering_mode(MMHandleType hplayer, MMPlayerBufferingMode mode, int second)
9403 mm_player_t* player = (mm_player_t*) hplayer;
9407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9409 LOGD("mode %d\n", mode);
9411 if ((mode < 0) || (mode > MM_PLAYER_BUFFERING_MODE_MAX) ||
9412 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) && (second <= 0)))
9413 return MM_ERROR_INVALID_ARGUMENT;
9415 if (player->streamer == NULL) {
9416 player->streamer = __mm_player_streaming_create();
9417 __mm_player_streaming_initialize(player->streamer);
9420 player->streamer->buffering_req.mode = mode;
9423 ((mode == MM_PLAYER_BUFFERING_MODE_FIXED) ||
9424 (mode == MM_PLAYER_BUFFERING_MODE_ADAPTIVE)))
9425 player->streamer->buffering_req.runtime_second = second;
9429 return MM_ERROR_NONE;
9433 __mmplayer_start_streaming_ext(mm_player_t *player)
9435 gint ret = MM_ERROR_NONE;
9438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9440 if (MMPLAYER_IS_HTTP_PD(player)) {
9441 if (!player->pd_downloader) {
9442 ret = __mmplayer_realize_streaming_ext(player);
9444 if (ret != MM_ERROR_NONE) {
9445 LOGE("failed to realize streaming ext\n");
9450 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9451 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9453 LOGE("ERROR while starting PD...\n");
9454 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9456 ret = MM_ERROR_NONE;
9465 _mmplayer_start(MMHandleType hplayer) // @
9467 mm_player_t* player = (mm_player_t*) hplayer;
9468 gint ret = MM_ERROR_NONE;
9472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9474 /* check current state */
9475 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9477 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9478 if (ret != MM_ERROR_NONE) {
9479 LOGE("failed to acquire sound focus.\n");
9483 /* NOTE : we should check and create pipeline again if not created as we destroy
9484 * whole pipeline when stopping in streamming playback
9486 if (!player->pipeline) {
9487 ret = __gst_realize(player);
9488 if (MM_ERROR_NONE != ret) {
9489 LOGE("failed to realize before starting. only in streamming\n");
9495 ret = __mmplayer_start_streaming_ext(player);
9496 if (ret != MM_ERROR_NONE)
9497 LOGE("failed to start streaming ext \n");
9499 /* start pipeline */
9500 ret = __gst_start(player);
9501 if (ret != MM_ERROR_NONE)
9502 LOGE("failed to start player.\n");
9509 /* NOTE: post "not supported codec message" to application
9510 * when one codec is not found during AUTOPLUGGING in MSL.
9511 * So, it's separated with error of __mmplayer_gst_callback().
9512 * And, if any codec is not found, don't send message here.
9513 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9516 __mmplayer_handle_missed_plugin(mm_player_t* player)
9518 MMMessageParamType msg_param;
9519 memset(&msg_param, 0, sizeof(MMMessageParamType));
9520 gboolean post_msg_direct = FALSE;
9524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9526 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9527 player->not_supported_codec, player->can_support_codec);
9529 if (player->not_found_demuxer) {
9530 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9531 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9533 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9534 MMPLAYER_FREEIF(msg_param.data);
9536 return MM_ERROR_NONE;
9539 if (player->not_supported_codec) {
9540 if (player->can_support_codec) {
9541 // There is one codec to play
9542 post_msg_direct = TRUE;
9544 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9545 post_msg_direct = TRUE;
9548 if (post_msg_direct) {
9549 MMMessageParamType msg_param;
9550 memset(&msg_param, 0, sizeof(MMMessageParamType));
9552 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9553 LOGW("not found AUDIO codec, posting error code to application.\n");
9555 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9556 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9557 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9558 LOGW("not found VIDEO codec, posting error code to application.\n");
9560 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9561 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9564 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9566 MMPLAYER_FREEIF(msg_param.data);
9568 return MM_ERROR_NONE;
9570 // no any supported codec case
9571 LOGW("not found any codec, posting error code to application.\n");
9573 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9574 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9575 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9577 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9578 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9581 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9583 MMPLAYER_FREEIF(msg_param.data);
9589 return MM_ERROR_NONE;
9592 static void __mmplayer_check_pipeline(mm_player_t* player)
9594 GstState element_state = GST_STATE_VOID_PENDING;
9595 GstState element_pending_state = GST_STATE_VOID_PENDING;
9597 int ret = MM_ERROR_NONE;
9599 if (player->gapless.reconfigure) {
9600 LOGW("pipeline is under construction.\n");
9602 MMPLAYER_PLAYBACK_LOCK(player);
9603 MMPLAYER_PLAYBACK_UNLOCK(player);
9605 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9607 /* wait for state transition */
9608 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9610 if (ret == GST_STATE_CHANGE_FAILURE)
9611 LOGE("failed to change pipeline state within %d sec\n", timeout);
9615 /* NOTE : it should be able to call 'stop' anytime*/
9617 _mmplayer_stop(MMHandleType hplayer) // @
9619 mm_player_t* player = (mm_player_t*)hplayer;
9620 int ret = MM_ERROR_NONE;
9624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9626 /* check current state */
9627 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9629 /* check pipline building state */
9630 __mmplayer_check_pipeline(player);
9631 __mmplayer_reset_gapless_state(player);
9633 /* NOTE : application should not wait for EOS after calling STOP */
9634 __mmplayer_cancel_eos_timer(player);
9636 __mmplayer_unrealize_streaming_ext(player);
9639 player->doing_seek = FALSE;
9642 ret = __gst_stop(player);
9644 if (ret != MM_ERROR_NONE)
9645 LOGE("failed to stop player.\n");
9653 _mmplayer_pause(MMHandleType hplayer) // @
9655 mm_player_t* player = (mm_player_t*)hplayer;
9656 gint64 pos_msec = 0;
9657 gboolean async = FALSE;
9658 gint ret = MM_ERROR_NONE;
9662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9664 /* check current state */
9665 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9667 /* check pipline building state */
9668 __mmplayer_check_pipeline(player);
9670 switch (MMPLAYER_CURRENT_STATE(player)) {
9671 case MM_PLAYER_STATE_READY:
9673 /* check prepare async or not.
9674 * In the case of streaming playback, it's recommned to avoid blocking wait.
9676 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9677 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9679 /* Changing back sync of rtspsrc to async */
9680 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9681 LOGD("async prepare working mode for rtsp");
9687 case MM_PLAYER_STATE_PLAYING:
9689 /* NOTE : store current point to overcome some bad operation
9690 *(returning zero when getting current position in paused state) of some
9693 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9694 LOGW("getting current position failed in paused\n");
9696 player->last_position = pos_msec;
9698 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9699 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9700 This causes problem is position calculation during normal pause resume scenarios also.
9701 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9702 if ((MMPLAYER_IS_RTSP_STREAMING( player )) &&
9703 (__mmplayer_get_stream_service_type(player) != STREAMING_SERVICE_LIVE)) {
9704 g_object_set( player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL );
9710 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9711 LOGD("doing async pause in case of ms buff src");
9715 /* pause pipeline */
9716 ret = __gst_pause(player, async);
9718 if (ret != MM_ERROR_NONE)
9719 LOGE("failed to pause player. ret : 0x%x\n", ret);
9721 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9722 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9723 LOGE("failed to update display_rotation");
9732 _mmplayer_resume(MMHandleType hplayer)
9734 mm_player_t* player = (mm_player_t*)hplayer;
9735 int ret = MM_ERROR_NONE;
9736 gboolean async = FALSE;
9740 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9742 /* Changing back sync mode rtspsrc to async */
9743 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9744 LOGD("async resume for rtsp case");
9748 /* check current state */
9749 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9751 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9752 if (ret != MM_ERROR_NONE) {
9753 LOGE("failed to acquire sound focus.\n");
9757 ret = __gst_resume(player, async);
9759 if (ret != MM_ERROR_NONE)
9760 LOGE("failed to resume player.\n");
9768 __mmplayer_set_play_count(mm_player_t* player, gint count)
9770 MMHandleType attrs = 0;
9774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9776 attrs = MMPLAYER_GET_ATTRS(player);
9778 LOGE("fail to get attributes.\n");
9779 return MM_ERROR_PLAYER_INTERNAL;
9782 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
9783 if (mmf_attrs_commit(attrs)) /* return -1 if error */
9784 LOGE("failed to commit\n");
9788 return MM_ERROR_NONE;
9792 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
9794 mm_player_t* player = (mm_player_t*)hplayer;
9795 gint64 start_pos = 0;
9801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9802 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
9804 player->section_repeat = TRUE;
9805 player->section_repeat_start = start;
9806 player->section_repeat_end = end;
9808 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
9809 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
9811 __mmplayer_set_play_count(player, infinity);
9813 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9814 player->playback_rate,
9816 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9817 GST_SEEK_TYPE_SET, start_pos,
9818 GST_SEEK_TYPE_SET, end_pos))) {
9819 LOGE("failed to activate section repeat\n");
9821 return MM_ERROR_PLAYER_SEEK;
9824 LOGD("succeeded to set section repeat from %d to %d\n",
9825 player->section_repeat_start, player->section_repeat_end);
9829 return MM_ERROR_NONE;
9833 __mmplayer_set_pcm_extraction(mm_player_t* player)
9835 gint64 start_nsec = 0;
9836 gint64 end_nsec = 0;
9837 gint64 dur_nsec = 0;
9838 gint64 dur_msec = 0;
9839 int required_start = 0;
9840 int required_end = 0;
9845 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9847 mm_attrs_multiple_get(player->attrs,
9849 "pcm_extraction_start_msec", &required_start,
9850 "pcm_extraction_end_msec", &required_end,
9853 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9855 if (required_start == 0 && required_end == 0) {
9856 LOGD("extracting entire stream");
9857 return MM_ERROR_NONE;
9858 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9859 LOGD("invalid range for pcm extraction");
9860 return MM_ERROR_INVALID_ARGUMENT;
9864 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9866 LOGE("failed to get duration");
9867 return MM_ERROR_PLAYER_INTERNAL;
9869 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9871 if (dur_msec < required_end) {
9873 LOGD("invalid end pos for pcm extraction");
9874 return MM_ERROR_INVALID_ARGUMENT;
9877 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9878 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9880 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9883 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9884 GST_SEEK_TYPE_SET, start_nsec,
9885 GST_SEEK_TYPE_SET, end_nsec))) {
9886 LOGE("failed to seek for pcm extraction\n");
9888 return MM_ERROR_PLAYER_SEEK;
9891 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9895 return MM_ERROR_NONE;
9899 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
9901 mm_player_t* player = (mm_player_t*)hplayer;
9907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9909 player->section_repeat = FALSE;
9911 __mmplayer_set_play_count(player, onetime);
9913 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
9915 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9918 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9919 GST_SEEK_TYPE_SET, cur_pos,
9920 GST_SEEK_TYPE_SET, player->duration))) {
9921 LOGE("failed to deactivate section repeat\n");
9923 return MM_ERROR_PLAYER_SEEK;
9928 return MM_ERROR_NONE;
9932 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9934 mm_player_t* player = (mm_player_t*)hplayer;
9935 gint64 pos_msec = 0;
9936 int ret = MM_ERROR_NONE;
9938 signed long long start = 0, stop = 0;
9939 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9942 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9943 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9945 /* The sound of video is not supported under 0.0 and over 2.0. */
9946 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9947 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9950 _mmplayer_set_mute(hplayer, mute);
9952 if (player->playback_rate == rate)
9953 return MM_ERROR_NONE;
9955 /* If the position is reached at start potion during fast backward, EOS is posted.
9956 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9958 player->playback_rate = rate;
9960 current_state = MMPLAYER_CURRENT_STATE(player);
9962 if (current_state != MM_PLAYER_STATE_PAUSED)
9963 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9965 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9967 if ((current_state == MM_PLAYER_STATE_PAUSED)
9968 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9969 LOGW("returning last point : %lld\n", player->last_position);
9970 pos_msec = player->last_position;
9976 stop = GST_CLOCK_TIME_NONE;
9978 start = GST_CLOCK_TIME_NONE;
9981 if ((!gst_element_seek(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9984 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9985 GST_SEEK_TYPE_SET, start,
9986 GST_SEEK_TYPE_SET, stop))) {
9987 LOGE("failed to set speed playback\n");
9988 return MM_ERROR_PLAYER_SEEK;
9991 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9995 return MM_ERROR_NONE;;
9999 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
10001 mm_player_t* player = (mm_player_t*)hplayer;
10002 int ret = MM_ERROR_NONE;
10006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10008 /* check pipline building state */
10009 __mmplayer_check_pipeline(player);
10011 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10019 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
10021 mm_player_t* player = (mm_player_t*)hplayer;
10022 int ret = MM_ERROR_NONE;
10024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10026 ret = __gst_get_position(player, format, position);
10032 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
10034 mm_player_t* player = (mm_player_t*)hplayer;
10035 int ret = MM_ERROR_NONE;
10037 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10039 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10045 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
10047 mm_player_t* player = (mm_player_t*)hplayer;
10048 int ret = MM_ERROR_NONE;
10052 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10054 ret = __gst_adjust_subtitle_position(player, format, position);
10061 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset) // @
10063 mm_player_t* player = (mm_player_t*)hplayer;
10064 int ret = MM_ERROR_NONE;
10068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10070 ret = __gst_adjust_video_position(player, offset);
10078 __mmplayer_is_midi_type(gchar* str_caps)
10080 if ((g_strrstr(str_caps, "audio/midi")) ||
10081 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10082 (g_strrstr(str_caps, "application/x-smaf")) ||
10083 (g_strrstr(str_caps, "audio/x-imelody")) ||
10084 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10085 (g_strrstr(str_caps, "audio/xmf")) ||
10086 (g_strrstr(str_caps, "audio/mxmf"))) {
10095 __mmplayer_is_only_mp3_type(gchar *str_caps)
10097 if (g_strrstr(str_caps, "application/x-id3") ||
10098 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10104 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10106 GstStructure* caps_structure = NULL;
10107 gint samplerate = 0;
10111 MMPLAYER_RETURN_IF_FAIL(player && caps);
10113 caps_structure = gst_caps_get_structure(caps, 0);
10115 /* set stream information */
10116 gst_structure_get_int(caps_structure, "rate", &samplerate);
10117 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10119 gst_structure_get_int(caps_structure, "channels", &channels);
10120 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10122 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10126 __mmplayer_update_content_type_info(mm_player_t* player)
10129 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10131 if (__mmplayer_is_midi_type(player->type)) {
10132 player->bypass_audio_effect = TRUE;
10133 } else if (g_strrstr(player->type, "application/x-hls")) {
10134 /* If it can't know exact type when it parses uri because of redirection case,
10135 * it will be fixed by typefinder or when doing autoplugging.
10137 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10138 if (player->streamer) {
10139 player->streamer->is_adaptive_streaming = TRUE;
10140 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10141 player->streamer->buffering_req.runtime_second = 5;
10143 } else if (g_strrstr(player->type, "application/dash+xml")) {
10144 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10151 __mmplayer_typefind_have_type(GstElement *tf, guint probability, // @
10152 GstCaps *caps, gpointer data)
10154 mm_player_t* player = (mm_player_t*)data;
10155 GstPad* pad = NULL;
10159 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10161 /* store type string */
10162 MMPLAYER_FREEIF(player->type);
10163 player->type = gst_caps_to_string(caps);
10165 LOGD("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
10167 if ((!MMPLAYER_IS_WFD_STREAMING(player)) &&
10168 (!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10169 (g_strrstr(player->type, "audio/x-raw-int"))) {
10170 LOGE("not support media format\n");
10172 if (player->msg_posted == FALSE) {
10173 MMMessageParamType msg_param;
10174 memset(&msg_param, 0, sizeof(MMMessageParamType));
10176 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10177 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10179 /* don't post more if one was sent already */
10180 player->msg_posted = TRUE;
10185 __mmplayer_update_content_type_info(player);
10187 pad = gst_element_get_static_pad(tf, "src");
10189 LOGE("fail to get typefind src pad.\n");
10193 if (player->use_decodebin) {
10194 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10195 gboolean async = FALSE;
10196 LOGE("failed to autoplug %s\n", player->type);
10198 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10200 if (async && player->msg_posted == FALSE)
10201 __mmplayer_handle_missed_plugin(player);
10207 if (!__mmplayer_try_to_plug(player, pad, caps)) {
10208 gboolean async = FALSE;
10209 LOGE("failed to autoplug %s\n", player->type);
10211 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10213 if (async && player->msg_posted == FALSE)
10214 __mmplayer_handle_missed_plugin(player);
10219 /* finish autopluging if no dynamic pad waiting */
10220 if ((!player->have_dynamic_pad) && (!player->has_many_types)) {
10221 if (!MMPLAYER_IS_RTSP_STREAMING(player))
10222 __mmplayer_pipeline_complete(NULL, (gpointer)player);
10227 gst_object_unref(GST_OBJECT(pad));
10234 static GstElement *
10235 __mmplayer_create_decodebin(mm_player_t* player)
10237 GstElement *decodebin = NULL;
10241 /* create decodebin */
10242 decodebin = gst_element_factory_make("decodebin", NULL);
10245 LOGE("fail to create decodebin\n");
10249 /* raw pad handling signal */
10250 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10251 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10253 /* no-more-pad pad handling signal */
10254 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10255 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10257 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10258 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10260 /* This signal is emitted when a pad for which there is no further possible
10261 decoding is added to the decodebin.*/
10262 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10263 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10265 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10266 before looking for any elements that can handle that stream.*/
10267 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10268 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10270 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10271 before looking for any elements that can handle that stream.*/
10272 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10273 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10275 /* This signal is emitted once decodebin has finished decoding all the data.*/
10276 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10277 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10279 /* This signal is emitted when a element is added to the bin.*/
10280 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10281 G_CALLBACK(__mmplayer_gst_element_added), player);
10288 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10290 MMPlayerGstElement* mainbin = NULL;
10291 GstElement* decodebin = NULL;
10292 GstElement* queue2 = NULL;
10293 GstPad* sinkpad = NULL;
10294 GstPad* qsrcpad = NULL;
10295 gint64 dur_bytes = 0L;
10297 guint max_buffer_size_bytes = 0;
10298 gdouble init_buffering_time = (gdouble)player->streamer->buffering_req.initial_second;
10301 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10303 mainbin = player->pipeline->mainbin;
10305 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10306 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10307 LOGD("creating http streaming buffering queue(queue2)\n");
10309 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10310 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10312 queue2 = gst_element_factory_make("queue2", "queue2");
10314 LOGE("failed to create buffering queue element\n");
10318 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10319 LOGE("failed to add buffering queue\n");
10323 sinkpad = gst_element_get_static_pad(queue2, "sink");
10324 qsrcpad = gst_element_get_static_pad(queue2, "src");
10326 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10327 LOGE("failed to link buffering queue\n");
10331 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10332 LOGE("fail to get duration.\n");
10334 LOGD("dur_bytes = %lld\n", dur_bytes);
10336 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10338 if (dur_bytes > 0) {
10339 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10340 type = MUXED_BUFFER_TYPE_FILE;
10342 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10343 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10349 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10350 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10351 if (!g_strrstr(player->type, "video/mpegts")) {
10352 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10353 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10355 __mm_player_streaming_set_queue2(player->streamer,
10358 max_buffer_size_bytes,
10359 player->ini.http_buffering_time,
10361 player->ini.http_buffering_limit, // no meaning
10363 player->http_file_buffering_path,
10364 (guint64)dur_bytes);
10367 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10368 LOGE("failed to sync queue2 state with parent\n");
10374 gst_object_unref(GST_OBJECT(sinkpad));
10376 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10377 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10381 /* create decodebin */
10382 decodebin = __mmplayer_create_decodebin(player);
10385 LOGE("can not create autoplug element\n");
10389 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10390 LOGE("failed to add decodebin\n");
10394 /* to force caps on the decodebin element and avoid reparsing stuff by
10395 * typefind. It also avoids a deadlock in the way typefind activates pads in
10396 * the state change */
10397 g_object_set(decodebin, "sink-caps", caps, NULL);
10399 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10401 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10402 LOGE("failed to link decodebin\n");
10406 gst_object_unref(GST_OBJECT(sinkpad));
10408 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10409 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10411 /* set decodebin property about buffer in streaming playback. *
10412 * in case of hls, it does not need to have big buffer *
10413 * because it is kind of adaptive streaming. */
10414 if (((!MMPLAYER_IS_HTTP_PD(player)) &&
10415 (MMPLAYER_IS_HTTP_STREAMING(player))) || MMPLAYER_IS_DASH_STREAMING(player)) {
10416 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10417 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10418 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10420 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
10421 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10422 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10425 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10426 "high-percent", (gint)player->ini.http_buffering_limit,
10427 "low-percent", 1, // 1%
10428 "max-size-bytes", max_size_bytes,
10429 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10430 "max-size-buffers", 0, NULL); // disable or automatic
10433 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10434 LOGE("failed to sync decodebin state with parent\n");
10445 gst_object_unref(GST_OBJECT(sinkpad));
10448 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10449 * You need to explicitly set elements to the NULL state before
10450 * dropping the final reference, to allow them to clean up.
10452 gst_element_set_state(queue2, GST_STATE_NULL);
10454 /* And, it still has a parent "player".
10455 * 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), queue2);
10458 gst_object_unref(queue2);
10463 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10464 * You need to explicitly set elements to the NULL state before
10465 * dropping the final reference, to allow them to clean up.
10467 gst_element_set_state(decodebin, GST_STATE_NULL);
10469 /* And, it still has a parent "player".
10470 * You need to let the parent manage the object instead of unreffing the object directly.
10473 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10474 gst_object_unref(decodebin);
10481 /* it will return first created element */
10483 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
10485 MMPlayerGstElement* mainbin = NULL;
10486 const char* mime = NULL;
10487 const GList* item = NULL;
10488 const gchar* klass = NULL;
10489 GstCaps* res = NULL;
10490 gboolean skip = FALSE;
10491 GstPad* queue_pad = NULL;
10492 GstElement* queue = NULL;
10493 GstElement *element = NULL;
10497 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10499 mainbin = player->pipeline->mainbin;
10501 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10503 /* return if we got raw output */
10504 if (g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw")
10505 || g_str_has_prefix(mime, "text/plain") || g_str_has_prefix(mime, "text/x-pango-markup")) {
10507 element = (GstElement*)gst_pad_get_parent(pad);
10508 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
10509 * No queue will be added. I think it can caused breaking sound when playing raw audio
10510 * frames but there's no different. Decodebin also doesn't add with those wav fils.
10511 * Anyway, currentely raw-queue seems not necessary.
10514 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
10515 * has linked. if so, we need to add queue for quality of output. note that
10516 * decodebin also has same problem.
10518 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
10520 /* add queue if needed */
10521 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Depayloader")
10522 || g_strrstr(klass, "Parse")) && !g_str_has_prefix(mime, "text")) {
10523 LOGD("adding raw queue\n");
10525 queue = gst_element_factory_make("queue", NULL);
10527 LOGW("failed to create queue\n");
10532 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
10533 LOGW("failed to set state READY to queue\n");
10537 /* add to pipeline */
10538 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
10539 LOGW("failed to add queue\n");
10544 queue_pad = gst_element_get_static_pad(queue, "sink");
10546 if (GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad)) {
10547 LOGW("failed to link queue\n");
10550 gst_object_unref(GST_OBJECT(queue_pad));
10554 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
10555 LOGW("failed to set state PAUSED to queue\n");
10559 /* replace given pad to queue:src */
10560 pad = gst_element_get_static_pad(queue, "src");
10562 LOGW("failed to get pad from queue\n");
10567 /* check if player can do start continually */
10568 MMPLAYER_CHECK_CMD_IF_EXIT(player);
10570 if (__mmplayer_link_sink(player, pad))
10571 __mmplayer_gst_decode_callback(element, pad, player);
10573 gst_object_unref(GST_OBJECT(element));
10579 item = player->factories;
10580 for (; item != NULL; item = item->next) {
10581 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
10587 /* filtering exclude keyword */
10588 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10589 if (g_strrstr(GST_OBJECT_NAME(factory),
10590 player->ini.exclude_element_keyword[idx])) {
10591 LOGW("skipping [%s] by exculde keyword [%s]\n",
10592 GST_OBJECT_NAME(factory),
10593 player->ini.exclude_element_keyword[idx]);
10600 if (MMPLAYER_IS_RTSP_STREAMING(player) && g_strrstr(GST_OBJECT_NAME(factory), "omx_mpeg4dec")) {
10601 // omx decoder can not support mpeg4video data partitioned
10602 // rtsp streaming didn't know mpeg4video data partitioned format
10603 // so, if rtsp playback, player will skip omx_mpeg4dec.
10604 LOGW("skipping [%s] when rtsp streaming \n",
10605 GST_OBJECT_NAME(factory));
10610 if (skip) continue;
10612 /* check factory class for filtering */
10613 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(factory), GST_ELEMENT_METADATA_KLASS);
10615 /*parsers are not required in case of external feeder*/
10616 if (g_strrstr(klass, "Codec/Parser") && MMPLAYER_IS_MS_BUFF_SRC(player))
10619 /* NOTE : msl don't need to use image plugins.
10620 * So, those plugins should be skipped for error handling.
10622 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10623 LOGD("skipping [%s] by not required\n", GST_OBJECT_NAME(factory));
10627 /* check pad compatability */
10628 for (pads = gst_element_factory_get_static_pad_templates(factory);
10629 pads != NULL; pads = pads->next) {
10630 GstStaticPadTemplate *temp1 = pads->data;
10631 GstCaps* static_caps = NULL;
10633 if (temp1->direction != GST_PAD_SINK
10634 || temp1->presence != GST_PAD_ALWAYS)
10637 /* using existing caps */
10638 if (GST_IS_CAPS(&temp1->static_caps.caps))
10639 static_caps = gst_caps_ref(temp1->static_caps.caps);
10642 static_caps = gst_caps_from_string(temp1->static_caps.string);
10644 res = gst_caps_intersect((GstCaps*)caps, static_caps);
10645 gst_caps_unref(static_caps);
10646 static_caps = NULL;
10648 if (res && !gst_caps_is_empty(res)) {
10649 GstElement *new_element;
10650 GList *elements = player->parsers;
10651 char *name_template = g_strdup(temp1->name_template);
10652 gchar *name_to_plug = GST_OBJECT_NAME(factory);
10653 gst_caps_unref(res);
10655 /* check ALP Codec can be used or not */
10656 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10657 /* consider mp3 audio only */
10658 if (!MMPLAYER_IS_STREAMING(player) && __mmplayer_is_only_mp3_type(player->type)) {
10659 /* try to use ALP decoder first instead of selected decoder */
10660 GstElement *element = NULL;
10661 GstElementFactory * element_facory;
10662 gchar *path = NULL;
10663 guint64 data_size = 0;
10664 #define MIN_THRESHOLD_SIZE 320 * 1024 // 320K
10667 mm_attrs_get_string_by_name(player->attrs, "profile_uri", &path);
10669 if (stat(path, &sb) == 0)
10670 data_size = (guint64)sb.st_size;
10671 LOGD("file size : %u", data_size);
10673 if (data_size > MIN_THRESHOLD_SIZE) {
10674 LOGD("checking if ALP can be used or not");
10675 element = gst_element_factory_make("omx_mp3dec", "omx mp3 decoder");
10677 /* check availability because multi-instance is not supported */
10678 GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY);
10680 if (ret != GST_STATE_CHANGE_SUCCESS) {
10681 // use just selected decoder
10682 gst_object_unref(element);
10683 } else if (ret == GST_STATE_CHANGE_SUCCESS) {
10684 // replace facotry to use omx
10686 gst_element_set_state(element, GST_STATE_NULL);
10687 gst_object_unref(element);
10689 element_facory = gst_element_factory_find("omx_mp3dec");
10690 /* replace, otherwise use selected thing instead */
10691 if (element_facory) {
10692 factory = element_facory;
10693 name_to_plug = GST_OBJECT_NAME(factory);
10699 } else if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
10700 if (g_strrstr(GST_OBJECT_NAME(factory), "omx_")) {
10701 char *env = getenv("MM_PLAYER_HW_CODEC_DISABLE");
10703 if (strncasecmp(env, "yes", 3) == 0) {
10704 LOGD("skipping [%s] by disabled\n", name_to_plug);
10705 MMPLAYER_FREEIF(name_template);
10712 LOGD("found %s to plug\n", name_to_plug);
10714 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
10715 if (!new_element) {
10716 LOGE("failed to create element [%s]. continue with next.\n",
10717 GST_OBJECT_NAME(factory));
10719 MMPLAYER_FREEIF(name_template);
10724 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
10725 * because parser can accept its own output as input.
10727 if (g_strrstr(klass, "Parser")) {
10728 gchar *selected = NULL;
10730 for (; elements; elements = g_list_next(elements)) {
10731 gchar *element_name = elements->data;
10733 if (g_strrstr(element_name, name_to_plug)) {
10734 LOGD("but, %s already linked, so skipping it\n", name_to_plug);
10740 MMPLAYER_FREEIF(name_template);
10744 selected = g_strdup(name_to_plug);
10745 player->parsers = g_list_append(player->parsers, selected);
10748 /* store specific handles for futher control */
10749 if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
10750 /* FIXIT : first value will be overwritten if there's more
10751 * than 1 demuxer/parser
10753 LOGD("plugged element is demuxer. take it\n");
10754 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
10755 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
10757 /*Added for multi audio support */
10758 if (g_strrstr(klass, "Demux")) {
10759 mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
10760 mainbin[MMPLAYER_M_DEMUX_EX].gst = new_element;
10762 /* NOTE : workaround for bug in mpegtsdemux since doesn't emit
10763 no-more-pad signal. this may cause wrong content attributes at PAUSED state
10764 this code should be removed after mpegtsdemux is fixed */
10765 if (g_strrstr(GST_OBJECT_NAME(factory), "mpegtsdemux")) {
10766 LOGW("force no-more-pad to TRUE since mpegtsdemux os not giving no-more-pad signal. content attributes may wrong");
10767 player->no_more_pad = TRUE;
10770 if (g_strrstr(name_to_plug, "asfdemux")) // to support trust-zone only
10771 g_object_set(mainbin[MMPLAYER_M_DEMUX_EX].gst, "file-location", player->profile.uri, NULL);
10772 } else if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, pad)) {
10773 if (mainbin[MMPLAYER_M_DEC1].gst == NULL) {
10774 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
10775 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
10776 mainbin[MMPLAYER_M_DEC1].gst = new_element;
10777 } else if (mainbin[MMPLAYER_M_DEC2].gst == NULL) {
10778 LOGD("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
10779 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
10780 mainbin[MMPLAYER_M_DEC2].gst = new_element;
10782 /* NOTE : IF one codec is found, add it to supported_codec and remove from
10783 * missing plugin. Both of them are used to check what's supported codec
10784 * before returning result of play start. And, missing plugin should be
10785 * updated here for multi track files.
10787 if (g_str_has_prefix(mime, "video")) {
10788 GstPad *src_pad = NULL;
10789 GstPadTemplate *pad_templ = NULL;
10790 GstCaps *caps = NULL;
10791 gchar *caps_str = NULL;
10793 LOGD("found VIDEO decoder\n");
10794 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10795 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10797 src_pad = gst_element_get_static_pad(new_element, "src");
10798 pad_templ = gst_pad_get_pad_template(src_pad);
10799 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
10801 caps_str = gst_caps_to_string(caps);
10804 MMPLAYER_FREEIF(caps_str);
10805 gst_object_unref(src_pad);
10806 } else if (g_str_has_prefix(mime, "audio")) {
10807 LOGD("found AUDIO decoder\n");
10808 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10809 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10813 if (!__mmplayer_close_link(player, pad, new_element,
10814 name_template, gst_element_factory_get_static_pad_templates(factory))) {
10815 MMPLAYER_FREEIF(name_template);
10816 if (player->keep_detecting_vcodec)
10819 /* Link is failed even though a supportable codec is found. */
10820 __mmplayer_check_not_supported_codec(player, klass, mime);
10822 LOGE("failed to call _close_link\n");
10826 MMPLAYER_FREEIF(name_template);
10830 gst_caps_unref(res);
10835 /* There is no available codec. */
10836 __mmplayer_check_not_supported_codec(player, klass, mime);
10844 gst_object_unref(queue);
10847 gst_object_unref(queue_pad);
10850 gst_object_unref(element);
10857 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10861 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10862 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10864 LOGD("class : %s, mime : %s \n", factory_class, mime);
10866 /* add missing plugin */
10867 /* NOTE : msl should check missing plugin for image mime type.
10868 * Some motion jpeg clips can have playable audio track.
10869 * So, msl have to play audio after displaying popup written video format not supported.
10871 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10872 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10873 LOGD("not found demuxer\n");
10874 player->not_found_demuxer = TRUE;
10875 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10881 if (!g_strrstr(factory_class, "Demuxer")) {
10882 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10883 LOGD("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
10884 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10886 /* check that clip have multi tracks or not */
10887 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10888 LOGD("video plugin is already linked\n");
10890 LOGW("add VIDEO to missing plugin\n");
10891 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10893 } else if (g_str_has_prefix(mime, "audio")) {
10894 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10895 LOGD("audio plugin is already linked\n");
10897 LOGW("add AUDIO to missing plugin\n");
10898 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10906 return MM_ERROR_NONE;
10911 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10913 mm_player_t* player = (mm_player_t*)data;
10917 MMPLAYER_RETURN_IF_FAIL(player);
10919 /* remove fakesink. */
10920 if (!__mmplayer_gst_remove_fakesink(player,
10921 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10922 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10923 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10924 * source element are not same. To overcome this situation, this function will called
10925 * several places and several times. Therefore, this is not an error case.
10930 LOGD("pipeline has completely constructed\n");
10932 if ((player->ini.async_start) &&
10933 (player->msg_posted == FALSE) &&
10934 (player->cmd >= MMPLAYER_COMMAND_START))
10935 __mmplayer_handle_missed_plugin(player);
10937 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10941 __mmplayer_verify_next_play_path(mm_player_t *player)
10943 MMHandleType attrs = 0;
10944 MMPlayerParseProfile profile;
10945 gint uri_idx = 0, check_cnt = 0;
10947 gint mode = MM_PLAYER_PD_MODE_NONE;
10951 guint num_of_list = 0;
10955 LOGD("checking for gapless play");
10957 if (player->pipeline->textbin) {
10958 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10962 attrs = MMPLAYER_GET_ATTRS(player);
10964 LOGE("fail to get attributes.\n");
10968 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10971 /* gapless playback is not supported in case of video at TV profile. */
10973 LOGW("not support video gapless playback");
10978 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10979 if (mode == TRUE) {
10985 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10986 LOGE("can not get play count\n");
10988 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10989 LOGE("can not get gapless mode\n");
10991 if (video && !gapless) {
10992 LOGW("not enabled video gapless playback");
10996 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
11000 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
11004 num_of_list = g_list_length(player->uri_info.uri_list);
11006 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
11008 if (num_of_list == 0) {
11009 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
11010 LOGE("can not get profile_uri\n");
11015 LOGE("uri list is empty.\n");
11019 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11020 LOGD("add original path : %s ", uri);
11026 uri_idx = player->uri_info.uri_idx;
11031 if (check_cnt > num_of_list) {
11032 LOGE("there is no valid uri.");
11036 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
11038 if (uri_idx < num_of_list-1) {
11041 if ((count <= 1) && (count != -1)) {
11042 LOGD("no repeat.");
11044 } else if (count > 1) {
11045 /* decrease play count */
11046 /* we succeeded to rewind. update play count and then wait for next EOS */
11049 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
11051 /* commit attribute */
11052 if (mmf_attrs_commit(attrs))
11053 LOGE("failed to commit attribute\n");
11056 /* count < 0 : repeat continually */
11060 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11061 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
11064 LOGW("next uri does not exist\n");
11068 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
11069 LOGE("failed to parse profile\n");
11073 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
11074 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
11075 LOGW("uri type is not supported(%d).", profile.uri_type);
11082 player->uri_info.uri_idx = uri_idx;
11083 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11085 if (mmf_attrs_commit(player->attrs)) {
11086 LOGE("failed to commit.\n");
11090 LOGD("next uri %s(%d)\n", uri, uri_idx);
11096 LOGE("unable to play next path. EOS will be posted soon.\n");
11101 __mmplayer_initialize_next_play(mm_player_t *player)
11107 player->smooth_streaming = FALSE;
11108 player->videodec_linked = 0;
11109 player->audiodec_linked = 0;
11110 player->videosink_linked = 0;
11111 player->audiosink_linked = 0;
11112 player->textsink_linked = 0;
11113 player->is_external_subtitle_present = FALSE;
11114 player->is_external_subtitle_added_now = FALSE;
11115 player->not_supported_codec = MISSING_PLUGIN_NONE;
11116 player->can_support_codec = FOUND_PLUGIN_NONE;
11117 player->pending_seek.is_pending = FALSE;
11118 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11119 player->pending_seek.pos = 0;
11120 player->msg_posted = FALSE;
11121 player->has_many_types = FALSE;
11122 player->no_more_pad = FALSE;
11123 player->not_found_demuxer = 0;
11124 player->doing_seek = FALSE;
11125 player->max_audio_channels = 0;
11126 player->is_subtitle_force_drop = FALSE;
11127 player->play_subtitle = FALSE;
11128 player->use_textoverlay = FALSE;
11129 player->adjust_subtitle_pos = 0;
11131 player->updated_bitrate_count = 0;
11132 player->total_bitrate = 0;
11133 player->updated_maximum_bitrate_count = 0;
11134 player->total_maximum_bitrate = 0;
11136 _mmplayer_track_initialize(player);
11137 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11139 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11140 player->bitrate[i] = 0;
11141 player->maximum_bitrate[i] = 0;
11144 if (player->v_stream_caps) {
11145 gst_caps_unref(player->v_stream_caps);
11146 player->v_stream_caps = NULL;
11149 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11150 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
11152 /* clean found parsers */
11153 if (player->parsers) {
11154 GList *parsers = player->parsers;
11155 for (; parsers; parsers = g_list_next(parsers)) {
11156 gchar *name = parsers->data;
11157 MMPLAYER_FREEIF(name);
11159 g_list_free(player->parsers);
11160 player->parsers = NULL;
11163 /* clean found audio decoders */
11164 if (player->audio_decoders) {
11165 GList *a_dec = player->audio_decoders;
11166 for (; a_dec; a_dec = g_list_next(a_dec)) {
11167 gchar *name = a_dec->data;
11168 MMPLAYER_FREEIF(name);
11170 g_list_free(player->audio_decoders);
11171 player->audio_decoders = NULL;
11178 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11180 MMPlayerGstElement *mainbin = NULL;
11181 MMMessageParamType msg_param = {0,};
11182 GstElement *element = NULL;
11183 MMHandleType attrs = 0;
11185 enum MainElementID elemId = MMPLAYER_M_NUM;
11189 if ((player == NULL) ||
11190 (player->pipeline == NULL) ||
11191 (player->pipeline->mainbin == NULL)) {
11192 LOGE("player is null.\n");
11196 mainbin = player->pipeline->mainbin;
11197 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11199 attrs = MMPLAYER_GET_ATTRS(player);
11201 LOGE("fail to get attributes.\n");
11205 /* Initialize Player values */
11206 __mmplayer_initialize_next_play(player);
11208 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11210 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11211 LOGE("failed to parse profile\n");
11212 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11216 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11217 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11218 LOGE("it's dash or hls. not support.");
11219 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11224 switch (player->profile.uri_type) {
11226 case MM_PLAYER_URI_TYPE_FILE:
11228 LOGD("using filesrc for 'file://' handler.\n");
11229 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
11230 LOGE("failed to get storage info");
11234 element = gst_element_factory_make("filesrc", "source");
11237 LOGE("failed to create filesrc\n");
11241 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11244 case MM_PLAYER_URI_TYPE_URL_HTTP:
11246 gchar *user_agent, *proxy, *cookies, **cookie_list;
11247 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11248 user_agent = proxy = cookies = NULL;
11249 cookie_list = NULL;
11251 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11253 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11256 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11258 /* get attribute */
11259 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11260 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11261 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11262 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11264 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11265 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11266 LOGD("get timeout from ini\n");
11267 http_timeout = player->ini.http_timeout;
11270 /* get attribute */
11271 SECURE_LOGD("location : %s\n", player->profile.uri);
11272 SECURE_LOGD("cookies : %s\n", cookies);
11273 SECURE_LOGD("proxy : %s\n", proxy);
11274 SECURE_LOGD("user_agent : %s\n", user_agent);
11275 LOGD("timeout : %d\n", http_timeout);
11277 /* setting property to streaming source */
11278 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11279 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11280 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11282 /* check if prosy is vailid or not */
11283 if (util_check_valid_url(proxy))
11284 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11285 /* parsing cookies */
11286 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11287 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11289 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11293 LOGE("not support uri type %d\n", player->profile.uri_type);
11298 LOGE("no source element was created.\n");
11302 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11303 LOGE("failed to add source element to pipeline\n");
11304 gst_object_unref(GST_OBJECT(element));
11309 /* take source element */
11310 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11311 mainbin[MMPLAYER_M_SRC].gst = element;
11315 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11316 if (player->streamer == NULL) {
11317 player->streamer = __mm_player_streaming_create();
11318 __mm_player_streaming_initialize(player->streamer);
11321 elemId = MMPLAYER_M_TYPEFIND;
11322 element = gst_element_factory_make("typefind", "typefinder");
11323 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11324 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11326 elemId = MMPLAYER_M_AUTOPLUG;
11327 element = __mmplayer_create_decodebin(player);
11330 /* check autoplug element is OK */
11332 LOGE("can not create element(%d)\n", elemId);
11336 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11337 LOGE("failed to add sinkbin to pipeline\n");
11338 gst_object_unref(GST_OBJECT(element));
11343 mainbin[elemId].id = elemId;
11344 mainbin[elemId].gst = element;
11346 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11347 LOGE("Failed to link src - autoplug(or typefind)\n");
11351 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11352 LOGE("Failed to change state of src element\n");
11356 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11357 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11358 LOGE("Failed to change state of decodebin\n");
11362 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11363 LOGE("Failed to change state of src element\n");
11368 player->gapless.stream_changed = TRUE;
11369 player->gapless.running = TRUE;
11375 MMPLAYER_PLAYBACK_UNLOCK(player);
11377 if (!player->msg_posted) {
11378 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11379 player->msg_posted = TRUE;
11386 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11388 mm_player_selector_t *selector = &player->selector[type];
11389 MMPlayerGstElement *sinkbin = NULL;
11390 enum MainElementID selectorId = MMPLAYER_M_NUM;
11391 enum MainElementID sinkId = MMPLAYER_M_NUM;
11392 GstPad *srcpad = NULL;
11393 GstPad *sinkpad = NULL;
11394 gboolean send_notice = FALSE;
11397 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11399 LOGD("type %d", type);
11402 case MM_PLAYER_TRACK_TYPE_AUDIO:
11403 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11404 sinkId = MMPLAYER_A_BIN;
11405 sinkbin = player->pipeline->audiobin;
11407 case MM_PLAYER_TRACK_TYPE_VIDEO:
11408 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11409 sinkId = MMPLAYER_V_BIN;
11410 sinkbin = player->pipeline->videobin;
11411 send_notice = TRUE;
11413 case MM_PLAYER_TRACK_TYPE_TEXT:
11414 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11415 sinkId = MMPLAYER_T_BIN;
11416 sinkbin = player->pipeline->textbin;
11419 LOGE("requested type is not supportable");
11424 if (player->pipeline->mainbin[selectorId].gst) {
11427 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11429 if (selector->event_probe_id != 0)
11430 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11431 selector->event_probe_id = 0;
11433 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11434 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11436 if (srcpad && sinkpad) {
11437 /* after getting drained signal there is no data flows, so no need to do pad_block */
11438 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11439 gst_pad_unlink(srcpad, sinkpad);
11441 /* send custom event to sink pad to handle it at video sink */
11443 LOGD("send custom event to sinkpad");
11444 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11445 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11446 gst_pad_send_event(sinkpad, event);
11450 gst_object_unref(sinkpad);
11453 gst_object_unref(srcpad);
11456 LOGD("selector release");
11458 /* release and unref requests pad from the selector */
11459 for (n = 0; n < selector->channels->len; n++) {
11460 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11461 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11463 g_ptr_array_set_size(selector->channels, 0);
11465 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11466 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11468 player->pipeline->mainbin[selectorId].gst = NULL;
11476 __mmplayer_deactivate_old_path(mm_player_t *player)
11479 MMPLAYER_RETURN_IF_FAIL(player);
11481 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11482 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11483 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11484 LOGE("deactivate selector error");
11488 _mmplayer_track_destroy(player);
11489 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11491 if (player->streamer) {
11492 __mm_player_streaming_deinitialize(player->streamer);
11493 __mm_player_streaming_destroy(player->streamer);
11494 player->streamer = NULL;
11497 MMPLAYER_PLAYBACK_LOCK(player);
11498 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11505 if (!player->msg_posted) {
11506 MMMessageParamType msg = {0,};
11509 msg.code = MM_ERROR_PLAYER_INTERNAL;
11510 LOGE("next_uri_play> deactivate error");
11512 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11513 player->msg_posted = TRUE;
11518 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11520 int result = MM_ERROR_NONE;
11521 mm_player_t* player = (mm_player_t*) hplayer;
11524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11527 player->http_file_buffering_path = (gchar*)file_path;
11528 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11534 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11536 int result = MM_ERROR_NONE;
11537 mm_player_t* player = (mm_player_t*) hplayer;
11540 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11542 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11543 if (mmf_attrs_commit(player->attrs)) {
11544 LOGE("failed to commit the original uri.\n");
11545 result = MM_ERROR_PLAYER_INTERNAL;
11547 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11548 LOGE("failed to add the original uri in the uri list.\n");
11555 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11557 mm_player_t* player = (mm_player_t*) hplayer;
11558 guint num_of_list = 0;
11562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11563 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11565 if (player->pipeline && player->pipeline->textbin) {
11566 LOGE("subtitle path is enabled.\n");
11567 return MM_ERROR_PLAYER_INVALID_STATE;
11570 num_of_list = g_list_length(player->uri_info.uri_list);
11572 if (is_first_path == TRUE) {
11573 if (num_of_list == 0) {
11574 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11575 LOGD("add original path : %s", uri);
11577 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11578 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11580 LOGD("change original path : %s", uri);
11583 MMHandleType attrs = 0;
11584 attrs = MMPLAYER_GET_ATTRS(player);
11586 if (num_of_list == 0) {
11587 char *original_uri = NULL;
11590 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11592 if (!original_uri) {
11593 LOGE("there is no original uri.");
11594 return MM_ERROR_PLAYER_INVALID_STATE;
11597 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11598 player->uri_info.uri_idx = 0;
11600 LOGD("add original path at first : %s(%d)", original_uri);
11604 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11605 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11609 return MM_ERROR_NONE;
11612 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11614 mm_player_t* player = (mm_player_t*) hplayer;
11615 char *next_uri = NULL;
11616 guint num_of_list = 0;
11619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11621 num_of_list = g_list_length(player->uri_info.uri_list);
11623 if (num_of_list > 0) {
11624 gint uri_idx = player->uri_info.uri_idx;
11626 if (uri_idx < num_of_list-1)
11631 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11632 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11634 *uri = g_strdup(next_uri);
11638 return MM_ERROR_NONE;
11642 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11643 GstCaps *caps, gpointer data)
11645 mm_player_t* player = (mm_player_t*)data;
11646 const gchar* klass = NULL;
11647 const gchar* mime = NULL;
11648 gchar* caps_str = NULL;
11650 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11651 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11652 caps_str = gst_caps_to_string(caps);
11654 LOGW("unknown type of caps : %s from %s",
11655 caps_str, GST_ELEMENT_NAME(elem));
11657 MMPLAYER_FREEIF(caps_str);
11659 /* There is no available codec. */
11660 __mmplayer_check_not_supported_codec(player, klass, mime);
11664 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11665 GstCaps * caps, gpointer data)
11667 mm_player_t* player = (mm_player_t*)data;
11668 const char* mime = NULL;
11669 gboolean ret = TRUE;
11671 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11672 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11674 if (g_str_has_prefix(mime, "audio")) {
11675 GstStructure* caps_structure = NULL;
11676 gint samplerate = 0;
11678 gchar *caps_str = NULL;
11680 caps_structure = gst_caps_get_structure(caps, 0);
11681 gst_structure_get_int(caps_structure, "rate", &samplerate);
11682 gst_structure_get_int(caps_structure, "channels", &channels);
11684 if ((channels > 0 && samplerate == 0)) {
11685 LOGD("exclude audio...");
11689 caps_str = gst_caps_to_string(caps);
11690 /* set it directly because not sent by TAG */
11691 if (g_strrstr(caps_str, "mobile-xmf"))
11692 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11693 MMPLAYER_FREEIF(caps_str);
11694 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11695 MMMessageParamType msg_param;
11696 memset(&msg_param, 0, sizeof(MMMessageParamType));
11697 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11698 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11699 LOGD("video file is not supported on this device");
11701 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11702 LOGD("already video linked");
11705 LOGD("found new stream");
11712 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11713 GstCaps* caps, GstElementFactory* factory, gpointer data)
11715 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11716 We are defining our own and will be removed when it actually exposed */
11718 GST_AUTOPLUG_SELECT_TRY,
11719 GST_AUTOPLUG_SELECT_EXPOSE,
11720 GST_AUTOPLUG_SELECT_SKIP
11721 } GstAutoplugSelectResult;
11723 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11724 mm_player_t* player = (mm_player_t*)data;
11726 gchar* factory_name = NULL;
11727 gchar* caps_str = NULL;
11728 const gchar* klass = NULL;
11731 factory_name = GST_OBJECT_NAME(factory);
11732 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11733 caps_str = gst_caps_to_string(caps);
11735 LOGD("found new element [%s] to link", factory_name);
11737 /* store type string */
11738 if (player->type == NULL) {
11739 player->type = gst_caps_to_string(caps);
11740 __mmplayer_update_content_type_info(player);
11743 /* filtering exclude keyword */
11744 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11745 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11746 LOGW("skipping [%s] by exculde keyword [%s]\n",
11747 factory_name, player->ini.exclude_element_keyword[idx]);
11749 // NOTE : does we need to check n_value against the number of item selected?
11750 result = GST_AUTOPLUG_SELECT_SKIP;
11755 /* exclude webm format */
11756 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11757 * because webm format is not supportable.
11758 * If webm is disabled in "autoplug-continue", there is no state change
11759 * failure or error because the decodebin will expose the pad directly.
11760 * It make MSL invoke _prepare_async_callback.
11761 * So, we need to disable webm format in "autoplug-select" */
11762 if (caps_str && strstr(caps_str, "webm")) {
11763 LOGW("webm is not supported");
11764 result = GST_AUTOPLUG_SELECT_SKIP;
11768 /* check factory class for filtering */
11769 /* NOTE : msl don't need to use image plugins.
11770 * So, those plugins should be skipped for error handling.
11772 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11773 LOGD("skipping [%s] by not required\n", factory_name);
11774 result = GST_AUTOPLUG_SELECT_SKIP;
11778 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11779 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11780 // TO CHECK : subtitle if needed, add subparse exception.
11781 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11782 result = GST_AUTOPLUG_SELECT_SKIP;
11786 if (g_strrstr(factory_name, "mpegpsdemux")) {
11787 LOGD("skipping PS container - not support\n");
11788 result = GST_AUTOPLUG_SELECT_SKIP;
11792 if (g_strrstr(factory_name, "mssdemux"))
11793 player->smooth_streaming = TRUE;
11795 /* check ALP Codec can be used or not */
11796 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11797 GstStructure* str = NULL;
11800 str = gst_caps_get_structure(caps, 0);
11802 gst_structure_get_int(str, "channels", &channels);
11804 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11805 if (player->max_audio_channels < channels)
11806 player->max_audio_channels = channels;
11808 /* set stream information */
11809 if (!player->audiodec_linked)
11810 __mmplayer_set_audio_attrs(player, caps);
11811 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11812 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11813 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11814 /* prepare resource manager for video decoder */
11815 MMPlayerResourceState resource_state = RESOURCE_STATE_NONE;
11817 if (_mmplayer_resource_manager_get_state(&player->resource_manager, &resource_state) == MM_ERROR_NONE) {
11818 /* prepare resource manager for video decoder */
11819 if ((resource_state >= RESOURCE_STATE_INITIALIZED) && (resource_state < RESOURCE_STATE_ACQUIRED)) {
11820 if (_mmplayer_resource_manager_prepare(&player->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)
11821 != MM_ERROR_NONE) {
11822 LOGW("could not prepare for video_decoder resource, skip it.");
11823 result = GST_AUTOPLUG_SELECT_SKIP;
11831 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11832 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11835 GstStructure *str = NULL;
11836 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11838 /* don't make video because of not required */
11839 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11840 (player->set_mode.media_packet_video_stream == FALSE)) {
11841 LOGD("no video because it's not required. -> return expose");
11842 result = GST_AUTOPLUG_SELECT_EXPOSE;
11846 /* get w/h for omx state-tune */
11847 str = gst_caps_get_structure(caps, 0);
11848 gst_structure_get_int(str, "width", &width);
11851 if (player->v_stream_caps) {
11852 gst_caps_unref(player->v_stream_caps);
11853 player->v_stream_caps = NULL;
11856 player->v_stream_caps = gst_caps_copy(caps);
11857 LOGD("take caps for video state tune");
11858 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11862 if (g_strrstr(klass, "Decoder")) {
11863 const char* mime = NULL;
11864 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11866 if (g_str_has_prefix(mime, "video")) {
11867 // __mmplayer_check_video_zero_cpoy(player, factory);
11869 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11870 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11872 player->videodec_linked = 1;
11873 } else if (g_str_has_prefix(mime, "audio")) {
11874 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11875 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11877 player->audiodec_linked = 1;
11882 MMPLAYER_FREEIF(caps_str);
11889 static GValueArray*
11890 __mmplayer_gst_decode_autoplug_factories(GstElement *bin, GstPad* pad,
11891 GstCaps * caps, gpointer data)
11893 //mm_player_t* player = (mm_player_t*)data;
11895 LOGD("decodebin is requesting factories for caps [%s] from element[%s]",
11896 gst_caps_to_string(caps),
11897 GST_ELEMENT_NAME(GST_PAD_PARENT(pad)));
11904 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11905 gpointer data) // @
11907 //mm_player_t* player = (mm_player_t*)data;
11908 GstCaps* caps = NULL;
11910 LOGD("[Decodebin2] pad-removed signal\n");
11912 caps = gst_pad_query_caps(new_pad, NULL);
11914 gchar* caps_str = NULL;
11915 caps_str = gst_caps_to_string(caps);
11917 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11919 MMPLAYER_FREEIF(caps_str);
11924 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11926 mm_player_t* player = (mm_player_t*)data;
11927 GstIterator *iter = NULL;
11928 GValue item = { 0, };
11929 GstPad *pad = NULL;
11930 gboolean done = FALSE;
11931 gboolean is_all_drained = TRUE;
11934 MMPLAYER_RETURN_IF_FAIL(player);
11936 LOGD("__mmplayer_gst_decode_drained");
11938 if (player->use_deinterleave == TRUE) {
11939 LOGD("group playing mode.");
11943 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11944 LOGW("Fail to get cmd lock");
11948 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11949 !__mmplayer_verify_next_play_path(player)) {
11950 LOGD("decoding is finished.");
11951 __mmplayer_reset_gapless_state(player);
11952 MMPLAYER_CMD_UNLOCK(player);
11956 player->gapless.reconfigure = TRUE;
11958 /* check decodebin src pads whether they received EOS or not */
11959 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11962 switch (gst_iterator_next(iter, &item)) {
11963 case GST_ITERATOR_OK:
11964 pad = g_value_get_object(&item);
11965 if (!GST_PAD_IS_EOS(pad)) {
11966 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11967 is_all_drained = FALSE;
11970 g_value_reset(&item);
11972 case GST_ITERATOR_RESYNC:
11973 gst_iterator_resync(iter);
11975 case GST_ITERATOR_ERROR:
11976 case GST_ITERATOR_DONE:
11981 g_value_unset(&item);
11982 gst_iterator_free(iter);
11984 if (!is_all_drained) {
11985 LOGD("Wait util the all pads get EOS.");
11986 MMPLAYER_CMD_UNLOCK(player);
11991 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11992 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11994 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11995 __mmplayer_deactivate_old_path(player);
11996 MMPLAYER_CMD_UNLOCK(player);
12002 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
12004 mm_player_t* player = (mm_player_t*)data;
12005 const gchar* klass = NULL;
12006 gchar* factory_name = NULL;
12008 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
12009 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
12011 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
12013 if (__mmplayer_add_dump_buffer_probe(player, element))
12014 LOGD("add buffer probe");
12017 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
12018 gchar* selected = NULL;
12019 selected = g_strdup(GST_ELEMENT_NAME(element));
12020 player->audio_decoders = g_list_append(player->audio_decoders, selected);
12024 if (g_strrstr(klass, "Parser")) {
12025 gchar* selected = NULL;
12027 selected = g_strdup(factory_name);
12028 player->parsers = g_list_append(player->parsers, selected);
12031 if ((g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) && !(g_strrstr(klass, "Adaptive"))) {
12032 /* FIXIT : first value will be overwritten if there's more
12033 * than 1 demuxer/parser
12036 //LOGD("plugged element is demuxer. take it\n");
12037 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
12038 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
12040 /*Added for multi audio support */ // Q. del?
12041 if (g_strrstr(klass, "Demux")) {
12042 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
12043 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
12047 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
12048 int surface_type = 0;
12050 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
12053 // to support trust-zone only
12054 if (g_strrstr(factory_name, "asfdemux")) {
12055 LOGD("set file-location %s\n", player->profile.uri);
12056 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
12058 if (player->video_hub_download_mode == TRUE)
12059 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
12060 } else if (g_strrstr(factory_name, "legacyh264parse")) {
12061 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
12062 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
12063 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
12064 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
12065 (__mmplayer_is_only_mp3_type(player->type))) {
12066 LOGD("[mpegaudioparse] set streaming pull mode.");
12067 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
12069 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw))
12070 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
12073 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
12074 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
12075 LOGD("plugged element is multiqueue. take it\n");
12077 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
12078 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
12080 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
12081 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
12082 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
12083 __mm_player_streaming_set_multiqueue(player->streamer,
12086 player->ini.http_buffering_time,
12088 player->ini.http_buffering_limit);
12090 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12097 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12100 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12102 if (MMPLAYER_IS_STREAMING(player))
12105 /* This callback can be set to music player only. */
12106 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12107 LOGW("audio callback is not supported for video");
12111 if (player->audio_stream_cb) {
12112 GstPad *pad = NULL;
12114 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12117 LOGE("failed to get sink pad from audiosink to probe data\n");
12120 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12121 __mmplayer_audio_stream_probe, player, NULL);
12123 gst_object_unref(pad);
12127 LOGE("There is no audio callback to configure.\n");
12137 __mmplayer_init_factories(mm_player_t* player) // @
12139 MMPLAYER_RETURN_IF_FAIL(player);
12141 player->factories = gst_registry_feature_filter(gst_registry_get(),
12142 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
12143 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
12147 __mmplayer_release_factories(mm_player_t* player) // @
12150 MMPLAYER_RETURN_IF_FAIL(player);
12152 if (player->factories) {
12153 gst_plugin_feature_list_free(player->factories);
12154 player->factories = NULL;
12161 __mmplayer_release_misc(mm_player_t* player)
12164 gboolean cur_mode = player->set_mode.rich_audio;
12167 MMPLAYER_RETURN_IF_FAIL(player);
12169 player->video_stream_cb = NULL;
12170 player->video_stream_cb_user_param = NULL;
12171 player->video_stream_prerolled = FALSE;
12173 player->audio_stream_cb = NULL;
12174 player->audio_stream_render_cb_ex = NULL;
12175 player->audio_stream_cb_user_param = NULL;
12176 player->audio_stream_sink_sync = false;
12178 player->video_stream_changed_cb = NULL;
12179 player->video_stream_changed_cb_user_param = NULL;
12181 player->audio_stream_changed_cb = NULL;
12182 player->audio_stream_changed_cb_user_param = NULL;
12184 player->sent_bos = FALSE;
12185 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12187 player->doing_seek = FALSE;
12189 player->updated_bitrate_count = 0;
12190 player->total_bitrate = 0;
12191 player->updated_maximum_bitrate_count = 0;
12192 player->total_maximum_bitrate = 0;
12194 player->not_found_demuxer = 0;
12196 player->last_position = 0;
12197 player->duration = 0;
12198 player->http_content_size = 0;
12199 player->not_supported_codec = MISSING_PLUGIN_NONE;
12200 player->can_support_codec = FOUND_PLUGIN_NONE;
12201 player->pending_seek.is_pending = FALSE;
12202 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12203 player->pending_seek.pos = 0;
12204 player->msg_posted = FALSE;
12205 player->has_many_types = FALSE;
12206 player->max_audio_channels = 0;
12207 player->video_share_api_delta = 0;
12208 player->video_share_clock_delta = 0;
12209 player->sound_focus.keep_last_pos = FALSE;
12210 player->sound_focus.acquired = FALSE;
12211 player->is_subtitle_force_drop = FALSE;
12212 player->play_subtitle = FALSE;
12213 player->use_textoverlay = FALSE;
12214 player->adjust_subtitle_pos = 0;
12215 player->last_multiwin_status = FALSE;
12216 player->has_closed_caption = FALSE;
12217 player->set_mode.media_packet_video_stream = FALSE;
12218 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12219 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12221 player->set_mode.rich_audio = cur_mode;
12223 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12224 player->bitrate[i] = 0;
12225 player->maximum_bitrate[i] = 0;
12228 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12230 /* remove media stream cb(appsrc cb) */
12231 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12232 player->media_stream_buffer_status_cb[i] = NULL;
12233 player->media_stream_seek_data_cb[i] = NULL;
12235 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12237 /* free memory related to audio effect */
12238 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12240 if (player->state_tune_caps) {
12241 gst_caps_unref(player->state_tune_caps);
12242 player->state_tune_caps = NULL;
12249 __mmplayer_release_misc_post(mm_player_t* player)
12251 char *original_uri = NULL;
12254 /* player->pipeline is already released before. */
12256 MMPLAYER_RETURN_IF_FAIL(player);
12258 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12259 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12261 /* clean found parsers */
12262 if (player->parsers) {
12263 GList *parsers = player->parsers;
12264 for (; parsers; parsers = g_list_next(parsers)) {
12265 gchar *name = parsers->data;
12266 MMPLAYER_FREEIF(name);
12268 g_list_free(player->parsers);
12269 player->parsers = NULL;
12272 /* clean found audio decoders */
12273 if (player->audio_decoders) {
12274 GList *a_dec = player->audio_decoders;
12275 for (; a_dec; a_dec = g_list_next(a_dec)) {
12276 gchar *name = a_dec->data;
12277 MMPLAYER_FREEIF(name);
12279 g_list_free(player->audio_decoders);
12280 player->audio_decoders = NULL;
12283 /* clean the uri list except original uri */
12284 if (player->uri_info.uri_list) {
12285 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12287 if (player->attrs) {
12288 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12289 LOGD("restore original uri = %s\n", original_uri);
12291 if (mmf_attrs_commit(player->attrs))
12292 LOGE("failed to commit the original uri.\n");
12295 GList *uri_list = player->uri_info.uri_list;
12296 for (; uri_list; uri_list = g_list_next(uri_list)) {
12297 gchar *uri = uri_list->data;
12298 MMPLAYER_FREEIF(uri);
12300 g_list_free(player->uri_info.uri_list);
12301 player->uri_info.uri_list = NULL;
12304 /* clear the audio stream buffer list */
12305 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12307 /* clear the video stream bo list */
12308 __mmplayer_video_stream_destroy_bo_list(player);
12309 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
12311 player->uri_info.uri_idx = 0;
12315 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12317 GstElement *element = NULL;
12320 LOGD("creating %s to plug\n", name);
12322 element = gst_element_factory_make(name, NULL);
12324 LOGE("failed to create queue\n");
12328 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12329 LOGE("failed to set state READY to %s\n", name);
12330 gst_object_unref(element);
12334 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12335 LOGE("failed to add %s\n", name);
12336 gst_object_unref(element);
12340 sinkpad = gst_element_get_static_pad(element, "sink");
12342 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12343 LOGE("failed to link %s\n", name);
12344 gst_object_unref(sinkpad);
12345 gst_object_unref(element);
12349 LOGD("linked %s to pipeline successfully\n", name);
12351 gst_object_unref(sinkpad);
12357 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
12358 const char *padname, const GList *templlist)
12360 GstPad *pad = NULL;
12361 gboolean has_dynamic_pads = FALSE;
12362 gboolean has_many_types = FALSE;
12363 const char *klass = NULL;
12364 GstStaticPadTemplate *padtemplate = NULL;
12365 GstElementFactory *factory = NULL;
12366 GstElement* queue = NULL;
12367 GstElement* parser = NULL;
12368 GstPad *pssrcpad = NULL;
12369 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
12370 MMPlayerGstElement *mainbin = NULL;
12371 GstStructure* str = NULL;
12372 GstCaps* srccaps = NULL;
12373 GstState target_state = GST_STATE_READY;
12374 gboolean isvideo_decoder = FALSE;
12375 guint q_max_size_time = 0;
12379 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12380 player->pipeline &&
12381 player->pipeline->mainbin,
12384 mainbin = player->pipeline->mainbin;
12386 LOGD("plugging pad %s:%s to newly create %s:%s\n",
12387 GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)),
12388 GST_PAD_NAME(srcpad),
12389 GST_ELEMENT_NAME(sinkelement),
12392 factory = gst_element_get_factory(sinkelement);
12393 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
12395 /* check if player can do start continually */
12396 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12398 /* need it to warm up omx before linking to pipeline */
12399 if (g_strrstr(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)), "demux")) {
12400 LOGD("get demux caps.\n");
12401 if (player->state_tune_caps) {
12402 gst_caps_unref(player->state_tune_caps);
12403 player->state_tune_caps = NULL;
12405 player->state_tune_caps = gst_caps_copy(gst_pad_get_current_caps(srcpad));
12408 /* NOTE : OMX Codec can check if resource is available or not at this state. */
12409 if (g_strrstr(GST_ELEMENT_NAME(sinkelement), "omx")) {
12410 if (player->state_tune_caps != NULL) {
12411 LOGD("set demux's caps to omx codec if resource is available");
12412 if (gst_pad_set_caps(gst_element_get_static_pad(sinkelement, "sink"), player->state_tune_caps)) {
12413 target_state = GST_STATE_PAUSED;
12414 isvideo_decoder = TRUE;
12415 g_object_set(G_OBJECT(sinkelement), "state-tuning", TRUE, NULL);
12417 LOGW("failed to set caps for state tuning");
12419 gst_caps_unref(player->state_tune_caps);
12420 player->state_tune_caps = NULL;
12423 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, target_state)) {
12424 LOGE("failed to set %d state to %s\n", target_state, GST_ELEMENT_NAME(sinkelement));
12425 if (isvideo_decoder) {
12426 gst_element_set_state(sinkelement, GST_STATE_NULL);
12427 gst_object_unref(G_OBJECT(sinkelement));
12428 player->keep_detecting_vcodec = TRUE;
12433 /* add to pipeline */
12434 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement)) {
12435 LOGE("failed to add %s to mainbin\n", GST_ELEMENT_NAME(sinkelement));
12439 LOGD("element klass : %s\n", klass);
12441 /* added to support multi track files */
12442 /* only decoder case and any of the video/audio still need to link*/
12443 if (g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player, srcpad)) {
12444 gchar *name = g_strdup(GST_ELEMENT_NAME(GST_PAD_PARENT(srcpad)));
12446 if (g_strrstr(name, "mpegtsdemux") || g_strrstr(name, "mssdemux")) {
12447 gchar *src_demux_caps_str = NULL;
12448 gchar *needed_parser = NULL;
12449 GstCaps *src_demux_caps = NULL;
12450 gboolean smooth_streaming = FALSE;
12452 src_demux_caps = gst_pad_query_caps(srcpad, NULL);
12453 src_demux_caps_str = gst_caps_to_string(src_demux_caps);
12455 gst_caps_unref(src_demux_caps);
12457 if (g_strrstr(src_demux_caps_str, "video/x-h264")) {
12458 if (g_strrstr(name, "mssdemux")) {
12459 needed_parser = g_strdup("legacyh264parse");
12460 smooth_streaming = TRUE;
12462 needed_parser = g_strdup("h264parse");
12463 } else if (g_strrstr(src_demux_caps_str, "video/mpeg"))
12464 needed_parser = g_strdup("mpeg4videoparse");
12466 MMPLAYER_FREEIF(src_demux_caps_str);
12468 if (needed_parser) {
12469 parser = __mmplayer_element_create_and_link(player, srcpad, needed_parser);
12470 MMPLAYER_FREEIF(needed_parser);
12473 LOGE("failed to create parser\n");
12475 if (smooth_streaming)
12476 g_object_set(parser, "output-format", 1, NULL); /* NALU/Byte Stream format */
12478 /* update srcpad if parser is created */
12479 pssrcpad = gst_element_get_static_pad(parser, "src");
12484 MMPLAYER_FREEIF(name);
12486 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
12488 LOGE("failed to create queue\n");
12492 /* update srcpad to link with decoder */
12493 qsrcpad = gst_element_get_static_pad(queue, "src");
12496 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
12498 /* assigning queue handle for futher manipulation purpose */
12499 /* FIXIT : make it some kind of list so that msl can support more then two stream(text, data, etc...) */
12500 if (mainbin[MMPLAYER_M_Q1].gst == NULL) {
12501 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
12502 mainbin[MMPLAYER_M_Q1].gst = queue;
12504 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12505 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", 0 , NULL);
12506 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-buffers", 2, NULL);
12507 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-bytes", 0, NULL);
12509 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12510 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12512 } else if (mainbin[MMPLAYER_M_Q2].gst == NULL) {
12513 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
12514 mainbin[MMPLAYER_M_Q2].gst = queue;
12516 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) {
12517 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", 0 , NULL);
12518 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-buffers", 2, NULL);
12519 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-bytes", 0, NULL);
12521 if (!MMPLAYER_IS_RTSP_STREAMING(player))
12522 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
12525 LOGE("Not supporting more then two elementary stream\n");
12529 pad = gst_element_get_static_pad(sinkelement, padname);
12532 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12533 padname, GST_ELEMENT_NAME(sinkelement));
12535 pad = gst_element_get_static_pad(sinkelement, "sink");
12537 LOGE("failed to get pad(sink) from %s. \n",
12538 GST_ELEMENT_NAME(sinkelement));
12543 /* to check the video/audio type set the proper flag*/
12544 const gchar *mime_type = NULL;
12545 srccaps = gst_pad_query_caps(srcpad, NULL);
12548 str = gst_caps_get_structure(srccaps, 0);
12551 mime_type = gst_structure_get_name(str);
12555 /* link queue and decoder. so, it will be queue - decoder. */
12556 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12557 gst_object_unref(GST_OBJECT(pad));
12558 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12560 /* reconstitute supportable codec */
12561 if (strstr(mime_type, "video"))
12562 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
12563 else if (strstr(mime_type, "audio"))
12564 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
12568 if (strstr(mime_type, "video")) {
12569 player->videodec_linked = 1;
12570 LOGI("player->videodec_linked set to 1\n");
12572 } else if (strstr(mime_type, "audio")) {
12573 player->audiodec_linked = 1;
12574 LOGI("player->auddiodec_linked set to 1\n");
12577 gst_object_unref(GST_OBJECT(pad));
12578 gst_caps_unref(GST_CAPS(srccaps));
12582 if (!MMPLAYER_IS_HTTP_PD(player)) {
12583 if ((g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser"))) {
12584 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
12585 gint64 dur_bytes = 0L;
12586 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
12588 if (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
12589 LOGD("creating http streaming buffering queue\n");
12591 queue = gst_element_factory_make("queue2", "queue2");
12593 LOGE("failed to create buffering queue element\n");
12597 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY)) {
12598 LOGE("failed to set state READY to buffering queue\n");
12602 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue)) {
12603 LOGE("failed to add buffering queue\n");
12607 qsinkpad = gst_element_get_static_pad(queue, "sink");
12608 qsrcpad = gst_element_get_static_pad(queue, "src");
12610 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad)) {
12611 LOGE("failed to link buffering queue\n");
12617 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
12618 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue;
12620 if (!MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {
12621 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
12622 LOGE("fail to get duration.\n");
12624 if (dur_bytes > 0) {
12625 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
12626 type = MUXED_BUFFER_TYPE_FILE;
12628 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
12629 if (player->streamer)
12630 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
12637 /* NOTE : we cannot get any duration info from ts container in case of streaming */
12638 if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux")) {
12639 __mm_player_streaming_set_queue2(player->streamer,
12642 player->ini.http_max_size_bytes,
12643 player->ini.http_buffering_time,
12645 player->ini.http_buffering_limit,
12647 player->http_file_buffering_path,
12648 (guint64)dur_bytes);
12654 /* if it is not decoder or */
12655 /* in decoder case any of the video/audio still need to link*/
12656 if (!g_strrstr(klass, "Decoder")) {
12657 pad = gst_element_get_static_pad(sinkelement, padname);
12659 LOGW("failed to get pad(%s) from %s. retrying with [sink]\n",
12660 padname, GST_ELEMENT_NAME(sinkelement));
12662 pad = gst_element_get_static_pad(sinkelement, "sink");
12665 LOGE("failed to get pad(sink) from %s. \n",
12666 GST_ELEMENT_NAME(sinkelement));
12671 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, pad)) {
12672 gst_object_unref(GST_OBJECT(pad));
12673 LOGE("failed to link(%s) to pad(%s)\n", GST_ELEMENT_NAME(sinkelement), padname);
12677 gst_object_unref(GST_OBJECT(pad));
12680 for (; templlist != NULL; templlist = templlist->next) {
12681 padtemplate = templlist->data;
12683 LOGD("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
12685 if (padtemplate->direction != GST_PAD_SRC ||
12686 padtemplate->presence == GST_PAD_REQUEST)
12689 switch (padtemplate->presence) {
12690 case GST_PAD_ALWAYS:
12692 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
12693 GstCaps *caps = gst_pad_query_caps(srcpad, NULL);
12695 /* Check whether caps has many types */
12696 if (!gst_caps_is_fixed(caps)) {
12697 LOGD("always pad but, caps has many types");
12698 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12699 has_many_types = TRUE;
12703 if (!__mmplayer_try_to_plug(player, srcpad, caps)) {
12704 gst_object_unref(GST_OBJECT(srcpad));
12705 gst_caps_unref(GST_CAPS(caps));
12707 LOGE("failed to plug something after %s\n", GST_ELEMENT_NAME(sinkelement));
12711 gst_caps_unref(GST_CAPS(caps));
12712 gst_object_unref(GST_OBJECT(srcpad));
12718 case GST_PAD_SOMETIMES:
12719 has_dynamic_pads = TRUE;
12727 /* check if player can do start continually */
12728 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12730 if (has_dynamic_pads) {
12731 player->have_dynamic_pad = TRUE;
12732 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
12733 G_CALLBACK(__mmplayer_add_new_pad), player);
12735 /* for streaming, more then one typefind will used for each elementary stream
12736 * so this doesn't mean the whole pipeline completion
12738 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
12739 MMPLAYER_SIGNAL_CONNECT(player, sinkelement, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
12740 G_CALLBACK(__mmplayer_pipeline_complete), player);
12744 if (has_many_types) {
12745 GstPad *pad = NULL;
12747 player->has_many_types = has_many_types;
12749 pad = gst_element_get_static_pad(sinkelement, "src");
12750 MMPLAYER_SIGNAL_CONNECT(player, pad, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
12751 gst_object_unref(GST_OBJECT(pad));
12755 /* check if player can do start continually */
12756 MMPLAYER_CHECK_CMD_IF_EXIT(player);
12758 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED)) {
12759 LOGE("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME(sinkelement));
12764 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED)) {
12765 LOGE("failed to set state PAUSED to queue\n");
12771 gst_object_unref(GST_OBJECT(qsrcpad));
12776 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(parser, GST_STATE_PAUSED)) {
12777 LOGE("failed to set state PAUSED to queue\n");
12783 gst_object_unref(GST_OBJECT(pssrcpad));
12794 gst_object_unref(GST_OBJECT(qsrcpad));
12796 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
12797 * You need to explicitly set elements to the NULL state before
12798 * dropping the final reference, to allow them to clean up.
12800 gst_element_set_state(queue, GST_STATE_NULL);
12801 /* And, it still has a parent "player".
12802 * You need to let the parent manage the object instead of unreffing the object directly.
12805 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
12806 //gst_object_unref(queue);
12810 gst_caps_unref(GST_CAPS(srccaps));
12815 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
12817 const gchar *klass;
12819 /* we only care about element factories */
12820 if (!GST_IS_ELEMENT_FACTORY(feature))
12823 /* only parsers, demuxers and decoders */
12824 klass = gst_element_factory_get_metadata(GST_ELEMENT_FACTORY(feature), GST_ELEMENT_METADATA_KLASS);
12826 if (g_strrstr(klass, "Demux") == NULL &&
12827 g_strrstr(klass, "Codec/Decoder") == NULL &&
12828 g_strrstr(klass, "Depayloader") == NULL &&
12829 g_strrstr(klass, "Parse") == NULL)
12835 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
12837 mm_player_t* player = (mm_player_t*) data;
12838 GstCaps *caps = NULL;
12839 GstStructure *str = NULL;
12844 MMPLAYER_RETURN_IF_FAIL(pad)
12845 MMPLAYER_RETURN_IF_FAIL(unused)
12846 MMPLAYER_RETURN_IF_FAIL(data)
12848 caps = gst_pad_query_caps(pad, NULL);
12852 str = gst_caps_get_structure(caps, 0);
12856 name = gst_structure_get_name(str);
12859 LOGD("name=%s\n", name);
12861 if (!__mmplayer_try_to_plug(player, pad, caps)) {
12862 LOGE("failed to autoplug for type(%s)\n", name);
12863 gst_caps_unref(caps);
12867 gst_caps_unref(caps);
12869 __mmplayer_pipeline_complete(NULL, (gpointer)player);
12876 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
12880 const char *stream_type;
12881 gchar *version_field = NULL;
12885 MMPLAYER_RETURN_IF_FAIL(player);
12886 MMPLAYER_RETURN_IF_FAIL(caps);
12888 str = gst_caps_get_structure(caps, 0);
12892 stream_type = gst_structure_get_name(str);
12897 /* set unlinked mime type for downloadable codec */
12898 if (g_str_has_prefix(stream_type, "video/")) {
12899 if (g_str_has_prefix(stream_type, "video/mpeg")) {
12900 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12901 version_field = MM_PLAYER_MPEG_VNAME;
12902 } else if (g_str_has_prefix(stream_type, "video/x-wmv")) {
12903 gst_structure_get_int(str, MM_PLAYER_WMV_VNAME, &version);
12904 version_field = MM_PLAYER_WMV_VNAME;
12906 } else if (g_str_has_prefix(stream_type, "video/x-divx")) {
12907 gst_structure_get_int(str, MM_PLAYER_DIVX_VNAME, &version);
12908 version_field = MM_PLAYER_DIVX_VNAME;
12912 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12914 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
12915 } else if (g_str_has_prefix(stream_type, "audio/")) {
12916 if (g_str_has_prefix(stream_type, "audio/mpeg")) {
12918 gst_structure_get_int(str, MM_PLAYER_MPEG_VNAME, &version);
12919 version_field = MM_PLAYER_MPEG_VNAME;
12920 } else if (g_str_has_prefix(stream_type, "audio/x-wma")) {
12921 gst_structure_get_int(str, MM_PLAYER_WMA_VNAME, &version);
12922 version_field = MM_PLAYER_WMA_VNAME;
12926 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
12928 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
12934 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
12936 mm_player_t* player = (mm_player_t*) data;
12937 GstCaps *caps = NULL;
12938 GstStructure *str = NULL;
12942 MMPLAYER_RETURN_IF_FAIL(player);
12943 MMPLAYER_RETURN_IF_FAIL(pad);
12945 GST_OBJECT_LOCK(pad);
12946 if ((caps = gst_pad_get_current_caps(pad)))
12947 gst_caps_ref(caps);
12948 GST_OBJECT_UNLOCK(pad);
12950 if (NULL == caps) {
12951 caps = gst_pad_query_caps(pad, NULL);
12955 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12957 str = gst_caps_get_structure(caps, 0);
12961 name = gst_structure_get_name(str);
12965 player->num_dynamic_pad++;
12966 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
12968 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
12969 * If want to play it, remove this code.
12971 if (g_strrstr(name, "application")) {
12972 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag")) {
12973 /* If id3/ape tag comes, keep going */
12974 LOGD("application mime exception : id3/ape tag");
12976 /* Otherwise, we assume that this stream is subtile. */
12977 LOGD(" application mime type pad is closed.");
12980 } else if (g_strrstr(name, "audio")) {
12981 gint samplerate = 0, channels = 0;
12983 if (player->audiodec_linked) {
12984 gst_caps_unref(caps);
12985 LOGD("multi tracks. skip to plug");
12989 /* set stream information */
12990 /* if possible, set it here because the caps is not distrubed by resampler. */
12991 gst_structure_get_int(str, "rate", &samplerate);
12992 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
12994 gst_structure_get_int(str, "channels", &channels);
12995 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
12997 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
12998 } else if (g_strrstr(name, "video")) {
13000 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
13002 /* don't make video because of not required */
13003 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
13004 LOGD("no video because it's not required");
13008 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
13011 if (!__mmplayer_try_to_plug(player, pad, caps)) {
13012 LOGE("failed to autoplug for type(%s)", name);
13014 __mmplayer_set_unlinked_mime_type(player, caps);
13017 gst_caps_unref(caps);
13024 __mmplayer_check_subtitle(mm_player_t* player)
13026 MMHandleType attrs = 0;
13027 char *subtitle_uri = NULL;
13031 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13033 /* get subtitle attribute */
13034 attrs = MMPLAYER_GET_ATTRS(player);
13038 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13039 if (!subtitle_uri || !strlen(subtitle_uri))
13042 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
13043 player->is_external_subtitle_present = TRUE;
13051 __mmplayer_can_extract_pcm(mm_player_t* player)
13053 MMHandleType attrs = 0;
13054 gboolean sound_extraction = FALSE;
13056 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13058 attrs = MMPLAYER_GET_ATTRS(player);
13060 LOGE("fail to get attributes.");
13064 /* get sound_extraction property */
13065 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
13067 if (!sound_extraction) {
13068 LOGD("checking pcm extraction mode : %d ", sound_extraction);
13076 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
13079 MMMessageParamType msg_param;
13080 gchar *msg_src_element = NULL;
13081 GstStructure *s = NULL;
13082 guint error_id = 0;
13083 gchar *error_string = NULL;
13087 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13088 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
13090 s = malloc(sizeof(GstStructure));
13091 memcpy(s, gst_message_get_structure(message), sizeof(GstStructure));
13093 if (!gst_structure_get_uint(s, "error_id", &error_id))
13094 error_id = MMPLAYER_STREAMING_ERROR_NONE;
13096 switch (error_id) {
13097 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
13098 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
13100 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
13101 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
13103 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
13104 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
13106 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
13107 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
13109 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
13110 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
13112 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
13113 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
13115 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
13116 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
13118 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
13119 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
13121 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
13122 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
13124 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
13125 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
13127 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
13128 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
13130 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
13131 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
13133 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
13134 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
13136 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
13137 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
13139 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
13140 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
13142 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
13143 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
13145 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
13146 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
13148 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
13149 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
13151 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
13152 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
13154 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
13155 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
13157 case MMPLAYER_STREAMING_ERROR_GONE:
13158 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
13160 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
13161 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
13163 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
13164 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
13166 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
13167 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
13169 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
13170 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
13172 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
13173 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
13175 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
13176 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
13178 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
13179 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
13181 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
13182 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
13184 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
13185 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
13187 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
13188 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
13190 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
13191 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
13193 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
13194 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
13196 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
13197 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
13199 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
13200 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
13202 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
13203 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
13205 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
13206 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
13208 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
13209 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
13211 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
13212 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
13214 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
13215 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
13217 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
13218 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
13220 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
13221 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
13223 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
13224 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
13226 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
13227 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
13229 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
13230 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
13234 MMPLAYER_FREEIF(s);
13235 return MM_ERROR_PLAYER_STREAMING_FAIL;
13239 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
13241 msg_param.data = (void *) error_string;
13243 if (message->src) {
13244 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
13246 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
13247 msg_src_element, msg_param.code, (char*)msg_param.data);
13250 /* post error to application */
13251 if (!player->msg_posted) {
13252 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13254 /* don't post more if one was sent already */
13255 player->msg_posted = TRUE;
13257 LOGD("skip error post because it's sent already.\n");
13259 MMPLAYER_FREEIF(s);
13261 g_free(error_string);
13268 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
13270 MMPLAYER_RETURN_IF_FAIL(player);
13273 /* post now if delay is zero */
13274 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
13275 LOGD("eos delay is zero. posting EOS now\n");
13276 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13278 if (player->set_mode.pcm_extraction)
13279 __mmplayer_cancel_eos_timer(player);
13284 /* cancel if existing */
13285 __mmplayer_cancel_eos_timer(player);
13287 /* init new timeout */
13288 /* NOTE : consider give high priority to this timer */
13289 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
13291 player->eos_timer = g_timeout_add(delay_in_ms,
13292 __mmplayer_eos_timer_cb, player);
13294 player->context.global_default = g_main_context_default();
13295 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
13297 /* check timer is valid. if not, send EOS now */
13298 if (player->eos_timer == 0) {
13299 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
13300 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13305 __mmplayer_cancel_eos_timer(mm_player_t* player)
13307 MMPLAYER_RETURN_IF_FAIL(player);
13309 if (player->eos_timer) {
13310 LOGD("cancel eos timer");
13311 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
13312 player->eos_timer = 0;
13319 __mmplayer_eos_timer_cb(gpointer u_data)
13321 mm_player_t* player = NULL;
13322 player = (mm_player_t*) u_data;
13324 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13326 if (player->play_count > 1) {
13327 gint ret_value = 0;
13328 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
13329 if (ret_value == MM_ERROR_NONE) {
13330 MMHandleType attrs = 0;
13331 attrs = MMPLAYER_GET_ATTRS(player);
13333 /* we successeded to rewind. update play count and then wait for next EOS */
13334 player->play_count--;
13336 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
13337 mmf_attrs_commit(attrs);
13339 LOGE("seeking to 0 failed in repeat play");
13343 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
13346 /* we are returning FALSE as we need only one posting */
13351 __mmplayer_link_decoder(mm_player_t* player, GstPad *srcpad)
13353 const gchar* name = NULL;
13354 GstStructure* str = NULL;
13355 GstCaps* srccaps = NULL;
13359 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13360 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13362 /* to check any of the decoder(video/audio) need to be linked to parser*/
13363 srccaps = gst_pad_query_caps(srcpad, NULL);
13367 str = gst_caps_get_structure(srccaps, 0);
13371 name = gst_structure_get_name(str);
13375 if (strstr(name, "video")) {
13376 if (player->videodec_linked) {
13377 LOGI("Video decoder already linked\n");
13381 if (strstr(name, "audio")) {
13382 if (player->audiodec_linked) {
13383 LOGI("Audio decoder already linked\n");
13388 gst_caps_unref(srccaps);
13396 gst_caps_unref(srccaps);
13402 __mmplayer_link_sink(mm_player_t* player , GstPad *srcpad)
13404 const gchar* name = NULL;
13405 GstStructure* str = NULL;
13406 GstCaps* srccaps = NULL;
13410 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13411 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
13413 /* to check any of the decoder(video/audio) need to be linked to parser*/
13414 srccaps = gst_pad_query_caps(srcpad, NULL);
13418 str = gst_caps_get_structure(srccaps, 0);
13422 name = gst_structure_get_name(str);
13426 if (strstr(name, "video")) {
13427 if (player->videosink_linked) {
13428 LOGI("Video Sink already linked\n");
13432 if (strstr(name, "audio")) {
13433 if (player->audiosink_linked) {
13434 LOGI("Audio Sink already linked\n");
13438 if (strstr(name, "text")) {
13439 if (player->textsink_linked) {
13440 LOGI("Text Sink already linked\n");
13445 gst_caps_unref(srccaps);
13449 //return (!player->videosink_linked || !player->audiosink_linked);
13454 gst_caps_unref(srccaps);
13460 /* sending event to one of sinkelements */
13462 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
13464 GstEvent * event2 = NULL;
13465 GList *sinks = NULL;
13466 gboolean res = FALSE;
13469 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13470 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
13472 /* While adding subtitles in live feeds seek is getting called.
13473 Adding defensive check in framework layer.*/
13474 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13475 if (MMPLAYER_IS_LIVE_STREAMING (player)) {
13476 LOGE ("Should not send seek event during live playback");
13481 if (player->play_subtitle && !player->use_textoverlay)
13482 event2 = gst_event_copy((const GstEvent *)event);
13484 sinks = player->sink_elements;
13486 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
13488 if (GST_IS_ELEMENT(sink)) {
13489 /* keep ref to the event */
13490 gst_event_ref(event);
13492 if ((res = gst_element_send_event(sink, event))) {
13493 LOGD("sending event[%s] to sink element [%s] success!\n",
13494 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13496 /* rtsp case, asyn_done is not called after seek during pause state */
13497 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
13498 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
13499 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
13500 LOGD("RTSP seek completed, after pause state..\n");
13501 player->doing_seek = FALSE;
13502 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
13508 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
13509 sinks = g_list_next(sinks);
13515 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
13516 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
13519 sinks = g_list_next(sinks);
13524 request pad name = sink0;
13526 request pad name = sink1; // external
13529 /* Note : Textbin is not linked to the video or audio bin.
13530 * It needs to send the event to the text sink seperatelly.
13532 if (player->play_subtitle && !player->use_textoverlay) {
13533 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
13535 if (GST_IS_ELEMENT(text_sink)) {
13536 /* keep ref to the event */
13537 gst_event_ref(event2);
13539 if ((res = gst_element_send_event(text_sink, event2)))
13540 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
13541 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13543 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
13544 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
13546 gst_event_unref(event2);
13550 gst_event_unref(event);
13558 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
13562 MMPLAYER_RETURN_IF_FAIL(player);
13563 MMPLAYER_RETURN_IF_FAIL(sink);
13565 player->sink_elements =
13566 g_list_append(player->sink_elements, sink);
13572 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
13576 MMPLAYER_RETURN_IF_FAIL(player);
13577 MMPLAYER_RETURN_IF_FAIL(sink);
13579 player->sink_elements =
13580 g_list_remove(player->sink_elements, sink);
13586 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
13587 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
13588 gint64 cur, GstSeekType stop_type, gint64 stop)
13590 GstEvent* event = NULL;
13591 gboolean result = FALSE;
13595 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13597 if (player->pipeline && player->pipeline->textbin)
13598 __mmplayer_drop_subtitle(player, FALSE);
13600 event = gst_event_new_seek(rate, format, flags, cur_type,
13601 cur, stop_type, stop);
13603 result = __gst_send_event_to_sink(player, event);
13610 /* NOTE : be careful with calling this api. please refer to below glib comment
13611 * glib comment : Note that there is a bug in GObject that makes this function much
13612 * less useful than it might seem otherwise. Once gobject is disposed, the callback
13613 * will no longer be called, but, the signal handler is not currently disconnected.
13614 * If the instance is itself being freed at the same time than this doesn't matter,
13615 * since the signal will automatically be removed, but if instance persists,
13616 * then the signal handler will leak. You should not remove the signal yourself
13617 * because in a future versions of GObject, the handler will automatically be
13620 * It's possible to work around this problem in a way that will continue to work
13621 * with future versions of GObject by checking that the signal handler is still
13622 * connected before disconnected it:
13624 * if (g_signal_handler_is_connected(instance, id))
13625 * g_signal_handler_disconnect(instance, id);
13628 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
13630 GList* sig_list = NULL;
13631 MMPlayerSignalItem* item = NULL;
13635 MMPLAYER_RETURN_IF_FAIL(player);
13637 LOGD("release signals type : %d", type);
13639 if ((type < MM_PLAYER_SIGNAL_TYPE_AUTOPLUG) || (type >= MM_PLAYER_SIGNAL_TYPE_ALL)) {
13640 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
13641 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
13642 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
13643 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13644 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
13648 sig_list = player->signals[type];
13650 for (; sig_list; sig_list = sig_list->next) {
13651 item = sig_list->data;
13653 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
13654 if (g_signal_handler_is_connected(item->obj, item->sig))
13655 g_signal_handler_disconnect(item->obj, item->sig);
13658 MMPLAYER_FREEIF(item);
13661 g_list_free(player->signals[type]);
13662 player->signals[type] = NULL;
13669 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
13671 mm_player_t* player = 0;
13672 int prev_display_surface_type = 0;
13673 void *prev_display_overlay = NULL;
13674 const gchar *klass = NULL;
13675 gchar *cur_videosink_name = NULL;
13678 int num_of_dec = 2; /* DEC1, DEC2 */
13682 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
13683 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13685 player = MM_PLAYER_CAST(handle);
13687 if (surface_type < MM_DISPLAY_SURFACE_OVERLAY || surface_type >= MM_DISPLAY_SURFACE_NUM) {
13688 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
13690 return MM_ERROR_INVALID_ARGUMENT;
13693 /* load previous attributes */
13694 if (player->attrs) {
13695 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
13696 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
13697 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
13698 if (prev_display_surface_type == surface_type) {
13699 LOGD("incoming display surface type is same as previous one, do nothing..");
13701 return MM_ERROR_NONE;
13704 LOGE("failed to load attributes");
13706 return MM_ERROR_PLAYER_INTERNAL;
13709 /* check videosink element is created */
13710 if (!player->pipeline || !player->pipeline->videobin ||
13711 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13712 LOGD("videosink element is not yet ready");
13714 /* videobin is not created yet, so we just set attributes related to display surface */
13715 LOGD("store display attribute for given surface type(%d)", surface_type);
13716 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13717 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13718 if (mmf_attrs_commit(player->attrs)) {
13719 LOGE("failed to commit attribute");
13721 return MM_ERROR_PLAYER_INTERNAL;
13724 return MM_ERROR_NONE;
13726 /* get player command status */
13727 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
13728 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
13730 return MM_ERROR_PLAYER_INVALID_STATE;
13733 /* surface change */
13734 for (i = 0 ; i < num_of_dec ; i++) {
13735 if (player->pipeline->mainbin &&
13736 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
13737 GstElementFactory *decfactory;
13738 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
13740 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
13741 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
13742 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
13743 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
13747 LOGW("success to changing display surface(%d)", surface_type);
13749 return MM_ERROR_NONE;
13751 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
13752 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
13756 LOGW("success to changing display surface(%d)", surface_type);
13758 return MM_ERROR_NONE;
13761 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
13762 ret = MM_ERROR_PLAYER_INTERNAL;
13771 /* rollback to previous attributes */
13772 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
13773 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
13774 if (mmf_attrs_commit(player->attrs)) {
13775 LOGE("failed to commit attributes to rollback");
13777 return MM_ERROR_PLAYER_INTERNAL;
13783 /* NOTE : It does not support some use cases, eg using colorspace converter */
13785 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
13787 GstPad *src_pad_dec = NULL;
13788 GstPad *sink_pad_videosink = NULL;
13789 GstPad *sink_pad_videobin = NULL;
13790 GstClock *clock = NULL;
13791 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
13792 int ret = MM_ERROR_NONE;
13793 gboolean is_audiobin_created = TRUE;
13797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
13798 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
13799 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
13801 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
13802 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
13804 /* get information whether if audiobin is created */
13805 if (!player->pipeline->audiobin ||
13806 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
13807 LOGW("audiobin is null, this video content may not have audio data");
13808 is_audiobin_created = FALSE;
13811 /* get current state of player */
13812 previous_state = MMPLAYER_CURRENT_STATE(player);
13813 LOGD("previous state(%d)", previous_state);
13816 /* get src pad of decoder and block it */
13817 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
13818 if (!src_pad_dec) {
13819 LOGE("failed to get src pad from decode in mainbin");
13820 return MM_ERROR_PLAYER_INTERNAL;
13823 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13824 LOGW("trying to block pad(video)");
13825 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
13826 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
13829 LOGE("failed to set block pad(video)");
13830 return MM_ERROR_PLAYER_INTERNAL;
13832 LOGW("pad is blocked(video)");
13834 /* no data flows, so no need to do pad_block */
13835 if (player->doing_seek)
13836 LOGW("not completed seek(%d), do nothing", player->doing_seek);
13838 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
13842 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
13843 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
13844 LOGE("failed to remove previous ghost_pad for videobin");
13845 return MM_ERROR_PLAYER_INTERNAL;
13848 /* change state of videobin to NULL */
13849 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
13850 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
13851 if (ret != GST_STATE_CHANGE_SUCCESS) {
13852 LOGE("failed to change state of videobin to NULL");
13853 return MM_ERROR_PLAYER_INTERNAL;
13856 /* unlink between decoder and videobin and remove previous videosink from videobin */
13857 GST_ELEMENT_UNLINK(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
13858 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
13859 LOGE("failed to remove former videosink from videobin");
13860 return MM_ERROR_PLAYER_INTERNAL;
13863 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13865 /* create a new videosink and add it to videobin */
13866 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
13867 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
13868 LOGE("failed to create videosink element\n");
13870 return MM_ERROR_PLAYER_INTERNAL;
13872 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
13873 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13874 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13876 /* save attributes */
13877 if (player->attrs) {
13878 /* set a new display surface type */
13879 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13880 /* set a new diplay overlay */
13881 switch (surface_type) {
13882 case MM_DISPLAY_SURFACE_OVERLAY:
13883 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13884 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13887 LOGE("invalid type(%d) for changing display surface", surface_type);
13889 return MM_ERROR_INVALID_ARGUMENT;
13891 if (mmf_attrs_commit(player->attrs)) {
13892 LOGE("failed to commit");
13894 return MM_ERROR_PLAYER_INTERNAL;
13897 LOGE("player->attrs is null, failed to save attributes");
13899 return MM_ERROR_PLAYER_INTERNAL;
13902 /* update video param */
13903 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13904 LOGE("failed to update video param");
13905 return MM_ERROR_PLAYER_INTERNAL;
13908 /* change state of videobin to READY */
13909 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13910 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13911 if (ret != GST_STATE_CHANGE_SUCCESS) {
13912 LOGE("failed to change state of videobin to READY");
13913 return MM_ERROR_PLAYER_INTERNAL;
13916 /* change ghostpad */
13917 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13918 if (!sink_pad_videosink) {
13919 LOGE("failed to get sink pad from videosink element");
13920 return MM_ERROR_PLAYER_INTERNAL;
13922 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13923 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13924 LOGE("failed to set active to ghost_pad");
13925 return MM_ERROR_PLAYER_INTERNAL;
13927 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13928 LOGE("failed to change ghostpad for videobin");
13929 return MM_ERROR_PLAYER_INTERNAL;
13931 gst_object_unref(sink_pad_videosink);
13933 /* link decoder with videobin */
13934 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13935 if (!sink_pad_videobin) {
13936 LOGE("failed to get sink pad from videobin");
13937 return MM_ERROR_PLAYER_INTERNAL;
13939 if (GST_PAD_LINK_OK != GST_PAD_LINK(src_pad_dec, sink_pad_videobin)) {
13940 LOGE("failed to link");
13941 return MM_ERROR_PLAYER_INTERNAL;
13943 gst_object_unref(sink_pad_videobin);
13945 /* clock setting for a new videosink plugin */
13946 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13947 so we set it from audiosink plugin or pipeline(system clock) */
13948 if (!is_audiobin_created) {
13949 LOGW("audiobin is not created, get clock from pipeline..");
13950 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13952 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13956 GstClockTime base_time;
13957 LOGD("set the clock to videosink");
13958 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13959 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13961 LOGD("got clock of videosink");
13962 now = gst_clock_get_time(clock);
13963 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13964 LOGD("at time %" GST_TIME_FORMAT ", base %"
13965 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13967 LOGE("failed to get clock of videosink after setting clock");
13968 return MM_ERROR_PLAYER_INTERNAL;
13971 LOGW("failed to get clock, maybe it is the time before first playing");
13973 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13974 /* change state of videobin to PAUSED */
13975 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13976 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13977 if (ret != GST_STATE_CHANGE_FAILURE) {
13978 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13980 LOGE("failed to change state of videobin to PLAYING");
13981 return MM_ERROR_PLAYER_INTERNAL;
13984 /* release blocked and unref src pad of video decoder */
13986 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13987 LOGE("failed to set pad blocked FALSE(video)");
13988 return MM_ERROR_PLAYER_INTERNAL;
13991 LOGW("pad is unblocked(video)");
13993 if (player->doing_seek)
13994 LOGW("not completed seek(%d)", player->doing_seek);
13995 /* change state of videobin to PAUSED */
13996 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13997 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13998 if (ret != GST_STATE_CHANGE_FAILURE) {
13999 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
14001 LOGE("failed to change state of videobin to PLAYING");
14002 return MM_ERROR_PLAYER_INTERNAL;
14005 /* already skipped pad block */
14006 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
14009 /* do get/set position for new videosink plugin */
14011 unsigned long position = 0;
14012 gint64 pos_msec = 0;
14014 LOGD("do get/set position for new videosink plugin");
14015 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
14016 LOGE("failed to get position");
14017 return MM_ERROR_PLAYER_INTERNAL;
14019 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
14020 /* accurate seek */
14021 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
14022 LOGE("failed to set position");
14023 return MM_ERROR_PLAYER_INTERNAL;
14026 /* key unit seek */
14027 pos_msec = position * G_GINT64_CONSTANT(1000000);
14028 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
14029 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
14030 GST_SEEK_TYPE_SET, pos_msec,
14031 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
14033 LOGE("failed to set position");
14034 return MM_ERROR_PLAYER_INTERNAL;
14040 gst_object_unref(src_pad_dec);
14041 LOGD("success to change sink");
14045 return MM_ERROR_NONE;
14049 /* Note : if silent is true, then subtitle would not be displayed. :*/
14050 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
14052 mm_player_t* player = (mm_player_t*) hplayer;
14056 /* check player handle */
14057 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14059 player->set_mode.subtitle_off = silent;
14061 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
14065 return MM_ERROR_NONE;
14068 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
14070 MMPlayerGstElement* mainbin = NULL;
14071 MMPlayerGstElement* textbin = NULL;
14072 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14073 GstState current_state = GST_STATE_VOID_PENDING;
14074 GstState element_state = GST_STATE_VOID_PENDING;
14075 GstState element_pending_state = GST_STATE_VOID_PENDING;
14077 GstEvent *event = NULL;
14078 int result = MM_ERROR_NONE;
14080 GstClock *curr_clock = NULL;
14081 GstClockTime base_time, start_time, curr_time;
14086 /* check player handle */
14087 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline , MM_ERROR_PLAYER_NOT_INITIALIZED);
14089 if (!(player->pipeline->mainbin) || !(player->pipeline->textbin)) {
14090 LOGE("Pipeline is not in proper state\n");
14091 result = MM_ERROR_PLAYER_NOT_INITIALIZED;
14095 mainbin = player->pipeline->mainbin;
14096 textbin = player->pipeline->textbin;
14098 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14100 // sync clock with current pipeline
14101 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
14102 curr_time = gst_clock_get_time(curr_clock);
14104 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14105 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
14107 LOGD("base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
14108 GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
14110 if (current_state > GST_STATE_READY) {
14111 // sync state with current pipeline
14112 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
14113 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
14114 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
14116 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
14117 if (GST_STATE_CHANGE_FAILURE == ret)
14118 LOGE("fail to state change.\n");
14121 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
14122 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
14125 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
14126 gst_object_unref(curr_clock);
14129 // seek to current position
14130 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14131 result = MM_ERROR_PLAYER_INVALID_STATE;
14132 LOGE("gst_element_query_position failed, invalid state\n");
14136 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
14137 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);
14139 __gst_send_event_to_sink(player, event);
14141 result = MM_ERROR_PLAYER_INTERNAL;
14142 LOGE("gst_event_new_seek failed\n");
14146 // sync state with current pipeline
14147 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
14148 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
14149 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
14156 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
14158 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
14159 GstState current_state = GST_STATE_VOID_PENDING;
14161 MMHandleType attrs = 0;
14162 MMPlayerGstElement* mainbin = NULL;
14163 MMPlayerGstElement* textbin = NULL;
14165 gchar* subtitle_uri = NULL;
14166 int result = MM_ERROR_NONE;
14167 const gchar *charset = NULL;
14171 /* check player handle */
14172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14173 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
14175 if (!(player->pipeline) || !(player->pipeline->mainbin)) {
14176 result = MM_ERROR_PLAYER_INVALID_STATE;
14177 LOGE("Pipeline is not in proper state\n");
14181 mainbin = player->pipeline->mainbin;
14182 textbin = player->pipeline->textbin;
14184 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14185 if (current_state < GST_STATE_READY) {
14186 result = MM_ERROR_PLAYER_INVALID_STATE;
14187 LOGE("Pipeline is not in proper state\n");
14191 attrs = MMPLAYER_GET_ATTRS(player);
14193 LOGE("cannot get content attribute\n");
14194 result = MM_ERROR_PLAYER_INTERNAL;
14198 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
14199 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
14200 LOGE("subtitle uri is not proper filepath\n");
14201 result = MM_ERROR_PLAYER_INVALID_URI;
14205 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
14206 LOGE("failed to get storage info of subtitle path");
14207 result = MM_ERROR_PLAYER_INVALID_URI;
14211 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
14212 LOGD("new subtitle file path is [%s]\n", filepath);
14214 if (!strcmp(filepath, subtitle_uri)) {
14215 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
14218 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14219 if (mmf_attrs_commit(player->attrs)) {
14220 LOGE("failed to commit.\n");
14225 //gst_pad_set_blocked_async(src-srcpad, TRUE)
14227 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
14228 if (ret != GST_STATE_CHANGE_SUCCESS) {
14229 LOGE("failed to change state of textbin to READY");
14230 result = MM_ERROR_PLAYER_INTERNAL;
14234 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
14235 if (ret != GST_STATE_CHANGE_SUCCESS) {
14236 LOGE("failed to change state of subparse to READY");
14237 result = MM_ERROR_PLAYER_INTERNAL;
14241 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
14242 if (ret != GST_STATE_CHANGE_SUCCESS) {
14243 LOGE("failed to change state of filesrc to READY");
14244 result = MM_ERROR_PLAYER_INTERNAL;
14248 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
14250 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
14252 charset = util_get_charset(filepath);
14254 LOGD("detected charset is %s\n", charset);
14255 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
14258 result = _mmplayer_sync_subtitle_pipeline(player);
14265 /* API to switch between external subtitles */
14266 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
14268 int result = MM_ERROR_NONE;
14269 mm_player_t* player = (mm_player_t*)hplayer;
14273 /* check player handle */
14274 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14276 if (!player->pipeline) {
14278 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14279 if (mmf_attrs_commit(player->attrs)) {
14280 LOGE("failed to commit.\n");
14281 result = MM_ERROR_PLAYER_INTERNAL;
14284 // cur state <> IDLE(READY, PAUSE, PLAYING..)
14285 if (filepath == NULL)
14286 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14288 if (!__mmplayer_check_subtitle(player)) {
14289 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
14290 if (mmf_attrs_commit(player->attrs)) {
14291 LOGE("failed to commit.\n");
14292 result = MM_ERROR_PLAYER_INTERNAL;
14295 if (MM_ERROR_NONE != __mmplayer_gst_create_subtitle_src(player))
14296 LOGE("fail to create subtitle src\n");
14298 result = _mmplayer_sync_subtitle_pipeline(player);
14300 result = __mmplayer_change_external_subtitle_language(player, filepath);
14302 player->is_external_subtitle_added_now = TRUE;
14310 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
14312 int result = MM_ERROR_NONE;
14313 gchar* change_pad_name = NULL;
14314 GstPad* sinkpad = NULL;
14315 MMPlayerGstElement* mainbin = NULL;
14316 enum MainElementID elemId = MMPLAYER_M_NUM;
14317 GstCaps* caps = NULL;
14318 gint total_track_num = 0;
14322 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
14323 MM_ERROR_PLAYER_NOT_INITIALIZED);
14325 LOGD("Change Track(%d) to %d\n", type, index);
14327 mainbin = player->pipeline->mainbin;
14329 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
14330 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
14331 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
14332 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
14334 /* Changing Video Track is not supported. */
14335 LOGE("Track Type Error\n");
14339 if (mainbin[elemId].gst == NULL) {
14340 result = MM_ERROR_PLAYER_NO_OP;
14341 LOGD("Req track doesn't exist\n");
14345 total_track_num = player->selector[type].total_track_num;
14346 if (total_track_num <= 0) {
14347 result = MM_ERROR_PLAYER_NO_OP;
14348 LOGD("Language list is not available \n");
14352 if ((index < 0) || (index >= total_track_num)) {
14353 result = MM_ERROR_INVALID_ARGUMENT;
14354 LOGD("Not a proper index : %d \n", index);
14358 /*To get the new pad from the selector*/
14359 change_pad_name = g_strdup_printf("sink_%u", index);
14360 if (change_pad_name == NULL) {
14361 result = MM_ERROR_PLAYER_INTERNAL;
14362 LOGD("Pad does not exists\n");
14366 LOGD("new active pad name: %s\n", change_pad_name);
14368 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
14369 if (sinkpad == NULL) {
14370 LOGD("sinkpad is NULL");
14371 result = MM_ERROR_PLAYER_INTERNAL;
14375 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
14376 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
14378 caps = gst_pad_get_current_caps(sinkpad);
14379 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
14382 gst_object_unref(sinkpad);
14384 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
14385 __mmplayer_set_audio_attrs(player, caps);
14389 MMPLAYER_FREEIF(change_pad_name);
14393 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
14395 int result = MM_ERROR_NONE;
14396 mm_player_t* player = NULL;
14397 MMPlayerGstElement* mainbin = NULL;
14399 gint current_active_index = 0;
14401 GstState current_state = GST_STATE_VOID_PENDING;
14402 GstEvent* event = NULL;
14407 player = (mm_player_t*)hplayer;
14408 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14410 if (!player->pipeline) {
14411 LOGE("Track %d pre setting -> %d\n", type, index);
14413 player->selector[type].active_pad_index = index;
14417 mainbin = player->pipeline->mainbin;
14419 current_active_index = player->selector[type].active_pad_index;
14421 /*If index is same as running index no need to change the pad*/
14422 if (current_active_index == index)
14425 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
14426 result = MM_ERROR_PLAYER_INVALID_STATE;
14430 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
14431 if (current_state < GST_STATE_PAUSED) {
14432 result = MM_ERROR_PLAYER_INVALID_STATE;
14433 LOGW("Pipeline not in porper state\n");
14437 result = __mmplayer_change_selector_pad(player, type, index);
14438 if (result != MM_ERROR_NONE) {
14439 LOGE("change selector pad error\n");
14443 player->selector[type].active_pad_index = index;
14445 if (current_state == GST_STATE_PLAYING) {
14446 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);
14448 __gst_send_event_to_sink(player, event);
14450 result = MM_ERROR_PLAYER_INTERNAL;
14459 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
14461 mm_player_t* player = (mm_player_t*) hplayer;
14465 /* check player handle */
14466 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14468 *silent = player->set_mode.subtitle_off;
14470 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
14474 return MM_ERROR_NONE;
14478 __is_ms_buff_src(mm_player_t* player)
14480 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14482 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
14486 __has_suffix(mm_player_t* player, const gchar* suffix)
14488 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14489 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
14491 gboolean ret = FALSE;
14492 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
14493 gchar* t_suffix = g_ascii_strdown(suffix, -1);
14495 if (g_str_has_suffix(player->profile.uri, suffix))
14498 MMPLAYER_FREEIF(t_url);
14499 MMPLAYER_FREEIF(t_suffix);
14505 _mmplayer_set_display_zoom(MMHandleType hplayer, float level, int x, int y)
14507 mm_player_t* player = (mm_player_t*) hplayer;
14509 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14511 MMPLAYER_VIDEO_SINK_CHECK(player);
14513 LOGD("setting display zoom level = %f, offset = %d, %d", level, x, y);
14515 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", level, "zoom-pos-x", x, "zoom-pos-y", y, NULL);
14517 return MM_ERROR_NONE;
14520 _mmplayer_get_display_zoom(MMHandleType hplayer, float *level, int *x, int *y)
14523 mm_player_t* player = (mm_player_t*) hplayer;
14524 float _level = 0.0;
14528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14530 MMPLAYER_VIDEO_SINK_CHECK(player);
14532 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "zoom", &_level, "zoom-pos-x", &_x, "zoom-pos-y", &_y, NULL);
14534 LOGD("display zoom level = %f, start off x = %d, y = %d", _level, _x, _y);
14540 return MM_ERROR_NONE;
14544 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
14546 mm_player_t* player = (mm_player_t*) hplayer;
14548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14550 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
14551 MMPLAYER_PRINT_STATE(player);
14552 LOGE("wrong-state : can't set the download mode to parse");
14553 return MM_ERROR_PLAYER_INVALID_STATE;
14556 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
14557 player->video_hub_download_mode = mode;
14559 return MM_ERROR_NONE;
14563 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
14565 mm_player_t* player = (mm_player_t*) hplayer;
14567 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14569 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
14570 player->sync_handler = enable;
14572 return MM_ERROR_NONE;
14576 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
14578 long long clock_delta,
14579 long long video_time,
14580 long long media_clock,
14581 long long audio_time)
14583 mm_player_t* player = (mm_player_t*) hplayer;
14584 MMPlayerGstElement* mainbin = NULL;
14585 GstClockTime start_time_audio = 0, start_time_video = 0;
14586 GstClockTimeDiff base_time = 0, new_base_time = 0;
14587 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14588 gint64 api_delta = 0;
14589 gint64 position = 0, position_delta = 0;
14590 gint64 adj_base_time = 0;
14591 GstClock *curr_clock = NULL;
14592 GstClockTime curr_time = 0;
14593 gboolean query_ret = TRUE;
14594 int result = MM_ERROR_NONE;
14598 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14599 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14600 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14602 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
14604 if ((video_time < 0) || (player->doing_seek)) {
14605 LOGD("skip setting master clock. %lld", video_time);
14609 mainbin = player->pipeline->mainbin;
14611 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14612 curr_time = gst_clock_get_time(curr_clock);
14614 current_state = MMPLAYER_CURRENT_STATE(player);
14616 if (current_state == MM_PLAYER_STATE_PLAYING)
14617 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14619 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
14621 position = player->last_position;
14622 LOGD("query fail. %lld", position);
14625 clock *= GST_USECOND;
14626 clock_delta *= GST_USECOND;
14628 api_delta = clock - curr_time;
14629 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
14630 player->video_share_api_delta = api_delta;
14632 clock_delta += (api_delta - player->video_share_api_delta);
14634 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
14635 player->video_share_clock_delta = (gint64)clock_delta;
14637 position_delta = (position/GST_USECOND) - video_time;
14638 position_delta *= GST_USECOND;
14640 adj_base_time = position_delta;
14641 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
14644 gint64 new_play_time = 0;
14645 gint64 network_delay = 0;
14647 video_time *= GST_USECOND;
14649 network_delay = clock_delta - player->video_share_clock_delta;
14650 new_play_time = video_time + network_delay;
14652 adj_base_time = position - new_play_time;
14654 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
14655 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
14658 /* Adjust Current Stream Time with base_time of sink
14659 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
14660 * 2. Set new base time
14661 * if adj_base_time is positive value, the stream time will be decreased.
14662 * 3. If seek event is occurred, the start time will be reset. */
14663 if ((player->pipeline->audiobin) &&
14664 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
14665 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14667 if (start_time_audio != GST_CLOCK_TIME_NONE) {
14668 LOGD("audio sink : gst_element_set_start_time -> NONE");
14669 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
14672 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
14675 if ((player->pipeline->videobin) &&
14676 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
14677 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14679 if (start_time_video != GST_CLOCK_TIME_NONE) {
14680 LOGD("video sink : gst_element_set_start_time -> NONE");
14681 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
14684 // if videobin exist, get base_time from videobin.
14685 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
14688 new_base_time = base_time + adj_base_time;
14690 if ((player->pipeline->audiobin) &&
14691 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
14692 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
14694 if ((player->pipeline->videobin) &&
14695 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
14696 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
14705 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
14706 long long *video_time,
14707 long long *media_clock,
14708 long long *audio_time)
14710 mm_player_t* player = (mm_player_t*) hplayer;
14711 MMPlayerGstElement* mainbin = NULL;
14712 GstClock *curr_clock = NULL;
14713 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
14714 gint64 position = 0;
14715 gboolean query_ret = TRUE;
14719 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
14720 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
14721 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
14723 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14724 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
14725 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
14727 mainbin = player->pipeline->mainbin;
14729 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
14731 current_state = MMPLAYER_CURRENT_STATE(player);
14733 if (current_state != MM_PLAYER_STATE_PAUSED)
14734 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
14736 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
14738 position = player->last_position;
14740 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
14742 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
14745 gst_object_unref(curr_clock);
14749 return MM_ERROR_NONE;
14753 _mmplayer_get_video_rotate_angle(MMHandleType hplayer, int *angle)
14755 mm_player_t* player = (mm_player_t*) hplayer;
14760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14761 MMPLAYER_RETURN_VAL_IF_FAIL(angle, MM_ERROR_COMMON_INVALID_ARGUMENT);
14763 if (player->v_stream_caps) {
14764 GstStructure *str = NULL;
14766 str = gst_caps_get_structure(player->v_stream_caps, 0);
14767 if (!gst_structure_get_int(str, "orientation", &org_angle))
14768 LOGD("missing 'orientation' field in video caps");
14771 LOGD("orientation: %d", org_angle);
14772 *angle = org_angle;
14775 return MM_ERROR_NONE;
14779 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
14781 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14782 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
14784 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
14785 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
14789 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
14790 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
14791 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
14792 mm_player_dump_t *dump_s;
14793 dump_s = g_malloc(sizeof(mm_player_dump_t));
14795 if (dump_s == NULL) {
14796 LOGE("malloc fail");
14800 dump_s->dump_element_file = NULL;
14801 dump_s->dump_pad = NULL;
14802 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
14804 if (dump_s->dump_pad) {
14805 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
14806 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]);
14807 dump_s->dump_element_file = fopen(dump_file_name, "w+");
14808 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);
14809 /* add list for removed buffer probe and close FILE */
14810 player->dump_list = g_list_append(player->dump_list, dump_s);
14811 LOGD("%s sink pad added buffer probe for dump", factory_name);
14816 LOGE("failed to get %s sink pad added", factory_name);
14825 static GstPadProbeReturn
14826 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
14828 FILE *dump_data = (FILE *) u_data;
14829 // int written = 0;
14830 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
14831 GstMapInfo probe_info = GST_MAP_INFO_INIT;
14833 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
14835 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
14837 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
14839 fwrite(probe_info.data, 1, probe_info.size , dump_data);
14841 return GST_PAD_PROBE_OK;
14845 __mmplayer_release_dump_list(GList *dump_list)
14848 GList *d_list = dump_list;
14849 for (; d_list; d_list = g_list_next(d_list)) {
14850 mm_player_dump_t *dump_s = d_list->data;
14851 if (dump_s->dump_pad) {
14852 if (dump_s->probe_handle_id)
14853 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
14855 if (dump_s->dump_element_file) {
14856 fclose(dump_s->dump_element_file);
14857 dump_s->dump_element_file = NULL;
14859 MMPLAYER_FREEIF(dump_s);
14861 g_list_free(dump_list);
14867 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
14869 mm_player_t* player = (mm_player_t*) hplayer;
14873 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14874 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
14876 *exist = player->has_closed_caption;
14880 return MM_ERROR_NONE;
14883 void * _mm_player_media_packet_video_stream_internal_buffer_ref(void *buffer)
14887 /* increase ref count of gst buffer */
14889 ret = gst_buffer_ref((GstBuffer *)buffer);
14895 void _mm_player_media_packet_video_stream_internal_buffer_unref(void *buffer)
14899 gst_buffer_unref((GstBuffer *)buffer);
14906 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14908 mm_player_t *player = (mm_player_t*)user_data;
14909 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14910 guint64 current_level_bytes = 0;
14912 MMPLAYER_RETURN_IF_FAIL(player);
14914 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14916 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14917 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14919 if (player->media_stream_buffer_status_cb[type])
14920 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14921 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14926 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
14928 mm_player_t *player = (mm_player_t*)user_data;
14929 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14930 guint64 current_level_bytes = 0;
14932 MMPLAYER_RETURN_IF_FAIL(player);
14934 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14936 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
14938 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14939 if (player->media_stream_buffer_status_cb[type])
14940 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14941 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14945 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
14947 mm_player_t *player = (mm_player_t*)user_data;
14948 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14949 guint64 current_level_bytes = 0;
14951 MMPLAYER_RETURN_IF_FAIL(player);
14953 LOGI("app-src: feed subtitle\n");
14955 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14957 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14958 if (player->media_stream_buffer_status_cb[type])
14959 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param);
14961 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14965 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
14967 mm_player_t *player = (mm_player_t*)user_data;
14968 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14969 guint64 current_level_bytes = 0;
14971 MMPLAYER_RETURN_IF_FAIL(player);
14973 LOGI("app-src: audio buffer is full.\n");
14975 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14977 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14979 if (player->media_stream_buffer_status_cb[type])
14980 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
14982 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14986 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
14988 mm_player_t *player = (mm_player_t*)user_data;
14989 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14990 guint64 current_level_bytes = 0;
14992 MMPLAYER_RETURN_IF_FAIL(player);
14994 LOGI("app-src: video buffer is full.\n");
14996 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14998 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14999 if (player->media_stream_buffer_status_cb[type])
15000 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param);
15002 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15006 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
15008 mm_player_t *player = (mm_player_t*)user_data;
15009 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
15011 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15013 LOGD("app-src: seek audio data %llu\n", position);
15014 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15016 if (player->media_stream_seek_data_cb[type])
15017 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15018 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15024 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
15026 mm_player_t *player = (mm_player_t*)user_data;
15027 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
15029 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15031 LOGD("app-src: seek video data %llu\n", position);
15032 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15033 if (player->media_stream_seek_data_cb[type])
15034 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15035 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15041 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
15043 mm_player_t *player = (mm_player_t*)user_data;
15044 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
15046 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
15048 LOGD("app-src: seek subtitle data\n");
15049 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
15051 if (player->media_stream_seek_data_cb[type])
15052 player->media_stream_seek_data_cb[type](type, position, player->buffer_cb_user_param);
15053 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
15059 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
15061 mm_player_t* player = (mm_player_t*) hplayer;
15065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15067 player->pcm_samplerate = samplerate;
15068 player->pcm_channel = channel;
15071 return MM_ERROR_NONE;
15074 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
15076 mm_player_t* player = (mm_player_t*) hplayer;
15080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15081 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
15083 if (MMPLAYER_IS_STREAMING(player))
15084 *timeout = player->ini.live_state_change_timeout;
15086 *timeout = player->ini.localplayback_state_change_timeout;
15088 LOGD("timeout = %d\n", *timeout);
15091 return MM_ERROR_NONE;
15094 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
15096 mm_player_t* player = (mm_player_t*) hplayer;
15100 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15101 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
15103 *num = player->video_num_buffers;
15104 *extra_num = player->video_extra_num_buffers;
15106 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
15109 return MM_ERROR_NONE;
15113 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
15117 MMPLAYER_RETURN_IF_FAIL(player);
15119 for (i=0; i<MMPLAYER_PATH_MAX; i++) {
15121 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
15122 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
15123 player->storage_info[i].state = STORAGE_STATE_MOUNTED;
15124 player->storage_info[i].id = -1;
15126 if (path_type != MMPLAYER_PATH_MAX)
15134 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int state)
15136 int ret = MM_ERROR_NONE;
15137 mm_player_t* player = (mm_player_t*) hplayer;
15138 MMMessageParamType msg_param = {0, };
15141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
15143 LOGD("storage state : %d", state);
15145 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
15146 return MM_ERROR_NONE;
15148 if ((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) ||
15149 (player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)) {
15150 LOGW("external storage is removed.");
15152 if (player->msg_posted == FALSE) {
15153 memset(&msg_param, 0, sizeof(MMMessageParamType));
15154 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
15155 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
15156 player->msg_posted = TRUE;
15159 /* unrealize the player */
15160 ret = _mmplayer_unrealize(hplayer);
15161 if (ret != MM_ERROR_NONE)
15162 LOGE("failed to unrealize");