4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.h>
44 #include <mm_sound_focus.h>
46 #include "mm_player_priv.h"
47 #include "mm_player_ini.h"
48 #include "mm_player_attrs.h"
49 #include "mm_player_capture.h"
50 #include "mm_player_utils.h"
51 #include "mm_player_tracks.h"
52 #include "mm_player_360.h"
54 #include <system_info.h>
55 #include <sound_manager.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
91 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
93 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
94 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
95 (player->ini.http_use_file_buffer) && \
96 (player->http_file_buffering_path) && \
97 (strlen(player->http_file_buffering_path) > 0))
99 #define PLAYER_DISPLAY_MODE_DST_ROI 5
101 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
103 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
104 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 100
106 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
108 /*---------------------------------------------------------------------------
109 | LOCAL CONSTANT DEFINITIONS: |
110 ---------------------------------------------------------------------------*/
112 /*---------------------------------------------------------------------------
113 | LOCAL DATA TYPE DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | GLOBAL VARIABLE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | LOCAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
123 static sound_stream_info_h stream_info;
125 /*---------------------------------------------------------------------------
126 | LOCAL FUNCTION PROTOTYPES: |
127 ---------------------------------------------------------------------------*/
128 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
129 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
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_text_sink_bin(mm_player_t* player);
134 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
136 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
137 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
138 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
139 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
140 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
141 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
142 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
143 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
144 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
145 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
146 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
147 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
148 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
149 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
150 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
151 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
152 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
154 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
155 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
156 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
157 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static void __mmplayer_release_misc(mm_player_t* player);
159 static void __mmplayer_release_misc_post(mm_player_t* player);
160 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
161 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
162 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
163 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
164 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
165 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
166 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
169 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
172 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
173 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
174 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
175 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
176 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
177 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
178 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
179 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
180 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
181 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
182 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
183 static gpointer __mmplayer_next_play_thread(gpointer data);
184 static gpointer __mmplayer_repeat_thread(gpointer data);
185 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
187 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
188 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
189 static void __mmplayer_release_dump_list(GList *dump_list);
191 static int __gst_realize(mm_player_t* player);
192 static int __gst_unrealize(mm_player_t* player);
193 static int __gst_start(mm_player_t* player);
194 static int __gst_stop(mm_player_t* player);
195 static int __gst_pause(mm_player_t* player, gboolean async);
196 static int __gst_resume(mm_player_t* player, gboolean async);
197 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
198 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
199 gint64 cur, GstSeekType stop_type, gint64 stop);
200 static int __gst_pending_seek(mm_player_t* player);
202 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
203 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
204 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
205 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
206 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
208 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
210 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
211 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
214 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
215 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
218 static gboolean __is_ms_buff_src(mm_player_t* player);
219 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
221 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
222 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
223 static int __mmplayer_start_streaming_ext(mm_player_t *player);
224 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
225 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
227 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
228 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
229 static void __mmplayer_check_pipeline(mm_player_t* player);
230 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
231 static void __mmplayer_deactivate_old_path(mm_player_t *player);
233 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
234 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
236 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
237 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
238 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
239 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
240 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
241 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
242 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
243 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
247 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
248 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
249 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
250 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
251 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
253 /*===========================================================================================
255 | FUNCTION DEFINITIONS |
257 ========================================================================================== */
261 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
265 count = gst_tag_list_get_tag_size(list, tag);
267 LOGD("count = %d", count);
269 for (i = 0; i < count; i++) {
272 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
273 if (!gst_tag_list_get_string_index(list, tag, i, &str))
274 g_assert_not_reached();
276 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
279 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
281 g_print(" : %s\n", str);
288 /* This function should be called after the pipeline goes PAUSED or higher
291 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
293 static gboolean has_duration = FALSE;
294 static gboolean has_video_attrs = FALSE;
295 static gboolean has_audio_attrs = FALSE;
296 static gboolean has_bitrate = FALSE;
297 gboolean missing_only = FALSE;
298 gboolean all = FALSE;
300 GstStructure* p = NULL;
301 MMHandleType attrs = 0;
303 MMStreamingType stream_service_type = STREAMING_SERVICE_NONE;
308 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
310 /* check player state here */
311 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
312 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
313 /* give warning now only */
314 LOGW("be careful. content attributes may not available in this state ");
317 /* get content attribute first */
318 attrs = MMPLAYER_GET_ATTRS(player);
320 LOGE("cannot get content attribute");
324 /* get update flag */
326 if (flag & ATTR_MISSING_ONLY) {
328 LOGD("updating missed attr only");
331 if (flag & ATTR_ALL) {
333 has_duration = FALSE;
334 has_video_attrs = FALSE;
335 has_audio_attrs = FALSE;
338 LOGD("updating all attrs");
341 if (missing_only && all) {
342 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
343 missing_only = FALSE;
346 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
347 LOGD("try to update duration");
348 has_duration = FALSE;
350 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
351 player->duration = dur_nsec;
352 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
355 if (player->duration < 0) {
356 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
357 player->duration = 0;
360 /* try to get streaming service type */
361 stream_service_type = __mmplayer_get_stream_service_type(player);
362 if (stream_service_type < STREAMING_SERVICE_NONE)
363 mm_attrs_set_int_by_name(attrs, "streaming_type", stream_service_type);
365 /* check duration is OK */
366 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
367 /* FIXIT : find another way to get duration here. */
368 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
371 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
376 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
377 /* update audio params
378 NOTE : We need original audio params and it can be only obtained from src pad of audio
379 decoder. Below code only valid when we are not using 'resampler' just before
382 LOGD("try to update audio attrs");
383 has_audio_attrs = FALSE;
385 if (player->pipeline->audiobin &&
386 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
387 GstCaps *caps_a = NULL;
389 gint samplerate = 0, channels = 0;
391 pad = gst_element_get_static_pad(
392 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
395 caps_a = gst_pad_get_current_caps(pad);
398 p = gst_caps_get_structure(caps_a, 0);
400 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
402 gst_structure_get_int(p, "rate", &samplerate);
403 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
405 gst_structure_get_int(p, "channels", &channels);
406 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
408 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
410 gst_caps_unref(caps_a);
413 has_audio_attrs = TRUE;
415 LOGW("not ready to get audio caps");
417 gst_object_unref(pad);
419 LOGW("failed to get pad from audiosink");
423 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
424 LOGD("try to update video attrs");
425 has_video_attrs = FALSE;
427 if (player->pipeline->videobin &&
428 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
429 GstCaps *caps_v = NULL;
434 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
436 caps_v = gst_pad_get_current_caps(pad);
438 /* Use v_stream_caps, if fail to get video_sink sink pad*/
439 if (!caps_v && player->v_stream_caps) {
440 caps_v = player->v_stream_caps;
441 gst_caps_ref(caps_v);
445 p = gst_caps_get_structure(caps_v, 0);
446 gst_structure_get_int(p, "width", &width);
447 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
449 gst_structure_get_int(p, "height", &height);
450 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
452 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
454 SECURE_LOGD("width : %d height : %d", width, height);
456 gst_caps_unref(caps_v);
460 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
461 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
464 has_video_attrs = TRUE;
466 LOGD("no negitiated caps from videosink");
467 gst_object_unref(pad);
470 LOGD("no videosink sink pad");
475 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
478 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
479 if (player->duration) {
480 guint64 data_size = 0;
482 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
483 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
485 if (stat(path, &sb) == 0)
486 data_size = (guint64)sb.st_size;
487 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
488 data_size = player->http_content_size;
490 LOGD("try to update bitrate : data_size = %lld", data_size);
494 guint64 msec_dur = 0;
496 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
498 bitrate = data_size * 8 * 1000 / msec_dur;
499 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
500 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
504 LOGD("player duration is less than 0");
508 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
509 if (player->total_bitrate) {
510 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
518 if (mmf_attrs_commit(attrs)) {
519 LOGE("failed to update attributes\n");
528 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
530 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
534 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
536 player->pipeline->mainbin &&
537 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
538 STREAMING_SERVICE_NONE);
540 /* streaming service type if streaming */
541 if (!MMPLAYER_IS_STREAMING(player))
542 return STREAMING_SERVICE_NONE;
544 if (MMPLAYER_IS_HTTP_STREAMING(player))
545 streaming_type = (player->duration == 0) ?
546 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
548 switch (streaming_type) {
549 case STREAMING_SERVICE_LIVE:
550 LOGD("it's live streaming");
552 case STREAMING_SERVICE_VOD:
553 LOGD("it's vod streaming");
556 LOGE("should not get here");
559 player->streaming_type = streaming_type;
562 return streaming_type;
566 /* this function sets the player state and also report
567 * it to applicaton by calling callback function
570 __mmplayer_set_state(mm_player_t* player, int state)
572 MMMessageParamType msg = {0, };
573 int sound_result = MM_ERROR_NONE;
574 gboolean post_bos = FALSE;
575 gboolean interrupted_by_focus = FALSE;
577 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
579 if (MMPLAYER_CURRENT_STATE(player) == state) {
580 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
581 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
582 return MM_ERROR_NONE;
585 /* update player states */
586 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
587 MMPLAYER_CURRENT_STATE(player) = state;
589 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
590 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
593 MMPLAYER_PRINT_STATE(player);
595 /* do some FSM stuffs before posting new state to application */
596 interrupted_by_focus = player->sound_focus.by_asm_cb;
598 switch (MMPLAYER_CURRENT_STATE(player)) {
599 case MM_PLAYER_STATE_NULL:
600 case MM_PLAYER_STATE_READY:
602 if (player->cmd == MMPLAYER_COMMAND_STOP) {
603 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
604 if (sound_result != MM_ERROR_NONE) {
605 LOGE("failed to release sound focus\n");
606 return MM_ERROR_POLICY_INTERNAL;
612 case MM_PLAYER_STATE_PAUSED:
614 if (!player->sent_bos) {
616 #define MMPLAYER_MAX_SOUND_PRIORITY 3
618 /* rtsp case, get content attrs by GstMessage */
619 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
620 /* it's first time to update all content attrs. */
621 _mmplayer_update_content_attrs(player, ATTR_ALL);
624 /* set max sound priority to keep own sound and not to mute other's one */
625 mm_attrs_get_int_by_name(player->attrs, "content_video_found", &found);
627 mm_attrs_get_int_by_name(player->attrs, "content_audio_found", &found);
629 LOGD("set max audio priority");
630 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "priority", MMPLAYER_MAX_SOUND_PRIORITY, NULL);
636 /* add audio callback probe if condition is satisfied */
637 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
638 __mmplayer_configure_audio_callback(player);
639 /* FIXIT : handle return value */
641 if (!MMPLAYER_IS_STREAMING(player) || (player->streamer && !player->streamer->is_buffering)) {
642 sound_result = _mmplayer_sound_release_focus(&player->sound_focus);
643 if (sound_result != MM_ERROR_NONE) {
644 LOGE("failed to release sound focus\n");
645 return MM_ERROR_POLICY_INTERNAL;
651 case MM_PLAYER_STATE_PLAYING:
653 /* try to get content metadata */
654 if (!player->sent_bos) {
655 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
656 * c-api since c-api doesn't use _start() anymore. It may not work propery with
657 * legacy mmfw-player api */
658 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
661 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
662 if (!player->sent_bos)
663 __mmplayer_handle_missed_plugin(player);
664 sound_result = _mmplayer_sound_acquire_focus(&player->sound_focus);
665 if (sound_result != MM_ERROR_NONE) {
666 // FIXME : need to check history
667 if (player->pipeline->videobin) {
668 MMMessageParamType msg = {0, };
670 LOGE("failed to go ahead because of video conflict\n");
672 msg.union_type = MM_MSG_UNION_CODE;
673 msg.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
674 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
676 _mmplayer_unrealize((MMHandleType)player);
678 LOGE("failed to play by sound focus error : 0x%X\n", sound_result);
679 _mmplayer_pause((MMHandleType)player);
682 return MM_ERROR_POLICY_INTERNAL;
686 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
687 /* initialize because auto resume is done well. */
688 player->resumed_by_rewind = FALSE;
689 player->playback_rate = 1.0;
692 if (!player->sent_bos) {
693 /* check audio codec field is set or not
694 * we can get it from typefinder or codec's caps.
696 gchar *audio_codec = NULL;
697 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
699 /* The codec format can't be sent for audio only case like amr, mid etc.
700 * Because, parser don't make related TAG.
701 * So, if it's not set yet, fill it with found data.
704 if (g_strrstr(player->type, "audio/midi"))
705 audio_codec = g_strdup("MIDI");
706 else if (g_strrstr(player->type, "audio/x-amr"))
707 audio_codec = g_strdup("AMR");
708 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
709 audio_codec = g_strdup("AAC");
711 audio_codec = g_strdup("unknown");
712 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
714 MMPLAYER_FREEIF(audio_codec);
715 if (mmf_attrs_commit(player->attrs))
716 LOGE("failed to update attributes\n");
718 LOGD("set audio codec type with caps\n");
726 case MM_PLAYER_STATE_NONE:
728 LOGW("invalid target state, there is nothing to do.\n");
733 /* post message to application */
734 if (MMPLAYER_TARGET_STATE(player) == state) {
735 /* fill the message with state of player */
736 msg.union_type = MM_MSG_UNION_STATE;
737 msg.state.previous = MMPLAYER_PREV_STATE(player);
738 msg.state.current = MMPLAYER_CURRENT_STATE(player);
740 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
742 /* state changed by focus or resource callback */
743 if (interrupted_by_focus || player->interrupted_by_resource) {
744 if (interrupted_by_focus)
745 msg.state.code = player->sound_focus.focus_changed_msg;
746 else if (player->interrupted_by_resource)
747 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
748 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
749 } else { /* state changed by usecase */
750 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
753 LOGD("intermediate state, do nothing.\n");
754 MMPLAYER_PRINT_STATE(player);
755 return MM_ERROR_NONE;
759 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
760 player->sent_bos = TRUE;
763 return MM_ERROR_NONE;
766 static gpointer __mmplayer_next_play_thread(gpointer data)
768 mm_player_t* player = (mm_player_t*) data;
769 MMPlayerGstElement *mainbin = NULL;
771 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
773 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
774 while (!player->next_play_thread_exit) {
775 LOGD("next play thread started. waiting for signal.\n");
776 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
778 LOGD("reconfigure pipeline for gapless play.\n");
780 if (player->next_play_thread_exit) {
781 if (player->gapless.reconfigure) {
782 player->gapless.reconfigure = false;
783 MMPLAYER_PLAYBACK_UNLOCK(player);
785 LOGD("exiting gapless play thread\n");
789 mainbin = player->pipeline->mainbin;
791 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
792 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
793 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
794 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
795 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
797 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
799 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
804 static gpointer __mmplayer_repeat_thread(gpointer data)
806 mm_player_t* player = (mm_player_t*) data;
807 gboolean ret_value = FALSE;
808 MMHandleType attrs = 0;
811 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
813 MMPLAYER_REPEAT_THREAD_LOCK(player);
814 while (!player->repeat_thread_exit) {
815 LOGD("repeat thread started. waiting for signal.\n");
816 MMPLAYER_REPEAT_THREAD_WAIT(player);
818 if (player->repeat_thread_exit) {
819 LOGD("exiting repeat thread\n");
825 MMPLAYER_CMD_LOCK(player);
827 attrs = MMPLAYER_GET_ATTRS(player);
829 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE) {
830 LOGE("can not get play count\n");
831 MMPLAYER_CMD_UNLOCK(player);
835 if (player->section_repeat) {
836 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
838 if (player->playback_rate < 0.0) {
839 player->resumed_by_rewind = TRUE;
840 _mmplayer_set_mute((MMHandleType)player, 0);
841 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
844 ret_value = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
845 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
846 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
849 player->sent_bos = FALSE;
853 LOGE("failed to set position to zero for rewind\n");
854 MMPLAYER_CMD_UNLOCK(player);
858 /* decrease play count */
860 /* we successeded to rewind. update play count and then wait for next EOS */
863 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
865 /* commit attribute */
866 if (mmf_attrs_commit(attrs))
867 LOGE("failed to commit attribute\n");
871 MMPLAYER_CMD_UNLOCK(player);
874 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
879 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
881 MMHandleType attrs = 0;
882 guint64 data_size = 0;
884 unsigned long pos_msec = 0;
887 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
889 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
891 attrs = MMPLAYER_GET_ATTRS(player);
893 LOGE("fail to get attributes.\n");
897 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
898 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
900 if (stat(path, &sb) == 0)
901 data_size = (guint64)sb.st_size;
902 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
903 data_size = player->http_content_size;
905 __mm_player_streaming_buffering(player->streamer,
908 player->last_position,
911 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
917 __mmplayer_handle_buffering_message(mm_player_t* player)
919 int ret = MM_ERROR_NONE;
920 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
921 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
922 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
923 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
925 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
926 LOGW("do nothing for buffering msg\n");
927 ret = MM_ERROR_PLAYER_INVALID_STATE;
931 prev_state = MMPLAYER_PREV_STATE(player);
932 current_state = MMPLAYER_CURRENT_STATE(player);
933 target_state = MMPLAYER_TARGET_STATE(player);
934 pending_state = MMPLAYER_PENDING_STATE(player);
936 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
937 MMPLAYER_STATE_GET_NAME(prev_state),
938 MMPLAYER_STATE_GET_NAME(current_state),
939 MMPLAYER_STATE_GET_NAME(pending_state),
940 MMPLAYER_STATE_GET_NAME(target_state),
941 player->streamer->is_buffering);
943 if (!player->streamer->is_buffering) {
944 /* NOTE : if buffering has done, player has to go to target state. */
945 switch (target_state) {
946 case MM_PLAYER_STATE_PAUSED:
948 switch (pending_state) {
949 case MM_PLAYER_STATE_PLAYING:
950 __gst_pause(player, TRUE);
953 case MM_PLAYER_STATE_PAUSED:
954 LOGD("player is already going to paused state, there is nothing to do.\n");
957 case MM_PLAYER_STATE_NONE:
958 case MM_PLAYER_STATE_NULL:
959 case MM_PLAYER_STATE_READY:
961 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
967 case MM_PLAYER_STATE_PLAYING:
969 switch (pending_state) {
970 case MM_PLAYER_STATE_NONE:
972 if (current_state != MM_PLAYER_STATE_PLAYING)
973 __gst_resume(player, TRUE);
977 case MM_PLAYER_STATE_PAUSED:
978 /* NOTE: It should be worked as asynchronously.
979 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
981 __gst_resume(player, TRUE);
984 case MM_PLAYER_STATE_PLAYING:
985 LOGD("player is already going to playing state, there is nothing to do.\n");
988 case MM_PLAYER_STATE_NULL:
989 case MM_PLAYER_STATE_READY:
991 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
997 case MM_PLAYER_STATE_NULL:
998 case MM_PLAYER_STATE_READY:
999 case MM_PLAYER_STATE_NONE:
1001 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1005 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1006 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1008 switch (pending_state) {
1009 case MM_PLAYER_STATE_NONE:
1011 if (current_state != MM_PLAYER_STATE_PAUSED) {
1012 /* rtsp streaming pause makes rtsp server stop sending data. */
1013 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1014 LOGD("set pause state during buffering\n");
1015 __gst_pause(player, TRUE);
1021 case MM_PLAYER_STATE_PLAYING:
1022 /* rtsp streaming pause makes rtsp server stop sending data. */
1023 if (!MMPLAYER_IS_RTSP_STREAMING(player))
1024 __gst_pause(player, TRUE);
1027 case MM_PLAYER_STATE_PAUSED:
1030 case MM_PLAYER_STATE_NULL:
1031 case MM_PLAYER_STATE_READY:
1033 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1043 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1045 MMPlayerGstElement *textbin;
1048 MMPLAYER_RETURN_IF_FAIL(player &&
1050 player->pipeline->textbin);
1052 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1054 textbin = player->pipeline->textbin;
1057 LOGD("Drop subtitle text after getting EOS\n");
1059 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
1060 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1062 player->is_subtitle_force_drop = TRUE;
1064 if (player->is_subtitle_force_drop == TRUE) {
1065 LOGD("Enable subtitle data path without drop\n");
1067 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1068 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
1070 LOGD("non-connected with external display");
1072 player->is_subtitle_force_drop = FALSE;
1077 static VariantData *
1078 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1080 VariantData *var_info = NULL;
1081 g_return_val_if_fail(self != NULL, NULL);
1083 var_info = g_new0(VariantData, 1);
1084 if (!var_info) return NULL;
1085 var_info->bandwidth = self->bandwidth;
1086 var_info->width = self->width;
1087 var_info->height = self->height;
1091 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
1093 mm_player_t* player = (mm_player_t*)hplayer;
1096 MMPLAYER_RETURN_IF_FAIL(player);
1098 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1100 /* destroy the gst bus msg thread */
1101 if (player->bus_msg_thread) {
1102 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1103 player->bus_msg_thread_exit = TRUE;
1104 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1105 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1107 LOGD("gst bus msg thread exit.");
1108 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
1109 player->bus_msg_thread = NULL;
1111 g_mutex_clear(&player->bus_msg_thread_mutex);
1112 g_cond_clear(&player->bus_msg_thread_cond);
1118 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1120 mm_player_t *player = (mm_player_t*)(data);
1121 GstMessage *msg = NULL;
1125 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1127 player->pipeline->mainbin &&
1128 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1131 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1133 LOGE("cannot get BUS from the pipeline");
1137 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1139 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1140 while (!player->bus_msg_thread_exit) {
1141 msg = gst_bus_pop(bus);
1143 int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1144 MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1148 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1149 /* handle the gst msg */
1150 __mmplayer_gst_callback(msg, player);
1151 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1152 gst_message_unref(msg);
1155 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1156 gst_object_unref(GST_OBJECT(bus));
1163 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1165 mm_player_t* player = (mm_player_t*)(data);
1166 static gboolean async_done = FALSE;
1168 MMPLAYER_RETURN_IF_FAIL(player);
1169 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1171 switch (GST_MESSAGE_TYPE(msg)) {
1172 case GST_MESSAGE_UNKNOWN:
1173 LOGD("unknown message received\n");
1176 case GST_MESSAGE_EOS:
1178 MMHandleType attrs = 0;
1181 LOGD("GST_MESSAGE_EOS received\n");
1183 /* NOTE : EOS event is comming multiple time. watch out it */
1184 /* check state. we only process EOS when pipeline state goes to PLAYING */
1185 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1186 LOGD("EOS received on non-playing state. ignoring it\n");
1190 if (player->pipeline) {
1191 if (player->pipeline->textbin)
1192 __mmplayer_drop_subtitle(player, TRUE);
1194 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1197 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1199 LOGD("release audio callback\n");
1201 /* release audio callback */
1202 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1203 player->audio_cb_probe_id = 0;
1204 /* audio callback should be free because it can be called even though probe remove.*/
1205 player->audio_stream_cb = NULL;
1206 player->audio_stream_cb_user_param = NULL;
1210 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1211 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1213 /* rewind if repeat count is greater then zero */
1214 /* get play count */
1215 attrs = MMPLAYER_GET_ATTRS(player);
1218 gboolean smooth_repeat = FALSE;
1220 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1221 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1223 player->play_count = count;
1225 LOGD("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1227 if (count > 1 || count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1228 if (smooth_repeat) {
1229 LOGD("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1231 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
1237 if (player->section_repeat) {
1238 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1240 if (player->playback_rate < 0.0) {
1241 player->resumed_by_rewind = TRUE;
1242 _mmplayer_set_mute((MMHandleType)player, 0);
1243 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1246 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1249 player->sent_bos = FALSE;
1252 if (MM_ERROR_NONE != ret_value)
1253 LOGE("failed to set position to zero for rewind\n");
1255 /* not posting eos when repeating */
1261 if (player->pipeline)
1262 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1264 /* post eos message to application */
1265 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1267 /* reset last position */
1268 player->last_position = 0;
1272 case GST_MESSAGE_ERROR:
1274 GError *error = NULL;
1275 gchar* debug = NULL;
1277 /* generating debug info before returning error */
1278 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1280 /* get error code */
1281 gst_message_parse_error(msg, &error, &debug);
1283 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1284 /* Note : the streaming error from the streaming source is handled
1285 * using __mmplayer_handle_streaming_error.
1287 __mmplayer_handle_streaming_error(player, msg);
1289 /* dump state of all element */
1290 __mmplayer_dump_pipeline_state(player);
1292 /* traslate gst error code to msl error code. then post it
1293 * to application if needed
1295 __mmplayer_handle_gst_error(player, msg, error);
1298 LOGE("error debug : %s", debug);
1301 if (MMPLAYER_IS_HTTP_PD(player))
1302 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1304 MMPLAYER_FREEIF(debug);
1305 g_error_free(error);
1309 case GST_MESSAGE_WARNING:
1312 GError* error = NULL;
1314 gst_message_parse_warning(msg, &error, &debug);
1316 LOGD("warning : %s\n", error->message);
1317 LOGD("debug : %s\n", debug);
1319 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1321 MMPLAYER_FREEIF(debug);
1322 g_error_free(error);
1326 case GST_MESSAGE_TAG:
1328 LOGD("GST_MESSAGE_TAG\n");
1329 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1330 LOGW("failed to extract tags from gstmessage\n");
1334 case GST_MESSAGE_BUFFERING:
1336 MMMessageParamType msg_param = {0, };
1337 int bRet = MM_ERROR_NONE;
1339 if (!(player->pipeline && player->pipeline->mainbin)) {
1340 LOGE("player pipeline handle is null");
1344 if (!MMPLAYER_IS_STREAMING(player))
1347 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1348 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1349 /* skip the playback control by buffering msg while user request is handled. */
1352 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1354 gst_message_parse_buffering(msg, &per);
1355 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1357 msg_param.connection.buffering = per;
1358 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1362 MMPLAYER_CMD_LOCK(player);
1365 /* ignore the prev buffering message */
1366 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1367 && (player->streamer->is_buffering_done == TRUE)) {
1368 gint buffer_percent = 0;
1370 gst_message_parse_buffering(msg, &buffer_percent);
1372 if (buffer_percent == MAX_BUFFER_PERCENT) {
1373 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1374 player->streamer->is_buffering_done = FALSE;
1376 MMPLAYER_CMD_UNLOCK(player);
1380 __mmplayer_update_buffer_setting(player, msg);
1382 bRet = __mmplayer_handle_buffering_message(player);
1384 if (bRet == MM_ERROR_NONE) {
1385 msg_param.connection.buffering = player->streamer->buffering_percent;
1386 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1388 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1389 player->pending_resume &&
1390 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1392 player->is_external_subtitle_added_now = FALSE;
1393 player->pending_resume = FALSE;
1394 _mmplayer_resume((MMHandleType)player);
1397 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1398 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1400 if (player->doing_seek) {
1401 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1402 player->doing_seek = FALSE;
1403 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1404 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1409 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1410 if (!player->streamer) {
1411 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1412 MMPLAYER_CMD_UNLOCK(player);
1416 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1418 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1419 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1421 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1422 msg_param.connection.buffering = player->streamer->buffering_percent;
1423 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1425 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1428 msg_param.connection.buffering = player->streamer->buffering_percent;
1429 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1432 MMPLAYER_CMD_UNLOCK(player);
1436 case GST_MESSAGE_STATE_CHANGED:
1438 MMPlayerGstElement *mainbin;
1439 const GValue *voldstate, *vnewstate, *vpending;
1440 GstState oldstate = GST_STATE_NULL;
1441 GstState newstate = GST_STATE_NULL;
1442 GstState pending = GST_STATE_NULL;
1444 if (!(player->pipeline && player->pipeline->mainbin)) {
1445 LOGE("player pipeline handle is null");
1449 mainbin = player->pipeline->mainbin;
1451 /* we only handle messages from pipeline */
1452 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1455 /* get state info from msg */
1456 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1457 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1458 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1460 if (!voldstate || !vnewstate) {
1461 LOGE("received msg has wrong format.");
1465 oldstate = (GstState)voldstate->data[0].v_int;
1466 newstate = (GstState)vnewstate->data[0].v_int;
1468 pending = (GstState)vpending->data[0].v_int;
1470 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1471 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1472 gst_element_state_get_name((GstState)oldstate),
1473 gst_element_state_get_name((GstState)newstate),
1474 gst_element_state_get_name((GstState)pending));
1476 if (newstate == GST_STATE_PLAYING) {
1477 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1479 int retVal = MM_ERROR_NONE;
1480 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1482 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1484 if (MM_ERROR_NONE != retVal)
1485 LOGE("failed to seek pending postion. just keep staying current position.\n");
1487 player->pending_seek.is_pending = FALSE;
1491 if (oldstate == newstate) {
1492 LOGD("pipeline reports state transition to old state");
1497 case GST_STATE_VOID_PENDING:
1500 case GST_STATE_NULL:
1503 case GST_STATE_READY:
1506 case GST_STATE_PAUSED:
1508 gboolean prepare_async = FALSE;
1509 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1511 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1512 __mmplayer_configure_audio_callback(player);
1514 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1515 // managed prepare async case
1516 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1517 LOGD("checking prepare mode for async transition - %d", prepare_async);
1520 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1521 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1523 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1524 __mm_player_streaming_set_content_bitrate(player->streamer,
1525 player->total_maximum_bitrate, player->total_bitrate);
1527 if (player->pending_seek.is_pending) {
1528 LOGW("trying to do pending seek");
1529 MMPLAYER_CMD_LOCK(player);
1530 __gst_pending_seek(player);
1531 MMPLAYER_CMD_UNLOCK(player);
1537 case GST_STATE_PLAYING:
1539 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1541 if (MMPLAYER_IS_STREAMING(player)) {
1542 // managed prepare async case when buffering is completed
1543 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1544 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1545 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1546 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1548 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1550 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1551 if (player->streamer->buffering_percent < 100) {
1553 MMMessageParamType msg_param = {0, };
1554 LOGW("Posting Buffering Completed Message to Application !!!");
1556 msg_param.connection.buffering = 100;
1557 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1562 if (player->gapless.stream_changed) {
1563 _mmplayer_update_content_attrs(player, ATTR_ALL);
1564 player->gapless.stream_changed = FALSE;
1567 if (player->doing_seek && async_done) {
1568 player->doing_seek = FALSE;
1570 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1581 case GST_MESSAGE_CLOCK_LOST:
1583 GstClock *clock = NULL;
1584 gboolean need_new_clock = FALSE;
1586 gst_message_parse_clock_lost(msg, &clock);
1587 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1589 if (!player->videodec_linked)
1590 need_new_clock = TRUE;
1591 else if (!player->ini.use_system_clock)
1592 need_new_clock = TRUE;
1594 if (need_new_clock) {
1595 LOGD("Provide clock is TRUE, do pause->resume\n");
1596 __gst_pause(player, FALSE);
1597 __gst_resume(player, FALSE);
1602 case GST_MESSAGE_NEW_CLOCK:
1604 GstClock *clock = NULL;
1605 gst_message_parse_new_clock(msg, &clock);
1606 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1610 case GST_MESSAGE_ELEMENT:
1612 const gchar *structure_name;
1613 gint count = 0, idx = 0;
1614 MMHandleType attrs = 0;
1616 attrs = MMPLAYER_GET_ATTRS(player);
1618 LOGE("cannot get content attribute");
1622 if (gst_message_get_structure(msg) == NULL)
1625 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1626 if (!structure_name)
1629 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1631 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1632 const GValue *var_info = NULL;
1634 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1635 if (var_info != NULL) {
1636 if (player->adaptive_info.var_list)
1637 g_list_free_full(player->adaptive_info.var_list, g_free);
1639 /* share addr or copy the list */
1640 player->adaptive_info.var_list =
1641 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1643 count = g_list_length(player->adaptive_info.var_list);
1645 VariantData *temp = NULL;
1647 /* print out for debug */
1648 LOGD("num of variant_info %d", count);
1649 for (idx = 0; idx < count; idx++) {
1650 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1652 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1658 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1659 gint num_buffers = 0;
1660 gint extra_num_buffers = 0;
1662 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1663 player->video_num_buffers = num_buffers;
1664 LOGD("video_num_buffers : %d", player->video_num_buffers);
1667 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1668 player->video_extra_num_buffers = extra_num_buffers;
1669 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1674 if (!strcmp(structure_name, "Language_list")) {
1675 const GValue *lang_list = NULL;
1676 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1677 if (lang_list != NULL) {
1678 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1680 LOGD("Total audio tracks(from parser) = %d \n", count);
1684 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1685 const GValue *lang_list = NULL;
1686 MMPlayerLangStruct *temp = NULL;
1688 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1689 if (lang_list != NULL) {
1690 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1692 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1693 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1694 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1695 if (mmf_attrs_commit(attrs))
1696 LOGE("failed to commit.\n");
1697 LOGD("Total subtitle tracks = %d \n", count);
1700 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1702 LOGD("value of lang_key is %s and lang_code is %s",
1703 temp->language_key, temp->language_code);
1706 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1707 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1712 /* custom message */
1713 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1714 MMMessageParamType msg_param = {0,};
1715 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1716 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1719 /* custom message for RTSP attribute :
1720 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1721 sdp which has contents info is received when rtsp connection is opened.
1722 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1723 if (!strcmp(structure_name, "rtspsrc_properties")) {
1725 gchar *audio_codec = NULL;
1726 gchar *video_codec = NULL;
1727 gchar *video_frame_size = NULL;
1729 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1730 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1731 __mmplayer_get_stream_service_type(player);
1732 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1734 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1735 LOGD("rtsp_audio_codec : %s", audio_codec);
1737 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1739 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1740 LOGD("rtsp_video_codec : %s", video_codec);
1742 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1744 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1745 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1746 if (video_frame_size) {
1748 char *seperator = strchr(video_frame_size, '-');
1751 char video_width[10] = {0,};
1752 int frame_size_len = strlen(video_frame_size);
1753 int separtor_len = strlen(seperator);
1755 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1756 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1759 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1763 if (mmf_attrs_commit(attrs))
1764 LOGE("failed to commit.\n");
1769 case GST_MESSAGE_DURATION_CHANGED:
1771 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1772 if (!__mmplayer_gst_handle_duration(player, msg))
1773 LOGW("failed to update duration");
1778 case GST_MESSAGE_ASYNC_START:
1779 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1782 case GST_MESSAGE_ASYNC_DONE:
1784 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1786 /* we only handle messages from pipeline */
1787 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1790 if (player->doing_seek) {
1791 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1792 player->doing_seek = FALSE;
1793 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1794 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1795 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1796 (player->streamer) &&
1797 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1798 (player->streamer->is_buffering == FALSE)) {
1799 GstQuery *query = NULL;
1800 gboolean busy = FALSE;
1803 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1804 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1805 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1806 gst_query_parse_buffering_percent(query, &busy, &percent);
1807 gst_query_unref(query);
1809 LOGD("buffered percent(%s): %d\n",
1810 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1813 if (percent >= 100) {
1814 player->streamer->is_buffering = FALSE;
1815 __mmplayer_handle_buffering_message(player);
1825 #if 0 /* delete unnecessary logs */
1826 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1827 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1828 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1829 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1830 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1831 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1832 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1833 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1834 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1835 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1836 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1837 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1838 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1839 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1840 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1847 /* should not call 'gst_message_unref(msg)' */
1852 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1858 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1859 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1861 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1862 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1863 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1865 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1866 LOGD("data total size of http content: %lld", bytes);
1867 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1870 /* handling audio clip which has vbr. means duration is keep changing */
1871 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1878 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1879 mm_player_spherical_metadata_t *metadata) {
1880 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1881 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1882 gst_tag_list_get_string(tags, "stitching_software",
1883 &metadata->stitching_software);
1884 gst_tag_list_get_string(tags, "projection_type",
1885 &metadata->projection_type_string);
1886 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1887 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1888 gst_tag_list_get_int(tags, "init_view_heading",
1889 &metadata->init_view_heading);
1890 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1891 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1892 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1893 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1894 &metadata->full_pano_width_pixels);
1895 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1896 &metadata->full_pano_height_pixels);
1897 gst_tag_list_get_int(tags, "cropped_area_image_width",
1898 &metadata->cropped_area_image_width);
1899 gst_tag_list_get_int(tags, "cropped_area_image_height",
1900 &metadata->cropped_area_image_height);
1901 gst_tag_list_get_int(tags, "cropped_area_left",
1902 &metadata->cropped_area_left);
1903 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1904 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1905 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1906 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1910 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1913 /* macro for better code readability */
1914 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1915 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1916 if (string != NULL) { \
1917 SECURE_LOGD("update tag string : %s\n", string); \
1918 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1919 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1920 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1921 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1922 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1923 g_free(new_string); \
1924 new_string = NULL; \
1926 mm_attrs_set_string_by_name(attribute, playertag, string); \
1933 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1935 GstSample *sample = NULL;\
1936 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1937 GstMapInfo info = GST_MAP_INFO_INIT;\
1938 buffer = gst_sample_get_buffer(sample);\
1939 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1940 LOGD("failed to get image data from tag");\
1941 gst_sample_unref(sample);\
1944 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1945 MMPLAYER_FREEIF(player->album_art);\
1946 player->album_art = (gchar *)g_malloc(info.size);\
1947 if (player->album_art) {\
1948 memcpy(player->album_art, info.data, info.size);\
1949 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1950 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1951 msg_param.data = (void *)player->album_art;\
1952 msg_param.size = info.size;\
1953 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1954 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1957 gst_buffer_unmap(buffer, &info);\
1958 gst_sample_unref(sample);\
1962 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1964 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1967 gchar *tag_list_str = NULL; \
1968 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1969 tag_list_str = gst_tag_list_to_string(tag_list); \
1970 if (tag_list_str && strstr(tag_list_str, "audio")) \
1971 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1972 else if (tag_list_str && strstr(tag_list_str, "video")) \
1973 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1975 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1976 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1977 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1978 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1979 player->bitrate[track_type] = v_uint; \
1980 player->total_bitrate = 0; \
1981 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1982 player->total_bitrate += player->bitrate[i]; \
1983 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1984 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1985 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1986 player->maximum_bitrate[track_type] = v_uint; \
1987 player->total_maximum_bitrate = 0; \
1988 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1989 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1990 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1991 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1993 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1996 g_free(tag_list_str); \
2001 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
2002 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
2003 if (date != NULL) {\
2004 string = g_strdup_printf("%d", g_date_get_year(date));\
2005 mm_attrs_set_string_by_name(attribute, playertag, string);\
2006 SECURE_LOGD("metainfo year : %s\n", string);\
2007 MMPLAYER_FREEIF(string);\
2012 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
2013 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
2014 if (datetime != NULL) {\
2015 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
2016 mm_attrs_set_string_by_name(attribute, playertag, string);\
2017 SECURE_LOGD("metainfo year : %s\n", string);\
2018 MMPLAYER_FREEIF(string);\
2019 gst_date_time_unref(datetime);\
2023 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
2024 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
2026 /* FIXIT : don't know how to store date */\
2032 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
2033 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
2035 /* FIXIT : don't know how to store date */\
2041 /* function start */
2042 GstTagList* tag_list = NULL;
2044 MMHandleType attrs = 0;
2046 char *string = NULL;
2049 GstDateTime *datetime = NULL;
2051 GstBuffer *buffer = NULL;
2053 MMMessageParamType msg_param = {0, };
2055 /* currently not used. but those are needed for above macro */
2056 //guint64 v_uint64 = 0;
2057 //gdouble v_double = 0;
2059 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
2061 attrs = MMPLAYER_GET_ATTRS(player);
2063 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
2065 /* get tag list from gst message */
2066 gst_message_parse_tag(msg, &tag_list);
2068 /* store tags to player attributes */
2069 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
2070 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
2071 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
2072 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
2073 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
2074 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
2075 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
2076 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
2077 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
2078 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
2079 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
2080 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
2081 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
2082 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
2083 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2084 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2085 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2086 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2087 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2088 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2089 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2090 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2091 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2092 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2093 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2094 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2095 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2096 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2097 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2098 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2099 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2100 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2101 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2102 MMPLAYER_UPDATE_TAG_LOCK(player);
2103 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2104 MMPLAYER_UPDATE_TAG_UNLOCK(player);
2105 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2106 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2107 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2108 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2109 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2110 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2111 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2112 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2113 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2114 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2115 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2116 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2117 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2119 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2120 if (player->video360_metadata.is_spherical == -1) {
2121 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2122 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2123 player->video360_metadata.is_spherical);
2124 if (player->video360_metadata.is_spherical == 1) {
2125 LOGD("This is spherical content for 360 playback.");
2126 player->is_content_spherical = TRUE;
2128 LOGD("This is not spherical content");
2129 player->is_content_spherical = FALSE;
2132 if (player->video360_metadata.projection_type_string) {
2133 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2134 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2136 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2137 player->is_content_spherical = player->is_video360_enabled = FALSE;
2141 if (player->video360_metadata.stereo_mode_string) {
2142 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2143 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2144 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2145 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2146 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2147 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2149 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2150 player->is_content_spherical = player->is_video360_enabled = FALSE;
2156 if (mmf_attrs_commit(attrs))
2157 LOGE("failed to commit.\n");
2159 gst_tag_list_free(tag_list);
2165 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2167 mm_player_t* player = (mm_player_t*) data;
2171 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2172 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2173 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2174 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2176 * [1] audio and video will be dumped with filesink.
2177 * [2] autoplugging is done by just using pad caps.
2178 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2179 * and the video will be dumped via filesink.
2181 if (player->num_dynamic_pad == 0) {
2182 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2184 if (!__mmplayer_gst_remove_fakesink(player,
2185 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2186 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2187 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2188 * source element are not same. To overcome this situation, this function will called
2189 * several places and several times. Therefore, this is not an error case.
2194 /* create dot before error-return. for debugging */
2195 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2197 player->no_more_pad = TRUE;
2203 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2205 GstElement* parent = NULL;
2207 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2209 /* if we have no fakesink. this meas we are using decodebin which doesn'
2210 t need to add extra fakesink */
2211 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2214 MMPLAYER_FSINK_LOCK(player);
2219 /* get parent of fakesink */
2220 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2222 LOGD("fakesink already removed\n");
2226 gst_element_set_locked_state(fakesink->gst, TRUE);
2228 /* setting the state to NULL never returns async
2229 * so no need to wait for completion of state transiton
2231 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2232 LOGE("fakesink state change failure!\n");
2233 /* FIXIT : should I return here? or try to proceed to next? */
2236 /* remove fakesink from it's parent */
2237 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2238 LOGE("failed to remove fakesink\n");
2240 gst_object_unref(parent);
2245 gst_object_unref(parent);
2247 LOGD("state-holder removed\n");
2249 gst_element_set_locked_state(fakesink->gst, FALSE);
2251 MMPLAYER_FSINK_UNLOCK(player);
2256 gst_element_set_locked_state(fakesink->gst, FALSE);
2258 MMPLAYER_FSINK_UNLOCK(player);
2264 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2266 GstPad *sinkpad = NULL;
2267 GstCaps* caps = NULL;
2268 GstElement* new_element = NULL;
2269 GstStructure* str = NULL;
2270 const gchar* name = NULL;
2272 mm_player_t* player = (mm_player_t*) data;
2276 MMPLAYER_RETURN_IF_FAIL(element && pad);
2277 MMPLAYER_RETURN_IF_FAIL(player &&
2279 player->pipeline->mainbin);
2282 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2283 * num_dynamic_pad will decreased after creating a sinkbin.
2285 player->num_dynamic_pad++;
2286 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2288 caps = gst_pad_query_caps(pad, NULL);
2290 MMPLAYER_CHECK_NULL(caps);
2292 /* clear previous result*/
2293 player->have_dynamic_pad = FALSE;
2295 str = gst_caps_get_structure(caps, 0);
2298 LOGE("cannot get structure from caps.\n");
2302 name = gst_structure_get_name(str);
2304 LOGE("cannot get mimetype from structure.\n");
2308 if (strstr(name, "video")) {
2310 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2312 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2313 if (player->v_stream_caps) {
2314 gst_caps_unref(player->v_stream_caps);
2315 player->v_stream_caps = NULL;
2318 new_element = gst_element_factory_make("fakesink", NULL);
2319 player->num_dynamic_pad--;
2324 /* clear previous result*/
2325 player->have_dynamic_pad = FALSE;
2327 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2328 LOGE("failed to autoplug for caps");
2332 /* check if there's dynamic pad*/
2333 if (player->have_dynamic_pad) {
2334 LOGE("using pad caps assums there's no dynamic pad !\n");
2338 gst_caps_unref(caps);
2343 /* excute new_element if created*/
2345 LOGD("adding new element to pipeline\n");
2347 /* set state to READY before add to bin */
2348 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2350 /* add new element to the pipeline */
2351 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2352 LOGE("failed to add autoplug element to bin\n");
2356 /* get pad from element */
2357 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2359 LOGE("failed to get sinkpad from autoplug element\n");
2364 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2365 LOGE("failed to link autoplug element\n");
2369 gst_object_unref(sinkpad);
2372 /* run. setting PLAYING here since streamming source is live source */
2373 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2377 gst_caps_unref(caps);
2383 STATE_CHANGE_FAILED:
2385 /* FIXIT : take care if new_element has already added to pipeline */
2387 gst_object_unref(GST_OBJECT(new_element));
2390 gst_object_unref(GST_OBJECT(sinkpad));
2393 gst_caps_unref(caps);
2395 /* FIXIT : how to inform this error to MSL ????? */
2396 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2397 * then post an error to application
2401 static GstPadProbeReturn
2402 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2404 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2405 return GST_PAD_PROBE_OK;
2408 static GstPadProbeReturn
2409 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2411 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2412 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2413 mm_player_t* player = (mm_player_t*)data;
2414 GstCaps* caps = NULL;
2415 GstStructure* str = NULL;
2416 const gchar* name = NULL;
2417 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2420 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2421 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2422 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2423 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2424 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2426 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2427 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2431 caps = gst_pad_query_caps(pad, NULL);
2433 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2437 str = gst_caps_get_structure(caps, 0);
2439 LOGE("failed to get structure from caps");
2443 name = gst_structure_get_name(str);
2445 LOGE("failed to get name from str");
2449 if (strstr(name, "audio")) {
2450 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2451 } else if (strstr(name, "video")) {
2452 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2454 /* text track is not supportable */
2455 LOGE("invalid name %s", name);
2459 switch (GST_EVENT_TYPE(event)) {
2462 /* in case of gapless, drop eos event not to send it to sink */
2463 if (player->gapless.reconfigure && !player->msg_posted) {
2464 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2465 ret = GST_PAD_PROBE_DROP;
2469 case GST_EVENT_STREAM_START:
2471 gint64 stop_running_time = 0;
2472 gint64 position_running_time = 0;
2473 gint64 position = 0;
2476 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2477 if ((player->gapless.update_segment[idx] == TRUE) ||
2478 !(player->selector[idx].event_probe_id)) {
2479 /* LOGW("[%d] skip", idx); */
2483 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2485 gst_segment_to_running_time(&player->gapless.segment[idx],
2486 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2487 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2489 gst_segment_to_running_time(&player->gapless.segment[idx],
2490 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2492 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2494 gst_segment_to_running_time(&player->gapless.segment[idx],
2495 GST_FORMAT_TIME, player->duration);
2498 position_running_time =
2499 gst_segment_to_running_time(&player->gapless.segment[idx],
2500 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2502 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2503 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2505 GST_TIME_ARGS(stop_running_time),
2506 GST_TIME_ARGS(position_running_time),
2507 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2508 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2510 position_running_time = MAX(position_running_time, stop_running_time);
2511 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2512 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2513 position_running_time = MAX(0, position_running_time);
2514 position = MAX(position, position_running_time);
2517 if (position != 0) {
2518 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2519 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2520 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2522 player->gapless.start_time[stream_type] += position;
2526 case GST_EVENT_FLUSH_STOP:
2528 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2529 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2530 player->gapless.start_time[stream_type] = 0;
2533 case GST_EVENT_SEGMENT:
2538 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2539 gst_event_copy_segment(event, &segment);
2541 if (segment.format == GST_FORMAT_TIME) {
2542 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2543 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2544 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2545 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2546 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2547 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2549 /* keep the all the segment ev to cover the seeking */
2550 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2551 player->gapless.update_segment[stream_type] = TRUE;
2553 if (!player->gapless.running)
2556 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2558 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2560 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2561 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2562 gst_event_unref(event);
2563 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2569 gdouble proportion = 0.0;
2570 GstClockTimeDiff diff = 0;
2571 GstClockTime timestamp = 0;
2572 gint64 running_time_diff = -1;
2573 GstQOSType type = 0;
2574 GstEvent *tmpev = NULL;
2576 running_time_diff = player->gapless.segment[stream_type].base;
2578 if (running_time_diff <= 0) /* don't need to adjust */
2581 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2582 gst_event_unref(event);
2584 if (timestamp < running_time_diff) {
2585 LOGW("QOS event from previous group");
2586 ret = GST_PAD_PROBE_DROP;
2590 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2591 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2592 stream_type, GST_TIME_ARGS(timestamp),
2593 GST_TIME_ARGS(running_time_diff),
2594 GST_TIME_ARGS(timestamp - running_time_diff));
2596 timestamp -= running_time_diff;
2598 /* That case is invalid for QoS events */
2599 if (diff < 0 && -diff > timestamp) {
2600 LOGW("QOS event from previous group");
2601 ret = GST_PAD_PROBE_DROP;
2605 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2606 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2616 gst_caps_unref(caps);
2621 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2623 mm_player_t* player = NULL;
2624 GstElement* pipeline = NULL;
2625 GstElement* selector = NULL;
2626 GstElement* fakesink = NULL;
2627 GstCaps* caps = NULL;
2628 GstStructure* str = NULL;
2629 const gchar* name = NULL;
2630 GstPad* sinkpad = NULL;
2631 GstPad* srcpad = NULL;
2632 gboolean first_track = FALSE;
2634 enum MainElementID elemId = MMPLAYER_M_NUM;
2635 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2638 player = (mm_player_t*)data;
2640 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2641 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2643 //LOGD("pad-added signal handling\n");
2645 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2647 /* get mimetype from caps */
2648 caps = gst_pad_query_caps(pad, NULL);
2650 LOGE("cannot get caps from pad.\n");
2654 str = gst_caps_get_structure(caps, 0);
2656 LOGE("cannot get structure from caps.\n");
2660 name = gst_structure_get_name(str);
2662 LOGE("cannot get mimetype from structure.\n");
2666 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2667 //LOGD("detected mimetype : %s\n", name);
2669 if (strstr(name, "video")) {
2672 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2673 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2675 /* don't make video because of not required, and not support multiple track */
2676 if (stype == MM_DISPLAY_SURFACE_NULL) {
2677 LOGD("no video sink by null surface");
2679 gchar *caps_str = gst_caps_to_string(caps);
2680 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2681 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2682 player->set_mode.video_zc = TRUE;
2684 MMPLAYER_FREEIF(caps_str);
2686 if (player->v_stream_caps) {
2687 gst_caps_unref(player->v_stream_caps);
2688 player->v_stream_caps = NULL;
2691 LOGD("create fakesink instead of videobin");
2694 fakesink = gst_element_factory_make("fakesink", NULL);
2695 if (fakesink == NULL) {
2696 LOGE("ERROR : fakesink create error\n");
2700 if (player->ini.set_dump_element_flag)
2701 __mmplayer_add_dump_buffer_probe(player, fakesink);
2703 player->video_fakesink = fakesink;
2705 /* store it as it's sink element */
2706 __mmplayer_add_sink(player, player->video_fakesink);
2708 gst_bin_add(GST_BIN(pipeline), fakesink);
2711 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2713 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2714 LOGW("failed to link fakesink\n");
2715 gst_object_unref(GST_OBJECT(fakesink));
2719 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2720 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2721 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2724 if (player->set_mode.media_packet_video_stream) {
2725 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2727 MMPLAYER_SIGNAL_CONNECT(player,
2729 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2731 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2734 MMPLAYER_SIGNAL_CONNECT(player,
2736 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2738 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2742 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2743 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2747 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2748 __mmplayer_gst_decode_callback(elem, pad, player);
2752 LOGD("video selector \n");
2753 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2754 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2756 if (strstr(name, "audio")) {
2757 gint samplerate = 0;
2760 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2761 __mmplayer_gst_decode_callback(elem, pad, player);
2765 LOGD("audio selector \n");
2766 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2767 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2769 gst_structure_get_int(str, "rate", &samplerate);
2770 gst_structure_get_int(str, "channels", &channels);
2772 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2774 fakesink = gst_element_factory_make("fakesink", NULL);
2775 if (fakesink == NULL) {
2776 LOGE("ERROR : fakesink create error\n");
2780 gst_bin_add(GST_BIN(pipeline), fakesink);
2783 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2785 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2786 LOGW("failed to link fakesink\n");
2787 gst_object_unref(GST_OBJECT(fakesink));
2791 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2792 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2793 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2797 } else if (strstr(name, "text")) {
2798 LOGD("text selector \n");
2799 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2800 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2802 LOGE("wrong elem id \n");
2807 selector = player->pipeline->mainbin[elemId].gst;
2808 if (selector == NULL) {
2809 selector = gst_element_factory_make("input-selector", NULL);
2810 LOGD("Creating input-selector\n");
2811 if (selector == NULL) {
2812 LOGE("ERROR : input-selector create error\n");
2815 g_object_set(selector, "sync-streams", TRUE, NULL);
2817 player->pipeline->mainbin[elemId].id = elemId;
2818 player->pipeline->mainbin[elemId].gst = selector;
2821 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2823 srcpad = gst_element_get_static_pad(selector, "src");
2825 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2826 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2827 __mmplayer_gst_selector_blocked, NULL, NULL);
2828 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2829 __mmplayer_gst_selector_event_probe, player, NULL);
2831 gst_element_set_state(selector, GST_STATE_PAUSED);
2832 gst_bin_add(GST_BIN(pipeline), selector);
2834 LOGD("input-selector is already created.\n");
2837 LOGD("Calling request pad with selector %p \n", selector);
2838 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2840 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2842 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2843 LOGW("failed to link selector\n");
2844 gst_object_unref(GST_OBJECT(selector));
2849 LOGD("this is first track --> active track \n");
2850 g_object_set(selector, "active-pad", sinkpad, NULL);
2853 _mmplayer_track_update_info(player, stream_type, sinkpad);
2860 gst_caps_unref(caps);
2863 gst_object_unref(GST_OBJECT(sinkpad));
2868 gst_object_unref(GST_OBJECT(srcpad));
2875 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2877 GstPad* srcpad = NULL;
2878 MMHandleType attrs = 0;
2879 gint active_index = 0;
2881 // [link] input-selector :: textbin
2882 srcpad = gst_element_get_static_pad(text_selector, "src");
2884 LOGE("failed to get srcpad from selector\n");
2888 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2890 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2891 if ((active_index != DEFAULT_TRACK) &&
2892 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2893 LOGW("failed to change text track\n");
2894 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2897 player->no_more_pad = TRUE;
2898 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2900 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2901 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2902 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2903 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2906 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2908 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2909 player->has_closed_caption = TRUE;
2911 attrs = MMPLAYER_GET_ATTRS(player);
2913 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2914 if (mmf_attrs_commit(attrs))
2915 LOGE("failed to commit.\n");
2917 LOGE("cannot get content attribute");
2920 gst_object_unref(GST_OBJECT(srcpad));
2926 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2928 mm_player_t* player = (mm_player_t*)data;
2929 GstElement* selector = NULL;
2930 GstElement* queue = NULL;
2932 GstPad* srcpad = NULL;
2933 GstPad* sinkpad = NULL;
2934 GstCaps* caps = NULL;
2935 gchar* caps_str = NULL;
2938 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2940 caps = gst_pad_get_current_caps(pad);
2941 caps_str = gst_caps_to_string(caps);
2942 LOGD("deinterleave new caps : %s\n", caps_str);
2943 MMPLAYER_FREEIF(caps_str);
2944 gst_caps_unref(caps);
2946 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2947 LOGE("ERROR : queue create error\n");
2951 g_object_set(G_OBJECT(queue),
2952 "max-size-buffers", 10,
2953 "max-size-bytes", 0,
2954 "max-size-time", (guint64)0,
2957 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2960 LOGE("there is no audio channel selector.\n");
2964 srcpad = gst_element_get_static_pad(queue, "src");
2965 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2967 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2969 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2970 LOGW("failed to link deinterleave - selector\n");
2974 gst_element_set_state(queue, GST_STATE_PAUSED);
2975 player->audio_mode.total_track_num++;
2980 gst_object_unref(GST_OBJECT(srcpad));
2985 gst_object_unref(GST_OBJECT(sinkpad));
2994 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2996 mm_player_t* player = NULL;
2997 GstElement* selector = NULL;
2998 GstPad* sinkpad = NULL;
2999 gint active_index = 0;
3000 gchar* change_pad_name = NULL;
3001 GstCaps* caps = NULL; // no need to unref
3002 gint default_audio_ch = 0;
3005 player = (mm_player_t*) data;
3007 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
3010 LOGE("there is no audio channel selector.\n");
3014 active_index = player->audio_mode.active_pad_index;
3016 if (active_index != default_audio_ch) {
3017 gint audio_ch = default_audio_ch;
3019 /*To get the new pad from the selector*/
3020 change_pad_name = g_strdup_printf("sink%d", active_index);
3021 if (change_pad_name != NULL) {
3022 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
3023 if (sinkpad != NULL) {
3024 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
3025 g_object_set(selector, "active-pad", sinkpad, NULL);
3027 audio_ch = active_index;
3029 caps = gst_pad_get_current_caps(sinkpad);
3030 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3032 __mmplayer_set_audio_attrs(player, caps);
3033 gst_caps_unref(caps);
3035 MMPLAYER_FREEIF(change_pad_name);
3038 player->audio_mode.active_pad_index = audio_ch;
3039 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
3045 gst_object_unref(sinkpad);
3052 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
3054 mm_player_t* player = NULL;
3055 MMPlayerGstElement *mainbin = NULL;
3057 GstElement* tee = NULL;
3058 GstElement* stereo_queue = NULL;
3059 GstElement* mono_queue = NULL;
3060 GstElement* conv = NULL;
3061 GstElement* filter = NULL;
3062 GstElement* deinterleave = NULL;
3063 GstElement* selector = NULL;
3065 GstPad* srcpad = NULL;
3066 GstPad* selector_srcpad = NULL;
3067 GstPad* sinkpad = NULL;
3068 GstCaps* caps = NULL;
3069 gulong block_id = 0;
3074 player = (mm_player_t*) data;
3076 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3077 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3079 mainbin = player->pipeline->mainbin;
3082 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
3083 LOGE("ERROR : tee create error\n");
3087 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3088 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3090 gst_element_set_state(tee, GST_STATE_PAUSED);
3093 srcpad = gst_element_get_request_pad(tee, "src_%u");
3094 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3095 LOGE("ERROR : stereo queue create error\n");
3099 g_object_set(G_OBJECT(stereo_queue),
3100 "max-size-buffers", 10,
3101 "max-size-bytes", 0,
3102 "max-size-time", (guint64)0,
3105 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3106 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3109 gst_object_unref(GST_OBJECT(srcpad));
3113 srcpad = gst_element_get_request_pad(tee, "src_%u");
3115 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3116 LOGE("ERROR : mono queue create error\n");
3120 g_object_set(G_OBJECT(mono_queue),
3121 "max-size-buffers", 10,
3122 "max-size-bytes", 0,
3123 "max-size-time", (guint64)0,
3126 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3127 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3129 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3130 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3133 srcpad = gst_element_get_static_pad(mono_queue, "src");
3134 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3135 LOGE("ERROR : audioconvert create error\n");
3139 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3140 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3144 gst_object_unref(GST_OBJECT(srcpad));
3147 srcpad = gst_element_get_static_pad(conv, "src");
3149 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3150 LOGE("ERROR : capsfilter create error\n");
3154 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3155 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3157 caps = gst_caps_from_string("audio/x-raw-int, "
3158 "width = (int) 16, "
3159 "depth = (int) 16, "
3160 "channels = (int) 2");
3162 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3163 gst_caps_unref(caps);
3165 gst_element_set_state(conv, GST_STATE_PAUSED);
3166 gst_element_set_state(filter, GST_STATE_PAUSED);
3170 gst_object_unref(GST_OBJECT(srcpad));
3173 srcpad = gst_element_get_static_pad(filter, "src");
3175 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3176 LOGE("ERROR : deinterleave create error\n");
3180 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3182 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3183 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3185 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3186 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3188 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3189 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3192 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3193 if (selector == NULL) {
3194 LOGE("ERROR : audio-selector create error\n");
3198 g_object_set(selector, "sync-streams", TRUE, NULL);
3199 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3201 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3202 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3204 selector_srcpad = gst_element_get_static_pad(selector, "src");
3206 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3208 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3209 __mmplayer_gst_selector_blocked, NULL, NULL);
3212 gst_object_unref(GST_OBJECT(srcpad));
3216 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3217 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3219 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3220 LOGW("failed to link queue_stereo - selector\n");
3224 player->audio_mode.total_track_num++;
3226 g_object_set(selector, "active-pad", sinkpad, NULL);
3227 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3228 gst_element_set_state(selector, GST_STATE_PAUSED);
3230 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3234 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3235 if (block_id != 0) {
3236 gst_pad_remove_probe(selector_srcpad, block_id);
3241 gst_object_unref(GST_OBJECT(sinkpad));
3246 gst_object_unref(GST_OBJECT(srcpad));
3250 if (selector_srcpad) {
3251 gst_object_unref(GST_OBJECT(selector_srcpad));
3252 selector_srcpad = NULL;
3260 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3262 mm_player_t* player = NULL;
3263 GstPad* srcpad = NULL;
3264 GstElement* video_selector = NULL;
3265 GstElement* audio_selector = NULL;
3266 GstElement* text_selector = NULL;
3267 MMHandleType attrs = 0;
3268 gint active_index = 0;
3269 gint64 dur_bytes = 0L;
3271 player = (mm_player_t*) data;
3273 LOGD("no-more-pad signal handling\n");
3275 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3276 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3277 LOGW("no need to go more");
3279 if (player->gapless.reconfigure) {
3280 player->gapless.reconfigure = FALSE;
3281 MMPLAYER_PLAYBACK_UNLOCK(player);
3287 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3288 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3289 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3290 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3291 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3293 if (NULL == player->streamer) {
3294 LOGW("invalid state for buffering");
3298 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3299 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3301 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3302 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3304 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3306 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3307 LOGE("fail to get duration.\n");
3309 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3310 // use file information was already set on Q2 when it was created.
3311 __mm_player_streaming_set_queue2(player->streamer,
3312 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3313 TRUE, // use_buffering
3315 init_buffering_time,
3317 player->ini.http_buffering_limit, // high percent
3318 MUXED_BUFFER_TYPE_MEM_QUEUE,
3320 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3323 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3324 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3325 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3326 if (video_selector) {
3327 // [link] input-selector :: videobin
3328 srcpad = gst_element_get_static_pad(video_selector, "src");
3330 LOGE("failed to get srcpad from video selector\n");
3334 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3335 if (!text_selector && !audio_selector)
3336 player->no_more_pad = TRUE;
3338 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3340 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3341 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3342 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3343 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3347 if (audio_selector) {
3348 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3349 if ((active_index != DEFAULT_TRACK) &&
3350 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3351 LOGW("failed to change audio track\n");
3352 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3355 // [link] input-selector :: audiobin
3356 srcpad = gst_element_get_static_pad(audio_selector, "src");
3358 LOGE("failed to get srcpad from selector\n");
3362 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3364 player->no_more_pad = TRUE;
3366 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3367 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3368 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3369 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3370 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3373 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3375 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3377 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3378 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3379 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3380 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3384 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3386 attrs = MMPLAYER_GET_ATTRS(player);
3388 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3389 if (mmf_attrs_commit(attrs))
3390 LOGE("failed to commit.\n");
3392 LOGE("cannot get content attribute");
3394 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3395 LOGD("There is no audio track : remove audiobin");
3397 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3398 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3400 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3401 MMPLAYER_FREEIF(player->pipeline->audiobin);
3404 if (player->num_dynamic_pad == 0)
3405 __mmplayer_pipeline_complete(NULL, player);
3408 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3410 __mmplayer_handle_text_decode_path(player, text_selector);
3417 gst_object_unref(GST_OBJECT(srcpad));
3421 if (player->gapless.reconfigure) {
3422 player->gapless.reconfigure = FALSE;
3423 MMPLAYER_PLAYBACK_UNLOCK(player);
3428 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3430 mm_player_t* player = NULL;
3431 MMHandleType attrs = 0;
3432 GstElement* pipeline = NULL;
3433 GstCaps* caps = NULL;
3434 gchar* caps_str = NULL;
3435 GstStructure* str = NULL;
3436 const gchar* name = NULL;
3437 GstPad* sinkpad = NULL;
3438 GstElement* sinkbin = NULL;
3439 gboolean reusing = FALSE;
3440 GstElement *text_selector = NULL;
3443 player = (mm_player_t*) data;
3445 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3446 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3448 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3450 attrs = MMPLAYER_GET_ATTRS(player);
3452 LOGE("cannot get content attribute\n");
3456 /* get mimetype from caps */
3457 caps = gst_pad_query_caps(pad, NULL);
3459 LOGE("cannot get caps from pad.\n");
3462 caps_str = gst_caps_to_string(caps);
3464 str = gst_caps_get_structure(caps, 0);
3466 LOGE("cannot get structure from caps.\n");
3470 name = gst_structure_get_name(str);
3472 LOGE("cannot get mimetype from structure.\n");
3476 //LOGD("detected mimetype : %s\n", name);
3478 if (strstr(name, "audio")) {
3479 if (player->pipeline->audiobin == NULL) {
3480 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3481 LOGE("failed to create audiobin. continuing without audio\n");
3485 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3486 LOGD("creating audiosink bin success\n");
3489 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3490 LOGD("reusing audiobin\n");
3491 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3494 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3495 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3497 player->audiosink_linked = 1;
3499 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3501 LOGE("failed to get pad from sinkbin\n");
3504 } else if (strstr(name, "video")) {
3505 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3506 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3507 player->set_mode.video_zc = TRUE;
3509 if (player->pipeline->videobin == NULL) {
3510 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3511 /* get video surface type */
3512 int surface_type = 0;
3513 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3514 LOGD("display_surface_type(%d)\n", surface_type);
3516 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3517 LOGD("not make videobin because it dose not want\n");
3521 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3522 /* mark video overlay for acquire */
3523 if (player->video_overlay_resource == NULL) {
3524 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3525 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3526 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3527 &player->video_overlay_resource)
3528 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3529 LOGE("could not mark video_overlay resource for acquire\n");
3535 player->interrupted_by_resource = FALSE;
3536 /* acquire resources for video overlay */
3537 if (mm_resource_manager_commit(player->resource_manager) !=
3538 MM_RESOURCE_MANAGER_ERROR_NONE) {
3539 LOGE("could not acquire resources for video playing\n");
3543 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3544 LOGE("failed to create videobin. continuing without video\n");
3548 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3549 LOGD("creating videosink bin success\n");
3552 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3553 LOGD("re-using videobin\n");
3554 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3557 /* FIXIT : track number shouldn't be hardcoded */
3558 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
3559 player->videosink_linked = 1;
3561 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3563 LOGE("failed to get pad from sinkbin\n");
3566 } else if (strstr(name, "text")) {
3567 if (player->pipeline->textbin == NULL) {
3568 MMPlayerGstElement* mainbin = NULL;
3570 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3571 LOGE("failed to create text sink bin. continuing without text\n");
3575 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3576 LOGD("creating textsink bin success\n");
3578 /* FIXIT : track number shouldn't be hardcoded */
3579 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3581 player->textsink_linked = 1;
3582 LOGI("player->textsink_linked set to 1\n");
3584 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3586 LOGE("failed to get pad from sinkbin\n");
3590 mainbin = player->pipeline->mainbin;
3592 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3593 /* input selector */
3594 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3595 if (!text_selector) {
3596 LOGE("failed to create subtitle input selector element\n");
3599 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3601 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3602 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3605 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3606 LOGE("failed to set state(READY) to sinkbin\n");
3610 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3611 LOGW("failed to add subtitle input selector\n");
3615 LOGD("created element input-selector");
3618 LOGD("already having subtitle input selector");
3619 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3622 if (!player->textsink_linked) {
3623 LOGD("re-using textbin\n");
3626 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3628 player->textsink_linked = 1;
3629 LOGI("player->textsink_linked set to 1\n");
3631 LOGD("ignoring internal subtutle since external subtitle is available");
3634 LOGW("unknown type of elementary stream!ignoring it...\n");
3641 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3642 LOGE("failed to set state(READY) to sinkbin\n");
3646 /* Added for multi audio support to avoid adding audio bin again*/
3648 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3649 LOGE("failed to add sinkbin to pipeline\n");
3655 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3656 LOGE("failed to get pad from sinkbin\n");
3662 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3663 LOGE("failed to set state(PAUSED) to sinkbin\n");
3667 if (text_selector) {
3668 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3669 LOGE("failed to set state(PAUSED) to sinkbin\n");
3675 gst_object_unref(sinkpad);
3679 LOGD("[handle: %p] linking sink bin success", player);
3681 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3682 * streaming task. if the task blocked, then buffer will not flow to the next element
3683 *(autoplugging element). so this is special hack for streaming. please try to remove it
3685 /* dec stream count. we can remove fakesink if it's zero */
3686 if (player->num_dynamic_pad)
3687 player->num_dynamic_pad--;
3689 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3691 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3692 __mmplayer_pipeline_complete(NULL, player);
3696 MMPLAYER_FREEIF(caps_str);
3699 gst_caps_unref(caps);
3702 gst_object_unref(GST_OBJECT(sinkpad));
3704 /* flusing out new attributes */
3705 if (mmf_attrs_commit(attrs))
3706 LOGE("failed to comit attributes\n");
3712 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3714 int pro_value = 0; // in the case of expection, default will be returned.
3715 int dest_angle = rotation_angle;
3716 int rotation_type = -1;
3718 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3719 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3720 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3722 if (rotation_angle >= 360)
3723 dest_angle = rotation_angle - 360;
3725 /* chech if supported or not */
3726 if (dest_angle % 90) {
3727 LOGD("not supported rotation angle = %d", rotation_angle);
3733 * custom_convert - none (B)
3734 * videoflip - none (C)
3736 if (player->set_mode.video_zc) {
3737 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3738 rotation_type = ROTATION_USING_CUSTOM;
3740 rotation_type = ROTATION_USING_SINK;
3742 int surface_type = 0;
3743 rotation_type = ROTATION_USING_FLIP;
3745 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3746 LOGD("check display surface type attribute: %d", surface_type);
3748 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3749 rotation_type = ROTATION_USING_SINK;
3751 rotation_type = ROTATION_USING_FLIP; //C
3753 LOGD("using %d type for rotation", rotation_type);
3756 /* get property value for setting */
3757 switch (rotation_type) {
3758 case ROTATION_USING_SINK: // tizenwlsink
3760 switch (dest_angle) {
3764 pro_value = 3; // clockwise 90
3770 pro_value = 1; // counter-clockwise 90
3775 case ROTATION_USING_CUSTOM:
3777 gchar *ename = NULL;
3778 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3780 if (g_strrstr(ename, "fimcconvert")) {
3781 switch (dest_angle) {
3785 pro_value = 90; // clockwise 90
3791 pro_value = 270; // counter-clockwise 90
3797 case ROTATION_USING_FLIP: // videoflip
3799 switch (dest_angle) {
3803 pro_value = 1; // clockwise 90
3809 pro_value = 3; // counter-clockwise 90
3816 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3824 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3826 /* check video sinkbin is created */
3827 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3829 player->pipeline->videobin &&
3830 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3831 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3832 MM_ERROR_PLAYER_NOT_INITIALIZED);
3834 return MM_ERROR_NONE;
3838 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3840 int rotation_value = 0;
3841 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3845 /* check video sinkbin is created */
3846 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3849 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3851 /* get rotation value to set */
3852 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3853 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3854 LOGD("set video param : rotate %d", rotation_value);
3858 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3860 MMHandleType attrs = 0;
3864 /* check video sinkbin is created */
3865 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3868 attrs = MMPLAYER_GET_ATTRS(player);
3869 MMPLAYER_RETURN_IF_FAIL(attrs);
3871 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3872 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3873 LOGD("set video param : visible %d", visible);
3877 __mmplayer_video_param_set_display_method(mm_player_t* player)
3879 MMHandleType attrs = 0;
3880 int display_method = 0;
3883 /* check video sinkbin is created */
3884 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3887 attrs = MMPLAYER_GET_ATTRS(player);
3888 MMPLAYER_RETURN_IF_FAIL(attrs);
3890 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3891 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3892 LOGD("set video param : method %d", display_method);
3896 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3898 MMHandleType attrs = 0;
3899 void *handle = NULL;
3901 int wl_window_x = 0;
3902 int wl_window_y = 0;
3903 int wl_window_width = 0;
3904 int wl_window_height = 0;
3907 /* check video sinkbin is created */
3908 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3909 return MM_ERROR_PLAYER_INTERNAL;
3911 attrs = MMPLAYER_GET_ATTRS(player);
3912 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3914 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3917 /*It should be set after setting window*/
3918 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3919 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3920 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3921 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3923 /* After setting window handle, set render rectangle */
3924 gst_video_overlay_set_render_rectangle(
3925 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3926 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3927 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3928 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3930 return MM_ERROR_PLAYER_INTERNAL;
3932 return MM_ERROR_NONE;
3935 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3937 MMHandleType attrs = 0;
3938 void *handle = NULL;
3940 /* check video sinkbin is created */
3941 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3944 attrs = MMPLAYER_GET_ATTRS(player);
3945 MMPLAYER_RETURN_IF_FAIL(attrs);
3947 /* common case if using overlay surface */
3948 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3951 /* default is using wl_surface_id */
3952 unsigned int wl_surface_id = 0;
3953 wl_surface_id = *(int*)handle;
3954 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3955 gst_video_overlay_set_wl_window_wl_surface_id(
3956 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3959 /* FIXIT : is it error case? */
3960 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3965 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3967 bool update_all_param = FALSE;
3968 MMHandleType attrs = 0;
3969 int display_method = 0;
3972 /* check video sinkbin is created */
3973 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3974 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3976 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3977 LOGE("can not find tizenwlsink");
3978 return MM_ERROR_PLAYER_INTERNAL;
3981 LOGD("param_name : %s", param_name);
3982 if (!g_strcmp0(param_name, "update_all_param"))
3983 update_all_param = TRUE;
3985 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3986 __mmplayer_video_param_set_display_overlay(player);
3987 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3988 __mmplayer_video_param_set_display_method(player);
3989 /* check roi mode is set */
3990 attrs = MMPLAYER_GET_ATTRS(player);
3991 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
3992 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3993 if ((display_method == PLAYER_DISPLAY_MODE_DST_ROI) && (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))) {
3994 if (MM_ERROR_NONE != __mmplayer_video_param_set_render_rectangle(player))
3995 return MM_ERROR_PLAYER_INTERNAL;
3997 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3998 __mmplayer_video_param_set_display_visible(player);
3999 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
4000 __mmplayer_video_param_set_display_rotation(player);
4002 return MM_ERROR_NONE;
4006 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
4008 MMHandleType attrs = 0;
4009 int surface_type = 0;
4010 int ret = MM_ERROR_NONE;
4014 /* check video sinkbin is created */
4015 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
4016 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4018 attrs = MMPLAYER_GET_ATTRS(player);
4020 LOGE("cannot get content attribute");
4021 return MM_ERROR_PLAYER_INTERNAL;
4023 LOGD("param_name : %s", param_name);
4025 /* update display surface */
4026 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
4027 LOGD("check display surface type attribute: %d", surface_type);
4029 /* configuring display */
4030 switch (surface_type) {
4031 case MM_DISPLAY_SURFACE_OVERLAY:
4033 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
4034 if (ret != MM_ERROR_NONE)
4042 return MM_ERROR_NONE;
4046 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
4048 gboolean disable_overlay = FALSE;
4049 mm_player_t* player = (mm_player_t*) hplayer;
4050 int ret = MM_ERROR_NONE;
4053 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4054 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4055 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4056 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4058 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4059 LOGW("Display control is not supported");
4060 return MM_ERROR_PLAYER_INTERNAL;
4063 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4065 if (audio_only == (bool)disable_overlay) {
4066 LOGE("It's the same with current setting: (%d)", audio_only);
4067 return MM_ERROR_NONE;
4071 LOGE("disable overlay");
4072 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
4074 /* release overlay resource */
4075 if (player->video_overlay_resource != NULL) {
4076 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4077 player->video_overlay_resource);
4078 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4079 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4082 player->video_overlay_resource = NULL;
4085 ret = mm_resource_manager_commit(player->resource_manager);
4086 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4087 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
4091 /* mark video overlay for acquire */
4092 if (player->video_overlay_resource == NULL) {
4093 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
4094 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
4095 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
4096 &player->video_overlay_resource);
4097 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4098 LOGE("could not prepare for video_overlay resource\n");
4103 player->interrupted_by_resource = FALSE;
4104 /* acquire resources for video overlay */
4105 ret = mm_resource_manager_commit(player->resource_manager);
4106 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4107 LOGE("could not acquire resources for video playing\n");
4111 LOGD("enable overlay");
4112 __mmplayer_video_param_set_display_overlay(player);
4113 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4118 return MM_ERROR_NONE;
4122 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4124 mm_player_t* player = (mm_player_t*) hplayer;
4125 gboolean disable_overlay = FALSE;
4129 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4130 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4131 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4132 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4133 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4135 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4136 LOGW("Display control is not supported");
4137 return MM_ERROR_PLAYER_INTERNAL;
4140 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4142 *paudio_only = (bool)(disable_overlay);
4144 LOGD("audio_only : %d", *paudio_only);
4148 return MM_ERROR_NONE;
4152 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4154 GList* bucket = element_bucket;
4155 MMPlayerGstElement* element = NULL;
4156 MMPlayerGstElement* prv_element = NULL;
4157 gint successful_link_count = 0;
4161 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4163 prv_element = (MMPlayerGstElement*)bucket->data;
4164 bucket = bucket->next;
4166 for (; bucket; bucket = bucket->next) {
4167 element = (MMPlayerGstElement*)bucket->data;
4169 if (element && element->gst) {
4170 /* If next element is audio appsrc then make a separate audio pipeline */
4171 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4172 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4173 prv_element = element;
4177 if (prv_element && prv_element->gst) {
4178 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4179 LOGD("linking [%s] to [%s] success\n",
4180 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4181 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4182 successful_link_count++;
4184 LOGD("linking [%s] to [%s] failed\n",
4185 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4186 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4192 prv_element = element;
4197 return successful_link_count;
4201 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4203 GList* bucket = element_bucket;
4204 MMPlayerGstElement* element = NULL;
4205 int successful_add_count = 0;
4209 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4210 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4212 for (; bucket; bucket = bucket->next) {
4213 element = (MMPlayerGstElement*)bucket->data;
4215 if (element && element->gst) {
4216 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4217 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4218 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4219 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4222 successful_add_count++;
4228 return successful_add_count;
4231 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4233 mm_player_t* player = (mm_player_t*) data;
4234 GstCaps *caps = NULL;
4235 GstStructure *str = NULL;
4240 MMPLAYER_RETURN_IF_FAIL(pad)
4241 MMPLAYER_RETURN_IF_FAIL(unused)
4242 MMPLAYER_RETURN_IF_FAIL(data)
4244 caps = gst_pad_get_current_caps(pad);
4248 str = gst_caps_get_structure(caps, 0);
4252 name = gst_structure_get_name(str);
4256 LOGD("name = %s\n", name);
4258 if (strstr(name, "audio")) {
4259 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4261 if (player->audio_stream_changed_cb) {
4262 LOGE("call the audio stream changed cb\n");
4263 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4265 } else if (strstr(name, "video")) {
4266 if ((name = gst_structure_get_string(str, "format")))
4267 player->set_mode.video_zc = name[0] == 'S';
4269 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4271 if (player->video_stream_changed_cb) {
4272 LOGE("call the video stream changed cb\n");
4273 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4280 gst_caps_unref(caps);
4290 * This function is to create audio pipeline for playing.
4292 * @param player [in] handle of player
4294 * @return This function returns zero on success.
4296 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4298 /* macro for code readability. just for sinkbin-creation functions */
4299 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4301 x_bin[x_id].id = x_id;\
4302 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4303 if (!x_bin[x_id].gst) {\
4304 LOGE("failed to create %s \n", x_factory);\
4307 if (x_player->ini.set_dump_element_flag)\
4308 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4311 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4315 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4320 MMPLAYER_RETURN_IF_FAIL(player);
4322 if (player->audio_stream_buff_list) {
4323 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4324 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4327 LOGD("[%lld] send remained data.", tmp->channel_mask);
4328 __mmplayer_audio_stream_send_data(player, tmp);
4331 g_free(tmp->pcm_data);
4335 g_list_free(player->audio_stream_buff_list);
4336 player->audio_stream_buff_list = NULL;
4343 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4345 MMPlayerAudioStreamDataType audio_stream = { 0, };
4348 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4350 audio_stream.bitrate = a_buffer->bitrate;
4351 audio_stream.channel = a_buffer->channel;
4352 audio_stream.depth = a_buffer->depth;
4353 audio_stream.is_little_endian = a_buffer->is_little_endian;
4354 audio_stream.channel_mask = a_buffer->channel_mask;
4355 audio_stream.data_size = a_buffer->data_size;
4356 audio_stream.data = a_buffer->pcm_data;
4358 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4359 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4365 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4367 mm_player_t* player = (mm_player_t*) data;
4372 gint endianness = 0;
4373 guint64 channel_mask = 0;
4374 void *a_data = NULL;
4376 mm_player_audio_stream_buff_t *a_buffer = NULL;
4377 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4381 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4383 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4384 a_data = mapinfo.data;
4385 a_size = mapinfo.size;
4387 GstCaps *caps = gst_pad_get_current_caps(pad);
4388 GstStructure *structure = gst_caps_get_structure(caps, 0);
4390 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4391 gst_structure_get_int(structure, "rate", &rate);
4392 gst_structure_get_int(structure, "channels", &channel);
4393 gst_structure_get_int(structure, "depth", &depth);
4394 gst_structure_get_int(structure, "endianness", &endianness);
4395 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4396 gst_caps_unref(GST_CAPS(caps));
4398 /* In case of the sync is false, use buffer list. *
4399 * The num of buffer list depends on the num of audio channels */
4400 if (player->audio_stream_buff_list) {
4401 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4402 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4404 if (channel_mask == tmp->channel_mask) {
4405 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4406 if (tmp->data_size + a_size < tmp->buff_size) {
4407 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4408 tmp->data_size += a_size;
4410 /* send data to client */
4411 __mmplayer_audio_stream_send_data(player, tmp);
4413 if (a_size > tmp->buff_size) {
4414 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4415 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4416 if (tmp->pcm_data == NULL) {
4417 LOGE("failed to realloc data.");
4420 tmp->buff_size = a_size;
4422 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4423 memcpy(tmp->pcm_data, a_data, a_size);
4424 tmp->data_size = a_size;
4429 LOGE("data is empty in list.");
4435 /* create new audio stream data */
4436 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4437 if (a_buffer == NULL) {
4438 LOGE("failed to alloc data.");
4441 a_buffer->bitrate = rate;
4442 a_buffer->channel = channel;
4443 a_buffer->depth = depth;
4444 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4445 a_buffer->channel_mask = channel_mask;
4446 a_buffer->data_size = a_size;
4448 if (!player->audio_stream_sink_sync) {
4449 /* If sync is FALSE, use buffer list to reduce the IPC. */
4450 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4451 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4452 if (a_buffer->pcm_data == NULL) {
4453 LOGE("failed to alloc data.");
4457 memcpy(a_buffer->pcm_data, a_data, a_size);
4458 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4459 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4461 /* If sync is TRUE, send data directly. */
4462 a_buffer->pcm_data = a_data;
4463 __mmplayer_audio_stream_send_data(player, a_buffer);
4468 gst_buffer_unmap(buffer, &mapinfo);
4473 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4475 mm_player_t* player = (mm_player_t*)data;
4476 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4477 GstPad* sinkpad = NULL;
4478 GstElement *queue = NULL, *sink = NULL;
4481 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4483 queue = gst_element_factory_make("queue", NULL);
4484 if (queue == NULL) {
4485 LOGD("fail make queue\n");
4489 sink = gst_element_factory_make("fakesink", NULL);
4491 LOGD("fail make fakesink\n");
4495 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4497 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4498 LOGW("failed to link queue & sink\n");
4502 sinkpad = gst_element_get_static_pad(queue, "sink");
4504 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4505 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4509 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4511 gst_object_unref(sinkpad);
4512 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4513 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4515 gst_element_set_state(sink, GST_STATE_PAUSED);
4516 gst_element_set_state(queue, GST_STATE_PAUSED);
4518 MMPLAYER_SIGNAL_CONNECT(player,
4520 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4522 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4529 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4531 gst_object_unref(GST_OBJECT(queue));
4535 gst_object_unref(GST_OBJECT(sink));
4539 gst_object_unref(GST_OBJECT(sinkpad));
4546 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4548 #define MAX_PROPS_LEN 128
4549 gint latency_mode = 0;
4550 gchar *stream_type = NULL;
4551 gchar *latency = NULL;
4553 gchar stream_props[MAX_PROPS_LEN] = {0,};
4554 GstStructure *props = NULL;
4557 * It should be set after player creation through attribute.
4558 * But, it can not be changed during playing.
4561 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4562 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4565 LOGE("stream_type is null.\n");
4567 if (player->sound_focus.focus_id)
4568 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d, mused.client_pid=%d",
4569 stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid);
4571 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, mused.client_pid=%d",
4572 stream_type, stream_id, player->sound_focus.pid);
4573 props = gst_structure_from_string(stream_props, NULL);
4574 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4575 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], client_pid[%d], result[%s].\n",
4576 stream_type, stream_id, player->sound_focus.focus_id, player->sound_focus.pid, stream_props);
4577 gst_structure_free(props);
4580 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4582 switch (latency_mode) {
4583 case AUDIO_LATENCY_MODE_LOW:
4584 latency = g_strndup("low", 3);
4586 case AUDIO_LATENCY_MODE_MID:
4587 latency = g_strndup("mid", 3);
4589 case AUDIO_LATENCY_MODE_HIGH:
4590 latency = g_strndup("high", 4);
4594 #if 0 //need to check
4595 if (player->sound_focus.user_route_policy != 0)
4596 route_path = player->sound_focus.user_route_policy;
4598 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4599 "latency", latency_mode,
4602 LOGD("audiosink property status...volume type:%d, user-route=%d, latency=%d \n",
4603 volume_type, route_path, latency_mode);
4608 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4612 LOGD("audiosink property - latency=%s \n", latency);
4620 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4622 MMPlayerGstElement* first_element = NULL;
4623 MMPlayerGstElement* audiobin = NULL;
4624 MMHandleType attrs = 0;
4626 GstPad *ghostpad = NULL;
4627 GList* element_bucket = NULL;
4628 gboolean link_audio_sink_now = TRUE;
4634 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4637 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4639 LOGE("failed to allocate memory for audiobin\n");
4640 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4643 attrs = MMPLAYER_GET_ATTRS(player);
4646 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4647 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4648 if (!audiobin[MMPLAYER_A_BIN].gst) {
4649 LOGE("failed to create audiobin\n");
4654 player->pipeline->audiobin = audiobin;
4656 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4658 /* Adding audiotp plugin for reverse trickplay feature */
4659 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4662 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4665 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4667 if (player->set_mode.pcm_extraction) {
4668 // pcm extraction only and no sound output
4669 if (player->audio_stream_render_cb_ex) {
4670 char *caps_str = NULL;
4671 GstCaps* caps = NULL;
4672 gchar *format = NULL;
4675 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4677 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4679 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4681 caps = gst_caps_new_simple("audio/x-raw",
4682 "format", G_TYPE_STRING, format,
4683 "rate", G_TYPE_INT, player->pcm_samplerate,
4684 "channels", G_TYPE_INT, player->pcm_channel,
4686 caps_str = gst_caps_to_string(caps);
4687 LOGD("new caps : %s\n", caps_str);
4689 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4692 gst_caps_unref(caps);
4693 MMPLAYER_FREEIF(caps_str);
4695 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4697 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4698 /* raw pad handling signal */
4699 MMPLAYER_SIGNAL_CONNECT(player,
4700 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4701 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4702 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4704 int dst_samplerate = 0;
4705 int dst_channels = 0;
4707 char *caps_str = NULL;
4708 GstCaps* caps = NULL;
4710 /* get conf. values */
4711 mm_attrs_multiple_get(player->attrs,
4713 "pcm_extraction_samplerate", &dst_samplerate,
4714 "pcm_extraction_channels", &dst_channels,
4715 "pcm_extraction_depth", &dst_depth,
4719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4720 caps = gst_caps_new_simple("audio/x-raw",
4721 "rate", G_TYPE_INT, dst_samplerate,
4722 "channels", G_TYPE_INT, dst_channels,
4723 "depth", G_TYPE_INT, dst_depth,
4725 caps_str = gst_caps_to_string(caps);
4726 LOGD("new caps : %s\n", caps_str);
4728 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4731 gst_caps_unref(caps);
4732 MMPLAYER_FREEIF(caps_str);
4735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4738 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4742 //GstCaps* caps = NULL;
4745 /* for logical volume control */
4746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4749 if (player->sound.mute) {
4750 LOGD("mute enabled\n");
4751 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4756 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4757 caps = gst_caps_from_string("audio/x-raw-int, "
4758 "endianness = (int) LITTLE_ENDIAN, "
4759 "signed = (boolean) true, "
4760 "width = (int) 16, "
4761 "depth = (int) 16");
4762 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4763 gst_caps_unref(caps);
4766 /* check if multi-channels */
4767 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4768 GstPad *srcpad = NULL;
4769 GstCaps *caps = NULL;
4771 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4772 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4773 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4774 GstStructure *str = gst_caps_get_structure(caps, 0);
4776 gst_structure_get_int(str, "channels", &channels);
4777 gst_caps_unref(caps);
4779 gst_object_unref(srcpad);
4783 /* audio effect element. if audio effect is enabled */
4784 if ((strcmp(player->ini.audioeffect_element, ""))
4786 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4789 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4791 if ((!player->bypass_audio_effect)
4792 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4793 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4794 if (!_mmplayer_audio_effect_custom_apply(player))
4795 LOGI("apply audio effect(custom) setting success\n");
4799 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4800 && (player->set_mode.rich_audio))
4801 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4804 /* create audio sink */
4805 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4806 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4807 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4809 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4810 if (player->is_content_spherical &&
4812 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4813 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4814 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4816 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4820 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4821 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4822 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4823 gst_caps_unref(acaps);
4825 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4826 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4827 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4828 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4830 player->is_openal_plugin_used = TRUE;
4832 if (player->video360_yaw_radians <= M_PI &&
4833 player->video360_yaw_radians >= -M_PI &&
4834 player->video360_pitch_radians <= M_PI_2 &&
4835 player->video360_pitch_radians >= -M_PI_2) {
4836 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4837 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4838 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4839 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4841 "source-orientation-y", player->video360_metadata.init_view_heading,
4842 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4845 if (player->is_content_spherical)
4846 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4847 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4851 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4852 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4855 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4856 (player->videodec_linked && player->ini.use_system_clock)) {
4857 LOGD("system clock will be used.\n");
4858 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4861 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4862 __mmplayer_gst_set_audiosink_property(player, attrs);
4865 if (audiobin[MMPLAYER_A_SINK].gst) {
4866 GstPad *sink_pad = NULL;
4867 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4868 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4869 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4870 gst_object_unref(GST_OBJECT(sink_pad));
4873 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4875 /* adding created elements to bin */
4876 LOGD("adding created elements to bin\n");
4877 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4878 LOGE("failed to add elements\n");
4882 /* linking elements in the bucket by added order. */
4883 LOGD("Linking elements in the bucket by added order.\n");
4884 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4885 LOGE("failed to link elements\n");
4889 /* get first element's sinkpad for creating ghostpad */
4890 first_element = (MMPlayerGstElement *)element_bucket->data;
4891 if (!first_element) {
4892 LOGE("failed to get first elem\n");
4896 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4898 LOGE("failed to get pad from first element of audiobin\n");
4902 ghostpad = gst_ghost_pad_new("sink", pad);
4904 LOGE("failed to create ghostpad\n");
4908 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4909 LOGE("failed to add ghostpad to audiobin\n");
4913 gst_object_unref(pad);
4915 g_list_free(element_bucket);
4917 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
4921 return MM_ERROR_NONE;
4925 LOGD("ERROR : releasing audiobin\n");
4928 gst_object_unref(GST_OBJECT(pad));
4931 gst_object_unref(GST_OBJECT(ghostpad));
4934 g_list_free(element_bucket);
4936 /* release element which are not added to bin */
4937 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4938 /* NOTE : skip bin */
4939 if (audiobin[i].gst) {
4940 GstObject* parent = NULL;
4941 parent = gst_element_get_parent(audiobin[i].gst);
4944 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4945 audiobin[i].gst = NULL;
4947 gst_object_unref(GST_OBJECT(parent));
4951 /* release audiobin with it's childs */
4952 if (audiobin[MMPLAYER_A_BIN].gst)
4953 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4955 MMPLAYER_FREEIF(audiobin);
4957 player->pipeline->audiobin = NULL;
4959 return MM_ERROR_PLAYER_INTERNAL;
4962 static GstPadProbeReturn
4963 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4965 mm_player_t* player = (mm_player_t*) u_data;
4966 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4967 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4969 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4971 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4972 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4974 return GST_PAD_PROBE_OK;
4977 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4979 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4982 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4984 int ret = MM_ERROR_NONE;
4986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4989 MMPLAYER_VIDEO_BO_LOCK(player);
4991 if (player->video_bo_list) {
4992 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4993 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4994 if (tmp && tmp->bo == bo) {
4996 LOGD("release bo %p", bo);
4997 tbm_bo_unref(tmp->bo);
4998 MMPLAYER_VIDEO_BO_UNLOCK(player);
4999 MMPLAYER_VIDEO_BO_SIGNAL(player);
5004 /* hw codec is running or the list was reset for DRC. */
5005 LOGW("there is no bo list.");
5007 MMPLAYER_VIDEO_BO_UNLOCK(player);
5009 LOGW("failed to find bo %p", bo);
5014 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
5019 MMPLAYER_RETURN_IF_FAIL(player);
5021 MMPLAYER_VIDEO_BO_LOCK(player);
5022 if (player->video_bo_list) {
5023 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
5024 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5025 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5028 tbm_bo_unref(tmp->bo);
5032 g_list_free(player->video_bo_list);
5033 player->video_bo_list = NULL;
5035 player->video_bo_size = 0;
5036 MMPLAYER_VIDEO_BO_UNLOCK(player);
5043 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
5046 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
5047 gboolean ret = TRUE;
5049 /* check DRC, if it is, destroy the prev bo list to create again */
5050 if (player->video_bo_size != size) {
5051 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
5052 __mmplayer_video_stream_destroy_bo_list(player);
5053 player->video_bo_size = size;
5056 MMPLAYER_VIDEO_BO_LOCK(player);
5058 if ((!player->video_bo_list) ||
5059 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
5061 /* create bo list */
5063 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
5065 if (player->video_bo_list) {
5066 /* if bo list did not created all, try it again. */
5067 idx = g_list_length(player->video_bo_list);
5068 LOGD("bo list exist(len: %d)", idx);
5071 for (; idx < player->ini.num_of_video_bo; idx++) {
5072 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
5074 LOGE("Fail to alloc bo_info.");
5077 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
5079 LOGE("Fail to tbm_bo_alloc.");
5083 bo_info->using = FALSE;
5084 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
5087 /* update video num buffers */
5088 player->video_num_buffers = idx;
5089 if (idx == player->ini.num_of_video_bo)
5090 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
5093 MMPLAYER_VIDEO_BO_UNLOCK(player);
5097 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
5101 /* get bo from list*/
5102 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
5103 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
5104 if (tmp && (tmp->using == FALSE)) {
5105 LOGD("found bo %p to use", tmp->bo);
5107 MMPLAYER_VIDEO_BO_UNLOCK(player);
5108 return tbm_bo_ref(tmp->bo);
5112 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5113 MMPLAYER_VIDEO_BO_UNLOCK(player);
5117 if (player->ini.video_bo_timeout <= 0) {
5118 MMPLAYER_VIDEO_BO_WAIT(player);
5120 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5121 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5128 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5130 mm_player_t* player = (mm_player_t*)data;
5132 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5134 /* send prerolled pkt */
5135 player->video_stream_prerolled = FALSE;
5137 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5139 /* not to send prerolled pkt again */
5140 player->video_stream_prerolled = TRUE;
5144 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5146 mm_player_t* player = (mm_player_t*)data;
5147 GstCaps *caps = NULL;
5148 MMPlayerVideoStreamDataType *stream = NULL;
5149 MMVideoBuffer *video_buffer = NULL;
5150 GstMemory *dataBlock = NULL;
5151 GstMemory *metaBlock = NULL;
5152 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5153 GstStructure *structure = NULL;
5154 const gchar *string_format = NULL;
5155 unsigned int fourcc = 0;
5158 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5160 if (player->video_stream_prerolled) {
5161 player->video_stream_prerolled = FALSE;
5162 LOGD("skip the prerolled pkt not to send it again");
5166 caps = gst_pad_get_current_caps(pad);
5168 LOGE("Caps is NULL.");
5172 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5174 /* clear stream data structure */
5175 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5177 LOGE("failed to alloc mem for video data");
5181 structure = gst_caps_get_structure(caps, 0);
5182 gst_structure_get_int(structure, "width", &(stream->width));
5183 gst_structure_get_int(structure, "height", &(stream->height));
5184 string_format = gst_structure_get_string(structure, "format");
5186 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5187 stream->format = util_get_pixtype(fourcc);
5188 gst_caps_unref(caps);
5192 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5193 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5196 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5197 LOGE("Wrong condition!!");
5201 /* set size and timestamp */
5202 dataBlock = gst_buffer_peek_memory(buffer, 0);
5203 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5204 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5206 /* check zero-copy */
5207 if (player->set_mode.video_zc &&
5208 player->set_mode.media_packet_video_stream &&
5209 gst_buffer_n_memory(buffer) > 1) {
5210 metaBlock = gst_buffer_peek_memory(buffer, 1);
5211 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5212 video_buffer = (MMVideoBuffer *)mapinfo.data;
5215 if (video_buffer) { /* hw codec */
5217 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5220 /* copy pointer of tbm bo, stride, elevation */
5221 while (video_buffer->handle.bo[i] && i < MM_VIDEO_BUFFER_PLANE_MAX) {
5222 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5226 LOGE("Not support video buffer format");
5229 memcpy(stream->stride, video_buffer->stride_width,
5230 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5231 memcpy(stream->elevation, video_buffer->stride_height,
5232 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5234 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5235 stream->internal_buffer = gst_buffer_ref(buffer);
5236 } else { /* sw codec */
5240 int ret = TBM_SURFACE_ERROR_NONE;
5241 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5242 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5244 unsigned char *src = NULL;
5245 unsigned char *dest = NULL;
5246 tbm_bo_handle thandle;
5247 tbm_surface_h surface;
5248 tbm_surface_info_s info;
5251 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5253 LOGE("fail to gst_memory_map");
5258 if (stream->format == MM_PIXEL_FORMAT_I420) {
5259 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5261 ret = tbm_surface_get_info(surface, &info);
5263 if (ret != TBM_SURFACE_ERROR_NONE) {
5264 tbm_surface_destroy(surface);
5267 tbm_surface_destroy(surface);
5269 src_stride[0] = GST_ROUND_UP_4(stream->width);
5270 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5271 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5272 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5273 stream->stride[0] = info.planes[0].stride;
5274 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5275 stream->stride[1] = info.planes[1].stride;
5276 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5277 stream->stride[2] = info.planes[2].stride;
5278 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5279 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5280 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5281 stream->stride[0] = stream->width * 4;
5282 stream->elevation[0] = stream->height;
5283 size = stream->stride[0] * stream->height;
5285 LOGE("Not support format %d", stream->format);
5289 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5290 if (!stream->bo[0]) {
5291 LOGE("Fail to tbm_bo_alloc!!");
5295 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5296 if (thandle.ptr && mapinfo.data) {
5297 if (stream->format == MM_PIXEL_FORMAT_I420) {
5298 for (i = 0; i < 3; i++) {
5299 src = mapinfo.data + src_offset[i];
5300 dest = thandle.ptr + info.planes[i].offset;
5303 for (j = 0; j < stream->height>>k; j++) {
5304 memcpy(dest, src, stream->width>>k);
5305 src += src_stride[i];
5306 dest += stream->stride[i];
5309 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5310 memcpy(thandle.ptr, mapinfo.data, size);
5312 LOGE("Not support format %d", stream->format);
5316 LOGE("data pointer is wrong. dest : %p, src : %p",
5317 thandle.ptr, mapinfo.data);
5320 tbm_bo_unmap(stream->bo[0]);
5323 if (player->video_stream_cb) { /* This has been already checked at the entry */
5324 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5325 LOGE("failed to send video stream data.");
5331 gst_memory_unmap(metaBlock, &mapinfo);
5333 gst_memory_unmap(dataBlock, &mapinfo);
5338 LOGE("release video stream resource.");
5341 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5343 tbm_bo_unref(stream->bo[i]);
5345 gst_memory_unmap(metaBlock, &mapinfo);
5347 /* unref gst buffer */
5348 if (stream->internal_buffer)
5349 gst_buffer_unref(stream->internal_buffer);
5350 } else if (dataBlock) {
5352 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5353 gst_memory_unmap(dataBlock, &mapinfo);
5361 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5363 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5364 GList* element_bucket = *bucket;
5366 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5370 if (player->set_mode.video_zc || player->is_content_spherical) {
5371 LOGD("do not need to add video filters.");
5372 return MM_ERROR_NONE;
5375 /* in case of sw codec except 360 playback,
5376 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5377 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5378 LOGD("using video converter: %s", video_csc);
5380 /* set video rotator */
5381 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5383 *bucket = element_bucket;
5385 return MM_ERROR_NONE;
5387 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5390 return MM_ERROR_PLAYER_INTERNAL;
5394 * This function is to create video pipeline.
5396 * @param player [in] handle of player
5397 * caps [in] src caps of decoder
5398 * surface_type [in] surface type for video rendering
5400 * @return This function returns zero on success.
5402 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5406 * - video overlay surface(arm/x86) : tizenwlsink
5409 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5413 GList*element_bucket = NULL;
5414 MMPlayerGstElement* first_element = NULL;
5415 MMPlayerGstElement* videobin = NULL;
5416 gchar *videosink_element = NULL;
5420 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5423 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5425 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5427 player->pipeline->videobin = videobin;
5429 attrs = MMPLAYER_GET_ATTRS(player);
5431 LOGE("cannot get content attribute");
5432 return MM_ERROR_PLAYER_INTERNAL;
5436 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5437 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5438 if (!videobin[MMPLAYER_V_BIN].gst) {
5439 LOGE("failed to create videobin");
5443 int enable_video_decoded_cb = 0;
5444 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5446 if (player->is_content_spherical) {
5447 LOGD("video360 elem will be added.");
5449 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5450 "video-360", TRUE, player);
5452 /* Set spatial media metadata and/or user settings to the element.
5454 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5455 "projection-type", player->video360_metadata.projection_type, NULL);
5457 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5458 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5460 if (player->video360_metadata.full_pano_width_pixels &&
5461 player->video360_metadata.full_pano_height_pixels &&
5462 player->video360_metadata.cropped_area_image_width &&
5463 player->video360_metadata.cropped_area_image_height) {
5464 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5465 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5466 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5467 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5468 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5469 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5470 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5474 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5475 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5476 "horizontal-fov", player->video360_horizontal_fov,
5477 "vertical-fov", player->video360_vertical_fov, NULL);
5480 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5481 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5482 "zoom", 1.0f / player->video360_zoom, NULL);
5485 if (player->video360_yaw_radians <= M_PI &&
5486 player->video360_yaw_radians >= -M_PI &&
5487 player->video360_pitch_radians <= M_PI_2 &&
5488 player->video360_pitch_radians >= -M_PI_2) {
5489 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5490 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5491 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5492 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5493 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5494 "pose-yaw", player->video360_metadata.init_view_heading,
5495 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5498 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5499 "passthrough", !player->is_video360_enabled, NULL);
5502 /* set video sink */
5503 switch (surface_type) {
5504 case MM_DISPLAY_SURFACE_OVERLAY:
5505 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5507 if (strlen(player->ini.videosink_element_overlay) > 0)
5508 videosink_element = player->ini.videosink_element_overlay;
5512 case MM_DISPLAY_SURFACE_NULL:
5513 if (strlen(player->ini.videosink_element_fake) > 0)
5514 videosink_element = player->ini.videosink_element_fake;
5518 case MM_DISPLAY_SURFACE_REMOTE:
5519 if (strlen(player->ini.videosink_element_fake) > 0)
5520 videosink_element = player->ini.videosink_element_fake;
5525 LOGE("unidentified surface type");
5528 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5530 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE, player);
5532 /* additional setting for sink plug-in */
5533 switch (surface_type) {
5534 case MM_DISPLAY_SURFACE_OVERLAY:
5536 bool use_tbm = (player->set_mode.video_zc || player->is_content_spherical);
5538 LOGD("selected videosink name: %s", videosink_element);
5540 /* support shard memory with S/W codec on HawkP */
5541 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5542 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5543 "use-tbm", use_tbm, NULL);
5549 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5552 LOGD("disable last-sample");
5553 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5557 if (player->set_mode.media_packet_video_stream) {
5559 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5561 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5563 MMPLAYER_SIGNAL_CONNECT(player,
5564 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5565 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5567 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5570 MMPLAYER_SIGNAL_CONNECT(player,
5571 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5572 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5574 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5579 case MM_DISPLAY_SURFACE_REMOTE:
5581 if (player->set_mode.media_packet_video_stream) {
5582 LOGE("add data probe at videosink");
5583 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5584 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5586 MMPLAYER_SIGNAL_CONNECT(player,
5587 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5588 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5590 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5593 MMPLAYER_SIGNAL_CONNECT(player,
5594 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5595 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5597 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5602 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5605 LOGD("disable last-sample");
5606 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5616 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5619 if (videobin[MMPLAYER_V_SINK].gst) {
5620 GstPad *sink_pad = NULL;
5621 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5623 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5624 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5625 gst_object_unref(GST_OBJECT(sink_pad));
5627 LOGW("failed to get sink pad from videosink\n");
5630 /* store it as it's sink element */
5631 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5633 /* adding created elements to bin */
5634 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5635 LOGE("failed to add elements\n");
5639 /* Linking elements in the bucket by added order */
5640 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5641 LOGE("failed to link elements\n");
5645 /* get first element's sinkpad for creating ghostpad */
5647 first_element = (MMPlayerGstElement *)element_bucket->data;
5648 if (!first_element) {
5649 LOGE("failed to get first element from bucket\n");
5653 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5655 LOGE("failed to get pad from first element\n");
5659 /* create ghostpad */
5660 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5661 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5662 LOGE("failed to add ghostpad to videobin\n");
5665 gst_object_unref(pad);
5667 /* done. free allocated variables */
5669 g_list_free(element_bucket);
5673 return MM_ERROR_NONE;
5676 LOGE("ERROR : releasing videobin\n");
5678 g_list_free(element_bucket);
5681 gst_object_unref(GST_OBJECT(pad));
5683 /* release videobin with it's childs */
5684 if (videobin[MMPLAYER_V_BIN].gst)
5685 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5688 MMPLAYER_FREEIF(videobin);
5690 player->pipeline->videobin = NULL;
5692 return MM_ERROR_PLAYER_INTERNAL;
5695 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5697 GList *element_bucket = NULL;
5698 MMPlayerGstElement *textbin = player->pipeline->textbin;
5700 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5701 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5702 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5703 "signal-handoffs", FALSE,
5706 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5707 MMPLAYER_SIGNAL_CONNECT(player,
5708 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5709 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5711 G_CALLBACK(__mmplayer_update_subtitle),
5714 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5715 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5716 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5718 if (!player->play_subtitle) {
5719 LOGD("add textbin sink as sink element of whole pipeline.\n");
5720 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5723 /* adding created elements to bin */
5724 LOGD("adding created elements to bin\n");
5725 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5726 LOGE("failed to add elements\n");
5730 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5731 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5732 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5734 /* linking elements in the bucket by added order. */
5735 LOGD("Linking elements in the bucket by added order.\n");
5736 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5737 LOGE("failed to link elements\n");
5741 /* done. free allocated variables */
5742 g_list_free(element_bucket);
5744 if (textbin[MMPLAYER_T_QUEUE].gst) {
5746 GstPad *ghostpad = NULL;
5748 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5750 LOGE("failed to get sink pad of text queue");
5754 ghostpad = gst_ghost_pad_new("text_sink", pad);
5755 gst_object_unref(pad);
5758 LOGE("failed to create ghostpad of textbin\n");
5762 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5763 LOGE("failed to add ghostpad to textbin\n");
5764 gst_object_unref(ghostpad);
5769 return MM_ERROR_NONE;
5772 g_list_free(element_bucket);
5774 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5775 LOGE("remove textbin sink from sink list");
5776 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5779 /* release element at __mmplayer_gst_create_text_sink_bin */
5780 return MM_ERROR_PLAYER_INTERNAL;
5783 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5785 MMPlayerGstElement *textbin = NULL;
5786 GList *element_bucket = NULL;
5787 int surface_type = 0;
5792 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5795 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5797 LOGE("failed to allocate memory for textbin\n");
5798 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5802 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5803 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5804 if (!textbin[MMPLAYER_T_BIN].gst) {
5805 LOGE("failed to create textbin\n");
5810 player->pipeline->textbin = textbin;
5813 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5814 LOGD("surface type for subtitle : %d", surface_type);
5815 switch (surface_type) {
5816 case MM_DISPLAY_SURFACE_OVERLAY:
5817 case MM_DISPLAY_SURFACE_NULL:
5818 case MM_DISPLAY_SURFACE_REMOTE:
5819 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5820 LOGE("failed to make plain text elements\n");
5831 return MM_ERROR_NONE;
5835 LOGD("ERROR : releasing textbin\n");
5837 g_list_free(element_bucket);
5839 /* release signal */
5840 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5842 /* release element which are not added to bin */
5843 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5844 /* NOTE : skip bin */
5845 if (textbin[i].gst) {
5846 GstObject* parent = NULL;
5847 parent = gst_element_get_parent(textbin[i].gst);
5850 gst_object_unref(GST_OBJECT(textbin[i].gst));
5851 textbin[i].gst = NULL;
5853 gst_object_unref(GST_OBJECT(parent));
5858 /* release textbin with it's childs */
5859 if (textbin[MMPLAYER_T_BIN].gst)
5860 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5862 MMPLAYER_FREEIF(player->pipeline->textbin);
5863 player->pipeline->textbin = NULL;
5866 return MM_ERROR_PLAYER_INTERNAL;
5871 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5873 MMPlayerGstElement* mainbin = NULL;
5874 MMPlayerGstElement* textbin = NULL;
5875 MMHandleType attrs = 0;
5876 GstElement *subsrc = NULL;
5877 GstElement *subparse = NULL;
5878 gchar *subtitle_uri = NULL;
5879 const gchar *charset = NULL;
5885 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5887 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5889 mainbin = player->pipeline->mainbin;
5891 attrs = MMPLAYER_GET_ATTRS(player);
5893 LOGE("cannot get content attribute\n");
5894 return MM_ERROR_PLAYER_INTERNAL;
5897 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5898 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5899 LOGE("subtitle uri is not proper filepath.\n");
5900 return MM_ERROR_PLAYER_INVALID_URI;
5903 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5904 LOGE("failed to get storage info of subtitle path");
5905 return MM_ERROR_PLAYER_INVALID_URI;
5908 LOGD("subtitle file path is [%s].\n", subtitle_uri);
5910 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5911 player->subtitle_language_list = NULL;
5912 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5914 /* create the subtitle source */
5915 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5917 LOGE("failed to create filesrc element\n");
5920 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5922 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5923 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5925 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5926 LOGW("failed to add queue\n");
5927 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5928 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5929 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5934 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5936 LOGE("failed to create subparse element\n");
5940 charset = util_get_charset(subtitle_uri);
5942 LOGD("detected charset is %s\n", charset);
5943 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5946 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5947 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5949 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5950 LOGW("failed to add subparse\n");
5951 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5952 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5953 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5957 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5958 LOGW("failed to link subsrc and subparse\n");
5962 player->play_subtitle = TRUE;
5963 player->adjust_subtitle_pos = 0;
5965 LOGD("play subtitle using subtitle file\n");
5967 if (player->pipeline->textbin == NULL) {
5968 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5969 LOGE("failed to create text sink bin. continuing without text\n");
5973 textbin = player->pipeline->textbin;
5975 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5976 LOGW("failed to add textbin\n");
5978 /* release signal */
5979 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5981 /* release textbin with it's childs */
5982 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5983 MMPLAYER_FREEIF(player->pipeline->textbin);
5984 player->pipeline->textbin = textbin = NULL;
5988 LOGD("link text input selector and textbin ghost pad");
5990 player->textsink_linked = 1;
5991 player->external_text_idx = 0;
5992 LOGI("player->textsink_linked set to 1\n");
5994 textbin = player->pipeline->textbin;
5995 LOGD("text bin has been created. reuse it.");
5996 player->external_text_idx = 1;
5999 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
6000 LOGW("failed to link subparse and textbin\n");
6004 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
6006 LOGE("failed to get sink pad from textsink to probe data");
6010 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
6011 __mmplayer_subtitle_adjust_position_probe, player, NULL);
6013 gst_object_unref(pad);
6016 /* create dot. for debugging */
6017 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
6020 return MM_ERROR_NONE;
6023 /* release text pipeline resource */
6024 player->textsink_linked = 0;
6026 /* release signal */
6027 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
6029 if (player->pipeline->textbin) {
6030 LOGE("remove textbin");
6032 /* release textbin with it's childs */
6033 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
6034 MMPLAYER_FREEIF(player->pipeline->textbin);
6035 player->pipeline->textbin = NULL;
6039 /* release subtitle elem */
6040 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
6041 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
6043 return MM_ERROR_PLAYER_INTERNAL;
6047 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
6049 mm_player_t* player = (mm_player_t*) data;
6050 MMMessageParamType msg = {0, };
6051 GstClockTime duration = 0;
6052 gpointer text = NULL;
6053 guint text_size = 0;
6054 gboolean ret = TRUE;
6055 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
6059 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6060 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
6062 if (player->is_subtitle_force_drop) {
6063 LOGW("subtitle is dropped forcedly.");
6067 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
6068 text = mapinfo.data;
6069 text_size = mapinfo.size;
6070 duration = GST_BUFFER_DURATION(buffer);
6072 if (player->set_mode.subtitle_off) {
6073 LOGD("subtitle is OFF.\n");
6077 if (!text || (text_size == 0)) {
6078 LOGD("There is no subtitle to be displayed.\n");
6082 msg.data = (void *) text;
6083 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
6085 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
6087 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
6088 gst_buffer_unmap(buffer, &mapinfo);
6095 static GstPadProbeReturn
6096 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
6099 mm_player_t *player = (mm_player_t *) u_data;
6100 GstClockTime cur_timestamp = 0;
6101 gint64 adjusted_timestamp = 0;
6102 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
6104 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6106 if (player->set_mode.subtitle_off) {
6107 LOGD("subtitle is OFF.\n");
6111 if (player->adjust_subtitle_pos == 0) {
6112 LOGD("nothing to do");
6116 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6117 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6119 if (adjusted_timestamp < 0) {
6120 LOGD("adjusted_timestamp under zero");
6125 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6126 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6127 GST_TIME_ARGS(cur_timestamp),
6128 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6130 return GST_PAD_PROBE_OK;
6132 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6136 /* check player and subtitlebin are created */
6137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6138 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6140 if (position == 0) {
6141 LOGD("nothing to do\n");
6143 return MM_ERROR_NONE;
6147 case MM_PLAYER_POS_FORMAT_TIME:
6149 /* check current postion */
6150 player->adjust_subtitle_pos = position;
6152 LOGD("save adjust_subtitle_pos in player") ;
6158 LOGW("invalid format.\n");
6160 return MM_ERROR_INVALID_ARGUMENT;
6166 return MM_ERROR_NONE;
6168 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6171 LOGD("adjusting video_pos in player") ;
6172 int current_pos = 0;
6173 /* check player and videobin are created */
6174 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6175 if (!player->pipeline->videobin ||
6176 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6177 LOGD("no video pipeline or sink is there");
6178 return MM_ERROR_PLAYER_INVALID_STATE ;
6181 LOGD("nothing to do\n");
6183 return MM_ERROR_NONE;
6185 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6186 LOGD("failed to get current position");
6187 return MM_ERROR_PLAYER_INTERNAL;
6189 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6190 LOGD("enter video delay is valid");
6192 LOGD("enter video delay is crossing content boundary");
6193 return MM_ERROR_INVALID_ARGUMENT ;
6195 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6196 LOGD("video delay has been done");
6199 return MM_ERROR_NONE;
6203 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6205 GstElement *appsrc = element;
6206 tBuffer *buf = (tBuffer *)user_data;
6207 GstBuffer *buffer = NULL;
6208 GstFlowReturn ret = GST_FLOW_OK;
6211 MMPLAYER_RETURN_IF_FAIL(element);
6212 MMPLAYER_RETURN_IF_FAIL(buf);
6214 buffer = gst_buffer_new();
6216 if (buf->offset >= buf->len) {
6217 LOGD("call eos appsrc\n");
6218 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6222 if (buf->len - buf->offset < size)
6223 len = buf->len - buf->offset;
6225 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6226 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6227 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6229 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6230 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6236 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6238 tBuffer *buf = (tBuffer *)user_data;
6240 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6242 buf->offset = (int)size;
6247 static GstBusSyncReply
6248 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6250 mm_player_t *player = (mm_player_t *)data;
6251 GstBusSyncReply reply = GST_BUS_DROP;
6253 if (!(player->pipeline && player->pipeline->mainbin)) {
6254 LOGE("player pipeline handle is null");
6255 return GST_BUS_PASS;
6258 if (!__mmplayer_check_useful_message(player, message)) {
6259 gst_message_unref(message);
6260 return GST_BUS_DROP;
6263 switch (GST_MESSAGE_TYPE(message)) {
6264 case GST_MESSAGE_STATE_CHANGED:
6265 /* post directly for fast launch */
6266 if (player->sync_handler) {
6267 __mmplayer_gst_callback(message, player);
6268 reply = GST_BUS_DROP;
6270 reply = GST_BUS_PASS;
6272 case GST_MESSAGE_TAG:
6273 __mmplayer_gst_extract_tag_from_msg(player, message);
6277 GstTagList *tags = NULL;
6279 gst_message_parse_tag(message, &tags);
6281 LOGE("TAGS received from element \"%s\".\n",
6282 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6284 gst_tag_list_foreach(tags, print_tag, NULL);
6285 gst_tag_list_free(tags);
6293 case GST_MESSAGE_DURATION_CHANGED:
6294 __mmplayer_gst_handle_duration(player, message);
6296 case GST_MESSAGE_ASYNC_DONE:
6297 /* NOTE:Don't call gst_callback directly
6298 * because previous frame can be showed even though this message is received for seek.
6301 reply = GST_BUS_PASS;
6305 if (reply == GST_BUS_DROP)
6306 gst_message_unref(message);
6312 __mmplayer_gst_create_decoder(mm_player_t *player,
6313 MMPlayerTrackType track,
6315 enum MainElementID elemId,
6318 gboolean ret = TRUE;
6319 GstPad *sinkpad = NULL;
6323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6325 player->pipeline->mainbin, FALSE);
6326 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6327 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6328 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6330 GstElement *decodebin = NULL;
6331 GstCaps *dec_caps = NULL;
6333 /* create decodebin */
6334 decodebin = gst_element_factory_make("decodebin", name);
6337 LOGE("error : fail to create decodebin for %d decoder\n", track);
6342 /* raw pad handling signal */
6343 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6344 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6346 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6347 before looking for any elements that can handle that stream.*/
6348 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6349 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6351 /* This signal is emitted when a element is added to the bin.*/
6352 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6353 G_CALLBACK(__mmplayer_gst_element_added), player);
6355 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6356 LOGE("failed to add new decodebin\n");
6361 dec_caps = gst_pad_query_caps(srcpad, NULL);
6363 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6364 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6365 gst_caps_unref(dec_caps);
6368 player->pipeline->mainbin[elemId].id = elemId;
6369 player->pipeline->mainbin[elemId].gst = decodebin;
6371 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6373 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6374 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6375 gst_object_unref(GST_OBJECT(decodebin));
6378 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6379 LOGE("failed to sync second level decodebin state with parent\n");
6381 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6385 gst_object_unref(GST_OBJECT(sinkpad));
6394 * This function is to create audio or video pipeline for playing.
6396 * @param player [in] handle of player
6398 * @return This function returns zero on success.
6403 __mmplayer_gst_create_pipeline(mm_player_t* player)
6406 MMPlayerGstElement *mainbin = NULL;
6407 MMHandleType attrs = 0;
6408 GstElement* element = NULL;
6409 GstElement* elem_src_audio = NULL;
6410 GstElement* elem_src_subtitle = NULL;
6411 GstElement* es_video_queue = NULL;
6412 GstElement* es_audio_queue = NULL;
6413 GstElement* es_subtitle_queue = NULL;
6414 GList* element_bucket = NULL;
6415 gboolean need_state_holder = TRUE;
6417 #ifdef SW_CODEC_ONLY
6418 int surface_type = 0;
6422 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6424 /* get profile attribute */
6425 attrs = MMPLAYER_GET_ATTRS(player);
6427 LOGE("cannot get content attribute\n");
6431 /* create pipeline handles */
6432 if (player->pipeline) {
6433 LOGW("pipeline should be released before create new one\n");
6437 player->video360_metadata.is_spherical = -1;
6438 player->is_openal_plugin_used = FALSE;
6440 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6441 if (player->pipeline == NULL)
6444 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6446 /* create mainbin */
6447 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6448 if (mainbin == NULL)
6451 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6453 /* create pipeline */
6454 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6455 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6456 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6457 LOGE("failed to create pipeline\n");
6460 player->demux_pad_index = 0;
6461 player->subtitle_language_list = NULL;
6463 player->is_subtitle_force_drop = FALSE;
6464 player->last_multiwin_status = FALSE;
6466 _mmplayer_track_initialize(player);
6467 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6469 /* create source element */
6470 switch (player->profile.uri_type) {
6471 /* rtsp streamming */
6472 case MM_PLAYER_URI_TYPE_URL_RTSP:
6474 gint network_bandwidth;
6475 gchar *user_agent, *wap_profile;
6477 element = gst_element_factory_make("rtspsrc", "rtsp source");
6480 LOGE("failed to create streaming source element\n");
6485 network_bandwidth = 0;
6486 user_agent = wap_profile = NULL;
6489 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6490 mm_attrs_get_string_by_name(attrs, "streaming_wap_profile", &wap_profile);
6491 mm_attrs_get_int_by_name(attrs, "streaming_network_bandwidth", &network_bandwidth);
6493 SECURE_LOGD("user_agent : %s\n", user_agent);
6494 SECURE_LOGD("wap_profile : %s\n", wap_profile);
6496 /* setting property to streaming source */
6497 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6499 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6501 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
6503 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6504 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6505 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6506 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6511 case MM_PLAYER_URI_TYPE_URL_HTTP:
6513 gchar *user_agent, *proxy, *cookies, **cookie_list;
6514 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6515 user_agent = proxy = cookies = NULL;
6517 gint mode = MM_PLAYER_PD_MODE_NONE;
6519 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6521 player->pd_mode = mode;
6523 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6525 if (!MMPLAYER_IS_HTTP_PD(player)) {
6526 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6528 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6531 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6534 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6535 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6536 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
6537 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6539 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6540 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6541 LOGD("get timeout from ini\n");
6542 http_timeout = player->ini.http_timeout;
6546 SECURE_LOGD("location : %s\n", player->profile.uri);
6547 SECURE_LOGD("cookies : %s\n", cookies);
6548 SECURE_LOGD("proxy : %s\n", proxy);
6549 SECURE_LOGD("user_agent : %s\n", user_agent);
6550 LOGD("timeout : %d\n", http_timeout);
6552 /* setting property to streaming source */
6553 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6554 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6555 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6557 /* check if proxy is valid or not */
6558 if (util_check_valid_url(proxy))
6559 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
6560 /* parsing cookies */
6561 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6562 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6563 g_strfreev(cookie_list);
6566 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6568 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6569 LOGW("it's dash. and it's still experimental feature.");
6571 // progressive download
6572 gchar* location = NULL;
6574 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6577 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6579 MMPLAYER_FREEIF(player->pd_file_save_path);
6581 LOGD("PD Location : %s\n", path);
6584 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6585 LOGE("failed to get storage info");
6588 player->pd_file_save_path = g_strdup(path);
6590 LOGE("can't find pd location so, it should be set \n");
6595 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6597 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6601 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6602 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6604 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6605 g_object_get(element, "location", &location, NULL);
6606 LOGD("PD_LOCATION [%s].\n", location);
6614 case MM_PLAYER_URI_TYPE_FILE:
6616 LOGD("using filesrc for 'file://' handler.\n");
6617 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6618 LOGE("failed to get storage info");
6622 element = gst_element_factory_make("filesrc", "source");
6624 LOGE("failed to create filesrc\n");
6628 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6632 case MM_PLAYER_URI_TYPE_SS:
6634 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6635 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6637 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6641 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
6643 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
6644 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
6645 LOGD("get timeout from ini\n");
6646 http_timeout = player->ini.http_timeout;
6649 /* setting property to streaming source */
6650 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6651 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6654 case MM_PLAYER_URI_TYPE_MS_BUFF:
6656 LOGD("MS buff src is selected\n");
6658 if (player->v_stream_caps) {
6659 element = gst_element_factory_make("appsrc", "video_appsrc");
6661 LOGF("failed to create video app source element[appsrc].\n");
6665 if (player->a_stream_caps) {
6666 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6667 if (!elem_src_audio) {
6668 LOGF("failed to create audio app source element[appsrc].\n");
6672 } else if (player->a_stream_caps) {
6673 /* no video, only audio pipeline*/
6674 element = gst_element_factory_make("appsrc", "audio_appsrc");
6676 LOGF("failed to create audio app source element[appsrc].\n");
6681 if (player->s_stream_caps) {
6682 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6683 if (!elem_src_subtitle) {
6684 LOGF("failed to create subtitle app source element[appsrc].\n");
6689 LOGD("setting app sources properties.\n");
6690 LOGD("location : %s\n", player->profile.uri);
6692 if (player->v_stream_caps && element) {
6693 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6694 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6695 "caps", player->v_stream_caps, NULL);
6697 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6698 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6699 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6700 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6702 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6703 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6704 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6705 G_CALLBACK(__gst_seek_video_data), player);
6707 if (player->a_stream_caps && elem_src_audio) {
6708 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6709 "caps", player->a_stream_caps, NULL);
6711 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6712 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6713 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6714 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6716 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6717 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6718 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6719 G_CALLBACK(__gst_seek_audio_data), player);
6721 } else if (player->a_stream_caps && element) {
6722 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6723 "caps", player->a_stream_caps, NULL);
6725 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6726 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6727 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6728 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6730 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6731 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6732 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6733 G_CALLBACK(__gst_seek_audio_data), player);
6736 if (player->s_stream_caps && elem_src_subtitle) {
6737 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6738 "caps", player->s_stream_caps, NULL);
6740 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6741 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6742 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6743 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6745 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6747 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6748 G_CALLBACK(__gst_seek_subtitle_data), player);
6751 if (player->v_stream_caps && element) {
6752 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6753 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6754 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6755 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6757 if (player->a_stream_caps && elem_src_audio) {
6758 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6759 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6760 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6761 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6763 } else if (player->a_stream_caps && element) {
6764 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6765 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6766 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6767 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6770 if (player->s_stream_caps && elem_src_subtitle)
6771 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6772 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6774 need_state_holder = FALSE;
6776 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6777 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6778 LOGE("failed to commit\n");
6782 case MM_PLAYER_URI_TYPE_MEM:
6784 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6786 LOGD("mem src is selected\n");
6788 element = gst_element_factory_make("appsrc", "mem-source");
6790 LOGE("failed to create appsrc element\n");
6794 g_object_set(element, "stream-type", stream_type, NULL);
6795 g_object_set(element, "size", player->mem_buf.len, NULL);
6796 g_object_set(element, "blocksize", (guint64)20480, NULL);
6798 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6799 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf);
6800 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6801 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf);
6804 case MM_PLAYER_URI_TYPE_URL:
6807 case MM_PLAYER_URI_TYPE_TEMP:
6810 case MM_PLAYER_URI_TYPE_NONE:
6815 /* check source element is OK */
6817 LOGE("no source element was created.\n");
6821 /* take source element */
6822 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6823 mainbin[MMPLAYER_M_SRC].gst = element;
6824 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6826 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6827 player->streamer = __mm_player_streaming_create();
6828 __mm_player_streaming_initialize(player->streamer);
6831 if (MMPLAYER_IS_HTTP_PD(player)) {
6832 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6834 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6835 element = gst_element_factory_make("queue2", "queue2");
6837 LOGE("failed to create http streaming buffer element\n");
6842 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6843 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6844 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6846 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6848 __mm_player_streaming_set_queue2(player->streamer,
6851 player->ini.http_max_size_bytes,
6854 player->ini.http_buffering_limit,
6855 MUXED_BUFFER_TYPE_MEM_QUEUE,
6859 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6860 if (player->v_stream_caps) {
6861 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6862 if (!es_video_queue) {
6863 LOGE("create es_video_queue for es player failed\n");
6866 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6867 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6868 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6869 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6871 /* Adding audio appsrc to bucket */
6872 if (player->a_stream_caps && elem_src_audio) {
6873 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6874 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6875 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6877 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6878 if (!es_audio_queue) {
6879 LOGE("create es_audio_queue for es player failed\n");
6882 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6884 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6885 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6886 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6888 } else if (player->a_stream_caps) {
6889 /* Only audio stream, no video */
6890 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6891 if (!es_audio_queue) {
6892 LOGE("create es_audio_queue for es player failed\n");
6895 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6896 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6897 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6900 if (player->s_stream_caps && elem_src_subtitle) {
6901 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6902 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6903 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6905 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6906 if (!es_subtitle_queue) {
6907 LOGE("create es_subtitle_queue for es player failed\n");
6910 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6911 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6912 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6916 /* create autoplugging element if src element is not a rtsp src */
6917 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6918 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6920 enum MainElementID elemId = MMPLAYER_M_NUM;
6922 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6923 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6924 elemId = MMPLAYER_M_AUTOPLUG;
6925 element = __mmplayer_create_decodebin(player);
6927 /* default size of mq in decodebin is 2M
6928 * but it can cause blocking issue during seeking depends on content. */
6929 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6931 need_state_holder = FALSE;
6933 elemId = MMPLAYER_M_TYPEFIND;
6934 element = gst_element_factory_make("typefind", "typefinder");
6935 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6936 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6940 /* check autoplug element is OK */
6942 LOGE("can not create element(%d)\n", elemId);
6946 mainbin[elemId].id = elemId;
6947 mainbin[elemId].gst = element;
6949 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6952 /* add elements to pipeline */
6953 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6954 LOGE("Failed to add elements to pipeline\n");
6959 /* linking elements in the bucket by added order. */
6960 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6961 LOGE("Failed to link some elements\n");
6966 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6967 if (need_state_holder) {
6969 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6970 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6972 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6973 LOGE("fakesink element could not be created\n");
6976 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6978 /* take ownership of fakesink. we are reusing it */
6979 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6982 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6983 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6984 LOGE("failed to add fakesink to bin\n");
6989 /* now we have completed mainbin. take it */
6990 player->pipeline->mainbin = mainbin;
6992 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6993 GstPad *srcpad = NULL;
6995 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6996 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6998 __mmplayer_gst_create_decoder(player,
6999 MM_PLAYER_TRACK_TYPE_VIDEO,
7001 MMPLAYER_M_AUTOPLUG_V_DEC,
7004 gst_object_unref(GST_OBJECT(srcpad));
7009 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
7010 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
7012 __mmplayer_gst_create_decoder(player,
7013 MM_PLAYER_TRACK_TYPE_AUDIO,
7015 MMPLAYER_M_AUTOPLUG_A_DEC,
7018 gst_object_unref(GST_OBJECT(srcpad));
7023 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
7024 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
7027 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
7028 if (__mmplayer_check_subtitle(player)) {
7029 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
7030 LOGE("fail to create text pipeline");
7033 /* connect bus callback */
7034 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7036 LOGE("cannot get bus from pipeline.\n");
7040 /* set sync handler to get tag synchronously */
7041 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
7044 gst_object_unref(GST_OBJECT(bus));
7045 g_list_free(element_bucket);
7047 /* create gst bus_msb_cb thread */
7048 g_mutex_init(&player->bus_msg_thread_mutex);
7049 g_cond_init(&player->bus_msg_thread_cond);
7050 player->bus_msg_thread_exit = FALSE;
7051 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
7052 player->bus_msg_thread =
7053 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
7054 if (!player->bus_msg_thread) {
7055 LOGE("failed to create gst BUS msg thread");
7056 g_mutex_clear(&player->bus_msg_thread_mutex);
7057 g_cond_clear(&player->bus_msg_thread_cond);
7063 return MM_ERROR_NONE;
7066 __mmplayer_gst_destroy_pipeline(player);
7067 g_list_free(element_bucket);
7070 /* release element which are not added to bin */
7071 for (i = 1; i < MMPLAYER_M_NUM; i++) {
7072 /* NOTE : skip pipeline */
7073 if (mainbin[i].gst) {
7074 GstObject* parent = NULL;
7075 parent = gst_element_get_parent(mainbin[i].gst);
7078 gst_object_unref(GST_OBJECT(mainbin[i].gst));
7079 mainbin[i].gst = NULL;
7081 gst_object_unref(GST_OBJECT(parent));
7085 /* release pipeline with it's childs */
7086 if (mainbin[MMPLAYER_M_PIPE].gst)
7087 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7089 MMPLAYER_FREEIF(mainbin);
7092 MMPLAYER_FREEIF(player->pipeline);
7093 return MM_ERROR_PLAYER_INTERNAL;
7097 __mmplayer_reset_gapless_state(mm_player_t* player)
7100 MMPLAYER_RETURN_IF_FAIL(player
7102 && player->pipeline->audiobin
7103 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
7105 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
7112 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
7115 int ret = MM_ERROR_NONE;
7119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
7121 /* cleanup stuffs */
7122 MMPLAYER_FREEIF(player->type);
7123 player->have_dynamic_pad = FALSE;
7124 player->no_more_pad = FALSE;
7125 player->num_dynamic_pad = 0;
7126 player->demux_pad_index = 0;
7127 player->use_deinterleave = FALSE;
7128 player->max_audio_channels = 0;
7129 player->video_share_api_delta = 0;
7130 player->video_share_clock_delta = 0;
7131 player->video_hub_download_mode = 0;
7133 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7134 player->subtitle_language_list = NULL;
7135 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7137 __mmplayer_reset_gapless_state(player);
7139 if (player->streamer) {
7140 __mm_player_streaming_deinitialize(player->streamer);
7141 __mm_player_streaming_destroy(player->streamer);
7142 player->streamer = NULL;
7145 /* cleanup unlinked mime type */
7146 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7147 MMPLAYER_FREEIF(player->unlinked_video_mime);
7148 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7150 /* cleanup running stuffs */
7151 __mmplayer_cancel_eos_timer(player);
7153 /* cleanup gst stuffs */
7154 if (player->pipeline) {
7155 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7156 GstTagList* tag_list = player->pipeline->tag_list;
7158 /* first we need to disconnect all signal hander */
7159 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7162 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7163 MMPlayerGstElement* videobin = player->pipeline->videobin;
7164 MMPlayerGstElement* textbin = player->pipeline->textbin;
7165 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7166 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7167 gst_object_unref(bus);
7169 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7170 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7171 if (ret != MM_ERROR_NONE) {
7172 LOGE("fail to change state to NULL\n");
7173 return MM_ERROR_PLAYER_INTERNAL;
7176 LOGW("succeeded in chaning state to NULL\n");
7178 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7181 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7182 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7184 /* free avsysaudiosink
7185 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7186 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7188 MMPLAYER_FREEIF(audiobin);
7189 MMPLAYER_FREEIF(videobin);
7190 MMPLAYER_FREEIF(textbin);
7191 MMPLAYER_FREEIF(mainbin);
7195 gst_tag_list_free(tag_list);
7197 MMPLAYER_FREEIF(player->pipeline);
7199 MMPLAYER_FREEIF(player->album_art);
7201 if (player->v_stream_caps) {
7202 gst_caps_unref(player->v_stream_caps);
7203 player->v_stream_caps = NULL;
7205 if (player->a_stream_caps) {
7206 gst_caps_unref(player->a_stream_caps);
7207 player->a_stream_caps = NULL;
7210 if (player->s_stream_caps) {
7211 gst_caps_unref(player->s_stream_caps);
7212 player->s_stream_caps = NULL;
7214 _mmplayer_track_destroy(player);
7216 if (player->sink_elements)
7217 g_list_free(player->sink_elements);
7218 player->sink_elements = NULL;
7220 if (player->bufmgr) {
7221 tbm_bufmgr_deinit(player->bufmgr);
7222 player->bufmgr = NULL;
7225 LOGW("finished destroy pipeline\n");
7232 static int __gst_realize(mm_player_t* player)
7235 int ret = MM_ERROR_NONE;
7239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7241 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7243 ret = __mmplayer_gst_create_pipeline(player);
7245 LOGE("failed to create pipeline\n");
7249 /* set pipeline state to READY */
7250 /* NOTE : state change to READY must be performed sync. */
7251 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7252 ret = __mmplayer_gst_set_state(player,
7253 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7255 if (ret != MM_ERROR_NONE) {
7256 /* return error if failed to set state */
7257 LOGE("failed to set READY state");
7261 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7263 /* create dot before error-return. for debugging */
7264 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7271 static int __gst_unrealize(mm_player_t* player)
7273 int ret = MM_ERROR_NONE;
7277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7279 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7280 MMPLAYER_PRINT_STATE(player);
7282 /* release miscellaneous information */
7283 __mmplayer_release_misc(player);
7285 /* destroy pipeline */
7286 ret = __mmplayer_gst_destroy_pipeline(player);
7287 if (ret != MM_ERROR_NONE) {
7288 LOGE("failed to destory pipeline\n");
7292 /* release miscellaneous information.
7293 these info needs to be released after pipeline is destroyed. */
7294 __mmplayer_release_misc_post(player);
7296 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7303 static int __gst_pending_seek(mm_player_t* player)
7305 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7306 int ret = MM_ERROR_NONE;
7310 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7312 if (!player->pending_seek.is_pending) {
7313 LOGD("pending seek is not reserved. nothing to do.\n");
7317 /* check player state if player could pending seek or not. */
7318 current_state = MMPLAYER_CURRENT_STATE(player);
7320 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7321 LOGW("try to pending seek in %s state, try next time. \n",
7322 MMPLAYER_STATE_GET_NAME(current_state));
7326 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7328 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7330 if (MM_ERROR_NONE != ret)
7331 LOGE("failed to seek pending postion. just keep staying current position.\n");
7333 player->pending_seek.is_pending = FALSE;
7340 static int __gst_start(mm_player_t* player)
7342 gboolean sound_extraction = 0;
7343 int ret = MM_ERROR_NONE;
7344 gboolean async = FALSE;
7348 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7350 /* get sound_extraction property */
7351 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7353 /* NOTE : if SetPosition was called before Start. do it now */
7354 /* streaming doesn't support it. so it should be always sync */
7355 /* !!create one more api to check if there is pending seek rather than checking variables */
7356 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7357 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7358 ret = __gst_pause(player, FALSE);
7359 if (ret != MM_ERROR_NONE) {
7360 LOGE("failed to set state to PAUSED for pending seek\n");
7364 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7366 if (sound_extraction) {
7367 LOGD("setting pcm extraction\n");
7369 ret = __mmplayer_set_pcm_extraction(player);
7370 if (MM_ERROR_NONE != ret) {
7371 LOGW("failed to set pcm extraction\n");
7375 if (MM_ERROR_NONE != __gst_pending_seek(player))
7376 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7380 LOGD("current state before doing transition");
7381 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7382 MMPLAYER_PRINT_STATE(player);
7384 /* set pipeline state to PLAYING */
7385 if (player->es_player_push_mode)
7387 /* set pipeline state to PLAYING */
7388 ret = __mmplayer_gst_set_state(player,
7389 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7391 if (ret == MM_ERROR_NONE) {
7392 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7394 LOGE("failed to set state to PLAYING");
7398 /* generating debug info before returning error */
7399 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7406 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
7410 MMPLAYER_RETURN_IF_FAIL(player
7412 && player->pipeline->audiobin
7413 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7415 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", TRUE, NULL);
7422 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
7426 MMPLAYER_RETURN_IF_FAIL(player
7428 && player->pipeline->audiobin
7429 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
7431 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", FALSE, NULL);
7436 static int __gst_stop(mm_player_t* player)
7438 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7439 MMHandleType attrs = 0;
7440 gboolean fadedown = FALSE;
7441 gboolean rewind = FALSE;
7443 int ret = MM_ERROR_NONE;
7444 gboolean async = FALSE;
7448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7449 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7451 LOGD("current state before doing transition");
7452 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7453 MMPLAYER_PRINT_STATE(player);
7455 attrs = MMPLAYER_GET_ATTRS(player);
7457 LOGE("cannot get content attribute\n");
7458 return MM_ERROR_PLAYER_INTERNAL;
7461 mm_attrs_get_int_by_name(attrs, "sound_fadedown", &fadedown);
7463 /* enable fadedown */
7464 if (fadedown || player->sound_focus.by_asm_cb)
7465 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
7467 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7468 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7470 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7471 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7474 if (player->es_player_push_mode)
7477 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7479 /* disable fadeout */
7480 if (fadedown || player->sound_focus.by_asm_cb)
7481 __mmplayer_undo_sound_fadedown(player);
7483 /* return if set_state has failed */
7484 if (ret != MM_ERROR_NONE) {
7485 LOGE("failed to set state.\n");
7491 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7492 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7493 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7494 LOGW("failed to rewind\n");
7495 ret = MM_ERROR_PLAYER_SEEK;
7500 player->sent_bos = FALSE;
7502 if (player->es_player_push_mode) //for cloudgame
7505 /* wait for seek to complete */
7506 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7507 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7508 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7510 LOGE("fail to stop player.\n");
7511 ret = MM_ERROR_PLAYER_INTERNAL;
7512 __mmplayer_dump_pipeline_state(player);
7515 /* generate dot file if enabled */
7516 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7523 int __gst_pause(mm_player_t* player, gboolean async)
7525 int ret = MM_ERROR_NONE;
7529 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7530 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7532 LOGD("current state before doing transition");
7533 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7534 MMPLAYER_PRINT_STATE(player);
7536 /* set pipeline status to PAUSED */
7537 ret = __mmplayer_gst_set_state(player,
7538 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7540 if (FALSE == async) {
7541 if (ret != MM_ERROR_NONE) {
7542 GstMessage *msg = NULL;
7543 GTimer *timer = NULL;
7544 gdouble MAX_TIMEOUT_SEC = 3;
7546 LOGE("failed to set state to PAUSED");
7548 if (player->msg_posted) {
7549 LOGE("error msg is already posted.");
7553 timer = g_timer_new();
7554 g_timer_start(timer);
7556 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7559 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7561 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7562 GError *error = NULL;
7564 /* parse error code */
7565 gst_message_parse_error(msg, &error, NULL);
7567 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7568 /* Note : the streaming error from the streaming source is handled
7569 * using __mmplayer_handle_streaming_error.
7571 __mmplayer_handle_streaming_error(player, msg);
7574 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7576 if (error->domain == GST_STREAM_ERROR)
7577 ret = __gst_handle_stream_error(player, error, msg);
7578 else if (error->domain == GST_RESOURCE_ERROR)
7579 ret = __gst_handle_resource_error(player, error->code, NULL);
7580 else if (error->domain == GST_LIBRARY_ERROR)
7581 ret = __gst_handle_library_error(player, error->code);
7582 else if (error->domain == GST_CORE_ERROR)
7583 ret = __gst_handle_core_error(player, error->code);
7585 g_error_free(error);
7587 player->msg_posted = TRUE;
7589 gst_message_unref(msg);
7591 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7593 gst_object_unref(bus);
7594 g_timer_stop(timer);
7595 g_timer_destroy(timer);
7599 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7600 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7602 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7604 } else if (ret == MM_ERROR_NONE) {
7606 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7610 /* generate dot file before returning error */
7611 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7618 int __gst_resume(mm_player_t* player, gboolean async)
7620 int ret = MM_ERROR_NONE;
7625 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7626 MM_ERROR_PLAYER_NOT_INITIALIZED);
7628 LOGD("current state before doing transition");
7629 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7630 MMPLAYER_PRINT_STATE(player);
7632 /* generate dot file before returning error */
7633 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7636 LOGD("do async state transition to PLAYING.\n");
7638 /* set pipeline state to PLAYING */
7639 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7641 ret = __mmplayer_gst_set_state(player,
7642 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7643 if (ret != MM_ERROR_NONE) {
7644 LOGE("failed to set state to PLAYING\n");
7647 if (async == FALSE) {
7648 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7649 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7650 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7654 /* generate dot file before returning error */
7655 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7663 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7665 unsigned long dur_msec = 0;
7666 gint64 dur_nsec = 0;
7667 gint64 pos_nsec = 0;
7668 gboolean ret = TRUE;
7669 gboolean accurated = FALSE;
7670 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7673 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7674 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7676 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7677 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7680 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7681 /* check duration */
7682 /* NOTE : duration cannot be zero except live streaming.
7683 * Since some element could have some timing problemn with quering duration, try again.
7685 if (!player->duration) {
7686 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7687 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7688 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7689 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7690 player->pending_seek.is_pending = TRUE;
7691 player->pending_seek.format = format;
7692 player->pending_seek.pos = position;
7693 player->doing_seek = FALSE;
7694 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7695 return MM_ERROR_NONE;
7700 player->duration = dur_nsec;
7703 if (player->duration) {
7704 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7706 LOGE("could not get the duration. fail to seek.\n");
7710 LOGD("playback rate: %f\n", player->playback_rate);
7712 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7714 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7716 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7720 case MM_PLAYER_POS_FORMAT_TIME:
7722 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7723 GstQuery *query = NULL;
7724 gboolean seekable = FALSE;
7726 /* check position is valid or not */
7727 if (position > dur_msec)
7730 query = gst_query_new_seeking(GST_FORMAT_TIME);
7731 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7732 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7733 gst_query_unref(query);
7736 LOGW("non-seekable content");
7737 player->doing_seek = FALSE;
7738 return MM_ERROR_PLAYER_NO_OP;
7741 LOGW("failed to get seeking query");
7742 gst_query_unref(query); /* keep seeking operation */
7745 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7747 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7748 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7749 This causes problem is position calculation during normal pause resume scenarios also.
7750 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7751 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7752 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7753 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7754 LOGW("getting current position failed in seek\n");
7756 player->last_position = pos_nsec;
7757 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7760 if (player->doing_seek) {
7761 LOGD("not completed seek");
7762 return MM_ERROR_PLAYER_DOING_SEEK;
7766 if (!internal_called)
7767 player->doing_seek = TRUE;
7769 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7771 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7772 gint64 cur_time = 0;
7774 /* get current position */
7775 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7778 GstEvent *event = gst_event_new_seek(1.0,
7780 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7781 GST_SEEK_TYPE_SET, cur_time,
7782 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7784 __gst_send_event_to_sink(player, event);
7786 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7787 __gst_pause(player, FALSE);
7790 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7791 that's why set position through property. */
7792 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7793 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7794 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7795 (!player->videodec_linked) && (!player->audiodec_linked)) {
7797 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7798 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7799 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7800 player->doing_seek = FALSE;
7801 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7803 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7804 GST_FORMAT_TIME, seek_flags,
7805 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7809 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7815 case MM_PLAYER_POS_FORMAT_PERCENT:
7817 LOGD("seeking to(%lu)%% \n", position);
7819 if (player->doing_seek) {
7820 LOGD("not completed seek");
7821 return MM_ERROR_PLAYER_DOING_SEEK;
7824 if (!internal_called)
7825 player->doing_seek = TRUE;
7827 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7828 pos_nsec = (gint64)((position * player->duration) / 100);
7829 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7830 GST_FORMAT_TIME, seek_flags,
7831 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7833 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7843 /* NOTE : store last seeking point to overcome some bad operation
7844 * (returning zero when getting current position) of some elements
7846 player->last_position = pos_nsec;
7848 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7849 if (player->playback_rate > 1.0)
7850 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7853 return MM_ERROR_NONE;
7856 player->pending_seek.is_pending = TRUE;
7857 player->pending_seek.format = format;
7858 player->pending_seek.pos = position;
7860 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7861 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7863 return MM_ERROR_NONE;
7866 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7867 return MM_ERROR_INVALID_ARGUMENT;
7870 player->doing_seek = FALSE;
7871 return MM_ERROR_PLAYER_SEEK;
7874 #define TRICKPLAY_OFFSET GST_MSECOND
7877 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7879 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7880 gint64 pos_msec = 0;
7881 gboolean ret = TRUE;
7883 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7884 MM_ERROR_PLAYER_NOT_INITIALIZED);
7886 current_state = MMPLAYER_CURRENT_STATE(player);
7888 /* NOTE : query position except paused state to overcome some bad operation
7889 * please refer to below comments in details
7891 if (current_state != MM_PLAYER_STATE_PAUSED)
7892 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7894 /* NOTE : get last point to overcome some bad operation of some elements
7895 *(returning zero when getting current position in paused state
7896 * and when failed to get postion during seeking
7898 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7899 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7901 if (player->playback_rate < 0.0)
7902 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7904 pos_msec = player->last_position;
7907 pos_msec = player->last_position;
7909 player->last_position = pos_msec;
7911 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7914 if (player->duration > 0 && pos_msec > player->duration)
7915 pos_msec = player->duration;
7917 if (player->sound_focus.keep_last_pos) {
7918 LOGD("return last pos as stop by asm, %"GST_TIME_FORMAT, GST_TIME_ARGS(player->last_position));
7919 pos_msec = player->last_position;
7921 player->last_position = pos_msec;
7926 case MM_PLAYER_POS_FORMAT_TIME:
7927 *position = GST_TIME_AS_MSECONDS(pos_msec);
7930 case MM_PLAYER_POS_FORMAT_PERCENT:
7932 if (player->duration <= 0) {
7933 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7936 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7937 *position = pos_msec * 100 / player->duration;
7942 return MM_ERROR_PLAYER_INTERNAL;
7945 return MM_ERROR_NONE;
7949 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7951 #define STREAMING_IS_FINISHED 0
7952 #define BUFFERING_MAX_PER 100
7953 #define DEFAULT_PER_VALUE -1
7954 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7956 MMPlayerGstElement *mainbin = NULL;
7957 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7958 gint64 buffered_total = 0;
7959 unsigned long position = 0;
7960 gint buffered_sec = -1;
7961 GstBufferingMode mode = GST_BUFFERING_STREAM;
7962 gint64 content_size_time = player->duration;
7963 guint64 content_size_bytes = player->http_content_size;
7965 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7967 player->pipeline->mainbin,
7968 MM_ERROR_PLAYER_NOT_INITIALIZED);
7970 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7975 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7976 /* and rtsp is not ready yet. */
7977 LOGW("it's only used for http streaming case.\n");
7978 return MM_ERROR_PLAYER_NO_OP;
7981 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7982 LOGW("Time format is not supported yet.\n");
7983 return MM_ERROR_INVALID_ARGUMENT;
7986 if (content_size_time <= 0 || content_size_bytes <= 0) {
7987 LOGW("there is no content size.");
7988 return MM_ERROR_NONE;
7991 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7992 LOGW("fail to get current position.");
7993 return MM_ERROR_NONE;
7996 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7997 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7999 mainbin = player->pipeline->mainbin;
8000 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
8002 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
8003 GstQuery *query = NULL;
8004 gint byte_in_rate = 0, byte_out_rate = 0;
8005 gint64 estimated_total = 0;
8007 query = gst_query_new_buffering(GST_FORMAT_BYTES);
8008 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
8009 LOGW("fail to get buffering query from queue2");
8011 gst_query_unref(query);
8012 return MM_ERROR_NONE;
8015 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
8016 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
8018 if (mode == GST_BUFFERING_STREAM) {
8019 /* using only queue in case of push mode(ts / mp3) */
8020 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
8021 GST_FORMAT_BYTES, &buffered_total)) {
8022 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
8023 stop_per = 100 * buffered_total / content_size_bytes;
8026 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
8028 guint num_of_ranges = 0;
8029 gint64 start_byte = 0, stop_byte = 0;
8031 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
8032 if (estimated_total != STREAMING_IS_FINISHED) {
8033 /* buffered size info from queue2 */
8034 num_of_ranges = gst_query_get_n_buffering_ranges(query);
8035 for (idx = 0; idx < num_of_ranges; idx++) {
8036 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
8037 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
8039 buffered_total += (stop_byte - start_byte);
8042 stop_per = BUFFERING_MAX_PER;
8044 gst_query_unref(query);
8047 if (stop_per == DEFAULT_PER_VALUE) {
8048 guint dur_sec = (guint)(content_size_time/GST_SECOND);
8050 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
8052 /* buffered size info from multiqueue */
8053 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
8054 guint curr_size_bytes = 0;
8055 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
8056 "curr-size-bytes", &curr_size_bytes, NULL);
8057 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
8058 buffered_total += curr_size_bytes;
8061 if (avg_byterate > 0)
8062 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
8063 else if (player->total_maximum_bitrate > 0)
8064 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
8065 else if (player->total_bitrate > 0)
8066 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
8068 if (buffered_sec >= 0)
8069 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
8073 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
8074 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
8076 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
8077 buffered_total, buffered_sec, *start_pos, *stop_pos);
8079 return MM_ERROR_NONE;
8083 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
8088 LOGW("set_message_callback is called with invalid player handle\n");
8089 return MM_ERROR_PLAYER_NOT_INITIALIZED;
8092 player->msg_cb = callback;
8093 player->msg_cb_param = user_param;
8095 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
8099 return MM_ERROR_NONE;
8102 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
8104 int ret = MM_ERROR_PLAYER_INVALID_URI;
8109 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
8110 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
8111 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
8113 memset(data, 0, sizeof(MMPlayerParseProfile));
8115 if ((path = strstr(uri, "es_buff://"))) {
8117 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8118 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
8119 ret = MM_ERROR_NONE;
8121 } else if ((path = strstr(uri, "rtsp://"))) {
8123 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8124 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8125 ret = MM_ERROR_NONE;
8127 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
8130 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8131 tmp = g_ascii_strdown(uri, strlen(uri));
8133 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
8134 data->uri_type = MM_PLAYER_URI_TYPE_SS;
8136 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
8138 ret = MM_ERROR_NONE;
8141 } else if ((path = strstr(uri, "rtspu://"))) {
8143 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8144 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8145 ret = MM_ERROR_NONE;
8147 } else if ((path = strstr(uri, "rtspr://"))) {
8148 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
8149 char *separater = strstr(path, "*");
8153 char *urgent = separater + strlen("*");
8155 if ((urgent_len = strlen(urgent))) {
8156 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
8157 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
8158 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8159 ret = MM_ERROR_NONE;
8162 } else if ((path = strstr(uri, "mms://"))) {
8164 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
8165 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
8166 ret = MM_ERROR_NONE;
8168 } else if ((path = strstr(uri, "mem://"))) {
8171 char *buffer = NULL;
8172 char *seperator = strchr(path, ',');
8173 char ext[100] = {0,}, size[100] = {0,};
8176 if ((buffer = strstr(path, "ext="))) {
8177 buffer += strlen("ext=");
8179 if (strlen(buffer)) {
8180 strncpy(ext, buffer, 99);
8182 if ((seperator = strchr(ext, ','))
8183 || (seperator = strchr(ext, ' '))
8184 || (seperator = strchr(ext, '\0'))) {
8185 seperator[0] = '\0';
8190 if ((buffer = strstr(path, "size="))) {
8191 buffer += strlen("size=");
8193 if (strlen(buffer) > 0) {
8194 strncpy(size, buffer, 99);
8196 if ((seperator = strchr(size, ','))
8197 || (seperator = strchr(size, ' '))
8198 || (seperator = strchr(size, '\0'))) {
8199 seperator[0] = '\0';
8202 mem_size = atoi(size);
8207 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8208 if (mem_size && param) {
8212 data->mem = malloc(mem_size);
8215 memcpy(data->mem, param, mem_size);
8216 data->mem_size = mem_size;
8218 LOGE("failed to alloc mem %d", mem_size);
8221 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8222 ret = MM_ERROR_NONE;
8226 gchar *location = NULL;
8229 if ((path = strstr(uri, "file://"))) {
8231 location = g_filename_from_uri(uri, NULL, &err);
8233 if (!location || (err != NULL)) {
8234 LOGE("Invalid URI '%s' for filesrc: %s", path,
8235 (err != NULL) ? err->message : "unknown error");
8237 if (err) g_error_free(err);
8238 if (location) g_free(location);
8240 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8244 LOGD("path from uri: %s", location);
8247 path = (location != NULL) ? (location) : ((char*)uri);
8248 int file_stat = MM_ERROR_NONE;
8250 file_stat = util_exist_file_path(path);
8252 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8253 if (file_stat == MM_ERROR_NONE) {
8254 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8256 if (util_is_sdp_file(path)) {
8257 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8258 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8260 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8262 ret = MM_ERROR_NONE;
8263 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8264 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8266 LOGE("invalid uri, could not play..\n");
8267 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8270 if (location) g_free(location);
8274 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8275 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8276 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8277 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8279 /* dump parse result */
8280 SECURE_LOGW("incomming uri : %s\n", uri);
8281 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8282 data->uri_type, data->mem, data->mem_size, data->urgent);
8289 gboolean _asm_postmsg(gpointer *data)
8291 mm_player_t* player = (mm_player_t*)data;
8292 MMMessageParamType msg = {0, };
8295 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8296 LOGW("get notified");
8298 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
8299 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
8305 msg.union_type = MM_MSG_UNION_CODE;
8306 msg.code = player->sound_focus.focus_changed_msg;
8308 MMPLAYER_POST_MSG(player, MM_MESSAGE_READY_TO_RESUME, &msg);
8309 player->resume_event_id = 0;
8315 gboolean _asm_lazy_pause(gpointer *data)
8317 mm_player_t* player = (mm_player_t*)data;
8318 int ret = MM_ERROR_NONE;
8322 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8324 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING) {
8325 LOGD("Ready to proceed lazy pause\n");
8326 ret = _mmplayer_pause((MMHandleType)player);
8327 if (MM_ERROR_NONE != ret)
8328 LOGE("MMPlayer pause failed in ASM callback lazy pause\n");
8330 LOGD("Invalid state to proceed lazy pause\n");
8333 if (player->pipeline && player->pipeline->audiobin)
8334 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
8336 player->sound_focus.by_asm_cb = FALSE; //should be reset here
8344 __mmplayer_can_do_interrupt(mm_player_t *player)
8346 if (!player || !player->pipeline || !player->attrs) {
8347 LOGW("not initialized");
8351 if ((player->sound_focus.exit_cb) || (player->set_mode.pcm_extraction)) {
8352 LOGW("leave from asm cb right now, %d, %d", player->sound_focus.exit_cb, player->set_mode.pcm_extraction);
8356 /* check if seeking */
8357 if (player->doing_seek) {
8358 MMMessageParamType msg_param;
8359 memset(&msg_param, 0, sizeof(MMMessageParamType));
8360 msg_param.code = MM_ERROR_PLAYER_SEEK;
8361 player->doing_seek = FALSE;
8362 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8366 /* check other thread */
8367 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8368 LOGW("locked already, cmd state : %d", player->cmd);
8370 /* check application command */
8371 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8372 LOGW("playing.. should wait cmd lock then, will be interrupted");
8374 /* lock will be released at mrp_resource_release_cb() */
8375 MMPLAYER_CMD_LOCK(player);
8378 LOGW("nothing to do");
8381 LOGW("can interrupt immediately");
8385 FAILED: /* with CMD UNLOCKED */
8388 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8393 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8396 mm_player_t *player = NULL;
8400 if (user_data == NULL) {
8401 LOGE("- user_data is null\n");
8404 player = (mm_player_t *)user_data;
8406 /* do something to release resource here.
8407 * player stop and interrupt forwarding */
8408 if (!__mmplayer_can_do_interrupt(player)) {
8409 LOGW("no need to interrupt, so leave");
8411 MMMessageParamType msg = {0, };
8412 unsigned long pos = 0;
8414 player->interrupted_by_resource = TRUE;
8416 /* get last play position */
8417 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8418 LOGW("failed to get play position.");
8420 msg.union_type = MM_MSG_UNION_TIME;
8421 msg.time.elapsed = (unsigned int)pos;
8422 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8424 LOGD("video resource conflict so, resource will be freed by unrealizing");
8425 if (_mmplayer_unrealize((MMHandleType)player))
8426 LOGW("failed to unrealize");
8428 /* lock is called in __mmplayer_can_do_interrupt() */
8429 MMPLAYER_CMD_UNLOCK(player);
8432 if (res == player->video_overlay_resource)
8433 player->video_overlay_resource = FALSE;
8435 player->video_decoder_resource = FALSE;
8442 /* if you want to enable USE_ASM, please check the history get the ASM cb code. */
8444 __mmplayer_convert_sound_focus_state(gboolean acquire, const char *reason_for_change, MMPlayerFocusChangedMsg *msg)
8446 int ret = MM_ERROR_NONE;
8447 MMPlayerFocusChangedMsg focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8449 if (strstr(reason_for_change, "alarm")) {
8450 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_ALARM;
8452 } else if (strstr(reason_for_change, "notification")) {
8453 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_NOTIFICATION;
8455 } else if (strstr(reason_for_change, "emergency")) {
8456 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_EMERGENCY;
8458 } else if (strstr(reason_for_change, "call-voice") ||
8459 strstr(reason_for_change, "call-video") ||
8460 strstr(reason_for_change, "voip") ||
8461 strstr(reason_for_change, "ringtone-voip") ||
8462 strstr(reason_for_change, "ringtone-call")) {
8463 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_CALL;
8465 } else if (strstr(reason_for_change, "media") ||
8466 strstr(reason_for_change, "radio") ||
8467 strstr(reason_for_change, "loopback") ||
8468 strstr(reason_for_change, "system") ||
8469 strstr(reason_for_change, "voice-information") ||
8470 strstr(reason_for_change, "voice-recognition")) {
8471 focus_msg = MM_PLAYER_FOCUS_CHANGED_BY_MEDIA;
8474 ret = MM_ERROR_INVALID_ARGUMENT;
8475 LOGW("not supported reason(%s), err(0x%08x)", reason_for_change, ret);
8479 if (acquire && (focus_msg != MM_PLAYER_FOCUS_CHANGED_BY_MEDIA))
8481 focus_msg = MM_PLAYER_FOCUS_CHANGED_COMPLETED;
8483 LOGD("converted from reason(%s) to msg(%d)", reason_for_change, focus_msg);
8490 /* FIXME: will be updated with new funct */
8491 void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8492 const char *reason_for_change, const char *additional_info, void *user_data)
8494 mm_player_t* player = (mm_player_t*) user_data;
8495 int result = MM_ERROR_NONE;
8496 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8498 LOGW("[handle: %p] focus watch notified", player);
8500 if (!__mmplayer_can_do_interrupt(player)) {
8501 LOGW("no need to interrupt, so leave");
8502 goto EXIT_WITHOUT_UNLOCK;
8505 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8506 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8510 LOGW("watch: state: %d, focus_type : %d, reason_for_change : %s",
8511 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8513 player->sound_focus.cb_pending = TRUE;
8514 player->sound_focus.by_asm_cb = TRUE;
8516 if (focus_state == FOCUS_IS_ACQUIRED) {
8517 LOGW("watch: FOCUS_IS_ACQUIRED");
8518 player->sound_focus.acquired = TRUE;
8520 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8521 player->sound_focus.focus_changed_msg = (int)msg;
8523 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_CALL ||
8524 player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_ALARM ||
8525 player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA) {
8526 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8527 // hold 0.7 second to excute "fadedown mute" effect
8528 LOGW("do fade down->pause->undo fade down");
8530 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8532 result = _mmplayer_pause((MMHandleType)player);
8533 if (result != MM_ERROR_NONE) {
8534 LOGW("fail to set Pause state by asm");
8538 __mmplayer_undo_sound_fadedown(player);
8540 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8541 _mmplayer_unrealize((MMHandleType)player);
8544 LOGW("pause immediately");
8545 result = _mmplayer_pause((MMHandleType)player);
8546 if (result != MM_ERROR_NONE) {
8547 LOGW("fail to set Pause state by asm");
8551 } else if (focus_state == FOCUS_IS_RELEASED) {
8552 LOGW("FOCUS_IS_RELEASED: Got msg from asm to resume");
8553 player->sound_focus.acquired = FALSE;
8554 player->sound_focus.antishock = TRUE;
8555 player->sound_focus.by_asm_cb = FALSE;
8557 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8558 player->sound_focus.focus_changed_msg = (int)msg;
8560 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8561 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8564 LOGW("unknown focus state %d", focus_state);
8567 player->sound_focus.by_asm_cb = FALSE;
8568 player->sound_focus.cb_pending = FALSE;
8571 MMPLAYER_CMD_UNLOCK(player);
8575 EXIT_WITHOUT_UNLOCK:
8581 __mmplayer_sound_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state,
8582 const char *reason_for_change, int option, const char *additional_info, void *user_data)
8584 mm_player_t* player = (mm_player_t*) user_data;
8585 int result = MM_ERROR_NONE;
8586 MMPlayerFocusChangedMsg msg = MM_PLAYER_FOCUS_CHANGED_BY_UNKNOWN;
8588 LOGW("get focus notified");
8590 if (!__mmplayer_can_do_interrupt(player)) {
8591 LOGW("no need to interrupt, so leave");
8592 goto EXIT_WITHOUT_UNLOCK;
8595 if (player->sound_focus.session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
8596 LOGW("flags is UNINTERRUPTIBLE. do nothing.");
8600 LOGW("state: %d, focus_type : %d, reason_for_change : %s",
8601 focus_state, focus_type, (reason_for_change ? reason_for_change : "N/A"));
8603 player->sound_focus.cb_pending = TRUE;
8604 player->sound_focus.by_asm_cb = TRUE;
8605 // player->sound_focus.event_src = event_src;
8607 if (focus_state == FOCUS_IS_RELEASED) {
8608 LOGW("FOCUS_IS_RELEASED");
8609 player->sound_focus.acquired = FALSE;
8611 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(FALSE, reason_for_change, &msg))
8612 player->sound_focus.focus_changed_msg = (int)msg;
8614 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_CALL ||
8615 player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_ALARM ||
8616 player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA) {
8617 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
8618 //hold 0.7 second to excute "fadedown mute" effect
8619 LOGW("do fade down->pause->undo fade down");
8621 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
8623 result = _mmplayer_pause((MMHandleType)player);
8624 if (result != MM_ERROR_NONE) {
8625 LOGW("fail to set Pause state by asm");
8628 __mmplayer_undo_sound_fadedown(player);
8630 /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
8631 _mmplayer_unrealize((MMHandleType)player);
8634 LOGW("pause immediately");
8635 result = _mmplayer_pause((MMHandleType)player);
8636 if (result != MM_ERROR_NONE) {
8637 LOGW("fail to set Pause state by asm");
8642 if (player->sound_focus.focus_changed_msg == MM_PLAYER_FOCUS_CHANGED_BY_MEDIA &&
8643 player->sound_focus.session_type == MM_SESSION_TYPE_MEDIA &&
8644 !(player->sound_focus.session_flags & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED)) {
8645 result = mm_sound_set_focus_reacquisition_for_session(player->sound_focus.focus_id, false);
8646 if (result != MM_ERROR_NONE)
8647 LOGW("fail to set focus reacquisition to FALSE, skip going on..");
8649 } else if (focus_state == FOCUS_IS_ACQUIRED) {
8650 LOGW("FOCUS_IS_ACQUIRED: Got msg from asm to resume");
8651 player->sound_focus.antishock = TRUE;
8652 player->sound_focus.by_asm_cb = FALSE;
8654 if (MM_ERROR_NONE == __mmplayer_convert_sound_focus_state(TRUE, reason_for_change, &msg))
8655 player->sound_focus.focus_changed_msg = (int)msg;
8657 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
8658 player->resume_event_id = g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
8661 LOGW("unknown focus state %d", focus_state);
8664 player->sound_focus.by_asm_cb = FALSE;
8665 player->sound_focus.cb_pending = FALSE;
8668 if (mm_sound_update_focus_status(id, 0))
8669 LOGE("failed to update focus status\n");
8670 MMPLAYER_CMD_UNLOCK(player);
8674 EXIT_WITHOUT_UNLOCK:
8681 _mmplayer_create_player(MMHandleType handle)
8683 int ret = MM_ERROR_PLAYER_INTERNAL;
8684 mm_player_t* player = MM_PLAYER_CAST(handle);
8688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8690 /* initialize player state */
8691 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8692 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8693 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8694 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8696 /* check current state */
8697 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8699 /* construct attributes */
8700 player->attrs = _mmplayer_construct_attribute(handle);
8702 if (!player->attrs) {
8703 LOGE("Failed to construct attributes\n");
8707 /* initialize gstreamer with configured parameter */
8708 if (!__mmplayer_init_gstreamer(player)) {
8709 LOGE("Initializing gstreamer failed\n");
8710 _mmplayer_deconstruct_attribute(handle);
8714 /* create lock. note that g_tread_init() has already called in gst_init() */
8715 g_mutex_init(&player->fsink_lock);
8717 /* create update tag lock */
8718 g_mutex_init(&player->update_tag_lock);
8720 /* create repeat mutex */
8721 g_mutex_init(&player->repeat_thread_mutex);
8723 /* create repeat cond */
8724 g_cond_init(&player->repeat_thread_cond);
8726 /* create repeat thread */
8727 player->repeat_thread =
8728 g_thread_try_new("repeat_thread", __mmplayer_repeat_thread, (gpointer)player, NULL);
8729 if (!player->repeat_thread) {
8730 LOGE("failed to create repeat_thread(%s)");
8731 g_mutex_clear(&player->repeat_thread_mutex);
8732 g_cond_clear(&player->repeat_thread_cond);
8733 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8737 /* create next play mutex */
8738 g_mutex_init(&player->next_play_thread_mutex);
8740 /* create next play cond */
8741 g_cond_init(&player->next_play_thread_cond);
8743 /* create next play thread */
8744 player->next_play_thread =
8745 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8746 if (!player->next_play_thread) {
8747 LOGE("failed to create next play thread");
8748 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8749 g_mutex_clear(&player->next_play_thread_mutex);
8750 g_cond_clear(&player->next_play_thread_cond);
8754 ret = _mmplayer_initialize_video_capture(player);
8755 if (ret != MM_ERROR_NONE) {
8756 LOGE("failed to initialize video capture\n");
8760 /* initialize resource manager */
8761 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8762 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8763 &player->resource_manager)) {
8764 LOGE("failed to initialize resource manager\n");
8768 if (MMPLAYER_IS_HTTP_PD(player)) {
8769 player->pd_downloader = NULL;
8770 player->pd_file_save_path = NULL;
8773 /* create video bo lock and cond */
8774 g_mutex_init(&player->video_bo_mutex);
8775 g_cond_init(&player->video_bo_cond);
8777 /* create media stream callback mutex */
8778 g_mutex_init(&player->media_stream_cb_lock);
8780 /* create subtitle info lock and cond */
8781 g_mutex_init(&player->subtitle_info_mutex);
8782 g_cond_init(&player->subtitle_info_cond);
8784 /* create sound focus lock */
8785 g_mutex_init(&player->sound_focus.focus_lock);
8787 player->streaming_type = STREAMING_SERVICE_NONE;
8789 /* give default value of audio effect setting */
8790 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8791 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8793 player->play_subtitle = FALSE;
8794 player->play_count = 0;
8795 player->use_deinterleave = FALSE;
8796 player->max_audio_channels = 0;
8797 player->video_share_api_delta = 0;
8798 player->video_share_clock_delta = 0;
8799 player->has_closed_caption = FALSE;
8800 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8801 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8802 player->pending_resume = FALSE;
8803 if (player->ini.dump_element_keyword[0][0] == '\0')
8804 player->ini.set_dump_element_flag = FALSE;
8806 player->ini.set_dump_element_flag = TRUE;
8808 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8809 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8810 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8812 /* Set video360 settings to their defaults for just-created player.
8814 player->is_content_spherical = FALSE;
8815 player->is_video360_enabled = TRUE;
8816 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8817 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8818 player->video360_yaw_radians = 4;
8819 player->video360_pitch_radians = 4;
8820 player->video360_zoom = 1.0f;
8821 player->video360_horizontal_fov = 0;
8822 player->video360_vertical_fov = 0;
8824 /* set player state to null */
8825 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8826 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8828 return MM_ERROR_NONE;
8832 g_mutex_clear(&player->fsink_lock);
8834 /* free update tag lock */
8835 g_mutex_clear(&player->update_tag_lock);
8838 if (player->repeat_thread) {
8839 MMPLAYER_REPEAT_THREAD_LOCK(player);
8840 player->repeat_thread_exit = TRUE;
8841 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
8842 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
8844 g_thread_join(player->repeat_thread);
8845 player->repeat_thread = NULL;
8847 g_mutex_clear(&player->repeat_thread_mutex);
8848 g_cond_clear(&player->repeat_thread_cond);
8851 /* free next play thread */
8852 if (player->next_play_thread) {
8853 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8854 player->next_play_thread_exit = TRUE;
8855 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8856 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8858 g_thread_join(player->next_play_thread);
8859 player->next_play_thread = NULL;
8861 g_mutex_clear(&player->next_play_thread_mutex);
8862 g_cond_clear(&player->next_play_thread_cond);
8865 /* release attributes */
8866 _mmplayer_deconstruct_attribute(handle);
8874 __mmplayer_init_gstreamer(mm_player_t* player)
8876 static gboolean initialized = FALSE;
8877 static const int max_argc = 50;
8879 gchar** argv = NULL;
8880 gchar** argv2 = NULL;
8886 LOGD("gstreamer already initialized.\n");
8891 argc = malloc(sizeof(int));
8892 argv = malloc(sizeof(gchar*) * max_argc);
8893 argv2 = malloc(sizeof(gchar*) * max_argc);
8895 if (!argc || !argv || !argv2)
8898 memset(argv, 0, sizeof(gchar*) * max_argc);
8899 memset(argv2, 0, sizeof(gchar*) * max_argc);
8903 argv[0] = g_strdup("mmplayer");
8906 for (i = 0; i < 5; i++) {
8907 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8908 if (strlen(player->ini.gst_param[i]) > 0) {
8909 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8914 /* we would not do fork for scanning plugins */
8915 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8918 /* check disable registry scan */
8919 if (player->ini.skip_rescan) {
8920 argv[*argc] = g_strdup("--gst-disable-registry-update");
8924 /* check disable segtrap */
8925 if (player->ini.disable_segtrap) {
8926 argv[*argc] = g_strdup("--gst-disable-segtrap");
8930 LOGD("initializing gstreamer with following parameter\n");
8931 LOGD("argc : %d\n", *argc);
8934 for (i = 0; i < arg_count; i++) {
8936 LOGD("argv[%d] : %s\n", i, argv2[i]);
8939 /* initializing gstreamer */
8940 if (!gst_init_check(argc, &argv, &err)) {
8941 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8948 for (i = 0; i < arg_count; i++) {
8949 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8950 MMPLAYER_FREEIF(argv2[i]);
8953 MMPLAYER_FREEIF(argv);
8954 MMPLAYER_FREEIF(argv2);
8955 MMPLAYER_FREEIF(argc);
8965 for (i = 0; i < arg_count; i++) {
8966 LOGD("free[%d] : %s\n", i, argv2[i]);
8967 MMPLAYER_FREEIF(argv2[i]);
8970 MMPLAYER_FREEIF(argv);
8971 MMPLAYER_FREEIF(argv2);
8972 MMPLAYER_FREEIF(argc);
8978 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8980 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8982 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8983 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8984 MMPLAYER_FREEIF(player->pd_file_save_path);
8987 return MM_ERROR_NONE;
8991 __mmplayer_check_async_state_transition(mm_player_t* player)
8993 GstState element_state = GST_STATE_VOID_PENDING;
8994 GstState element_pending_state = GST_STATE_VOID_PENDING;
8995 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8996 GstElement * element = NULL;
8997 gboolean async = FALSE;
8999 /* check player handle */
9000 MMPLAYER_RETURN_IF_FAIL(player &&
9002 player->pipeline->mainbin &&
9003 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
9006 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9008 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
9009 LOGD("don't need to check the pipeline state");
9013 MMPLAYER_PRINT_STATE(player);
9015 /* wait for state transition */
9016 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
9017 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
9019 if (ret == GST_STATE_CHANGE_FAILURE) {
9020 LOGE(" [%s] state : %s pending : %s \n",
9021 GST_ELEMENT_NAME(element),
9022 gst_element_state_get_name(element_state),
9023 gst_element_state_get_name(element_pending_state));
9025 /* dump state of all element */
9026 __mmplayer_dump_pipeline_state(player);
9031 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
9036 _mmplayer_destroy(MMHandleType handle)
9038 mm_player_t* player = MM_PLAYER_CAST(handle);
9042 /* check player handle */
9043 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9045 /* destroy can called at anytime */
9046 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
9048 /* check async state transition */
9049 __mmplayer_check_async_state_transition(player);
9051 __mmplayer_destroy_streaming_ext(player);
9053 /* release repeat thread */
9054 if (player->repeat_thread) {
9055 MMPLAYER_REPEAT_THREAD_LOCK(player);
9056 player->repeat_thread_exit = TRUE;
9057 MMPLAYER_REPEAT_THREAD_SIGNAL(player);
9058 MMPLAYER_REPEAT_THREAD_UNLOCK(player);
9060 LOGD("waitting for repeat thread exit\n");
9061 g_thread_join(player->repeat_thread);
9062 g_mutex_clear(&player->repeat_thread_mutex);
9063 g_cond_clear(&player->repeat_thread_cond);
9064 LOGD("repeat thread released\n");
9067 /* release next play thread */
9068 if (player->next_play_thread) {
9069 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
9070 player->next_play_thread_exit = TRUE;
9071 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
9072 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
9074 LOGD("waitting for next play thread exit\n");
9075 g_thread_join(player->next_play_thread);
9076 g_mutex_clear(&player->next_play_thread_mutex);
9077 g_cond_clear(&player->next_play_thread_cond);
9078 LOGD("next play thread released\n");
9081 _mmplayer_release_video_capture(player);
9083 /* flush any pending asm_cb */
9084 if (player->sound_focus.cb_pending) {
9085 /* set a flag for make sure asm_cb to be returned immediately */
9086 LOGW("asm cb has pending state");
9087 player->sound_focus.exit_cb = TRUE;
9089 /* make sure to release any pending asm_cb which locked by cmd_lock */
9090 MMPLAYER_CMD_UNLOCK(player);
9092 MMPLAYER_CMD_LOCK(player);
9096 if (MM_ERROR_NONE != _mmplayer_sound_unregister(&player->sound_focus))
9097 LOGE("failed to deregister asm server\n");
9099 /* de-initialize resource manager */
9100 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
9101 player->resource_manager))
9102 LOGE("failed to deinitialize resource manager\n");
9104 if (player->resume_event_id) {
9105 g_source_remove(player->resume_event_id);
9106 player->resume_event_id = 0;
9109 if (player->resumable_cancel_id) {
9110 g_source_remove(player->resumable_cancel_id);
9111 player->resumable_cancel_id = 0;
9114 /* release pipeline */
9115 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
9116 LOGE("failed to destory pipeline\n");
9117 return MM_ERROR_PLAYER_INTERNAL;
9120 /* release subtitle info lock and cond */
9121 g_mutex_clear(&player->subtitle_info_mutex);
9122 g_cond_clear(&player->subtitle_info_cond);
9124 __mmplayer_release_dump_list(player->dump_list);
9126 /* release miscellaneous information */
9127 __mmplayer_release_misc(player);
9129 /* release miscellaneous information.
9130 these info needs to be released after pipeline is destroyed. */
9131 __mmplayer_release_misc_post(player);
9133 /* release attributes */
9134 _mmplayer_deconstruct_attribute(handle);
9137 g_mutex_clear(&player->fsink_lock);
9140 g_mutex_clear(&player->update_tag_lock);
9142 /* release video bo lock and cond */
9143 g_mutex_clear(&player->video_bo_mutex);
9144 g_cond_clear(&player->video_bo_cond);
9146 /* release media stream callback lock */
9147 g_mutex_clear(&player->media_stream_cb_lock);
9149 /* release sound focus lock */
9150 g_mutex_clear(&player->sound_focus.focus_lock);
9154 return MM_ERROR_NONE;
9158 __mmplayer_realize_streaming_ext(mm_player_t* player)
9160 int ret = MM_ERROR_NONE;
9163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9165 if (MMPLAYER_IS_HTTP_PD(player)) {
9166 gboolean bret = FALSE;
9168 player->pd_downloader = _mmplayer_create_pd_downloader();
9169 if (!player->pd_downloader) {
9170 LOGE("Unable to create PD Downloader...");
9171 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
9174 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
9176 if (FALSE == bret) {
9177 LOGE("Unable to create PD Downloader...");
9178 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
9187 _mmplayer_sound_register_with_pid(MMHandleType hplayer, int pid)
9189 mm_player_t* player = (mm_player_t*)hplayer;
9190 MMHandleType attrs = 0;
9191 int ret = MM_ERROR_NONE;
9193 attrs = MMPLAYER_GET_ATTRS(player);
9195 LOGE("fail to get attributes.\n");
9196 return MM_ERROR_PLAYER_INTERNAL;
9199 player->sound_focus.pid = pid;
9201 /* register to asm */
9202 if (MM_ERROR_NONE != _mmplayer_sound_register(&player->sound_focus,
9203 (mm_sound_focus_changed_cb)__mmplayer_sound_focus_callback,
9204 (mm_sound_focus_changed_watch_cb)__mmplayer_sound_focus_watch_callback,
9206 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
9207 LOGE("failed to register asm server\n");
9208 return MM_ERROR_POLICY_INTERNAL;
9214 _mmplayer_get_client_pid(MMHandleType hplayer, int* pid)
9216 mm_player_t* player = (mm_player_t*) hplayer;
9220 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9222 *pid = player->sound_focus.pid;
9224 LOGD("registered pid[%d] %p", *pid, player);
9228 return MM_ERROR_NONE;
9232 _mmplayer_realize(MMHandleType hplayer)
9234 mm_player_t* player = (mm_player_t*)hplayer;
9237 gboolean update_registry = FALSE;
9238 MMHandleType attrs = 0;
9239 int ret = MM_ERROR_NONE;
9243 /* check player handle */
9244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
9246 /* check current state */
9247 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
9249 attrs = MMPLAYER_GET_ATTRS(player);
9251 LOGE("fail to get attributes.\n");
9252 return MM_ERROR_PLAYER_INTERNAL;
9254 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
9255 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
9257 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
9258 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
9260 if (ret != MM_ERROR_NONE) {
9261 LOGE("failed to parse profile\n");
9266 /* profile.mem or mem_buf.buf have to be free when player is destroyed */
9267 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) {
9268 player->mem_buf.buf = (char *)player->profile.mem;
9269 player->mem_buf.len = player->profile.mem_size;
9270 player->mem_buf.offset = 0;
9273 if (uri && (strstr(uri, "es_buff://"))) {
9274 if (strstr(uri, "es_buff://push_mode"))
9275 player->es_player_push_mode = TRUE;
9277 player->es_player_push_mode = FALSE;
9280 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
9281 LOGW("mms protocol is not supported format.\n");
9282 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9285 if (MMPLAYER_IS_STREAMING(player))
9286 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
9288 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
9290 player->smooth_streaming = FALSE;
9291 player->videodec_linked = 0;
9292 player->videosink_linked = 0;
9293 player->audiodec_linked = 0;
9294 player->audiosink_linked = 0;
9295 player->textsink_linked = 0;
9296 player->is_external_subtitle_present = FALSE;
9297 player->is_external_subtitle_added_now = FALSE;
9298 /* set the subtitle ON default */
9299 player->is_subtitle_off = FALSE;
9301 /* registry should be updated for downloadable codec */
9302 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
9304 if (update_registry) {
9305 LOGD("updating registry...\n");
9306 gst_update_registry();
9309 /* realize pipeline */
9310 ret = __gst_realize(player);
9311 if (ret != MM_ERROR_NONE)
9312 LOGE("fail to realize the player.\n");
9314 ret = __mmplayer_realize_streaming_ext(player);
9316 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
9317 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
9325 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
9328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9330 /* destroy can called at anytime */
9331 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
9332 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
9335 return MM_ERROR_NONE;
9339 _mmplayer_unrealize(MMHandleType hplayer)
9341 mm_player_t* player = (mm_player_t*)hplayer;
9342 int ret = MM_ERROR_NONE;
9346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9348 MMPLAYER_CMD_UNLOCK(player);
9349 /* destroy the gst bus msg thread which is created during realize.
9350 this funct have to be called before getting cmd lock. */
9351 _mmplayer_bus_msg_thread_destroy(player);
9352 MMPLAYER_CMD_LOCK(player);
9354 /* check current state */
9355 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
9357 /* check async state transition */
9358 __mmplayer_check_async_state_transition(player);
9360 __mmplayer_unrealize_streaming_ext(player);
9362 /* unrealize pipeline */
9363 ret = __gst_unrealize(player);
9365 /* set asm stop if success */
9366 if (MM_ERROR_NONE == ret) {
9367 ret = _mmplayer_sound_release_focus(&player->sound_focus);
9368 if (ret != MM_ERROR_NONE)
9369 LOGE("failed to release sound focus, ret(0x%x)\n", ret);
9371 if (!player->interrupted_by_resource) {
9372 if (player->video_decoder_resource != NULL) {
9373 ret = mm_resource_manager_mark_for_release(player->resource_manager,
9374 player->video_decoder_resource);
9375 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9376 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
9378 player->video_decoder_resource = NULL;
9381 if (player->video_overlay_resource != NULL) {
9382 ret = mm_resource_manager_mark_for_release(player->resource_manager,
9383 player->video_overlay_resource);
9384 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9385 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
9387 player->video_overlay_resource = NULL;
9390 ret = mm_resource_manager_commit(player->resource_manager);
9391 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
9392 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
9395 LOGE("failed and don't change asm state to stop");
9403 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
9405 mm_player_t* player = (mm_player_t*)hplayer;
9407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9409 return __gst_set_message_callback(player, callback, user_param);
9413 _mmplayer_get_state(MMHandleType hplayer, int* state)
9415 mm_player_t *player = (mm_player_t*)hplayer;
9417 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
9419 *state = MMPLAYER_CURRENT_STATE(player);
9421 return MM_ERROR_NONE;
9426 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
9428 mm_player_t* player = (mm_player_t*) hplayer;
9429 GstElement* vol_element = NULL;
9434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9436 LOGD("volume [L]=%f:[R]=%f\n",
9437 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
9439 /* invalid factor range or not */
9440 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
9441 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
9442 LOGE("Invalid factor!(valid factor:0~1.0)\n");
9443 return MM_ERROR_INVALID_ARGUMENT;
9447 /* not support to set other value into each channel */
9448 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
9449 return MM_ERROR_INVALID_ARGUMENT;
9451 /* Save volume to handle. Currently the first array element will be saved. */
9452 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
9454 /* check pipeline handle */
9455 if (!player->pipeline || !player->pipeline->audiobin) {
9456 LOGD("audiobin is not created yet\n");
9457 LOGD("but, current stored volume will be set when it's created.\n");
9459 /* NOTE : stored volume will be used in create_audiobin
9460 * returning MM_ERROR_NONE here makes application to able to
9461 * set volume at anytime.
9463 return MM_ERROR_NONE;
9466 /* setting volume to volume element */
9467 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9470 LOGD("volume is set [%f]\n", player->sound.volume);
9471 g_object_set(vol_element, "volume", player->sound.volume, NULL);
9476 return MM_ERROR_NONE;
9481 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
9483 mm_player_t* player = (mm_player_t*) hplayer;
9488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9489 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
9491 /* returning stored volume */
9492 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
9493 volume->level[i] = player->sound.volume;
9497 return MM_ERROR_NONE;
9501 _mmplayer_set_mute(MMHandleType hplayer, int mute)
9503 mm_player_t* player = (mm_player_t*) hplayer;
9504 GstElement* vol_element = NULL;
9508 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9510 /* mute value shoud 0 or 1 */
9511 if (mute != 0 && mute != 1) {
9512 LOGE("bad mute value\n");
9514 /* FIXIT : definitly, we need _BAD_PARAM error code */
9515 return MM_ERROR_INVALID_ARGUMENT;
9518 player->sound.mute = mute;
9520 /* just hold mute value if pipeline is not ready */
9521 if (!player->pipeline || !player->pipeline->audiobin) {
9522 LOGD("pipeline is not ready. holding mute value\n");
9523 return MM_ERROR_NONE;
9526 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
9528 /* NOTE : volume will only created when the bt is enabled */
9530 LOGD("mute : %d\n", mute);
9531 g_object_set(vol_element, "mute", mute, NULL);
9533 LOGD("volume elemnet is not created. using volume in audiosink\n");
9537 return MM_ERROR_NONE;
9541 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
9543 mm_player_t* player = (mm_player_t*) hplayer;
9547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9548 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
9550 /* just hold mute value if pipeline is not ready */
9551 if (!player->pipeline || !player->pipeline->audiobin) {
9552 LOGD("pipeline is not ready. returning stored value\n");
9553 *pmute = player->sound.mute;
9554 return MM_ERROR_NONE;
9557 *pmute = player->sound.mute;
9561 return MM_ERROR_NONE;
9565 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9567 mm_player_t* player = (mm_player_t*) hplayer;
9571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9573 player->video_stream_changed_cb = callback;
9574 player->video_stream_changed_cb_user_param = user_param;
9575 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
9579 return MM_ERROR_NONE;
9583 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
9585 mm_player_t* player = (mm_player_t*) hplayer;
9589 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9591 player->audio_stream_changed_cb = callback;
9592 player->audio_stream_changed_cb_user_param = user_param;
9593 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9597 return MM_ERROR_NONE;
9601 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9603 mm_player_t* player = (mm_player_t*) hplayer;
9607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9609 player->audio_stream_render_cb_ex = callback;
9610 player->audio_stream_cb_user_param = user_param;
9611 player->audio_stream_sink_sync = sync;
9612 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);
9616 return MM_ERROR_NONE;
9620 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9622 mm_player_t* player = (mm_player_t*) hplayer;
9626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9628 if (callback && !player->bufmgr)
9629 player->bufmgr = tbm_bufmgr_init(-1);
9631 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9632 player->video_stream_cb = callback;
9633 player->video_stream_cb_user_param = user_param;
9635 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9639 return MM_ERROR_NONE;
9643 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9645 mm_player_t* player = (mm_player_t*) hplayer;
9649 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9651 player->audio_stream_cb = callback;
9652 player->audio_stream_cb_user_param = user_param;
9653 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9657 return MM_ERROR_NONE;
9661 __mmplayer_start_streaming_ext(mm_player_t *player)
9663 gint ret = MM_ERROR_NONE;
9666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9668 if (MMPLAYER_IS_HTTP_PD(player)) {
9669 if (!player->pd_downloader) {
9670 ret = __mmplayer_realize_streaming_ext(player);
9672 if (ret != MM_ERROR_NONE) {
9673 LOGE("failed to realize streaming ext\n");
9678 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9679 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9681 LOGE("ERROR while starting PD...\n");
9682 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9684 ret = MM_ERROR_NONE;
9693 _mmplayer_start(MMHandleType hplayer)
9695 mm_player_t* player = (mm_player_t*) hplayer;
9696 gint ret = MM_ERROR_NONE;
9700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9702 /* check current state */
9703 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9705 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9706 if (ret != MM_ERROR_NONE) {
9707 LOGE("failed to acquire sound focus.\n");
9711 /* NOTE : we should check and create pipeline again if not created as we destroy
9712 * whole pipeline when stopping in streamming playback
9714 if (!player->pipeline) {
9715 ret = __gst_realize(player);
9716 if (MM_ERROR_NONE != ret) {
9717 LOGE("failed to realize before starting. only in streamming\n");
9723 ret = __mmplayer_start_streaming_ext(player);
9724 if (ret != MM_ERROR_NONE) {
9725 LOGE("failed to start streaming ext 0x%X", ret);
9729 /* start pipeline */
9730 ret = __gst_start(player);
9731 if (ret != MM_ERROR_NONE)
9732 LOGE("failed to start player.\n");
9739 /* NOTE: post "not supported codec message" to application
9740 * when one codec is not found during AUTOPLUGGING in MSL.
9741 * So, it's separated with error of __mmplayer_gst_callback().
9742 * And, if any codec is not found, don't send message here.
9743 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9746 __mmplayer_handle_missed_plugin(mm_player_t* player)
9748 MMMessageParamType msg_param;
9749 memset(&msg_param, 0, sizeof(MMMessageParamType));
9750 gboolean post_msg_direct = FALSE;
9754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9756 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9757 player->not_supported_codec, player->can_support_codec);
9759 if (player->not_found_demuxer) {
9760 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9761 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9763 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9764 MMPLAYER_FREEIF(msg_param.data);
9766 return MM_ERROR_NONE;
9769 if (player->not_supported_codec) {
9770 if (player->can_support_codec) {
9771 // There is one codec to play
9772 post_msg_direct = TRUE;
9774 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9775 post_msg_direct = TRUE;
9778 if (post_msg_direct) {
9779 MMMessageParamType msg_param;
9780 memset(&msg_param, 0, sizeof(MMMessageParamType));
9782 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9783 LOGW("not found AUDIO codec, posting error code to application.\n");
9785 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9786 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9787 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9788 LOGW("not found VIDEO codec, posting error code to application.\n");
9790 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9791 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9794 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9796 MMPLAYER_FREEIF(msg_param.data);
9798 return MM_ERROR_NONE;
9800 // no any supported codec case
9801 LOGW("not found any codec, posting error code to application.\n");
9803 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9804 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9805 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9807 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9808 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9811 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9813 MMPLAYER_FREEIF(msg_param.data);
9819 return MM_ERROR_NONE;
9822 static void __mmplayer_check_pipeline(mm_player_t* player)
9824 GstState element_state = GST_STATE_VOID_PENDING;
9825 GstState element_pending_state = GST_STATE_VOID_PENDING;
9827 int ret = MM_ERROR_NONE;
9829 if (player->gapless.reconfigure) {
9830 LOGW("pipeline is under construction.\n");
9832 MMPLAYER_PLAYBACK_LOCK(player);
9833 MMPLAYER_PLAYBACK_UNLOCK(player);
9835 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9837 /* wait for state transition */
9838 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9840 if (ret == GST_STATE_CHANGE_FAILURE)
9841 LOGE("failed to change pipeline state within %d sec\n", timeout);
9845 /* NOTE : it should be able to call 'stop' anytime*/
9847 _mmplayer_stop(MMHandleType hplayer)
9849 mm_player_t* player = (mm_player_t*)hplayer;
9850 int ret = MM_ERROR_NONE;
9854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9856 /* check current state */
9857 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9859 /* check pipline building state */
9860 __mmplayer_check_pipeline(player);
9861 __mmplayer_reset_gapless_state(player);
9863 /* NOTE : application should not wait for EOS after calling STOP */
9864 __mmplayer_cancel_eos_timer(player);
9866 __mmplayer_unrealize_streaming_ext(player);
9869 player->doing_seek = FALSE;
9872 ret = __gst_stop(player);
9874 if (ret != MM_ERROR_NONE)
9875 LOGE("failed to stop player.\n");
9883 _mmplayer_pause(MMHandleType hplayer)
9885 mm_player_t* player = (mm_player_t*)hplayer;
9886 gint64 pos_msec = 0;
9887 gboolean async = FALSE;
9888 gint ret = MM_ERROR_NONE;
9892 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9894 /* check current state */
9895 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9897 /* check pipline building state */
9898 __mmplayer_check_pipeline(player);
9900 switch (MMPLAYER_CURRENT_STATE(player)) {
9901 case MM_PLAYER_STATE_READY:
9903 /* check prepare async or not.
9904 * In the case of streaming playback, it's recommned to avoid blocking wait.
9906 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9907 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9909 /* Changing back sync of rtspsrc to async */
9910 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9911 LOGD("async prepare working mode for rtsp");
9917 case MM_PLAYER_STATE_PLAYING:
9919 /* NOTE : store current point to overcome some bad operation
9920 *(returning zero when getting current position in paused state) of some
9923 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9924 LOGW("getting current position failed in paused\n");
9926 player->last_position = pos_msec;
9928 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9929 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9930 This causes problem is position calculation during normal pause resume scenarios also.
9931 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9932 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9933 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9934 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9940 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9941 LOGD("doing async pause in case of ms buff src");
9945 /* pause pipeline */
9946 ret = __gst_pause(player, async);
9948 if (ret != MM_ERROR_NONE)
9949 LOGE("failed to pause player. ret : 0x%x\n", ret);
9951 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9952 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9953 LOGE("failed to update display_rotation");
9962 _mmplayer_resume(MMHandleType hplayer)
9964 mm_player_t* player = (mm_player_t*)hplayer;
9965 int ret = MM_ERROR_NONE;
9966 gboolean async = FALSE;
9970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9972 /* Changing back sync mode rtspsrc to async */
9973 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9974 LOGD("async resume for rtsp case");
9978 /* check current state */
9979 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9981 ret = _mmplayer_sound_acquire_focus(&player->sound_focus);
9982 if (ret != MM_ERROR_NONE) {
9983 LOGE("failed to acquire sound focus.\n");
9987 ret = __gst_resume(player, async);
9989 if (ret != MM_ERROR_NONE)
9990 LOGE("failed to resume player.\n");
9998 __mmplayer_set_play_count(mm_player_t* player, gint count)
10000 MMHandleType attrs = 0;
10004 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10006 attrs = MMPLAYER_GET_ATTRS(player);
10008 LOGE("fail to get attributes.\n");
10009 return MM_ERROR_PLAYER_INTERNAL;
10012 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10013 if (mmf_attrs_commit(attrs)) /* return -1 if error */
10014 LOGE("failed to commit\n");
10018 return MM_ERROR_NONE;
10022 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
10024 mm_player_t* player = (mm_player_t*)hplayer;
10025 gint64 start_pos = 0;
10026 gint64 end_pos = 0;
10027 gint infinity = -1;
10031 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10032 MMPLAYER_RETURN_VAL_IF_FAIL(end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT);
10034 player->section_repeat = TRUE;
10035 player->section_repeat_start = start;
10036 player->section_repeat_end = end;
10038 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
10039 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
10041 __mmplayer_set_play_count(player, infinity);
10043 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10044 player->playback_rate,
10046 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10047 GST_SEEK_TYPE_SET, start_pos,
10048 GST_SEEK_TYPE_SET, end_pos))) {
10049 LOGE("failed to activate section repeat\n");
10051 return MM_ERROR_PLAYER_SEEK;
10054 LOGD("succeeded to set section repeat from %d to %d\n",
10055 player->section_repeat_start, player->section_repeat_end);
10059 return MM_ERROR_NONE;
10063 __mmplayer_set_pcm_extraction(mm_player_t* player)
10065 gint64 start_nsec = 0;
10066 gint64 end_nsec = 0;
10067 gint64 dur_nsec = 0;
10068 gint64 dur_msec = 0;
10069 int required_start = 0;
10070 int required_end = 0;
10075 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10077 mm_attrs_multiple_get(player->attrs,
10079 "pcm_extraction_start_msec", &required_start,
10080 "pcm_extraction_end_msec", &required_end,
10083 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
10085 if (required_start == 0 && required_end == 0) {
10086 LOGD("extracting entire stream");
10087 return MM_ERROR_NONE;
10088 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
10089 LOGD("invalid range for pcm extraction");
10090 return MM_ERROR_INVALID_ARGUMENT;
10094 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
10096 LOGE("failed to get duration");
10097 return MM_ERROR_PLAYER_INTERNAL;
10099 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
10101 if (dur_msec < required_end) {
10103 LOGD("invalid end pos for pcm extraction");
10104 return MM_ERROR_INVALID_ARGUMENT;
10107 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
10108 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
10110 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10113 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10114 GST_SEEK_TYPE_SET, start_nsec,
10115 GST_SEEK_TYPE_SET, end_nsec))) {
10116 LOGE("failed to seek for pcm extraction\n");
10118 return MM_ERROR_PLAYER_SEEK;
10121 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
10125 return MM_ERROR_NONE;
10129 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
10131 mm_player_t* player = (mm_player_t*)hplayer;
10132 gint64 cur_pos = 0;
10137 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10139 player->section_repeat = FALSE;
10141 __mmplayer_set_play_count(player, onetime);
10143 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_pos);
10145 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10148 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10149 GST_SEEK_TYPE_SET, cur_pos,
10150 GST_SEEK_TYPE_SET, player->duration))) {
10151 LOGE("failed to deactivate section repeat\n");
10153 return MM_ERROR_PLAYER_SEEK;
10158 return MM_ERROR_NONE;
10162 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
10164 mm_player_t* player = (mm_player_t*)hplayer;
10165 gint64 pos_msec = 0;
10166 int ret = MM_ERROR_NONE;
10168 signed long long start = 0, stop = 0;
10169 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10172 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10173 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
10175 /* The sound of video is not supported under 0.0 and over 2.0. */
10176 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
10177 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
10180 _mmplayer_set_mute(hplayer, mute);
10182 if (player->playback_rate == rate)
10183 return MM_ERROR_NONE;
10185 /* If the position is reached at start potion during fast backward, EOS is posted.
10186 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
10188 player->playback_rate = rate;
10190 current_state = MMPLAYER_CURRENT_STATE(player);
10192 if (current_state != MM_PLAYER_STATE_PAUSED)
10193 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
10195 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
10197 if ((current_state == MM_PLAYER_STATE_PAUSED)
10198 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
10199 LOGW("returning last point : %lld\n", player->last_position);
10200 pos_msec = player->last_position;
10205 stop = GST_CLOCK_TIME_NONE;
10207 start = GST_CLOCK_TIME_NONE;
10211 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
10212 player->playback_rate,
10214 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
10215 GST_SEEK_TYPE_SET, start,
10216 GST_SEEK_TYPE_SET, stop)) {
10217 LOGE("failed to set speed playback\n");
10218 return MM_ERROR_PLAYER_SEEK;
10221 LOGD("succeeded to set speed playback as %0.1f\n", rate);
10225 return MM_ERROR_NONE;;
10229 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
10231 mm_player_t* player = (mm_player_t*)hplayer;
10232 int ret = MM_ERROR_NONE;
10236 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10238 /* check pipline building state */
10239 __mmplayer_check_pipeline(player);
10241 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
10249 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
10251 mm_player_t* player = (mm_player_t*)hplayer;
10252 int ret = MM_ERROR_NONE;
10254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10256 ret = __gst_get_position(player, format, position);
10262 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
10264 mm_player_t* player = (mm_player_t*)hplayer;
10265 int ret = MM_ERROR_NONE;
10267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10269 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
10275 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
10277 mm_player_t* player = (mm_player_t*)hplayer;
10278 int ret = MM_ERROR_NONE;
10282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10284 ret = __gst_adjust_subtitle_position(player, format, position);
10291 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
10293 mm_player_t* player = (mm_player_t*)hplayer;
10294 int ret = MM_ERROR_NONE;
10298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10300 ret = __gst_adjust_video_position(player, offset);
10308 __mmplayer_is_midi_type(gchar* str_caps)
10310 if ((g_strrstr(str_caps, "audio/midi")) ||
10311 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
10312 (g_strrstr(str_caps, "application/x-smaf")) ||
10313 (g_strrstr(str_caps, "audio/x-imelody")) ||
10314 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
10315 (g_strrstr(str_caps, "audio/xmf")) ||
10316 (g_strrstr(str_caps, "audio/mxmf"))) {
10325 __mmplayer_is_only_mp3_type(gchar *str_caps)
10327 if (g_strrstr(str_caps, "application/x-id3") ||
10328 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
10334 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
10336 GstStructure* caps_structure = NULL;
10337 gint samplerate = 0;
10341 MMPLAYER_RETURN_IF_FAIL(player && caps);
10343 caps_structure = gst_caps_get_structure(caps, 0);
10345 /* set stream information */
10346 gst_structure_get_int(caps_structure, "rate", &samplerate);
10347 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
10349 gst_structure_get_int(caps_structure, "channels", &channels);
10350 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
10352 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
10356 __mmplayer_update_content_type_info(mm_player_t* player)
10359 MMPLAYER_RETURN_IF_FAIL(player && player->type);
10361 if (__mmplayer_is_midi_type(player->type)) {
10362 player->bypass_audio_effect = TRUE;
10363 } else if (g_strrstr(player->type, "application/x-hls")) {
10364 /* If it can't know exact type when it parses uri because of redirection case,
10365 * it will be fixed by typefinder or when doing autoplugging.
10367 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
10368 if (player->streamer) {
10369 player->streamer->is_adaptive_streaming = TRUE;
10370 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
10371 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
10373 } else if (g_strrstr(player->type, "application/dash+xml")) {
10374 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
10381 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
10382 GstCaps *caps, gpointer data)
10384 mm_player_t* player = (mm_player_t*)data;
10385 GstPad* pad = NULL;
10389 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
10391 /* store type string */
10392 MMPLAYER_FREEIF(player->type);
10393 player->type = gst_caps_to_string(caps);
10394 if (player->type) {
10395 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
10396 player, player->type, probability, gst_caps_get_size(caps));
10399 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
10400 (g_strrstr(player->type, "audio/x-raw-int"))) {
10401 LOGE("not support media format\n");
10403 if (player->msg_posted == FALSE) {
10404 MMMessageParamType msg_param;
10405 memset(&msg_param, 0, sizeof(MMMessageParamType));
10407 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
10408 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10410 /* don't post more if one was sent already */
10411 player->msg_posted = TRUE;
10416 __mmplayer_update_content_type_info(player);
10418 pad = gst_element_get_static_pad(tf, "src");
10420 LOGE("fail to get typefind src pad.\n");
10424 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
10425 gboolean async = FALSE;
10426 LOGE("failed to autoplug %s\n", player->type);
10428 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
10430 if (async && player->msg_posted == FALSE)
10431 __mmplayer_handle_missed_plugin(player);
10437 gst_object_unref(GST_OBJECT(pad));
10444 static GstElement *
10445 __mmplayer_create_decodebin(mm_player_t* player)
10447 GstElement *decodebin = NULL;
10451 /* create decodebin */
10452 decodebin = gst_element_factory_make("decodebin", NULL);
10455 LOGE("fail to create decodebin\n");
10459 /* raw pad handling signal */
10460 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
10461 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
10463 /* no-more-pad pad handling signal */
10464 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
10465 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
10467 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
10468 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
10470 /* This signal is emitted when a pad for which there is no further possible
10471 decoding is added to the decodebin.*/
10472 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
10473 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
10475 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10476 before looking for any elements that can handle that stream.*/
10477 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
10478 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
10480 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
10481 before looking for any elements that can handle that stream.*/
10482 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
10483 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
10485 /* This signal is emitted once decodebin has finished decoding all the data.*/
10486 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
10487 G_CALLBACK(__mmplayer_gst_decode_drained), player);
10489 /* This signal is emitted when a element is added to the bin.*/
10490 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
10491 G_CALLBACK(__mmplayer_gst_element_added), player);
10498 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
10500 MMPlayerGstElement* mainbin = NULL;
10501 GstElement* decodebin = NULL;
10502 GstElement* queue2 = NULL;
10503 GstPad* sinkpad = NULL;
10504 GstPad* qsrcpad = NULL;
10505 gint64 dur_bytes = 0L;
10507 guint max_buffer_size_bytes = 0;
10508 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
10511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
10513 mainbin = player->pipeline->mainbin;
10515 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
10516 (MMPLAYER_IS_HTTP_STREAMING(player))) {
10517 LOGD("creating http streaming buffering queue(queue2)\n");
10519 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
10520 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
10522 queue2 = gst_element_factory_make("queue2", "queue2");
10524 LOGE("failed to create buffering queue element\n");
10528 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
10529 LOGE("failed to add buffering queue\n");
10533 sinkpad = gst_element_get_static_pad(queue2, "sink");
10534 qsrcpad = gst_element_get_static_pad(queue2, "src");
10536 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10537 LOGE("failed to link buffering queue\n");
10541 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
10542 LOGE("fail to get duration.\n");
10544 LOGD("dur_bytes = %lld\n", dur_bytes);
10546 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
10548 if (dur_bytes > 0) {
10549 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
10550 type = MUXED_BUFFER_TYPE_FILE;
10552 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
10553 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
10559 /* NOTE : we cannot get any duration info from ts container in case of streaming */
10560 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
10561 if (!g_strrstr(player->type, "video/mpegts")) {
10562 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
10563 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
10565 // FIXME : pass ini setting directly. is this ok?
10566 __mm_player_streaming_set_queue2(player->streamer,
10569 max_buffer_size_bytes,
10570 player->ini.http_buffering_time,
10572 player->ini.http_buffering_limit, // no meaning
10574 player->http_file_buffering_path,
10575 (guint64)dur_bytes);
10578 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
10579 LOGE("failed to sync queue2 state with parent\n");
10585 gst_object_unref(GST_OBJECT(sinkpad));
10587 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
10588 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
10592 /* create decodebin */
10593 decodebin = __mmplayer_create_decodebin(player);
10596 LOGE("can not create autoplug element\n");
10600 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
10601 LOGE("failed to add decodebin\n");
10605 /* to force caps on the decodebin element and avoid reparsing stuff by
10606 * typefind. It also avoids a deadlock in the way typefind activates pads in
10607 * the state change */
10608 g_object_set(decodebin, "sink-caps", caps, NULL);
10610 sinkpad = gst_element_get_static_pad(decodebin, "sink");
10612 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
10613 LOGE("failed to link decodebin\n");
10617 gst_object_unref(GST_OBJECT(sinkpad));
10619 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
10620 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
10622 /* set decodebin property about buffer in streaming playback. *
10623 * in case of HLS/DASH, it does not need to have big buffer *
10624 * because it is kind of adaptive streaming. */
10625 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
10626 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
10627 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
10628 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
10630 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
10631 || MMPLAYER_IS_DASH_STREAMING(player)) {
10632 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
10633 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
10636 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
10637 "high-percent", (gint)player->ini.http_buffering_limit,
10638 "low-percent", 1, // 1%
10639 "max-size-bytes", max_size_bytes,
10640 "max-size-time", (guint64)(max_size_time * GST_SECOND),
10641 "max-size-buffers", 0, NULL); // disable or automatic
10644 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
10645 LOGE("failed to sync decodebin state with parent\n");
10656 gst_object_unref(GST_OBJECT(sinkpad));
10659 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10660 * You need to explicitly set elements to the NULL state before
10661 * dropping the final reference, to allow them to clean up.
10663 gst_element_set_state(queue2, GST_STATE_NULL);
10665 /* And, it still has a parent "player".
10666 * You need to let the parent manage the object instead of unreffing the object directly.
10668 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
10669 gst_object_unref(queue2);
10674 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
10675 * You need to explicitly set elements to the NULL state before
10676 * dropping the final reference, to allow them to clean up.
10678 gst_element_set_state(decodebin, GST_STATE_NULL);
10680 /* And, it still has a parent "player".
10681 * You need to let the parent manage the object instead of unreffing the object directly.
10684 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
10685 gst_object_unref(decodebin);
10693 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
10697 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10698 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10700 LOGD("class : %s, mime : %s \n", factory_class, mime);
10702 /* add missing plugin */
10703 /* NOTE : msl should check missing plugin for image mime type.
10704 * Some motion jpeg clips can have playable audio track.
10705 * So, msl have to play audio after displaying popup written video format not supported.
10707 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10708 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10709 LOGD("not found demuxer\n");
10710 player->not_found_demuxer = TRUE;
10711 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10717 if (!g_strrstr(factory_class, "Demuxer")) {
10718 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10719 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10720 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10722 /* check that clip have multi tracks or not */
10723 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10724 LOGD("video plugin is already linked\n");
10726 LOGW("add VIDEO to missing plugin\n");
10727 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10728 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10730 } else if (g_str_has_prefix(mime, "audio")) {
10731 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10732 LOGD("audio plugin is already linked\n");
10734 LOGW("add AUDIO to missing plugin\n");
10735 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10736 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10744 return MM_ERROR_NONE;
10749 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10751 mm_player_t* player = (mm_player_t*)data;
10755 MMPLAYER_RETURN_IF_FAIL(player);
10757 /* remove fakesink. */
10758 if (!__mmplayer_gst_remove_fakesink(player,
10759 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10760 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10761 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10762 * source element are not same. To overcome this situation, this function will called
10763 * several places and several times. Therefore, this is not an error case.
10768 LOGD("[handle: %p] pipeline has completely constructed", player);
10770 if ((player->ini.async_start) &&
10771 (player->msg_posted == FALSE) &&
10772 (player->cmd >= MMPLAYER_COMMAND_START))
10773 __mmplayer_handle_missed_plugin(player);
10775 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10779 __mmplayer_verify_next_play_path(mm_player_t *player)
10781 MMHandleType attrs = 0;
10782 MMPlayerParseProfile profile;
10783 gint uri_idx = 0, check_cnt = 0;
10785 gint mode = MM_PLAYER_PD_MODE_NONE;
10789 guint num_of_list = 0;
10790 static int profile_tv = -1;
10794 LOGD("checking for gapless play");
10796 if (player->pipeline->textbin) {
10797 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10801 attrs = MMPLAYER_GET_ATTRS(player);
10803 LOGE("fail to get attributes.\n");
10807 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10809 if (__builtin_expect(profile_tv == -1, 0)) {
10811 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10812 switch (*profileName) {
10822 /* gapless playback is not supported in case of video at TV profile. */
10823 if (profile_tv && video) {
10824 LOGW("not support video gapless playback");
10828 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10829 if (mode == TRUE) {
10835 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10836 LOGE("can not get play count\n");
10838 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10839 LOGE("can not get gapless mode\n");
10841 if (video && !gapless) {
10842 LOGW("not enabled video gapless playback");
10846 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10850 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10854 num_of_list = g_list_length(player->uri_info.uri_list);
10856 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10858 if (num_of_list == 0) {
10859 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10860 LOGE("can not get profile_uri\n");
10865 LOGE("uri list is empty.\n");
10869 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10870 LOGD("add original path : %s ", uri);
10876 uri_idx = player->uri_info.uri_idx;
10881 if (check_cnt > num_of_list) {
10882 LOGE("there is no valid uri.");
10886 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10888 if (uri_idx < num_of_list-1) {
10891 if ((count <= 1) && (count != -1)) {
10892 LOGD("no repeat.");
10894 } else if (count > 1) {
10895 /* decrease play count */
10896 /* we succeeded to rewind. update play count and then wait for next EOS */
10899 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10901 /* commit attribute */
10902 if (mmf_attrs_commit(attrs))
10903 LOGE("failed to commit attribute\n");
10906 /* count < 0 : repeat continually */
10910 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10911 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10914 LOGW("next uri does not exist\n");
10918 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10919 LOGE("failed to parse profile\n");
10923 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10924 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10925 LOGW("uri type is not supported(%d).", profile.uri_type);
10932 player->uri_info.uri_idx = uri_idx;
10933 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10935 if (mmf_attrs_commit(player->attrs)) {
10936 LOGE("failed to commit.\n");
10940 LOGD("next uri %s(%d)\n", uri, uri_idx);
10946 LOGE("unable to play next path. EOS will be posted soon.\n");
10951 __mmplayer_initialize_next_play(mm_player_t *player)
10957 player->smooth_streaming = FALSE;
10958 player->videodec_linked = 0;
10959 player->audiodec_linked = 0;
10960 player->videosink_linked = 0;
10961 player->audiosink_linked = 0;
10962 player->textsink_linked = 0;
10963 player->is_external_subtitle_present = FALSE;
10964 player->is_external_subtitle_added_now = FALSE;
10965 player->not_supported_codec = MISSING_PLUGIN_NONE;
10966 player->can_support_codec = FOUND_PLUGIN_NONE;
10967 player->pending_seek.is_pending = FALSE;
10968 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10969 player->pending_seek.pos = 0;
10970 player->msg_posted = FALSE;
10971 player->has_many_types = FALSE;
10972 player->no_more_pad = FALSE;
10973 player->not_found_demuxer = 0;
10974 player->doing_seek = FALSE;
10975 player->max_audio_channels = 0;
10976 player->is_subtitle_force_drop = FALSE;
10977 player->play_subtitle = FALSE;
10978 player->adjust_subtitle_pos = 0;
10980 player->total_bitrate = 0;
10981 player->total_maximum_bitrate = 0;
10983 _mmplayer_track_initialize(player);
10984 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10986 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10987 player->bitrate[i] = 0;
10988 player->maximum_bitrate[i] = 0;
10991 if (player->v_stream_caps) {
10992 gst_caps_unref(player->v_stream_caps);
10993 player->v_stream_caps = NULL;
10996 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10997 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
10999 /* clean found parsers */
11000 if (player->parsers) {
11001 GList *parsers = player->parsers;
11002 for (; parsers; parsers = g_list_next(parsers)) {
11003 gchar *name = parsers->data;
11004 MMPLAYER_FREEIF(name);
11006 g_list_free(player->parsers);
11007 player->parsers = NULL;
11010 /* clean found audio decoders */
11011 if (player->audio_decoders) {
11012 GList *a_dec = player->audio_decoders;
11013 for (; a_dec; a_dec = g_list_next(a_dec)) {
11014 gchar *name = a_dec->data;
11015 MMPLAYER_FREEIF(name);
11017 g_list_free(player->audio_decoders);
11018 player->audio_decoders = NULL;
11025 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
11027 MMPlayerGstElement *mainbin = NULL;
11028 MMMessageParamType msg_param = {0,};
11029 GstElement *element = NULL;
11030 MMHandleType attrs = 0;
11032 enum MainElementID elemId = MMPLAYER_M_NUM;
11036 if ((player == NULL) ||
11037 (player->pipeline == NULL) ||
11038 (player->pipeline->mainbin == NULL)) {
11039 LOGE("player is null.\n");
11043 mainbin = player->pipeline->mainbin;
11044 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
11046 attrs = MMPLAYER_GET_ATTRS(player);
11048 LOGE("fail to get attributes.\n");
11052 /* Initialize Player values */
11053 __mmplayer_initialize_next_play(player);
11055 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
11057 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
11058 LOGE("failed to parse profile\n");
11059 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11063 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
11064 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
11065 LOGE("it's dash or hls. not support.");
11066 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11071 switch (player->profile.uri_type) {
11073 case MM_PLAYER_URI_TYPE_FILE:
11075 LOGD("using filesrc for 'file://' handler.\n");
11076 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
11077 LOGE("failed to get storage info");
11081 element = gst_element_factory_make("filesrc", "source");
11084 LOGE("failed to create filesrc\n");
11088 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
11091 case MM_PLAYER_URI_TYPE_URL_HTTP:
11093 gchar *user_agent, *proxy, *cookies, **cookie_list;
11094 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
11095 user_agent = proxy = cookies = NULL;
11096 cookie_list = NULL;
11098 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
11100 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
11103 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
11105 /* get attribute */
11106 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
11107 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
11108 mm_attrs_get_string_by_name(attrs, "streaming_proxy", &proxy);
11109 mm_attrs_get_int_by_name(attrs, "streaming_timeout", &http_timeout);
11111 if ((http_timeout == DEFAULT_HTTP_TIMEOUT) &&
11112 (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)) {
11113 LOGD("get timeout from ini\n");
11114 http_timeout = player->ini.http_timeout;
11117 /* get attribute */
11118 SECURE_LOGD("location : %s\n", player->profile.uri);
11119 SECURE_LOGD("cookies : %s\n", cookies);
11120 SECURE_LOGD("proxy : %s\n", proxy);
11121 SECURE_LOGD("user_agent : %s\n", user_agent);
11122 LOGD("timeout : %d\n", http_timeout);
11124 /* setting property to streaming source */
11125 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
11126 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
11127 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
11129 /* check if prosy is vailid or not */
11130 if (util_check_valid_url(proxy))
11131 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
11132 /* parsing cookies */
11133 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
11134 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
11136 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
11140 LOGE("not support uri type %d\n", player->profile.uri_type);
11145 LOGE("no source element was created.\n");
11149 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11150 LOGE("failed to add source element to pipeline\n");
11151 gst_object_unref(GST_OBJECT(element));
11156 /* take source element */
11157 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
11158 mainbin[MMPLAYER_M_SRC].gst = element;
11162 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
11163 if (player->streamer == NULL) {
11164 player->streamer = __mm_player_streaming_create();
11165 __mm_player_streaming_initialize(player->streamer);
11168 elemId = MMPLAYER_M_TYPEFIND;
11169 element = gst_element_factory_make("typefind", "typefinder");
11170 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
11171 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
11173 elemId = MMPLAYER_M_AUTOPLUG;
11174 element = __mmplayer_create_decodebin(player);
11177 /* check autoplug element is OK */
11179 LOGE("can not create element(%d)\n", elemId);
11183 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
11184 LOGE("failed to add sinkbin to pipeline\n");
11185 gst_object_unref(GST_OBJECT(element));
11190 mainbin[elemId].id = elemId;
11191 mainbin[elemId].gst = element;
11193 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
11194 LOGE("Failed to link src - autoplug(or typefind)\n");
11198 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
11199 LOGE("Failed to change state of src element\n");
11203 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
11204 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
11205 LOGE("Failed to change state of decodebin\n");
11209 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
11210 LOGE("Failed to change state of src element\n");
11215 player->gapless.stream_changed = TRUE;
11216 player->gapless.running = TRUE;
11222 MMPLAYER_PLAYBACK_UNLOCK(player);
11224 if (!player->msg_posted) {
11225 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11226 player->msg_posted = TRUE;
11233 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
11235 mm_player_selector_t *selector = &player->selector[type];
11236 MMPlayerGstElement *sinkbin = NULL;
11237 enum MainElementID selectorId = MMPLAYER_M_NUM;
11238 enum MainElementID sinkId = MMPLAYER_M_NUM;
11239 GstPad *srcpad = NULL;
11240 GstPad *sinkpad = NULL;
11241 gboolean send_notice = FALSE;
11244 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11246 LOGD("type %d", type);
11249 case MM_PLAYER_TRACK_TYPE_AUDIO:
11250 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
11251 sinkId = MMPLAYER_A_BIN;
11252 sinkbin = player->pipeline->audiobin;
11254 case MM_PLAYER_TRACK_TYPE_VIDEO:
11255 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
11256 sinkId = MMPLAYER_V_BIN;
11257 sinkbin = player->pipeline->videobin;
11258 send_notice = TRUE;
11260 case MM_PLAYER_TRACK_TYPE_TEXT:
11261 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
11262 sinkId = MMPLAYER_T_BIN;
11263 sinkbin = player->pipeline->textbin;
11266 LOGE("requested type is not supportable");
11271 if (player->pipeline->mainbin[selectorId].gst) {
11274 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
11276 if (selector->event_probe_id != 0)
11277 gst_pad_remove_probe(srcpad, selector->event_probe_id);
11278 selector->event_probe_id = 0;
11280 if ((sinkbin) && (sinkbin[sinkId].gst)) {
11281 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
11283 if (srcpad && sinkpad) {
11284 /* after getting drained signal there is no data flows, so no need to do pad_block */
11285 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
11286 gst_pad_unlink(srcpad, sinkpad);
11288 /* send custom event to sink pad to handle it at video sink */
11290 LOGD("send custom event to sinkpad");
11291 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
11292 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
11293 gst_pad_send_event(sinkpad, event);
11297 gst_object_unref(sinkpad);
11300 gst_object_unref(srcpad);
11303 LOGD("selector release");
11305 /* release and unref requests pad from the selector */
11306 for (n = 0; n < selector->channels->len; n++) {
11307 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
11308 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
11310 g_ptr_array_set_size(selector->channels, 0);
11312 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
11313 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
11315 player->pipeline->mainbin[selectorId].gst = NULL;
11323 __mmplayer_deactivate_old_path(mm_player_t *player)
11326 MMPLAYER_RETURN_IF_FAIL(player);
11328 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
11329 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
11330 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
11331 LOGE("deactivate selector error");
11335 _mmplayer_track_destroy(player);
11336 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11338 if (player->streamer) {
11339 __mm_player_streaming_deinitialize(player->streamer);
11340 __mm_player_streaming_destroy(player->streamer);
11341 player->streamer = NULL;
11344 MMPLAYER_PLAYBACK_LOCK(player);
11345 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
11352 if (!player->msg_posted) {
11353 MMMessageParamType msg = {0,};
11356 msg.code = MM_ERROR_PLAYER_INTERNAL;
11357 LOGE("next_uri_play> deactivate error");
11359 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
11360 player->msg_posted = TRUE;
11365 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
11367 int result = MM_ERROR_NONE;
11368 mm_player_t* player = (mm_player_t*) hplayer;
11371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11374 player->http_file_buffering_path = (gchar*)file_path;
11375 LOGD("temp file path: %s\n", player->http_file_buffering_path);
11381 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
11383 int result = MM_ERROR_NONE;
11384 mm_player_t* player = (mm_player_t*) hplayer;
11387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11389 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
11390 if (mmf_attrs_commit(player->attrs)) {
11391 LOGE("failed to commit the original uri.\n");
11392 result = MM_ERROR_PLAYER_INTERNAL;
11394 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
11395 LOGE("failed to add the original uri in the uri list.\n");
11402 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
11404 mm_player_t* player = (mm_player_t*) hplayer;
11405 guint num_of_list = 0;
11409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11410 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
11412 if (player->pipeline && player->pipeline->textbin) {
11413 LOGE("subtitle path is enabled.\n");
11414 return MM_ERROR_PLAYER_INVALID_STATE;
11417 num_of_list = g_list_length(player->uri_info.uri_list);
11419 if (is_first_path == TRUE) {
11420 if (num_of_list == 0) {
11421 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11422 LOGD("add original path : %s", uri);
11424 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
11425 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
11427 LOGD("change original path : %s", uri);
11430 MMHandleType attrs = 0;
11431 attrs = MMPLAYER_GET_ATTRS(player);
11433 if (num_of_list == 0) {
11434 char *original_uri = NULL;
11437 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
11439 if (!original_uri) {
11440 LOGE("there is no original uri.");
11441 return MM_ERROR_PLAYER_INVALID_STATE;
11444 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
11445 player->uri_info.uri_idx = 0;
11447 LOGD("add original path at first : %s(%d)", original_uri);
11451 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
11452 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
11456 return MM_ERROR_NONE;
11459 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
11461 mm_player_t* player = (mm_player_t*) hplayer;
11462 char *next_uri = NULL;
11463 guint num_of_list = 0;
11466 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11468 num_of_list = g_list_length(player->uri_info.uri_list);
11470 if (num_of_list > 0) {
11471 gint uri_idx = player->uri_info.uri_idx;
11473 if (uri_idx < num_of_list-1)
11478 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
11479 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
11481 *uri = g_strdup(next_uri);
11485 return MM_ERROR_NONE;
11489 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
11490 GstCaps *caps, gpointer data)
11492 mm_player_t* player = (mm_player_t*)data;
11493 const gchar* klass = NULL;
11494 const gchar* mime = NULL;
11495 gchar* caps_str = NULL;
11497 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
11498 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11499 caps_str = gst_caps_to_string(caps);
11501 LOGW("unknown type of caps : %s from %s",
11502 caps_str, GST_ELEMENT_NAME(elem));
11504 MMPLAYER_FREEIF(caps_str);
11506 /* There is no available codec. */
11507 __mmplayer_check_not_supported_codec(player, klass, mime);
11511 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
11512 GstCaps * caps, gpointer data)
11514 mm_player_t* player = (mm_player_t*)data;
11515 const char* mime = NULL;
11516 gboolean ret = TRUE;
11518 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
11519 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
11521 if (g_str_has_prefix(mime, "audio")) {
11522 GstStructure* caps_structure = NULL;
11523 gint samplerate = 0;
11525 gchar *caps_str = NULL;
11527 caps_structure = gst_caps_get_structure(caps, 0);
11528 gst_structure_get_int(caps_structure, "rate", &samplerate);
11529 gst_structure_get_int(caps_structure, "channels", &channels);
11531 if ((channels > 0 && samplerate == 0)) {
11532 LOGD("exclude audio...");
11536 caps_str = gst_caps_to_string(caps);
11537 /* set it directly because not sent by TAG */
11538 if (g_strrstr(caps_str, "mobile-xmf"))
11539 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
11540 MMPLAYER_FREEIF(caps_str);
11541 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
11542 MMMessageParamType msg_param;
11543 memset(&msg_param, 0, sizeof(MMMessageParamType));
11544 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
11545 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11546 LOGD("video file is not supported on this device");
11548 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
11549 LOGD("already video linked");
11552 LOGD("found new stream");
11559 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
11561 int ret = MM_ERROR_NONE;
11563 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
11565 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
11566 GstStructure* str = NULL;
11568 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
11570 LOGD("audio codec type: %d", codec_type);
11571 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
11572 /* sw codec will be skipped */
11573 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
11574 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
11575 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
11576 ret = MM_ERROR_PLAYER_INTERNAL;
11580 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
11581 /* hw codec will be skipped */
11582 if (strcmp(player->ini.audiocodec_element_hw, "") &&
11583 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
11584 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
11585 ret = MM_ERROR_PLAYER_INTERNAL;
11590 str = gst_caps_get_structure(caps, 0);
11592 gst_structure_get_int(str, "channels", &channels);
11594 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
11595 if (player->max_audio_channels < channels)
11596 player->max_audio_channels = channels;
11598 /* set stream information */
11599 if (!player->audiodec_linked)
11600 __mmplayer_set_audio_attrs(player, caps);
11602 /* update codec info */
11603 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
11604 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
11605 player->audiodec_linked = 1;
11607 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
11609 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
11611 LOGD("video codec type: %d", codec_type);
11612 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
11613 /* sw codec is skipped */
11614 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
11615 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
11616 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
11617 ret = MM_ERROR_PLAYER_INTERNAL;
11621 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
11622 /* hw codec is skipped */
11623 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11624 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
11625 ret = MM_ERROR_PLAYER_INTERNAL;
11630 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
11631 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
11633 /* mark video decoder for acquire */
11634 if (player->video_decoder_resource == NULL) {
11635 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
11636 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
11637 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
11638 &player->video_decoder_resource)
11639 != MM_RESOURCE_MANAGER_ERROR_NONE) {
11640 LOGE("could not mark video_decoder resource for acquire");
11641 ret = MM_ERROR_PLAYER_INTERNAL;
11645 LOGW("video decoder resource is already acquired, skip it.");
11646 ret = MM_ERROR_PLAYER_INTERNAL;
11650 player->interrupted_by_resource = FALSE;
11651 /* acquire resources for video playing */
11652 if (mm_resource_manager_commit(player->resource_manager)
11653 != MM_RESOURCE_MANAGER_ERROR_NONE) {
11654 LOGE("could not acquire resources for video decoding\n");
11655 ret = MM_ERROR_PLAYER_INTERNAL;
11660 /* update codec info */
11661 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
11662 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
11663 player->videodec_linked = 1;
11671 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
11672 GstCaps* caps, GstElementFactory* factory, gpointer data)
11674 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
11675 We are defining our own and will be removed when it actually exposed */
11677 GST_AUTOPLUG_SELECT_TRY,
11678 GST_AUTOPLUG_SELECT_EXPOSE,
11679 GST_AUTOPLUG_SELECT_SKIP
11680 } GstAutoplugSelectResult;
11682 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
11683 mm_player_t* player = (mm_player_t*)data;
11685 gchar* factory_name = NULL;
11686 gchar* caps_str = NULL;
11687 const gchar* klass = NULL;
11690 factory_name = GST_OBJECT_NAME(factory);
11691 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
11692 caps_str = gst_caps_to_string(caps);
11694 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
11696 /* store type string */
11697 if (player->type == NULL) {
11698 player->type = gst_caps_to_string(caps);
11699 __mmplayer_update_content_type_info(player);
11702 /* filtering exclude keyword */
11703 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
11704 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
11705 LOGW("skipping [%s] by exculde keyword [%s]\n",
11706 factory_name, player->ini.exclude_element_keyword[idx]);
11708 result = GST_AUTOPLUG_SELECT_SKIP;
11713 /* exclude webm format */
11714 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11715 * because webm format is not supportable.
11716 * If webm is disabled in "autoplug-continue", there is no state change
11717 * failure or error because the decodebin will expose the pad directly.
11718 * It make MSL invoke _prepare_async_callback.
11719 * So, we need to disable webm format in "autoplug-select" */
11720 if (caps_str && strstr(caps_str, "webm")) {
11721 LOGW("webm is not supported");
11722 result = GST_AUTOPLUG_SELECT_SKIP;
11726 /* check factory class for filtering */
11727 /* NOTE : msl don't need to use image plugins.
11728 * So, those plugins should be skipped for error handling.
11730 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11731 LOGD("skipping [%s] by not required\n", factory_name);
11732 result = GST_AUTOPLUG_SELECT_SKIP;
11736 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11737 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11738 // TO CHECK : subtitle if needed, add subparse exception.
11739 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11740 result = GST_AUTOPLUG_SELECT_SKIP;
11744 if (g_strrstr(factory_name, "mpegpsdemux")) {
11745 LOGD("skipping PS container - not support\n");
11746 result = GST_AUTOPLUG_SELECT_SKIP;
11750 if (g_strrstr(factory_name, "mssdemux"))
11751 player->smooth_streaming = TRUE;
11753 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11754 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11757 GstStructure *str = NULL;
11758 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11760 /* don't make video because of not required */
11761 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11762 (player->set_mode.media_packet_video_stream == FALSE)) {
11763 LOGD("no video because it's not required. -> return expose");
11764 result = GST_AUTOPLUG_SELECT_EXPOSE;
11768 /* get w/h for omx state-tune */
11769 /* FIXME: deprecated? */
11770 str = gst_caps_get_structure(caps, 0);
11771 gst_structure_get_int(str, "width", &width);
11774 if (player->v_stream_caps) {
11775 gst_caps_unref(player->v_stream_caps);
11776 player->v_stream_caps = NULL;
11779 player->v_stream_caps = gst_caps_copy(caps);
11780 LOGD("take caps for video state tune");
11781 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11785 if (g_strrstr(klass, "Codec/Decoder")) {
11786 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11787 LOGD("skipping %s codec", factory_name);
11788 result = GST_AUTOPLUG_SELECT_SKIP;
11794 MMPLAYER_FREEIF(caps_str);
11800 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11803 //mm_player_t* player = (mm_player_t*)data;
11804 GstCaps* caps = NULL;
11806 LOGD("[Decodebin2] pad-removed signal\n");
11808 caps = gst_pad_query_caps(new_pad, NULL);
11810 gchar* caps_str = NULL;
11811 caps_str = gst_caps_to_string(caps);
11813 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11815 MMPLAYER_FREEIF(caps_str);
11816 gst_caps_unref(caps);
11821 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11823 mm_player_t* player = (mm_player_t*)data;
11824 GstIterator *iter = NULL;
11825 GValue item = { 0, };
11826 GstPad *pad = NULL;
11827 gboolean done = FALSE;
11828 gboolean is_all_drained = TRUE;
11831 MMPLAYER_RETURN_IF_FAIL(player);
11833 LOGD("__mmplayer_gst_decode_drained");
11835 if (player->use_deinterleave == TRUE) {
11836 LOGD("group playing mode.");
11840 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11841 LOGW("Fail to get cmd lock");
11845 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11846 !__mmplayer_verify_next_play_path(player)) {
11847 LOGD("decoding is finished.");
11848 __mmplayer_reset_gapless_state(player);
11849 MMPLAYER_CMD_UNLOCK(player);
11853 player->gapless.reconfigure = TRUE;
11855 /* check decodebin src pads whether they received EOS or not */
11856 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11859 switch (gst_iterator_next(iter, &item)) {
11860 case GST_ITERATOR_OK:
11861 pad = g_value_get_object(&item);
11862 if (pad && !GST_PAD_IS_EOS(pad)) {
11863 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11864 is_all_drained = FALSE;
11867 g_value_reset(&item);
11869 case GST_ITERATOR_RESYNC:
11870 gst_iterator_resync(iter);
11872 case GST_ITERATOR_ERROR:
11873 case GST_ITERATOR_DONE:
11878 g_value_unset(&item);
11879 gst_iterator_free(iter);
11881 if (!is_all_drained) {
11882 LOGD("Wait util the all pads get EOS.");
11883 MMPLAYER_CMD_UNLOCK(player);
11888 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11889 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11891 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11892 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11893 __mmplayer_deactivate_old_path(player);
11894 MMPLAYER_CMD_UNLOCK(player);
11900 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11902 mm_player_t* player = (mm_player_t*)data;
11903 const gchar* klass = NULL;
11904 gchar* factory_name = NULL;
11906 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11907 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11909 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11911 if (__mmplayer_add_dump_buffer_probe(player, element))
11912 LOGD("add buffer probe");
11915 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11916 gchar* selected = NULL;
11917 selected = g_strdup(GST_ELEMENT_NAME(element));
11918 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11922 if (g_strrstr(klass, "Parser")) {
11923 gchar* selected = NULL;
11925 selected = g_strdup(factory_name);
11926 player->parsers = g_list_append(player->parsers, selected);
11929 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11930 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11931 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11933 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11934 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11936 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11937 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11938 "max-video-width", player->adaptive_info.limit.width,
11939 "max-video-height", player->adaptive_info.limit.height, NULL);
11941 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11942 /* FIXIT : first value will be overwritten if there's more
11943 * than 1 demuxer/parser
11946 //LOGD("plugged element is demuxer. take it\n");
11947 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11948 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11950 /*Added for multi audio support */ // Q. del?
11951 if (g_strrstr(klass, "Demux")) {
11952 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11953 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11957 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11958 int surface_type = 0;
11960 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11963 // to support trust-zone only
11964 if (g_strrstr(factory_name, "asfdemux")) {
11965 LOGD("set file-location %s\n", player->profile.uri);
11966 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11968 if (player->video_hub_download_mode == TRUE)
11969 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11970 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11971 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11972 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11973 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11974 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11975 (__mmplayer_is_only_mp3_type(player->type))) {
11976 LOGD("[mpegaudioparse] set streaming pull mode.");
11977 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11979 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11980 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11983 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11984 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11985 LOGD("plugged element is multiqueue. take it\n");
11987 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11988 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11990 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11991 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))) {
11992 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11993 __mm_player_streaming_set_multiqueue(player->streamer,
11996 player->ini.http_buffering_time,
11998 player->ini.http_buffering_limit);
12000 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
12007 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
12010 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12012 if (MMPLAYER_IS_STREAMING(player))
12015 /* This callback can be set to music player only. */
12016 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
12017 LOGW("audio callback is not supported for video");
12021 if (player->audio_stream_cb) {
12022 GstPad *pad = NULL;
12024 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
12027 LOGE("failed to get sink pad from audiosink to probe data\n");
12030 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
12031 __mmplayer_audio_stream_probe, player, NULL);
12033 gst_object_unref(pad);
12037 LOGE("There is no audio callback to configure.\n");
12047 __mmplayer_release_misc(mm_player_t* player)
12050 bool cur_mode = player->set_mode.rich_audio;
12053 MMPLAYER_RETURN_IF_FAIL(player);
12055 player->video_stream_cb = NULL;
12056 player->video_stream_cb_user_param = NULL;
12057 player->video_stream_prerolled = FALSE;
12059 player->audio_stream_cb = NULL;
12060 player->audio_stream_render_cb_ex = NULL;
12061 player->audio_stream_cb_user_param = NULL;
12062 player->audio_stream_sink_sync = false;
12064 player->video_stream_changed_cb = NULL;
12065 player->video_stream_changed_cb_user_param = NULL;
12067 player->audio_stream_changed_cb = NULL;
12068 player->audio_stream_changed_cb_user_param = NULL;
12070 player->sent_bos = FALSE;
12071 player->playback_rate = DEFAULT_PLAYBACK_RATE;
12073 player->doing_seek = FALSE;
12075 player->total_bitrate = 0;
12076 player->total_maximum_bitrate = 0;
12078 player->not_found_demuxer = 0;
12080 player->last_position = 0;
12081 player->duration = 0;
12082 player->http_content_size = 0;
12083 player->not_supported_codec = MISSING_PLUGIN_NONE;
12084 player->can_support_codec = FOUND_PLUGIN_NONE;
12085 player->pending_seek.is_pending = FALSE;
12086 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
12087 player->pending_seek.pos = 0;
12088 player->msg_posted = FALSE;
12089 player->has_many_types = FALSE;
12090 player->max_audio_channels = 0;
12091 player->video_share_api_delta = 0;
12092 player->video_share_clock_delta = 0;
12093 player->sound_focus.keep_last_pos = FALSE;
12094 player->is_subtitle_force_drop = FALSE;
12095 player->play_subtitle = FALSE;
12096 player->adjust_subtitle_pos = 0;
12097 player->last_multiwin_status = FALSE;
12098 player->has_closed_caption = FALSE;
12099 player->set_mode.media_packet_video_stream = FALSE;
12100 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
12101 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
12103 player->set_mode.rich_audio = cur_mode;
12105 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
12106 player->bitrate[i] = 0;
12107 player->maximum_bitrate[i] = 0;
12110 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
12112 /* remove media stream cb(appsrc cb) */
12113 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
12114 player->media_stream_buffer_status_cb[i] = NULL;
12115 player->media_stream_seek_data_cb[i] = NULL;
12116 player->buffer_cb_user_param[i] = NULL;
12117 player->seek_cb_user_param[i] = NULL;
12119 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
12121 /* free memory related to audio effect */
12122 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
12124 if (player->adaptive_info.var_list) {
12125 g_list_free_full(player->adaptive_info.var_list, g_free);
12126 player->adaptive_info.var_list = NULL;
12129 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12130 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12131 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
12133 /* Reset video360 settings to their defaults in case if the pipeline is to be
12136 player->video360_metadata.is_spherical = -1;
12137 player->is_openal_plugin_used = FALSE;
12139 player->is_content_spherical = FALSE;
12140 player->is_video360_enabled = TRUE;
12141 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
12142 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
12143 player->video360_yaw_radians = 4;
12144 player->video360_pitch_radians = 4;
12145 player->video360_zoom = 1.0f;
12146 player->video360_horizontal_fov = 0;
12147 player->video360_vertical_fov = 0;
12153 __mmplayer_release_misc_post(mm_player_t* player)
12155 char *original_uri = NULL;
12158 /* player->pipeline is already released before. */
12160 MMPLAYER_RETURN_IF_FAIL(player);
12162 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
12163 mm_attrs_set_int_by_name(player->attrs, "content_audio_found", 0);
12165 /* clean found parsers */
12166 if (player->parsers) {
12167 GList *parsers = player->parsers;
12168 for (; parsers; parsers = g_list_next(parsers)) {
12169 gchar *name = parsers->data;
12170 MMPLAYER_FREEIF(name);
12172 g_list_free(player->parsers);
12173 player->parsers = NULL;
12176 /* clean found audio decoders */
12177 if (player->audio_decoders) {
12178 GList *a_dec = player->audio_decoders;
12179 for (; a_dec; a_dec = g_list_next(a_dec)) {
12180 gchar *name = a_dec->data;
12181 MMPLAYER_FREEIF(name);
12183 g_list_free(player->audio_decoders);
12184 player->audio_decoders = NULL;
12187 /* clean the uri list except original uri */
12188 if (player->uri_info.uri_list) {
12189 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
12191 if (player->attrs) {
12192 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
12193 LOGD("restore original uri = %s\n", original_uri);
12195 if (mmf_attrs_commit(player->attrs))
12196 LOGE("failed to commit the original uri.\n");
12199 GList *uri_list = player->uri_info.uri_list;
12200 for (; uri_list; uri_list = g_list_next(uri_list)) {
12201 gchar *uri = uri_list->data;
12202 MMPLAYER_FREEIF(uri);
12204 g_list_free(player->uri_info.uri_list);
12205 player->uri_info.uri_list = NULL;
12208 /* clear the audio stream buffer list */
12209 __mmplayer_audio_stream_clear_buffer(player, FALSE);
12211 /* clear the video stream bo list */
12212 __mmplayer_video_stream_destroy_bo_list(player);
12213 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
12215 if (player->profile.mem) {
12216 free(player->profile.mem);
12217 player->profile.mem = NULL;
12218 player->mem_buf.buf = NULL;
12220 player->uri_info.uri_idx = 0;
12224 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
12226 GstElement *element = NULL;
12229 LOGD("creating %s to plug\n", name);
12231 element = gst_element_factory_make(name, NULL);
12233 LOGE("failed to create queue\n");
12237 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
12238 LOGE("failed to set state READY to %s\n", name);
12239 gst_object_unref(element);
12243 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
12244 LOGE("failed to add %s\n", name);
12245 gst_object_unref(element);
12249 sinkpad = gst_element_get_static_pad(element, "sink");
12251 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
12252 LOGE("failed to link %s\n", name);
12253 gst_object_unref(sinkpad);
12254 gst_object_unref(element);
12258 LOGD("linked %s to pipeline successfully\n", name);
12260 gst_object_unref(sinkpad);
12266 __mmplayer_check_subtitle(mm_player_t* player)
12268 MMHandleType attrs = 0;
12269 char *subtitle_uri = NULL;
12273 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12275 /* get subtitle attribute */
12276 attrs = MMPLAYER_GET_ATTRS(player);
12280 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12281 if (!subtitle_uri || !strlen(subtitle_uri))
12284 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
12285 player->is_external_subtitle_present = TRUE;
12293 __mmplayer_can_extract_pcm(mm_player_t* player)
12295 MMHandleType attrs = 0;
12296 gboolean sound_extraction = FALSE;
12298 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12300 attrs = MMPLAYER_GET_ATTRS(player);
12302 LOGE("fail to get attributes.");
12306 /* get sound_extraction property */
12307 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
12309 if (!sound_extraction) {
12310 LOGD("checking pcm extraction mode : %d ", sound_extraction);
12318 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
12321 MMMessageParamType msg_param;
12322 gchar *msg_src_element = NULL;
12323 GstStructure *s = NULL;
12324 guint error_id = 0;
12325 gchar *error_string = NULL;
12329 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12330 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
12332 s = gst_structure_copy(gst_message_get_structure(message));
12335 if (!gst_structure_get_uint(s, "error_id", &error_id))
12336 error_id = MMPLAYER_STREAMING_ERROR_NONE;
12338 switch (error_id) {
12339 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
12340 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
12342 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
12343 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
12345 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
12346 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
12348 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
12349 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
12351 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
12352 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
12354 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
12355 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
12357 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
12358 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
12360 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
12361 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
12363 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
12364 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
12366 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
12367 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
12369 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
12370 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
12372 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
12373 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
12375 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
12376 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
12378 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
12379 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
12381 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
12382 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
12384 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
12385 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
12387 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
12388 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
12390 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
12391 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
12393 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
12394 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
12396 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
12397 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
12399 case MMPLAYER_STREAMING_ERROR_GONE:
12400 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
12402 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
12403 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
12405 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
12406 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
12408 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
12409 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
12411 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
12412 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
12414 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
12415 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
12417 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
12418 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
12420 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
12421 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
12423 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
12424 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
12426 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
12427 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
12429 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
12430 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
12432 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
12433 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
12435 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
12436 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
12438 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
12439 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
12441 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
12442 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
12444 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
12445 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
12447 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
12448 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
12450 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
12451 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
12453 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
12454 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
12456 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
12457 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
12459 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
12460 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
12462 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
12463 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
12465 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
12466 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
12468 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
12469 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
12471 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
12472 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
12476 gst_structure_free(s);
12477 return MM_ERROR_PLAYER_STREAMING_FAIL;
12481 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
12483 msg_param.data = (void *) error_string;
12485 if (message->src) {
12486 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
12488 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
12489 msg_src_element, msg_param.code, (char*)msg_param.data);
12492 /* post error to application */
12493 if (!player->msg_posted) {
12494 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
12496 /* don't post more if one was sent already */
12497 player->msg_posted = TRUE;
12499 LOGD("skip error post because it's sent already.\n");
12501 gst_structure_free(s);
12503 g_free(error_string);
12510 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
12512 MMPLAYER_RETURN_IF_FAIL(player);
12514 /* post now if delay is zero */
12515 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
12516 LOGD("eos delay is zero. posting EOS now\n");
12517 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12519 if (player->set_mode.pcm_extraction)
12520 __mmplayer_cancel_eos_timer(player);
12525 /* cancel if existing */
12526 __mmplayer_cancel_eos_timer(player);
12528 /* init new timeout */
12529 /* NOTE : consider give high priority to this timer */
12530 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
12532 player->eos_timer = g_timeout_add(delay_in_ms,
12533 __mmplayer_eos_timer_cb, player);
12535 player->global_default = g_main_context_default();
12536 LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
12538 /* check timer is valid. if not, send EOS now */
12539 if (player->eos_timer == 0) {
12540 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
12541 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12546 __mmplayer_cancel_eos_timer(mm_player_t* player)
12548 MMPLAYER_RETURN_IF_FAIL(player);
12550 if (player->eos_timer) {
12551 LOGD("cancel eos timer");
12552 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
12553 player->eos_timer = 0;
12560 __mmplayer_eos_timer_cb(gpointer u_data)
12562 mm_player_t* player = NULL;
12563 player = (mm_player_t*) u_data;
12565 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12567 if (player->play_count > 1) {
12568 gint ret_value = 0;
12569 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
12570 if (ret_value == MM_ERROR_NONE) {
12571 MMHandleType attrs = 0;
12572 attrs = MMPLAYER_GET_ATTRS(player);
12574 /* we successeded to rewind. update play count and then wait for next EOS */
12575 player->play_count--;
12577 mm_attrs_set_int_by_name(attrs, "profile_play_count", player->play_count);
12578 if (mmf_attrs_commit(attrs))
12579 LOGE("failed to update attributes\n");
12581 LOGE("seeking to 0 failed in repeat play");
12585 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
12588 /* we are returning FALSE as we need only one posting */
12592 /* sending event to one of sinkelements */
12594 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
12596 GstEvent * event2 = NULL;
12597 GList *sinks = NULL;
12598 gboolean res = FALSE;
12601 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12602 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
12604 /* While adding subtitles in live feeds seek is getting called.
12605 Adding defensive check in framework layer.*/
12606 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
12607 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
12608 LOGE("Should not send seek event during live playback");
12613 if (player->play_subtitle)
12614 event2 = gst_event_copy((const GstEvent *)event);
12616 sinks = player->sink_elements;
12618 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
12620 if (GST_IS_ELEMENT(sink)) {
12621 /* keep ref to the event */
12622 gst_event_ref(event);
12624 if ((res = gst_element_send_event(sink, event))) {
12625 LOGD("sending event[%s] to sink element [%s] success!\n",
12626 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
12628 /* rtsp case, asyn_done is not called after seek during pause state */
12629 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
12630 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
12631 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
12632 LOGD("RTSP seek completed, after pause state..\n");
12633 player->doing_seek = FALSE;
12634 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
12640 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
12641 sinks = g_list_next(sinks);
12648 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
12649 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
12652 sinks = g_list_next(sinks);
12655 /* Note : Textbin is not linked to the video or audio bin.
12656 * It needs to send the event to the text sink seperatelly.
12658 if (player->play_subtitle && player->pipeline) {
12659 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
12661 if (GST_IS_ELEMENT(text_sink)) {
12662 /* keep ref to the event */
12663 gst_event_ref(event2);
12665 if ((res = gst_element_send_event(text_sink, event2)))
12666 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
12667 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
12669 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
12670 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
12672 gst_event_unref(event2);
12676 gst_event_unref(event);
12684 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
12688 MMPLAYER_RETURN_IF_FAIL(player);
12689 MMPLAYER_RETURN_IF_FAIL(sink);
12691 player->sink_elements =
12692 g_list_append(player->sink_elements, sink);
12698 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
12702 MMPLAYER_RETURN_IF_FAIL(player);
12703 MMPLAYER_RETURN_IF_FAIL(sink);
12705 player->sink_elements =
12706 g_list_remove(player->sink_elements, sink);
12712 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
12713 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
12714 gint64 cur, GstSeekType stop_type, gint64 stop)
12716 GstEvent* event = NULL;
12717 gboolean result = FALSE;
12721 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12723 if (player->pipeline && player->pipeline->textbin)
12724 __mmplayer_drop_subtitle(player, FALSE);
12726 event = gst_event_new_seek(rate, format, flags, cur_type,
12727 cur, stop_type, stop);
12729 result = __gst_send_event_to_sink(player, event);
12736 /* NOTE : be careful with calling this api. please refer to below glib comment
12737 * glib comment : Note that there is a bug in GObject that makes this function much
12738 * less useful than it might seem otherwise. Once gobject is disposed, the callback
12739 * will no longer be called, but, the signal handler is not currently disconnected.
12740 * If the instance is itself being freed at the same time than this doesn't matter,
12741 * since the signal will automatically be removed, but if instance persists,
12742 * then the signal handler will leak. You should not remove the signal yourself
12743 * because in a future versions of GObject, the handler will automatically be
12746 * It's possible to work around this problem in a way that will continue to work
12747 * with future versions of GObject by checking that the signal handler is still
12748 * connected before disconnected it:
12750 * if (g_signal_handler_is_connected(instance, id))
12751 * g_signal_handler_disconnect(instance, id);
12754 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12756 GList* sig_list = NULL;
12757 MMPlayerSignalItem* item = NULL;
12761 MMPLAYER_RETURN_IF_FAIL(player);
12763 LOGD("release signals type : %d", type);
12765 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12766 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12767 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12768 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12769 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12770 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12774 sig_list = player->signals[type];
12776 for (; sig_list; sig_list = sig_list->next) {
12777 item = sig_list->data;
12779 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12780 if (g_signal_handler_is_connected(item->obj, item->sig))
12781 g_signal_handler_disconnect(item->obj, item->sig);
12784 MMPLAYER_FREEIF(item);
12787 g_list_free(player->signals[type]);
12788 player->signals[type] = NULL;
12795 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12797 mm_player_t* player = 0;
12798 int prev_display_surface_type = 0;
12799 void *prev_display_overlay = NULL;
12800 const gchar *klass = NULL;
12801 gchar *cur_videosink_name = NULL;
12804 int num_of_dec = 2; /* DEC1, DEC2 */
12808 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12809 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12811 player = MM_PLAYER_CAST(handle);
12813 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12814 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12816 return MM_ERROR_INVALID_ARGUMENT;
12819 /* load previous attributes */
12820 if (player->attrs) {
12821 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12822 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12823 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12824 if (prev_display_surface_type == surface_type) {
12825 LOGD("incoming display surface type is same as previous one, do nothing..");
12827 return MM_ERROR_NONE;
12830 LOGE("failed to load attributes");
12832 return MM_ERROR_PLAYER_INTERNAL;
12835 /* check videosink element is created */
12836 if (!player->pipeline || !player->pipeline->videobin ||
12837 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12838 LOGD("videosink element is not yet ready");
12840 /* videobin is not created yet, so we just set attributes related to display surface */
12841 LOGD("store display attribute for given surface type(%d)", surface_type);
12842 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12843 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12844 if (mmf_attrs_commit(player->attrs)) {
12845 LOGE("failed to commit attribute");
12847 return MM_ERROR_PLAYER_INTERNAL;
12850 return MM_ERROR_NONE;
12852 /* get player command status */
12853 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12854 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12856 return MM_ERROR_PLAYER_INVALID_STATE;
12859 /* surface change */
12860 for (i = 0 ; i < num_of_dec ; i++) {
12861 if (player->pipeline->mainbin &&
12862 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12863 GstElementFactory *decfactory;
12864 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12866 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12867 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12868 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12869 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12873 LOGW("success to changing display surface(%d)", surface_type);
12875 return MM_ERROR_NONE;
12877 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12878 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12882 LOGW("success to changing display surface(%d)", surface_type);
12884 return MM_ERROR_NONE;
12887 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12888 ret = MM_ERROR_PLAYER_INTERNAL;
12897 /* rollback to previous attributes */
12898 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12899 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12900 if (mmf_attrs_commit(player->attrs)) {
12901 LOGE("failed to commit attributes to rollback");
12903 return MM_ERROR_PLAYER_INTERNAL;
12909 /* NOTE : It does not support some use cases, eg using colorspace converter */
12911 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12913 GstPad *src_pad_dec = NULL;
12914 GstPad *sink_pad_videosink = NULL;
12915 GstPad *sink_pad_videobin = NULL;
12916 GstClock *clock = NULL;
12917 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12918 int ret = MM_ERROR_NONE;
12919 gboolean is_audiobin_created = TRUE;
12923 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12924 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12925 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12927 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12928 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12930 /* get information whether if audiobin is created */
12931 if (!player->pipeline->audiobin ||
12932 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12933 LOGW("audiobin is null, this video content may not have audio data");
12934 is_audiobin_created = FALSE;
12937 /* get current state of player */
12938 previous_state = MMPLAYER_CURRENT_STATE(player);
12939 LOGD("previous state(%d)", previous_state);
12942 /* get src pad of decoder and block it */
12943 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12944 if (!src_pad_dec) {
12945 LOGE("failed to get src pad from decode in mainbin");
12946 return MM_ERROR_PLAYER_INTERNAL;
12949 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12950 LOGW("trying to block pad(video)");
12951 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12952 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12955 LOGE("failed to set block pad(video)");
12956 return MM_ERROR_PLAYER_INTERNAL;
12958 LOGW("pad is blocked(video)");
12960 /* no data flows, so no need to do pad_block */
12961 if (player->doing_seek)
12962 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12964 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12968 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12969 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12970 LOGE("failed to remove previous ghost_pad for videobin");
12971 return MM_ERROR_PLAYER_INTERNAL;
12974 /* change state of videobin to NULL */
12975 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12976 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12977 if (ret != GST_STATE_CHANGE_SUCCESS) {
12978 LOGE("failed to change state of videobin to NULL");
12979 return MM_ERROR_PLAYER_INTERNAL;
12982 /* unlink between decoder and videobin and remove previous videosink from videobin */
12983 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12984 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12985 LOGE("failed to remove former videosink from videobin");
12986 return MM_ERROR_PLAYER_INTERNAL;
12989 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12991 /* create a new videosink and add it to videobin */
12992 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, videosink_element);
12993 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12994 LOGE("failed to create videosink element\n");
12996 return MM_ERROR_PLAYER_INTERNAL;
12998 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12999 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13000 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
13002 /* save attributes */
13003 if (player->attrs) {
13004 /* set a new display surface type */
13005 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
13006 /* set a new diplay overlay */
13007 switch (surface_type) {
13008 case MM_DISPLAY_SURFACE_OVERLAY:
13009 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
13010 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
13013 LOGE("invalid type(%d) for changing display surface", surface_type);
13015 return MM_ERROR_INVALID_ARGUMENT;
13017 if (mmf_attrs_commit(player->attrs)) {
13018 LOGE("failed to commit");
13020 return MM_ERROR_PLAYER_INTERNAL;
13023 LOGE("player->attrs is null, failed to save attributes");
13025 return MM_ERROR_PLAYER_INTERNAL;
13028 /* update video param */
13029 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
13030 LOGE("failed to update video param");
13031 return MM_ERROR_PLAYER_INTERNAL;
13034 /* change state of videobin to READY */
13035 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
13036 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
13037 if (ret != GST_STATE_CHANGE_SUCCESS) {
13038 LOGE("failed to change state of videobin to READY");
13039 return MM_ERROR_PLAYER_INTERNAL;
13042 /* change ghostpad */
13043 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
13044 if (!sink_pad_videosink) {
13045 LOGE("failed to get sink pad from videosink element");
13046 return MM_ERROR_PLAYER_INTERNAL;
13048 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
13049 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
13050 LOGE("failed to set active to ghost_pad");
13051 return MM_ERROR_PLAYER_INTERNAL;
13053 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
13054 LOGE("failed to change ghostpad for videobin");
13055 return MM_ERROR_PLAYER_INTERNAL;
13057 gst_object_unref(sink_pad_videosink);
13059 /* link decoder with videobin */
13060 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
13061 if (!sink_pad_videobin) {
13062 LOGE("failed to get sink pad from videobin");
13063 return MM_ERROR_PLAYER_INTERNAL;
13065 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
13066 LOGE("failed to link");
13067 return MM_ERROR_PLAYER_INTERNAL;
13069 gst_object_unref(sink_pad_videobin);
13071 /* clock setting for a new videosink plugin */
13072 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
13073 so we set it from audiosink plugin or pipeline(system clock) */
13074 if (!is_audiobin_created) {
13075 LOGW("audiobin is not created, get clock from pipeline..");
13076 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13078 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13082 GstClockTime base_time;
13083 LOGD("set the clock to videosink");
13084 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
13085 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13087 LOGD("got clock of videosink");
13088 now = gst_clock_get_time(clock);
13089 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
13090 LOGD("at time %" GST_TIME_FORMAT ", base %"
13091 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
13093 LOGE("failed to get clock of videosink after setting clock");
13094 return MM_ERROR_PLAYER_INTERNAL;
13097 LOGW("failed to get clock, maybe it is the time before first playing");
13099 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
13100 /* change state of videobin to PAUSED */
13101 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
13102 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
13103 if (ret != GST_STATE_CHANGE_FAILURE) {
13104 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
13106 LOGE("failed to change state of videobin to PLAYING");
13107 return MM_ERROR_PLAYER_INTERNAL;
13110 /* release blocked and unref src pad of video decoder */
13112 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
13113 LOGE("failed to set pad blocked FALSE(video)");
13114 return MM_ERROR_PLAYER_INTERNAL;
13117 LOGW("pad is unblocked(video)");
13119 if (player->doing_seek)
13120 LOGW("not completed seek(%d)", player->doing_seek);
13121 /* change state of videobin to PAUSED */
13122 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
13123 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
13124 if (ret != GST_STATE_CHANGE_FAILURE) {
13125 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
13127 LOGE("failed to change state of videobin to PLAYING");
13128 return MM_ERROR_PLAYER_INTERNAL;
13131 /* already skipped pad block */
13132 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
13135 /* do get/set position for new videosink plugin */
13137 unsigned long position = 0;
13138 gint64 pos_msec = 0;
13140 LOGD("do get/set position for new videosink plugin");
13141 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
13142 LOGE("failed to get position");
13143 return MM_ERROR_PLAYER_INTERNAL;
13145 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
13146 /* accurate seek */
13147 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
13148 LOGE("failed to set position");
13149 return MM_ERROR_PLAYER_INTERNAL;
13152 /* key unit seek */
13153 pos_msec = position * G_GINT64_CONSTANT(1000000);
13154 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
13155 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
13156 GST_SEEK_TYPE_SET, pos_msec,
13157 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
13159 LOGE("failed to set position");
13160 return MM_ERROR_PLAYER_INTERNAL;
13166 gst_object_unref(src_pad_dec);
13167 LOGD("success to change sink");
13171 return MM_ERROR_NONE;
13175 /* Note : if silent is true, then subtitle would not be displayed. :*/
13176 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
13178 mm_player_t* player = (mm_player_t*) hplayer;
13182 /* check player handle */
13183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13185 player->set_mode.subtitle_off = silent;
13187 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
13191 return MM_ERROR_NONE;
13194 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
13196 MMPlayerGstElement* mainbin = NULL;
13197 MMPlayerGstElement* textbin = NULL;
13198 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
13199 GstState current_state = GST_STATE_VOID_PENDING;
13200 GstState element_state = GST_STATE_VOID_PENDING;
13201 GstState element_pending_state = GST_STATE_VOID_PENDING;
13203 GstEvent *event = NULL;
13204 int result = MM_ERROR_NONE;
13206 GstClock *curr_clock = NULL;
13207 GstClockTime base_time, start_time, curr_time;
13212 /* check player handle */
13213 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
13214 player->pipeline &&
13215 player->pipeline->mainbin &&
13216 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13218 mainbin = player->pipeline->mainbin;
13219 textbin = player->pipeline->textbin;
13221 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13223 // sync clock with current pipeline
13224 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
13225 curr_time = gst_clock_get_time(curr_clock);
13227 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
13228 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
13230 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
13231 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
13233 if (current_state > GST_STATE_READY) {
13234 // sync state with current pipeline
13235 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
13236 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
13237 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
13239 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
13240 if (GST_STATE_CHANGE_FAILURE == ret) {
13241 LOGE("fail to state change.\n");
13242 result = MM_ERROR_PLAYER_INTERNAL;
13247 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
13248 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
13251 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
13252 gst_object_unref(curr_clock);
13255 // seek to current position
13256 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
13257 result = MM_ERROR_PLAYER_INVALID_STATE;
13258 LOGE("gst_element_query_position failed, invalid state\n");
13262 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
13263 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);
13265 __gst_send_event_to_sink(player, event);
13267 result = MM_ERROR_PLAYER_INTERNAL;
13268 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
13272 /* sync state with current pipeline */
13273 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
13274 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
13275 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
13277 return MM_ERROR_NONE;
13280 /* release text pipeline resource */
13281 player->textsink_linked = 0;
13283 /* release signal */
13284 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
13286 /* release textbin with it's childs */
13287 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
13288 MMPLAYER_FREEIF(player->pipeline->textbin);
13289 player->pipeline->textbin = NULL;
13291 /* release subtitle elem */
13292 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
13293 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
13299 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
13301 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
13302 GstState current_state = GST_STATE_VOID_PENDING;
13304 MMHandleType attrs = 0;
13305 MMPlayerGstElement* mainbin = NULL;
13306 MMPlayerGstElement* textbin = NULL;
13308 gchar* subtitle_uri = NULL;
13309 int result = MM_ERROR_NONE;
13310 const gchar *charset = NULL;
13314 /* check player handle */
13315 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
13316 player->pipeline &&
13317 player->pipeline->mainbin &&
13318 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13319 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
13321 mainbin = player->pipeline->mainbin;
13322 textbin = player->pipeline->textbin;
13324 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13325 if (current_state < GST_STATE_READY) {
13326 result = MM_ERROR_PLAYER_INVALID_STATE;
13327 LOGE("Pipeline is not in proper state\n");
13331 attrs = MMPLAYER_GET_ATTRS(player);
13333 LOGE("cannot get content attribute\n");
13334 result = MM_ERROR_PLAYER_INTERNAL;
13338 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
13339 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
13340 LOGE("subtitle uri is not proper filepath\n");
13341 result = MM_ERROR_PLAYER_INVALID_URI;
13345 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
13346 LOGE("failed to get storage info of subtitle path");
13347 result = MM_ERROR_PLAYER_INVALID_URI;
13351 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
13352 LOGD("new subtitle file path is [%s]\n", filepath);
13354 if (!strcmp(filepath, subtitle_uri)) {
13355 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
13358 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13359 if (mmf_attrs_commit(player->attrs)) {
13360 LOGE("failed to commit.\n");
13365 //gst_pad_set_blocked_async(src-srcpad, TRUE)
13366 MMPLAYER_SUBTITLE_INFO_LOCK(player);
13367 player->subtitle_language_list = NULL;
13368 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
13370 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
13371 if (ret != GST_STATE_CHANGE_SUCCESS) {
13372 LOGE("failed to change state of textbin to READY");
13373 result = MM_ERROR_PLAYER_INTERNAL;
13377 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
13378 if (ret != GST_STATE_CHANGE_SUCCESS) {
13379 LOGE("failed to change state of subparse to READY");
13380 result = MM_ERROR_PLAYER_INTERNAL;
13384 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
13385 if (ret != GST_STATE_CHANGE_SUCCESS) {
13386 LOGE("failed to change state of filesrc to READY");
13387 result = MM_ERROR_PLAYER_INTERNAL;
13391 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
13393 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
13395 charset = util_get_charset(filepath);
13397 LOGD("detected charset is %s\n", charset);
13398 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
13401 result = _mmplayer_sync_subtitle_pipeline(player);
13408 /* API to switch between external subtitles */
13409 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
13411 int result = MM_ERROR_NONE;
13412 mm_player_t* player = (mm_player_t*)hplayer;
13417 /* check player handle */
13418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13420 /* filepath can be null in idle state */
13422 /* check file path */
13423 if ((path = strstr(filepath, "file://")))
13424 result = util_exist_file_path(path + 7);
13426 result = util_exist_file_path(filepath);
13429 if (result != MM_ERROR_NONE) {
13430 LOGE("invalid subtitle path 0x%X", result);
13431 return result; /* file not found or permission denied */
13435 if (!player->pipeline) {
13437 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13438 if (mmf_attrs_commit(player->attrs)) {
13439 LOGE("failed to commit"); /* subtitle path will not be created */
13440 return MM_ERROR_PLAYER_INTERNAL;
13443 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
13444 /* check filepath */
13445 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
13447 if (!__mmplayer_check_subtitle(player)) {
13448 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
13449 if (mmf_attrs_commit(player->attrs)) {
13450 LOGE("failed to commit");
13451 return MM_ERROR_PLAYER_INTERNAL;
13454 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
13455 LOGE("fail to create text pipeline");
13456 return MM_ERROR_PLAYER_INTERNAL;
13459 result = _mmplayer_sync_subtitle_pipeline(player);
13461 result = __mmplayer_change_external_subtitle_language(player, filepath);
13464 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
13465 player->is_external_subtitle_added_now = TRUE;
13467 MMPLAYER_SUBTITLE_INFO_LOCK(player);
13468 if (!player->subtitle_language_list) {
13469 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
13470 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
13471 LOGW("subtitle language list is not updated yet");
13473 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
13481 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
13483 int result = MM_ERROR_NONE;
13484 gchar* change_pad_name = NULL;
13485 GstPad* sinkpad = NULL;
13486 MMPlayerGstElement* mainbin = NULL;
13487 enum MainElementID elemId = MMPLAYER_M_NUM;
13488 GstCaps* caps = NULL;
13489 gint total_track_num = 0;
13493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
13494 MM_ERROR_PLAYER_NOT_INITIALIZED);
13496 LOGD("Change Track(%d) to %d\n", type, index);
13498 mainbin = player->pipeline->mainbin;
13500 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
13501 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
13502 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
13503 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
13505 /* Changing Video Track is not supported. */
13506 LOGE("Track Type Error\n");
13510 if (mainbin[elemId].gst == NULL) {
13511 result = MM_ERROR_PLAYER_NO_OP;
13512 LOGD("Req track doesn't exist\n");
13516 total_track_num = player->selector[type].total_track_num;
13517 if (total_track_num <= 0) {
13518 result = MM_ERROR_PLAYER_NO_OP;
13519 LOGD("Language list is not available \n");
13523 if ((index < 0) || (index >= total_track_num)) {
13524 result = MM_ERROR_INVALID_ARGUMENT;
13525 LOGD("Not a proper index : %d \n", index);
13529 /*To get the new pad from the selector*/
13530 change_pad_name = g_strdup_printf("sink_%u", index);
13531 if (change_pad_name == NULL) {
13532 result = MM_ERROR_PLAYER_INTERNAL;
13533 LOGD("Pad does not exists\n");
13537 LOGD("new active pad name: %s\n", change_pad_name);
13539 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
13540 if (sinkpad == NULL) {
13541 LOGD("sinkpad is NULL");
13542 result = MM_ERROR_PLAYER_INTERNAL;
13546 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
13547 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
13549 caps = gst_pad_get_current_caps(sinkpad);
13550 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
13553 gst_object_unref(sinkpad);
13555 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
13556 __mmplayer_set_audio_attrs(player, caps);
13560 MMPLAYER_FREEIF(change_pad_name);
13564 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
13566 int result = MM_ERROR_NONE;
13567 mm_player_t* player = NULL;
13568 MMPlayerGstElement* mainbin = NULL;
13570 gint current_active_index = 0;
13572 GstState current_state = GST_STATE_VOID_PENDING;
13573 GstEvent* event = NULL;
13578 player = (mm_player_t*)hplayer;
13579 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13581 if (!player->pipeline) {
13582 LOGE("Track %d pre setting -> %d\n", type, index);
13584 player->selector[type].active_pad_index = index;
13588 mainbin = player->pipeline->mainbin;
13590 current_active_index = player->selector[type].active_pad_index;
13592 /*If index is same as running index no need to change the pad*/
13593 if (current_active_index == index)
13596 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
13597 result = MM_ERROR_PLAYER_INVALID_STATE;
13601 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
13602 if (current_state < GST_STATE_PAUSED) {
13603 result = MM_ERROR_PLAYER_INVALID_STATE;
13604 LOGW("Pipeline not in porper state\n");
13608 result = __mmplayer_change_selector_pad(player, type, index);
13609 if (result != MM_ERROR_NONE) {
13610 LOGE("change selector pad error\n");
13614 player->selector[type].active_pad_index = index;
13616 if (current_state == GST_STATE_PLAYING) {
13617 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);
13619 __gst_send_event_to_sink(player, event);
13621 result = MM_ERROR_PLAYER_INTERNAL;
13630 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
13632 mm_player_t* player = (mm_player_t*) hplayer;
13636 /* check player handle */
13637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13639 *silent = player->set_mode.subtitle_off;
13641 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
13645 return MM_ERROR_NONE;
13649 __is_ms_buff_src(mm_player_t* player)
13651 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13653 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
13657 __has_suffix(mm_player_t* player, const gchar* suffix)
13659 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13660 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
13662 gboolean ret = FALSE;
13663 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
13664 gchar* t_suffix = g_ascii_strdown(suffix, -1);
13666 if (g_str_has_suffix(player->profile.uri, suffix))
13669 MMPLAYER_FREEIF(t_url);
13670 MMPLAYER_FREEIF(t_suffix);
13676 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
13678 mm_player_t* player = (mm_player_t*) hplayer;
13680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13682 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
13683 MMPLAYER_PRINT_STATE(player);
13684 LOGE("wrong-state : can't set the download mode to parse");
13685 return MM_ERROR_PLAYER_INVALID_STATE;
13688 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
13689 player->video_hub_download_mode = mode;
13691 return MM_ERROR_NONE;
13695 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
13697 mm_player_t* player = (mm_player_t*) hplayer;
13699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13701 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
13702 player->sync_handler = enable;
13704 return MM_ERROR_NONE;
13708 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
13710 long long clock_delta,
13711 long long video_time,
13712 long long media_clock,
13713 long long audio_time)
13715 mm_player_t* player = (mm_player_t*) hplayer;
13716 MMPlayerGstElement* mainbin = NULL;
13717 GstClockTime start_time_audio = 0, start_time_video = 0;
13718 GstClockTimeDiff base_time = 0, new_base_time = 0;
13719 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13720 gint64 api_delta = 0;
13721 gint64 position = 0, position_delta = 0;
13722 gint64 adj_base_time = 0;
13723 GstClock *curr_clock = NULL;
13724 GstClockTime curr_time = 0;
13725 gboolean query_ret = TRUE;
13726 int result = MM_ERROR_NONE;
13730 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13731 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13732 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13734 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13736 if ((video_time < 0) || (player->doing_seek)) {
13737 LOGD("skip setting master clock. %lld", video_time);
13741 mainbin = player->pipeline->mainbin;
13743 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13744 curr_time = gst_clock_get_time(curr_clock);
13746 current_state = MMPLAYER_CURRENT_STATE(player);
13748 if (current_state == MM_PLAYER_STATE_PLAYING)
13749 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13751 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13753 position = player->last_position;
13754 LOGD("query fail. %lld", position);
13757 clock *= GST_USECOND;
13758 clock_delta *= GST_USECOND;
13760 api_delta = clock - curr_time;
13761 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13762 player->video_share_api_delta = api_delta;
13764 clock_delta += (api_delta - player->video_share_api_delta);
13766 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13767 player->video_share_clock_delta = (gint64)clock_delta;
13769 position_delta = (position/GST_USECOND) - video_time;
13770 position_delta *= GST_USECOND;
13772 adj_base_time = position_delta;
13773 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13776 gint64 new_play_time = 0;
13777 gint64 network_delay = 0;
13779 video_time *= GST_USECOND;
13781 network_delay = clock_delta - player->video_share_clock_delta;
13782 new_play_time = video_time + network_delay;
13784 adj_base_time = position - new_play_time;
13786 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13787 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13790 /* Adjust Current Stream Time with base_time of sink
13791 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13792 * 2. Set new base time
13793 * if adj_base_time is positive value, the stream time will be decreased.
13794 * 3. If seek event is occurred, the start time will be reset. */
13795 if ((player->pipeline->audiobin) &&
13796 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13797 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13799 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13800 LOGD("audio sink : gst_element_set_start_time -> NONE");
13801 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13804 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13807 if ((player->pipeline->videobin) &&
13808 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13809 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13811 if (start_time_video != GST_CLOCK_TIME_NONE) {
13812 LOGD("video sink : gst_element_set_start_time -> NONE");
13813 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13816 // if videobin exist, get base_time from videobin.
13817 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13820 new_base_time = base_time + adj_base_time;
13822 if ((player->pipeline->audiobin) &&
13823 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13824 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13826 if ((player->pipeline->videobin) &&
13827 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13828 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13837 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13838 long long *video_time,
13839 long long *media_clock,
13840 long long *audio_time)
13842 mm_player_t* player = (mm_player_t*) hplayer;
13843 MMPlayerGstElement* mainbin = NULL;
13844 GstClock *curr_clock = NULL;
13845 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13846 gint64 position = 0;
13847 gboolean query_ret = TRUE;
13851 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13852 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13853 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13855 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13856 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13857 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13859 mainbin = player->pipeline->mainbin;
13861 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13863 current_state = MMPLAYER_CURRENT_STATE(player);
13865 if (current_state != MM_PLAYER_STATE_PAUSED)
13866 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13868 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13870 position = player->last_position;
13872 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13874 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13877 gst_object_unref(curr_clock);
13881 return MM_ERROR_NONE;
13885 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13887 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13888 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13890 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13891 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13895 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13896 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13897 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13898 mm_player_dump_t *dump_s;
13899 dump_s = g_malloc(sizeof(mm_player_dump_t));
13901 if (dump_s == NULL) {
13902 LOGE("malloc fail");
13906 dump_s->dump_element_file = NULL;
13907 dump_s->dump_pad = NULL;
13908 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13910 if (dump_s->dump_pad) {
13911 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13912 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]);
13913 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13914 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);
13915 /* add list for removed buffer probe and close FILE */
13916 player->dump_list = g_list_append(player->dump_list, dump_s);
13917 LOGD("%s sink pad added buffer probe for dump", factory_name);
13922 LOGE("failed to get %s sink pad added", factory_name);
13931 static GstPadProbeReturn
13932 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13934 FILE *dump_data = (FILE *) u_data;
13935 // int written = 0;
13936 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13937 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13939 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13941 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13943 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13945 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13947 return GST_PAD_PROBE_OK;
13951 __mmplayer_release_dump_list(GList *dump_list)
13954 GList *d_list = dump_list;
13955 for (; d_list; d_list = g_list_next(d_list)) {
13956 mm_player_dump_t *dump_s = d_list->data;
13957 if (dump_s->dump_pad) {
13958 if (dump_s->probe_handle_id)
13959 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13961 if (dump_s->dump_element_file) {
13962 fclose(dump_s->dump_element_file);
13963 dump_s->dump_element_file = NULL;
13965 MMPLAYER_FREEIF(dump_s);
13967 g_list_free(dump_list);
13973 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13975 mm_player_t* player = (mm_player_t*) hplayer;
13979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13980 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13982 *exist = player->has_closed_caption;
13986 return MM_ERROR_NONE;
13989 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13993 // LOGD("unref internal gst buffer %p", buffer);
13994 gst_buffer_unref((GstBuffer *)buffer);
14001 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
14003 mm_player_t *player = (mm_player_t*)user_data;
14004 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14005 guint64 current_level_bytes = 0;
14007 MMPLAYER_RETURN_IF_FAIL(player);
14009 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14011 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
14012 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14014 if (player->media_stream_buffer_status_cb[type])
14015 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14016 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14021 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
14023 mm_player_t *player = (mm_player_t*)user_data;
14024 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14025 guint64 current_level_bytes = 0;
14027 MMPLAYER_RETURN_IF_FAIL(player);
14029 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14031 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
14033 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14034 if (player->media_stream_buffer_status_cb[type])
14035 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14036 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14040 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
14042 mm_player_t *player = (mm_player_t*)user_data;
14043 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14044 guint64 current_level_bytes = 0;
14046 MMPLAYER_RETURN_IF_FAIL(player);
14048 LOGI("app-src: feed subtitle\n");
14050 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14052 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14053 if (player->media_stream_buffer_status_cb[type])
14054 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
14056 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14060 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
14062 mm_player_t *player = (mm_player_t*)user_data;
14063 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14064 guint64 current_level_bytes = 0;
14066 MMPLAYER_RETURN_IF_FAIL(player);
14068 LOGI("app-src: audio buffer is full.\n");
14070 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14072 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14074 if (player->media_stream_buffer_status_cb[type])
14075 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
14077 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14081 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
14083 mm_player_t *player = (mm_player_t*)user_data;
14084 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14085 guint64 current_level_bytes = 0;
14087 MMPLAYER_RETURN_IF_FAIL(player);
14089 LOGI("app-src: video buffer is full.\n");
14091 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
14093 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14094 if (player->media_stream_buffer_status_cb[type])
14095 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
14097 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14101 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
14103 mm_player_t *player = (mm_player_t*)user_data;
14104 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
14106 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14108 LOGD("app-src: seek audio data %llu\n", position);
14109 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14111 if (player->media_stream_seek_data_cb[type])
14112 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14113 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14119 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
14121 mm_player_t *player = (mm_player_t*)user_data;
14122 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
14124 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14126 LOGD("app-src: seek video data %llu\n", position);
14127 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14128 if (player->media_stream_seek_data_cb[type])
14129 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14130 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14136 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
14138 mm_player_t *player = (mm_player_t*)user_data;
14139 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
14141 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
14143 LOGD("app-src: seek subtitle data\n");
14144 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
14146 if (player->media_stream_seek_data_cb[type])
14147 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
14148 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
14154 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
14156 mm_player_t* player = (mm_player_t*) hplayer;
14160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14162 player->pcm_samplerate = samplerate;
14163 player->pcm_channel = channel;
14166 return MM_ERROR_NONE;
14169 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
14171 mm_player_t* player = (mm_player_t*) hplayer;
14175 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14176 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
14178 if (MMPLAYER_IS_STREAMING(player))
14179 *timeout = player->ini.live_state_change_timeout;
14181 *timeout = player->ini.localplayback_state_change_timeout;
14183 LOGD("timeout = %d\n", *timeout);
14186 return MM_ERROR_NONE;
14189 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
14191 mm_player_t* player = (mm_player_t*) hplayer;
14195 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14196 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
14198 *num = player->video_num_buffers;
14199 *extra_num = player->video_extra_num_buffers;
14201 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
14204 return MM_ERROR_NONE;
14208 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
14212 MMPLAYER_RETURN_IF_FAIL(player);
14214 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
14216 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
14217 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
14218 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
14219 player->storage_info[i].id = -1;
14220 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
14222 if (path_type != MMPLAYER_PATH_MAX)
14230 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
14232 int ret = MM_ERROR_NONE;
14233 mm_player_t* player = (mm_player_t*)hplayer;
14234 MMMessageParamType msg_param = {0, };
14237 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14239 LOGW("state changed storage %d:%d", id, state);
14241 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
14242 return MM_ERROR_NONE;
14244 /* FIXME: text path should be handled seperately. */
14245 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
14246 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
14247 LOGW("external storage is removed");
14249 if (player->msg_posted == FALSE) {
14250 memset(&msg_param, 0, sizeof(MMMessageParamType));
14251 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
14252 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
14253 player->msg_posted = TRUE;
14256 /* unrealize the player */
14257 ret = _mmplayer_unrealize(hplayer);
14258 if (ret != MM_ERROR_NONE)
14259 LOGE("failed to unrealize");
14266 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
14268 int ret = MM_ERROR_NONE;
14269 mm_player_t* player = (mm_player_t*) hplayer;
14270 int idx = 0, total = 0;
14271 gchar *result = NULL, *tmp = NULL;
14274 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14275 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
14277 total = *num = g_list_length(player->adaptive_info.var_list);
14279 LOGW("There is no stream variant info.");
14283 result = g_strdup("");
14284 for (idx = 0 ; idx < total ; idx++) {
14285 VariantData *v_data = NULL;
14286 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
14289 gchar data[64] = {0};
14290 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
14292 tmp = g_strconcat(result, data, NULL);
14296 LOGW("There is no variant data in %d", idx);
14301 *var_info = (char *)result;
14303 LOGD("variant info %d:%s", *num, *var_info);
14308 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
14310 int ret = MM_ERROR_NONE;
14311 mm_player_t* player = (mm_player_t*) hplayer;
14314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14316 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
14318 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14319 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14320 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
14322 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
14323 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
14324 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
14325 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
14327 /* FIXME: seek to current position for applying new variant limitation */
14335 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
14337 int ret = MM_ERROR_NONE;
14338 mm_player_t* player = (mm_player_t*) hplayer;
14341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14342 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
14344 *bandwidth = player->adaptive_info.limit.bandwidth;
14345 *width = player->adaptive_info.limit.width;
14346 *height = player->adaptive_info.limit.height;
14348 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
14354 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
14356 int ret = MM_ERROR_NONE;
14357 mm_player_t* player = (mm_player_t*) hplayer;
14360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14362 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
14363 LOGW("buffer_ms will not be applied.");
14366 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
14368 if (player->streamer == NULL) {
14369 player->streamer = __mm_player_streaming_create();
14370 __mm_player_streaming_initialize(player->streamer);
14373 if (buffer_ms >= 0)
14374 player->streamer->buffering_req.prebuffer_time = buffer_ms;
14376 if (rebuffer_ms >= 0)
14377 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
14384 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
14386 int ret = MM_ERROR_NONE;
14387 mm_player_t* player = (mm_player_t*) hplayer;
14390 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14391 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
14393 if (player->streamer == NULL) {
14394 player->streamer = __mm_player_streaming_create();
14395 __mm_player_streaming_initialize(player->streamer);
14398 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
14399 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
14401 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
14407 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
14409 #define IDX_FIRST_SW_CODEC 0
14410 mm_player_t* player = (mm_player_t*) hplayer;
14411 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
14412 MMHandleType attrs = 0;
14415 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
14417 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
14418 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
14419 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
14421 switch (stream_type) {
14422 case MM_PLAYER_STREAM_TYPE_AUDIO:
14423 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
14424 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
14425 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
14426 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
14427 LOGE("There is no a codec for codec_type %d", codec_type);
14428 return MM_ERROR_PLAYER_NO_OP;
14431 case MM_PLAYER_STREAM_TYPE_VIDEO:
14432 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
14433 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
14434 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
14435 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
14436 LOGE("There is no v codec for codec_type %d", codec_type);
14437 return MM_ERROR_PLAYER_NO_OP;
14442 LOGE("Invalid stream type %d", stream_type);
14443 return MM_ERROR_COMMON_INVALID_ARGUMENT;
14447 LOGD("update %s codec_type to %d", attr_name, codec_type);
14449 attrs = MMPLAYER_GET_ATTRS(player);
14450 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
14452 if (mmf_attrs_commit(player->attrs)) {
14453 LOGE("failed to commit codec_type attributes");
14454 return MM_ERROR_PLAYER_INTERNAL;
14458 return MM_ERROR_NONE;