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_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
55 /*===========================================================================================
57 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
59 ========================================================================================== */
61 /*---------------------------------------------------------------------------
62 | GLOBAL CONSTANT DEFINITIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED VARIABLE DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED FUNCTION DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
79 #define MM_VOLUME_FACTOR_DEFAULT 1.0
80 #define MM_VOLUME_FACTOR_MIN 0
81 #define MM_VOLUME_FACTOR_MAX 1.0
83 /* Don't need to sleep for sound fadeout
84 * fadeout related fucntion will be deleted(Deprecated)
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
88 #define DEFAULT_PLAYBACK_RATE 1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93 (player->ini.http_use_file_buffer) && \
94 (player->http_file_buffering_path) && \
95 (strlen(player->http_file_buffering_path) > 0))
97 #define PLAYER_DISPLAY_MODE_DST_ROI 5
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
104 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
109 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
158 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
159 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_release_misc(mm_player_t* player);
163 static void __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
194 static int __gst_realize(mm_player_t* player);
195 static int __gst_unrealize(mm_player_t* player);
196 static int __gst_start(mm_player_t* player);
197 static int __gst_stop(mm_player_t* player);
198 static int __gst_pause(mm_player_t* player, gboolean async);
199 static int __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202 gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
205 static int __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
213 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
216 static gboolean __is_ms_buff_src(mm_player_t* player);
217 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
219 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
220 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
221 static int __mmplayer_start_streaming_ext(mm_player_t *player);
222 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
223 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
225 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
226 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
227 static void __mmplayer_check_pipeline(mm_player_t* player);
228 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
229 static void __mmplayer_deactivate_old_path(mm_player_t *player);
231 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
232 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
234 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
235 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
236 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
237 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
238 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
239 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
240 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
241 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
242 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
245 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
246 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
247 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
248 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
249 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
250 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type);
252 /*===========================================================================================
254 | FUNCTION DEFINITIONS |
256 ========================================================================================== */
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
264 count = gst_tag_list_get_tag_size(list, tag);
266 LOGD("count = %d", count);
268 for (i = 0; i < count; i++) {
271 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272 if (!gst_tag_list_get_string_index(list, tag, i, &str))
273 g_assert_not_reached();
275 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
278 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
280 g_print(" : %s\n", str);
287 /* This function should be called after the pipeline goes PAUSED or higher
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
292 static gboolean has_duration = FALSE;
293 static gboolean has_video_attrs = FALSE;
294 static gboolean has_audio_attrs = FALSE;
295 static gboolean has_bitrate = FALSE;
296 gboolean missing_only = FALSE;
297 gboolean all = FALSE;
299 GstStructure* p = NULL;
300 MMHandleType attrs = 0;
306 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
308 /* check player state here */
309 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311 /* give warning now only */
312 LOGW("be careful. content attributes may not available in this state ");
315 /* get content attribute first */
316 attrs = MMPLAYER_GET_ATTRS(player);
318 LOGE("cannot get content attribute");
322 /* get update flag */
324 if (flag & ATTR_MISSING_ONLY) {
326 LOGD("updating missed attr only");
329 if (flag & ATTR_ALL) {
331 has_duration = FALSE;
332 has_video_attrs = FALSE;
333 has_audio_attrs = FALSE;
336 LOGD("updating all attrs");
339 if (missing_only && all) {
340 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341 missing_only = FALSE;
344 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345 LOGD("try to update duration");
346 has_duration = FALSE;
348 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349 player->duration = dur_nsec;
350 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
354 if (player->duration < 0) {
355 LOGW("duration is Non-Initialized !!!");
356 player->duration = 0;
359 /* update streaming service type */
360 player->streaming_type = __mmplayer_get_stream_service_type(player);
362 /* check duration is OK */
363 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364 /* FIXIT : find another way to get duration here. */
365 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
369 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370 /* update audio params
371 NOTE : We need original audio params and it can be only obtained from src pad of audio
372 decoder. Below code only valid when we are not using 'resampler' just before
375 LOGD("try to update audio attrs");
376 has_audio_attrs = FALSE;
378 if (player->pipeline->audiobin &&
379 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380 GstCaps *caps_a = NULL;
382 gint samplerate = 0, channels = 0;
384 pad = gst_element_get_static_pad(
385 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
388 caps_a = gst_pad_get_current_caps(pad);
391 p = gst_caps_get_structure(caps_a, 0);
393 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
395 gst_structure_get_int(p, "rate", &samplerate);
396 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
398 gst_structure_get_int(p, "channels", &channels);
399 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
401 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
403 gst_caps_unref(caps_a);
406 has_audio_attrs = TRUE;
408 LOGW("not ready to get audio caps");
410 gst_object_unref(pad);
412 LOGW("failed to get pad from audiosink");
416 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417 LOGD("try to update video attrs");
418 has_video_attrs = FALSE;
420 if (player->pipeline->videobin &&
421 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422 GstCaps *caps_v = NULL;
427 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
429 caps_v = gst_pad_get_current_caps(pad);
431 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432 if (!caps_v && player->v_stream_caps) {
433 caps_v = player->v_stream_caps;
434 gst_caps_ref(caps_v);
438 p = gst_caps_get_structure(caps_v, 0);
439 gst_structure_get_int(p, "width", &width);
440 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
442 gst_structure_get_int(p, "height", &height);
443 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
445 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
447 SECURE_LOGD("width : %d height : %d", width, height);
449 gst_caps_unref(caps_v);
453 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
457 has_video_attrs = TRUE;
459 LOGD("no negitiated caps from videosink");
460 gst_object_unref(pad);
463 LOGD("no videosink sink pad");
469 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
472 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473 if (player->duration) {
474 guint64 data_size = 0;
476 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
479 if (stat(path, &sb) == 0)
480 data_size = (guint64)sb.st_size;
481 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482 data_size = player->http_content_size;
484 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
488 guint64 msec_dur = 0;
490 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
492 bitrate = data_size * 8 * 1000 / msec_dur;
493 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
498 LOGD("player duration is less than 0");
502 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503 if (player->total_bitrate) {
504 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
512 if (mmf_attrs_commit(attrs)) {
513 LOGE("failed to update attributes\n");
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
524 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
528 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
530 player->pipeline->mainbin &&
531 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532 STREAMING_SERVICE_NONE);
534 /* streaming service type if streaming */
535 if (!MMPLAYER_IS_STREAMING(player))
536 return STREAMING_SERVICE_NONE;
538 if (MMPLAYER_IS_HTTP_STREAMING(player))
539 streaming_type = (player->duration == 0) ?
540 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
542 switch (streaming_type) {
543 case STREAMING_SERVICE_LIVE:
544 LOGD("it's live streaming");
546 case STREAMING_SERVICE_VOD:
547 LOGD("it's vod streaming");
550 LOGE("should not get here");
556 return streaming_type;
560 /* this function sets the player state and also report
561 * it to applicaton by calling callback function
564 __mmplayer_set_state(mm_player_t* player, int state)
566 MMMessageParamType msg = {0, };
567 gboolean post_bos = FALSE;
569 MMPLAYER_RETURN_IF_FAIL(player);
571 if (MMPLAYER_CURRENT_STATE(player) == state) {
572 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
577 /* update player states */
578 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579 MMPLAYER_CURRENT_STATE(player) = state;
581 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
585 MMPLAYER_PRINT_STATE(player);
587 switch (MMPLAYER_CURRENT_STATE(player)) {
588 case MM_PLAYER_STATE_NULL:
589 case MM_PLAYER_STATE_READY:
592 case MM_PLAYER_STATE_PAUSED:
594 if (!player->sent_bos) {
595 /* rtsp case, get content attrs by GstMessage */
596 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597 /* it's first time to update all content attrs. */
598 _mmplayer_update_content_attrs(player, ATTR_ALL);
602 /* add audio callback probe if condition is satisfied */
603 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604 __mmplayer_configure_audio_callback(player);
606 /* FIXIT : handle return value */
610 case MM_PLAYER_STATE_PLAYING:
612 /* try to get content metadata */
613 if (!player->sent_bos) {
614 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615 * c-api since c-api doesn't use _start() anymore. It may not work propery with
616 * legacy mmfw-player api */
617 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
620 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621 if (!player->sent_bos)
622 __mmplayer_handle_missed_plugin(player);
625 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626 /* initialize because auto resume is done well. */
627 player->resumed_by_rewind = FALSE;
628 player->playback_rate = 1.0;
631 if (!player->sent_bos) {
632 /* check audio codec field is set or not
633 * we can get it from typefinder or codec's caps.
635 gchar *audio_codec = NULL;
636 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
638 /* The codec format can't be sent for audio only case like amr, mid etc.
639 * Because, parser don't make related TAG.
640 * So, if it's not set yet, fill it with found data.
643 if (g_strrstr(player->type, "audio/midi"))
644 audio_codec = g_strdup("MIDI");
645 else if (g_strrstr(player->type, "audio/x-amr"))
646 audio_codec = g_strdup("AMR");
647 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648 audio_codec = g_strdup("AAC");
650 audio_codec = g_strdup("unknown");
651 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
653 MMPLAYER_FREEIF(audio_codec);
654 if (mmf_attrs_commit(player->attrs))
655 LOGE("failed to update attributes\n");
657 LOGD("set audio codec type with caps\n");
665 case MM_PLAYER_STATE_NONE:
667 LOGW("invalid target state, there is nothing to do.\n");
672 /* post message to application */
673 if (MMPLAYER_TARGET_STATE(player) == state) {
674 /* fill the message with state of player */
675 msg.union_type = MM_MSG_UNION_STATE;
676 msg.state.previous = MMPLAYER_PREV_STATE(player);
677 msg.state.current = MMPLAYER_CURRENT_STATE(player);
679 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
681 /* state changed by resource callback */
682 if (player->interrupted_by_resource) {
683 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
684 } else { /* state changed by usecase */
685 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
688 LOGD("intermediate state, do nothing.\n");
689 MMPLAYER_PRINT_STATE(player);
694 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
695 player->sent_bos = TRUE;
701 static gpointer __mmplayer_next_play_thread(gpointer data)
703 mm_player_t* player = (mm_player_t*) data;
704 MMPlayerGstElement *mainbin = NULL;
706 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
708 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
709 while (!player->next_play_thread_exit) {
710 LOGD("next play thread started. waiting for signal.\n");
711 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
713 LOGD("reconfigure pipeline for gapless play.\n");
715 if (player->next_play_thread_exit) {
716 if (player->gapless.reconfigure) {
717 player->gapless.reconfigure = false;
718 MMPLAYER_PLAYBACK_UNLOCK(player);
720 LOGD("exiting gapless play thread\n");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
734 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
740 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
742 MMHandleType attrs = 0;
743 guint64 data_size = 0;
748 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
750 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec); /* to update player->last_position */
752 attrs = MMPLAYER_GET_ATTRS(player);
754 LOGE("fail to get attributes.\n");
758 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
759 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
761 if (stat(path, &sb) == 0)
762 data_size = (guint64)sb.st_size;
763 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
764 data_size = player->http_content_size;
766 __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
767 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
773 __mmplayer_handle_buffering_message(mm_player_t* player)
775 int ret = MM_ERROR_NONE;
776 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
777 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
778 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
779 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
781 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
782 LOGW("do nothing for buffering msg\n");
783 ret = MM_ERROR_PLAYER_INVALID_STATE;
787 prev_state = MMPLAYER_PREV_STATE(player);
788 current_state = MMPLAYER_CURRENT_STATE(player);
789 target_state = MMPLAYER_TARGET_STATE(player);
790 pending_state = MMPLAYER_PENDING_STATE(player);
792 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
793 MMPLAYER_STATE_GET_NAME(prev_state),
794 MMPLAYER_STATE_GET_NAME(current_state),
795 MMPLAYER_STATE_GET_NAME(pending_state),
796 MMPLAYER_STATE_GET_NAME(target_state),
797 player->streamer->buffering_state);
799 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
800 /* NOTE : if buffering has done, player has to go to target state. */
801 switch (target_state) {
802 case MM_PLAYER_STATE_PAUSED:
804 switch (pending_state) {
805 case MM_PLAYER_STATE_PLAYING:
806 __gst_pause(player, TRUE);
809 case MM_PLAYER_STATE_PAUSED:
810 LOGD("player is already going to paused state, there is nothing to do.\n");
813 case MM_PLAYER_STATE_NONE:
814 case MM_PLAYER_STATE_NULL:
815 case MM_PLAYER_STATE_READY:
817 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
823 case MM_PLAYER_STATE_PLAYING:
825 switch (pending_state) {
826 case MM_PLAYER_STATE_NONE:
828 if (current_state != MM_PLAYER_STATE_PLAYING)
829 __gst_resume(player, TRUE);
833 case MM_PLAYER_STATE_PAUSED:
834 /* NOTE: It should be worked as asynchronously.
835 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
837 if (current_state == MM_PLAYER_STATE_PLAYING) {
838 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
839 * The current state should be changed to paused purposely to prevent state conflict.
841 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
843 __gst_resume(player, TRUE);
846 case MM_PLAYER_STATE_PLAYING:
847 LOGD("player is already going to playing state, there is nothing to do.\n");
850 case MM_PLAYER_STATE_NULL:
851 case MM_PLAYER_STATE_READY:
853 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
859 case MM_PLAYER_STATE_NULL:
860 case MM_PLAYER_STATE_READY:
861 case MM_PLAYER_STATE_NONE:
863 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
867 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
868 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
870 switch (pending_state) {
871 case MM_PLAYER_STATE_NONE:
873 if (current_state != MM_PLAYER_STATE_PAUSED) {
874 /* rtsp streaming pause makes rtsp server stop sending data. */
875 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
876 LOGD("set pause state during buffering\n");
877 __gst_pause(player, TRUE);
883 case MM_PLAYER_STATE_PLAYING:
884 /* rtsp streaming pause makes rtsp server stop sending data. */
885 if (!MMPLAYER_IS_RTSP_STREAMING(player))
886 __gst_pause(player, TRUE);
889 case MM_PLAYER_STATE_PAUSED:
892 case MM_PLAYER_STATE_NULL:
893 case MM_PLAYER_STATE_READY:
895 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
905 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
907 MMPlayerGstElement *textbin;
910 MMPLAYER_RETURN_IF_FAIL(player &&
912 player->pipeline->textbin);
914 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
916 textbin = player->pipeline->textbin;
919 LOGD("Drop subtitle text after getting EOS\n");
921 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
922 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
924 player->is_subtitle_force_drop = TRUE;
926 if (player->is_subtitle_force_drop == TRUE) {
927 LOGD("Enable subtitle data path without drop\n");
929 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
930 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
932 LOGD("non-connected with external display");
934 player->is_subtitle_force_drop = FALSE;
940 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
942 VariantData *var_info = NULL;
943 g_return_val_if_fail(self != NULL, NULL);
945 var_info = g_new0(VariantData, 1);
946 if (!var_info) return NULL;
947 var_info->bandwidth = self->bandwidth;
948 var_info->width = self->width;
949 var_info->height = self->height;
953 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
955 mm_player_t* player = (mm_player_t*)hplayer;
956 GstMessage *msg = NULL;
957 GQueue *queue = NULL;
960 MMPLAYER_RETURN_IF_FAIL(player);
962 /* disconnecting bus watch */
963 if (player->bus_watcher)
964 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
965 player->bus_watcher = 0;
967 /* destroy the gst bus msg thread */
968 if (player->bus_msg_thread) {
969 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
970 player->bus_msg_thread_exit = TRUE;
971 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
972 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
974 LOGD("gst bus msg thread exit.");
975 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
976 player->bus_msg_thread = NULL;
978 g_mutex_clear(&player->bus_msg_thread_mutex);
979 g_cond_clear(&player->bus_msg_thread_cond);
982 g_mutex_lock(&player->bus_msg_q_lock);
983 queue = player->bus_msg_q;
984 while (!g_queue_is_empty(queue)) {
985 msg = (GstMessage *)g_queue_pop_head(queue);
986 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
987 gst_message_unref(msg);
989 g_mutex_unlock(&player->bus_msg_q_lock);
994 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
996 mm_player_t *player = (mm_player_t *) data;
998 g_return_val_if_fail(player, FALSE);
999 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1001 gst_message_ref(msg);
1003 g_mutex_lock(&player->bus_msg_q_lock);
1004 g_queue_push_tail(player->bus_msg_q, msg);
1005 g_mutex_unlock(&player->bus_msg_q_lock);
1007 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1008 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1009 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1013 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1015 mm_player_t *player = (mm_player_t*)(data);
1016 GstMessage *msg = NULL;
1020 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1022 player->pipeline->mainbin &&
1023 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1026 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1028 LOGE("cannot get BUS from the pipeline");
1032 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1034 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1035 while (!player->bus_msg_thread_exit) {
1036 g_mutex_lock(&player->bus_msg_q_lock);
1037 msg = g_queue_pop_head(player->bus_msg_q);
1038 g_mutex_unlock(&player->bus_msg_q_lock);
1040 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1043 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1044 /* handle the gst msg */
1045 __mmplayer_gst_callback(msg, player);
1046 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1047 gst_message_unref(msg);
1050 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1051 gst_object_unref(GST_OBJECT(bus));
1058 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1060 mm_player_t* player = (mm_player_t*)(data);
1062 MMPLAYER_RETURN_IF_FAIL(player);
1063 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1065 switch (GST_MESSAGE_TYPE(msg)) {
1066 case GST_MESSAGE_UNKNOWN:
1067 LOGD("unknown message received\n");
1070 case GST_MESSAGE_EOS:
1072 MMHandleType attrs = 0;
1075 LOGD("GST_MESSAGE_EOS received\n");
1077 /* NOTE : EOS event is comming multiple time. watch out it */
1078 /* check state. we only process EOS when pipeline state goes to PLAYING */
1079 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1080 LOGD("EOS received on non-playing state. ignoring it\n");
1084 if (player->pipeline) {
1085 if (player->pipeline->textbin)
1086 __mmplayer_drop_subtitle(player, TRUE);
1088 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1091 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1093 LOGD("release audio callback\n");
1095 /* release audio callback */
1096 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1097 player->audio_cb_probe_id = 0;
1098 /* audio callback should be free because it can be called even though probe remove.*/
1099 player->audio_stream_cb = NULL;
1100 player->audio_stream_cb_user_param = NULL;
1104 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1105 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1107 /* rewind if repeat count is greater then zero */
1108 /* get play count */
1109 attrs = MMPLAYER_GET_ATTRS(player);
1112 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1114 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1116 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1117 if (player->playback_rate < 0.0) {
1118 player->resumed_by_rewind = TRUE;
1119 _mmplayer_set_mute((MMHandleType)player, 0);
1120 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1123 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1126 player->sent_bos = FALSE;
1128 /* not posting eos when repeating */
1133 if (player->pipeline)
1134 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1136 /* post eos message to application */
1137 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1139 /* reset last position */
1140 player->last_position = 0;
1144 case GST_MESSAGE_ERROR:
1146 GError *error = NULL;
1147 gchar* debug = NULL;
1149 /* generating debug info before returning error */
1150 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1152 /* get error code */
1153 gst_message_parse_error(msg, &error, &debug);
1155 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1156 /* Note : the streaming error from the streaming source is handled
1157 * using __mmplayer_handle_streaming_error.
1159 __mmplayer_handle_streaming_error(player, msg);
1161 /* dump state of all element */
1162 __mmplayer_dump_pipeline_state(player);
1164 /* traslate gst error code to msl error code. then post it
1165 * to application if needed
1167 __mmplayer_handle_gst_error(player, msg, error);
1170 LOGE("error debug : %s", debug);
1173 if (MMPLAYER_IS_HTTP_PD(player))
1174 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1176 MMPLAYER_FREEIF(debug);
1177 g_error_free(error);
1181 case GST_MESSAGE_WARNING:
1184 GError* error = NULL;
1186 gst_message_parse_warning(msg, &error, &debug);
1188 LOGD("warning : %s\n", error->message);
1189 LOGD("debug : %s\n", debug);
1191 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1193 MMPLAYER_FREEIF(debug);
1194 g_error_free(error);
1198 case GST_MESSAGE_TAG:
1200 LOGD("GST_MESSAGE_TAG\n");
1201 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1202 LOGW("failed to extract tags from gstmessage\n");
1206 case GST_MESSAGE_BUFFERING:
1208 MMMessageParamType msg_param = {0, };
1209 int bRet = MM_ERROR_NONE;
1211 if (!(player->pipeline && player->pipeline->mainbin)) {
1212 LOGE("Pipeline is not initialized");
1216 if (!MMPLAYER_IS_STREAMING(player))
1219 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1220 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1221 /* skip the playback control by buffering msg while user request is handled. */
1224 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1226 gst_message_parse_buffering(msg, &per);
1227 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1229 msg_param.connection.buffering = per;
1230 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1234 MMPLAYER_CMD_LOCK(player);
1237 if (!player->streamer) {
1238 LOGW("Pipeline is shutting down");
1239 MMPLAYER_CMD_UNLOCK(player);
1243 /* ignore the remained buffering message till getting 100% msg */
1244 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1245 gint buffer_percent = 0;
1247 gst_message_parse_buffering(msg, &buffer_percent);
1249 if (buffer_percent == MAX_BUFFER_PERCENT) {
1250 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1251 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1253 MMPLAYER_CMD_UNLOCK(player);
1257 /* ignore the remained buffering message */
1258 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1259 gint buffer_percent = 0;
1261 gst_message_parse_buffering(msg, &buffer_percent);
1263 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1264 player->streamer->buffering_percent, buffer_percent);
1266 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1267 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1268 player->streamer->buffering_req.is_pre_buffering = FALSE;
1270 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1272 LOGD("interrupted buffering - ignored the remained buffering msg!");
1273 MMPLAYER_CMD_UNLOCK(player);
1278 __mmplayer_update_buffer_setting(player, msg);
1280 bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1282 if (bRet == MM_ERROR_NONE) {
1283 msg_param.connection.buffering = player->streamer->buffering_percent;
1284 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1286 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1287 player->pending_resume &&
1288 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1290 player->is_external_subtitle_added_now = FALSE;
1291 player->pending_resume = FALSE;
1292 _mmplayer_resume((MMHandleType)player);
1295 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1296 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1298 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1299 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1300 player->seek_state = MMPLAYER_SEEK_NONE;
1301 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1302 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1303 /* Considering the async state trasition in case of RTSP.
1304 After getting state change gst msg, seek cmpleted msg will be posted. */
1305 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1309 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310 if (!player->streamer) {
1311 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312 MMPLAYER_CMD_UNLOCK(player);
1316 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1318 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1321 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322 msg_param.connection.buffering = player->streamer->buffering_percent;
1323 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1325 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1328 msg_param.connection.buffering = player->streamer->buffering_percent;
1329 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1332 MMPLAYER_CMD_UNLOCK(player);
1336 case GST_MESSAGE_STATE_CHANGED:
1338 MMPlayerGstElement *mainbin;
1339 const GValue *voldstate, *vnewstate, *vpending;
1340 GstState oldstate = GST_STATE_NULL;
1341 GstState newstate = GST_STATE_NULL;
1342 GstState pending = GST_STATE_NULL;
1344 if (!(player->pipeline && player->pipeline->mainbin)) {
1345 LOGE("player pipeline handle is null");
1349 mainbin = player->pipeline->mainbin;
1351 /* we only handle messages from pipeline */
1352 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1355 /* get state info from msg */
1356 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1360 if (!voldstate || !vnewstate) {
1361 LOGE("received msg has wrong format.");
1365 oldstate = (GstState)voldstate->data[0].v_int;
1366 newstate = (GstState)vnewstate->data[0].v_int;
1368 pending = (GstState)vpending->data[0].v_int;
1370 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1371 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372 gst_element_state_get_name((GstState)oldstate),
1373 gst_element_state_get_name((GstState)newstate),
1374 gst_element_state_get_name((GstState)pending));
1376 if (newstate == GST_STATE_PLAYING) {
1377 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1379 int retVal = MM_ERROR_NONE;
1380 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1382 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1384 if (MM_ERROR_NONE != retVal)
1385 LOGE("failed to seek pending postion. just keep staying current position.\n");
1387 player->pending_seek.is_pending = FALSE;
1391 if (oldstate == newstate) {
1392 LOGD("pipeline reports state transition to old state");
1397 case GST_STATE_VOID_PENDING:
1400 case GST_STATE_NULL:
1403 case GST_STATE_READY:
1406 case GST_STATE_PAUSED:
1408 gboolean prepare_async = FALSE;
1410 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411 __mmplayer_configure_audio_callback(player);
1413 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414 // managed prepare async case
1415 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416 LOGD("checking prepare mode for async transition - %d", prepare_async);
1419 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1422 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423 __mm_player_streaming_set_content_bitrate(player->streamer,
1424 player->total_maximum_bitrate, player->total_bitrate);
1426 if (player->pending_seek.is_pending) {
1427 LOGW("trying to do pending seek");
1428 MMPLAYER_CMD_LOCK(player);
1429 __gst_pending_seek(player);
1430 MMPLAYER_CMD_UNLOCK(player);
1436 case GST_STATE_PLAYING:
1438 if (MMPLAYER_IS_STREAMING(player)) {
1439 // managed prepare async case when buffering is completed
1440 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1445 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1447 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448 if (player->streamer->buffering_percent < 100) {
1450 MMMessageParamType msg_param = {0, };
1451 LOGW("Posting Buffering Completed Message to Application !!!");
1453 msg_param.connection.buffering = 100;
1454 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1459 if (player->gapless.stream_changed) {
1460 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461 player->gapless.stream_changed = FALSE;
1464 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1465 player->seek_state = MMPLAYER_SEEK_NONE;
1466 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1477 case GST_MESSAGE_CLOCK_LOST:
1479 GstClock *clock = NULL;
1480 gboolean need_new_clock = FALSE;
1482 gst_message_parse_clock_lost(msg, &clock);
1483 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1485 if (!player->videodec_linked)
1486 need_new_clock = TRUE;
1487 else if (!player->ini.use_system_clock)
1488 need_new_clock = TRUE;
1490 if (need_new_clock) {
1491 LOGD("Provide clock is TRUE, do pause->resume\n");
1492 __gst_pause(player, FALSE);
1493 __gst_resume(player, FALSE);
1498 case GST_MESSAGE_NEW_CLOCK:
1500 GstClock *clock = NULL;
1501 gst_message_parse_new_clock(msg, &clock);
1502 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1506 case GST_MESSAGE_ELEMENT:
1508 const gchar *structure_name;
1509 gint count = 0, idx = 0;
1510 MMHandleType attrs = 0;
1512 attrs = MMPLAYER_GET_ATTRS(player);
1514 LOGE("cannot get content attribute");
1518 if (gst_message_get_structure(msg) == NULL)
1521 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1522 if (!structure_name)
1525 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1527 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1528 const GValue *var_info = NULL;
1530 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1531 if (var_info != NULL) {
1532 if (player->adaptive_info.var_list)
1533 g_list_free_full(player->adaptive_info.var_list, g_free);
1535 /* share addr or copy the list */
1536 player->adaptive_info.var_list =
1537 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1539 count = g_list_length(player->adaptive_info.var_list);
1541 VariantData *temp = NULL;
1543 /* print out for debug */
1544 LOGD("num of variant_info %d", count);
1545 for (idx = 0; idx < count; idx++) {
1546 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1548 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1554 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1555 gint num_buffers = 0;
1556 gint extra_num_buffers = 0;
1558 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1559 player->video_num_buffers = num_buffers;
1560 LOGD("video_num_buffers : %d", player->video_num_buffers);
1563 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1564 player->video_extra_num_buffers = extra_num_buffers;
1565 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1570 if (!strcmp(structure_name, "Language_list")) {
1571 const GValue *lang_list = NULL;
1572 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1573 if (lang_list != NULL) {
1574 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1576 LOGD("Total audio tracks(from parser) = %d \n", count);
1580 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1581 const GValue *lang_list = NULL;
1582 MMPlayerLangStruct *temp = NULL;
1584 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1585 if (lang_list != NULL) {
1586 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1588 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1589 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1590 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1591 if (mmf_attrs_commit(attrs))
1592 LOGE("failed to commit.\n");
1593 LOGD("Total subtitle tracks = %d \n", count);
1596 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1598 LOGD("value of lang_key is %s and lang_code is %s",
1599 temp->language_key, temp->language_code);
1602 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1603 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1608 /* custom message */
1609 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1610 MMMessageParamType msg_param = {0,};
1611 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1612 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1615 /* custom message for RTSP attribute :
1616 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1617 sdp which has contents info is received when rtsp connection is opened.
1618 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1619 if (!strcmp(structure_name, "rtspsrc_properties")) {
1621 gchar *audio_codec = NULL;
1622 gchar *video_codec = NULL;
1623 gchar *video_frame_size = NULL;
1625 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1626 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1627 player->streaming_type = __mmplayer_get_stream_service_type(player);
1629 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1630 LOGD("rtsp_audio_codec : %s", audio_codec);
1632 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1634 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1635 LOGD("rtsp_video_codec : %s", video_codec);
1637 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1639 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1640 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1641 if (video_frame_size) {
1643 char *seperator = strchr(video_frame_size, '-');
1646 char video_width[10] = {0,};
1647 int frame_size_len = strlen(video_frame_size);
1648 int separtor_len = strlen(seperator);
1650 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1651 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1654 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1658 if (mmf_attrs_commit(attrs))
1659 LOGE("failed to commit.\n");
1664 case GST_MESSAGE_DURATION_CHANGED:
1666 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1667 if (!__mmplayer_gst_handle_duration(player, msg))
1668 LOGW("failed to update duration");
1673 case GST_MESSAGE_ASYNC_START:
1674 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1677 case GST_MESSAGE_ASYNC_DONE:
1679 MMPlayerGstElement *mainbin;
1681 if (!(player->pipeline && player->pipeline->mainbin)) {
1682 LOGE("player pipeline handle is null");
1686 mainbin = player->pipeline->mainbin;
1688 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1690 /* we only handle messages from pipeline */
1691 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1694 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1695 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1696 player->seek_state = MMPLAYER_SEEK_NONE;
1697 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1698 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1699 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1700 LOGD("sync %s state(%s) with parent state(%s)",
1701 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1702 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1703 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1705 /* In case of streaming, pause is required before finishing seeking by buffering.
1706 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1707 Because the buffering state is controlled according to the state transition for force resume,
1708 the decodebin state should be paused as player state. */
1709 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1712 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1713 (player->streamer) &&
1714 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1715 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1716 GstQuery *query = NULL;
1717 gboolean busy = FALSE;
1720 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1721 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1722 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1723 gst_query_parse_buffering_percent(query, &busy, &percent);
1724 gst_query_unref(query);
1726 LOGD("buffered percent(%s): %d\n",
1727 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1731 __mmplayer_handle_buffering_message(player);
1734 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1740 #if 0 /* delete unnecessary logs */
1741 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1742 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1743 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1744 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1745 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1746 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1747 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1748 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1749 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1750 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1751 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1752 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1753 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1754 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1755 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1762 /* should not call 'gst_message_unref(msg)' */
1767 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1773 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1774 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1776 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1777 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1778 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1780 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1781 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1782 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1785 /* handling audio clip which has vbr. means duration is keep changing */
1786 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1794 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1795 mm_player_spherical_metadata_t *metadata) {
1796 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1797 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1798 gst_tag_list_get_string(tags, "stitching_software",
1799 &metadata->stitching_software);
1800 gst_tag_list_get_string(tags, "projection_type",
1801 &metadata->projection_type_string);
1802 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1803 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1804 gst_tag_list_get_int(tags, "init_view_heading",
1805 &metadata->init_view_heading);
1806 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1807 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1808 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1809 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1810 &metadata->full_pano_width_pixels);
1811 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1812 &metadata->full_pano_height_pixels);
1813 gst_tag_list_get_int(tags, "cropped_area_image_width",
1814 &metadata->cropped_area_image_width);
1815 gst_tag_list_get_int(tags, "cropped_area_image_height",
1816 &metadata->cropped_area_image_height);
1817 gst_tag_list_get_int(tags, "cropped_area_left",
1818 &metadata->cropped_area_left);
1819 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1820 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1821 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1822 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1826 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1829 /* macro for better code readability */
1830 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1831 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1832 if (string != NULL) { \
1833 SECURE_LOGD("update tag string : %s\n", string); \
1834 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1835 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1836 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1837 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1838 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1839 g_free(new_string); \
1840 new_string = NULL; \
1842 mm_attrs_set_string_by_name(attribute, playertag, string); \
1849 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1851 GstSample *sample = NULL;\
1852 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1853 GstMapInfo info = GST_MAP_INFO_INIT;\
1854 buffer = gst_sample_get_buffer(sample);\
1855 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1856 LOGD("failed to get image data from tag");\
1857 gst_sample_unref(sample);\
1860 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1861 MMPLAYER_FREEIF(player->album_art);\
1862 player->album_art = (gchar *)g_malloc(info.size);\
1863 if (player->album_art) {\
1864 memcpy(player->album_art, info.data, info.size);\
1865 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1866 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1867 msg_param.data = (void *)player->album_art;\
1868 msg_param.size = info.size;\
1869 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1870 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1873 gst_buffer_unmap(buffer, &info);\
1874 gst_sample_unref(sample);\
1878 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1880 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1883 gchar *tag_list_str = NULL; \
1884 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1885 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1886 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1887 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1888 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1890 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1891 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1892 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1893 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1894 player->bitrate[track_type] = v_uint; \
1895 player->total_bitrate = 0; \
1896 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1897 player->total_bitrate += player->bitrate[i]; \
1898 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1899 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1900 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1901 player->maximum_bitrate[track_type] = v_uint; \
1902 player->total_maximum_bitrate = 0; \
1903 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1904 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1905 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1906 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1908 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1911 g_free(tag_list_str); \
1916 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1917 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1918 if (date != NULL) {\
1919 string = g_strdup_printf("%d", g_date_get_year(date));\
1920 mm_attrs_set_string_by_name(attribute, playertag, string);\
1921 SECURE_LOGD("metainfo year : %s\n", string);\
1922 MMPLAYER_FREEIF(string);\
1927 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1928 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1929 if (datetime != NULL) {\
1930 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1931 mm_attrs_set_string_by_name(attribute, playertag, string);\
1932 SECURE_LOGD("metainfo year : %s\n", string);\
1933 MMPLAYER_FREEIF(string);\
1934 gst_date_time_unref(datetime);\
1938 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1939 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1941 /* FIXIT : don't know how to store date */\
1947 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1948 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1950 /* FIXIT : don't know how to store date */\
1956 /* function start */
1957 GstTagList* tag_list = NULL;
1959 MMHandleType attrs = 0;
1961 char *string = NULL;
1964 GstDateTime *datetime = NULL;
1966 GstBuffer *buffer = NULL;
1968 MMMessageParamType msg_param = {0, };
1970 /* currently not used. but those are needed for above macro */
1971 //guint64 v_uint64 = 0;
1972 //gdouble v_double = 0;
1974 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1976 attrs = MMPLAYER_GET_ATTRS(player);
1978 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1980 /* get tag list from gst message */
1981 gst_message_parse_tag(msg, &tag_list);
1983 /* store tags to player attributes */
1984 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1985 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1986 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1987 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1988 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1989 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1990 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1991 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1992 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1993 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1994 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1995 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1996 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1997 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1998 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1999 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2000 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2001 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2002 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2003 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2004 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2005 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2006 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2007 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2008 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2009 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2010 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2011 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2012 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2013 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2014 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2015 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2016 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2017 MMPLAYER_UPDATE_TAG_LOCK(player);
2018 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2019 MMPLAYER_UPDATE_TAG_UNLOCK(player);
2020 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2021 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2022 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2023 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2024 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2025 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2026 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2027 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2028 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2029 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2030 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2031 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2032 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2034 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2035 if (player->video360_metadata.is_spherical == -1) {
2036 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2037 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2038 player->video360_metadata.is_spherical);
2039 if (player->video360_metadata.is_spherical == 1) {
2040 LOGD("This is spherical content for 360 playback.");
2041 player->is_content_spherical = TRUE;
2043 LOGD("This is not spherical content");
2044 player->is_content_spherical = FALSE;
2047 if (player->video360_metadata.projection_type_string) {
2048 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2049 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2051 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2052 player->is_content_spherical = player->is_video360_enabled = FALSE;
2056 if (player->video360_metadata.stereo_mode_string) {
2057 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2058 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2059 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2060 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2061 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2062 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2064 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2065 player->is_content_spherical = player->is_video360_enabled = FALSE;
2071 if (mmf_attrs_commit(attrs))
2072 LOGE("failed to commit.\n");
2074 gst_tag_list_free(tag_list);
2080 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2082 mm_player_t* player = (mm_player_t*) data;
2086 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2087 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2088 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2089 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2091 * [1] audio and video will be dumped with filesink.
2092 * [2] autoplugging is done by just using pad caps.
2093 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2094 * and the video will be dumped via filesink.
2096 if (player->num_dynamic_pad == 0) {
2097 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2099 if (!__mmplayer_gst_remove_fakesink(player,
2100 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2101 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2102 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2103 * source element are not same. To overcome this situation, this function will called
2104 * several places and several times. Therefore, this is not an error case.
2109 /* create dot before error-return. for debugging */
2110 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2112 player->no_more_pad = TRUE;
2118 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2120 GstElement* parent = NULL;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2124 /* if we have no fakesink. this meas we are using decodebin which doesn'
2125 t need to add extra fakesink */
2126 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2129 MMPLAYER_FSINK_LOCK(player);
2134 /* get parent of fakesink */
2135 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2137 LOGD("fakesink already removed\n");
2141 gst_element_set_locked_state(fakesink->gst, TRUE);
2143 /* setting the state to NULL never returns async
2144 * so no need to wait for completion of state transiton
2146 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2147 LOGE("fakesink state change failure!\n");
2148 /* FIXIT : should I return here? or try to proceed to next? */
2151 /* remove fakesink from it's parent */
2152 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2153 LOGE("failed to remove fakesink\n");
2155 gst_object_unref(parent);
2160 gst_object_unref(parent);
2162 LOGD("state-holder removed\n");
2164 gst_element_set_locked_state(fakesink->gst, FALSE);
2166 MMPLAYER_FSINK_UNLOCK(player);
2171 gst_element_set_locked_state(fakesink->gst, FALSE);
2173 MMPLAYER_FSINK_UNLOCK(player);
2179 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2181 GstPad *sinkpad = NULL;
2182 GstCaps* caps = NULL;
2183 GstElement* new_element = NULL;
2184 GstStructure* str = NULL;
2185 const gchar* name = NULL;
2187 mm_player_t* player = (mm_player_t*) data;
2191 MMPLAYER_RETURN_IF_FAIL(element && pad);
2192 MMPLAYER_RETURN_IF_FAIL(player &&
2194 player->pipeline->mainbin);
2197 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2198 * num_dynamic_pad will decreased after creating a sinkbin.
2200 player->num_dynamic_pad++;
2201 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2203 caps = gst_pad_query_caps(pad, NULL);
2205 MMPLAYER_CHECK_NULL(caps);
2207 /* clear previous result*/
2208 player->have_dynamic_pad = FALSE;
2210 str = gst_caps_get_structure(caps, 0);
2213 LOGE("cannot get structure from caps.\n");
2217 name = gst_structure_get_name(str);
2219 LOGE("cannot get mimetype from structure.\n");
2223 if (strstr(name, "video")) {
2225 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2227 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2228 if (player->v_stream_caps) {
2229 gst_caps_unref(player->v_stream_caps);
2230 player->v_stream_caps = NULL;
2233 new_element = gst_element_factory_make("fakesink", NULL);
2234 player->num_dynamic_pad--;
2239 /* clear previous result*/
2240 player->have_dynamic_pad = FALSE;
2242 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2243 LOGE("failed to autoplug for caps");
2247 /* check if there's dynamic pad*/
2248 if (player->have_dynamic_pad) {
2249 LOGE("using pad caps assums there's no dynamic pad !\n");
2253 gst_caps_unref(caps);
2258 /* excute new_element if created*/
2260 LOGD("adding new element to pipeline\n");
2262 /* set state to READY before add to bin */
2263 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2265 /* add new element to the pipeline */
2266 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2267 LOGE("failed to add autoplug element to bin\n");
2271 /* get pad from element */
2272 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2274 LOGE("failed to get sinkpad from autoplug element\n");
2279 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2280 LOGE("failed to link autoplug element\n");
2284 gst_object_unref(sinkpad);
2287 /* run. setting PLAYING here since streamming source is live source */
2288 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2292 gst_caps_unref(caps);
2298 STATE_CHANGE_FAILED:
2300 /* FIXIT : take care if new_element has already added to pipeline */
2302 gst_object_unref(GST_OBJECT(new_element));
2305 gst_object_unref(GST_OBJECT(sinkpad));
2308 gst_caps_unref(caps);
2310 /* FIXIT : how to inform this error to MSL ????? */
2311 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2312 * then post an error to application
2316 static GstPadProbeReturn
2317 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2319 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2320 return GST_PAD_PROBE_OK;
2323 static GstPadProbeReturn
2324 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2326 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2327 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2328 mm_player_t* player = (mm_player_t*)data;
2329 GstCaps* caps = NULL;
2330 GstStructure* str = NULL;
2331 const gchar* name = NULL;
2332 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2335 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2336 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2337 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2338 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2339 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2341 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2342 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2346 caps = gst_pad_query_caps(pad, NULL);
2348 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2352 str = gst_caps_get_structure(caps, 0);
2354 LOGE("failed to get structure from caps");
2358 name = gst_structure_get_name(str);
2360 LOGE("failed to get name from str");
2364 if (strstr(name, "audio")) {
2365 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2366 } else if (strstr(name, "video")) {
2367 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2369 /* text track is not supportable */
2370 LOGE("invalid name %s", name);
2374 switch (GST_EVENT_TYPE(event)) {
2377 /* in case of gapless, drop eos event not to send it to sink */
2378 if (player->gapless.reconfigure && !player->msg_posted) {
2379 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2380 ret = GST_PAD_PROBE_DROP;
2384 case GST_EVENT_STREAM_START:
2386 gint64 stop_running_time = 0;
2387 gint64 position_running_time = 0;
2388 gint64 position = 0;
2391 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2392 if ((player->gapless.update_segment[idx] == TRUE) ||
2393 !(player->selector[idx].event_probe_id)) {
2394 /* LOGW("[%d] skip", idx); */
2398 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2400 gst_segment_to_running_time(&player->gapless.segment[idx],
2401 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2402 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2404 gst_segment_to_running_time(&player->gapless.segment[idx],
2405 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2407 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2409 gst_segment_to_running_time(&player->gapless.segment[idx],
2410 GST_FORMAT_TIME, player->duration);
2413 position_running_time =
2414 gst_segment_to_running_time(&player->gapless.segment[idx],
2415 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2417 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2418 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2420 GST_TIME_ARGS(stop_running_time),
2421 GST_TIME_ARGS(position_running_time),
2422 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2423 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2425 position_running_time = MAX(position_running_time, stop_running_time);
2426 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2427 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2428 position_running_time = MAX(0, position_running_time);
2429 position = MAX(position, position_running_time);
2432 if (position != 0) {
2433 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2434 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2435 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2437 player->gapless.start_time[stream_type] += position;
2441 case GST_EVENT_FLUSH_STOP:
2443 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2444 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2445 player->gapless.start_time[stream_type] = 0;
2448 case GST_EVENT_SEGMENT:
2453 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2454 gst_event_copy_segment(event, &segment);
2456 if (segment.format == GST_FORMAT_TIME) {
2457 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2458 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2459 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2460 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2461 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2462 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2464 /* keep the all the segment ev to cover the seeking */
2465 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2466 player->gapless.update_segment[stream_type] = TRUE;
2468 if (!player->gapless.running)
2471 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2473 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2475 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2476 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2477 gst_event_unref(event);
2478 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2484 gdouble proportion = 0.0;
2485 GstClockTimeDiff diff = 0;
2486 GstClockTime timestamp = 0;
2487 gint64 running_time_diff = -1;
2488 GstQOSType type = 0;
2489 GstEvent *tmpev = NULL;
2491 running_time_diff = player->gapless.segment[stream_type].base;
2493 if (running_time_diff <= 0) /* don't need to adjust */
2496 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2497 gst_event_unref(event);
2499 if (timestamp < running_time_diff) {
2500 LOGW("QOS event from previous group");
2501 ret = GST_PAD_PROBE_DROP;
2505 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2506 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2507 stream_type, GST_TIME_ARGS(timestamp),
2508 GST_TIME_ARGS(running_time_diff),
2509 GST_TIME_ARGS(timestamp - running_time_diff));
2511 timestamp -= running_time_diff;
2513 /* That case is invalid for QoS events */
2514 if (diff < 0 && -diff > timestamp) {
2515 LOGW("QOS event from previous group");
2516 ret = GST_PAD_PROBE_DROP;
2520 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2521 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2531 gst_caps_unref(caps);
2536 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2538 mm_player_t* player = NULL;
2539 GstElement* pipeline = NULL;
2540 GstElement* selector = NULL;
2541 GstElement* fakesink = NULL;
2542 GstCaps* caps = NULL;
2543 GstStructure* str = NULL;
2544 const gchar* name = NULL;
2545 GstPad* sinkpad = NULL;
2546 GstPad* srcpad = NULL;
2547 gboolean first_track = FALSE;
2549 enum MainElementID elemId = MMPLAYER_M_NUM;
2550 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2553 player = (mm_player_t*)data;
2555 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2556 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2558 //LOGD("pad-added signal handling\n");
2560 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2562 /* get mimetype from caps */
2563 caps = gst_pad_query_caps(pad, NULL);
2565 LOGE("cannot get caps from pad.\n");
2569 str = gst_caps_get_structure(caps, 0);
2571 LOGE("cannot get structure from caps.\n");
2575 name = gst_structure_get_name(str);
2577 LOGE("cannot get mimetype from structure.\n");
2581 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2582 //LOGD("detected mimetype : %s\n", name);
2584 if (strstr(name, "video")) {
2587 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2588 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2590 /* don't make video because of not required, and not support multiple track */
2591 if (stype == MM_DISPLAY_SURFACE_NULL) {
2592 LOGD("no video sink by null surface");
2594 gchar *caps_str = gst_caps_to_string(caps);
2595 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2596 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2597 player->set_mode.video_zc = TRUE;
2599 MMPLAYER_FREEIF(caps_str);
2601 if (player->v_stream_caps) {
2602 gst_caps_unref(player->v_stream_caps);
2603 player->v_stream_caps = NULL;
2606 LOGD("create fakesink instead of videobin");
2609 fakesink = gst_element_factory_make("fakesink", NULL);
2610 if (fakesink == NULL) {
2611 LOGE("ERROR : fakesink create error\n");
2615 if (player->ini.set_dump_element_flag)
2616 __mmplayer_add_dump_buffer_probe(player, fakesink);
2618 player->video_fakesink = fakesink;
2620 /* store it as it's sink element */
2621 __mmplayer_add_sink(player, player->video_fakesink);
2623 gst_bin_add(GST_BIN(pipeline), fakesink);
2626 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2628 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2629 LOGW("failed to link fakesink\n");
2630 gst_object_unref(GST_OBJECT(fakesink));
2634 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2635 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2636 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2639 if (player->set_mode.media_packet_video_stream) {
2640 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2642 MMPLAYER_SIGNAL_CONNECT(player,
2644 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2646 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2649 MMPLAYER_SIGNAL_CONNECT(player,
2651 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2653 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2657 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2658 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2662 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2663 __mmplayer_gst_decode_callback(elem, pad, player);
2667 LOGD("video selector \n");
2668 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2669 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2671 if (strstr(name, "audio")) {
2672 gint samplerate = 0;
2675 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2676 __mmplayer_gst_decode_callback(elem, pad, player);
2680 LOGD("audio selector \n");
2681 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2682 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2684 gst_structure_get_int(str, "rate", &samplerate);
2685 gst_structure_get_int(str, "channels", &channels);
2687 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2689 fakesink = gst_element_factory_make("fakesink", NULL);
2690 if (fakesink == NULL) {
2691 LOGE("ERROR : fakesink create error\n");
2695 gst_bin_add(GST_BIN(pipeline), fakesink);
2698 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2700 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2701 LOGW("failed to link fakesink\n");
2702 gst_object_unref(GST_OBJECT(fakesink));
2706 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2707 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2711 } else if (strstr(name, "text")) {
2712 LOGD("text selector \n");
2713 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2714 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2716 LOGE("wrong elem id \n");
2721 selector = player->pipeline->mainbin[elemId].gst;
2722 if (selector == NULL) {
2723 selector = gst_element_factory_make("input-selector", NULL);
2724 LOGD("Creating input-selector\n");
2725 if (selector == NULL) {
2726 LOGE("ERROR : input-selector create error\n");
2729 g_object_set(selector, "sync-streams", TRUE, NULL);
2731 player->pipeline->mainbin[elemId].id = elemId;
2732 player->pipeline->mainbin[elemId].gst = selector;
2735 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2737 srcpad = gst_element_get_static_pad(selector, "src");
2739 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2740 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2741 __mmplayer_gst_selector_blocked, NULL, NULL);
2742 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2743 __mmplayer_gst_selector_event_probe, player, NULL);
2745 gst_element_set_state(selector, GST_STATE_PAUSED);
2746 gst_bin_add(GST_BIN(pipeline), selector);
2748 LOGD("input-selector is already created.\n");
2751 LOGD("Calling request pad with selector %p \n", selector);
2752 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2754 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2756 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2757 LOGW("failed to link selector\n");
2758 gst_object_unref(GST_OBJECT(selector));
2763 LOGD("this is first track --> active track \n");
2764 g_object_set(selector, "active-pad", sinkpad, NULL);
2767 _mmplayer_track_update_info(player, stream_type, sinkpad);
2774 gst_caps_unref(caps);
2777 gst_object_unref(GST_OBJECT(sinkpad));
2782 gst_object_unref(GST_OBJECT(srcpad));
2789 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2791 GstPad* srcpad = NULL;
2792 MMHandleType attrs = 0;
2793 gint active_index = 0;
2795 // [link] input-selector :: textbin
2796 srcpad = gst_element_get_static_pad(text_selector, "src");
2798 LOGE("failed to get srcpad from selector\n");
2802 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2804 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2805 if ((active_index != DEFAULT_TRACK) &&
2806 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2807 LOGW("failed to change text track\n");
2808 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2811 player->no_more_pad = TRUE;
2812 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2814 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2815 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2816 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2817 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2820 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2822 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2823 player->has_closed_caption = TRUE;
2825 attrs = MMPLAYER_GET_ATTRS(player);
2827 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2828 if (mmf_attrs_commit(attrs))
2829 LOGE("failed to commit.\n");
2831 LOGE("cannot get content attribute");
2834 gst_object_unref(GST_OBJECT(srcpad));
2840 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2842 mm_player_t* player = (mm_player_t*)data;
2843 GstElement* selector = NULL;
2844 GstElement* queue = NULL;
2846 GstPad* srcpad = NULL;
2847 GstPad* sinkpad = NULL;
2848 GstCaps* caps = NULL;
2849 gchar* caps_str = NULL;
2852 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2854 caps = gst_pad_get_current_caps(pad);
2855 caps_str = gst_caps_to_string(caps);
2856 LOGD("deinterleave new caps : %s\n", caps_str);
2857 MMPLAYER_FREEIF(caps_str);
2858 gst_caps_unref(caps);
2860 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2861 LOGE("ERROR : queue create error\n");
2865 g_object_set(G_OBJECT(queue),
2866 "max-size-buffers", 10,
2867 "max-size-bytes", 0,
2868 "max-size-time", (guint64)0,
2871 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2874 LOGE("there is no audio channel selector.\n");
2878 srcpad = gst_element_get_static_pad(queue, "src");
2879 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2881 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2883 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2884 LOGW("failed to link deinterleave - selector\n");
2888 gst_element_set_state(queue, GST_STATE_PAUSED);
2889 player->audio_mode.total_track_num++;
2894 gst_object_unref(GST_OBJECT(srcpad));
2899 gst_object_unref(GST_OBJECT(sinkpad));
2908 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2910 mm_player_t* player = NULL;
2911 GstElement* selector = NULL;
2912 GstPad* sinkpad = NULL;
2913 gint active_index = 0;
2914 gchar* change_pad_name = NULL;
2915 GstCaps* caps = NULL; // no need to unref
2916 gint default_audio_ch = 0;
2919 player = (mm_player_t*) data;
2921 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2924 LOGE("there is no audio channel selector.\n");
2928 active_index = player->audio_mode.active_pad_index;
2930 if (active_index != default_audio_ch) {
2931 gint audio_ch = default_audio_ch;
2933 /*To get the new pad from the selector*/
2934 change_pad_name = g_strdup_printf("sink%d", active_index);
2935 if (change_pad_name != NULL) {
2936 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2937 if (sinkpad != NULL) {
2938 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2939 g_object_set(selector, "active-pad", sinkpad, NULL);
2941 audio_ch = active_index;
2943 caps = gst_pad_get_current_caps(sinkpad);
2944 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2946 __mmplayer_set_audio_attrs(player, caps);
2947 gst_caps_unref(caps);
2949 MMPLAYER_FREEIF(change_pad_name);
2952 player->audio_mode.active_pad_index = audio_ch;
2953 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2959 gst_object_unref(sinkpad);
2966 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2968 mm_player_t* player = NULL;
2969 MMPlayerGstElement *mainbin = NULL;
2971 GstElement* tee = NULL;
2972 GstElement* stereo_queue = NULL;
2973 GstElement* mono_queue = NULL;
2974 GstElement* conv = NULL;
2975 GstElement* filter = NULL;
2976 GstElement* deinterleave = NULL;
2977 GstElement* selector = NULL;
2979 GstPad* srcpad = NULL;
2980 GstPad* selector_srcpad = NULL;
2981 GstPad* sinkpad = NULL;
2982 GstCaps* caps = NULL;
2983 gulong block_id = 0;
2988 player = (mm_player_t*) data;
2990 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2991 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2993 mainbin = player->pipeline->mainbin;
2996 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2997 LOGE("ERROR : tee create error\n");
3001 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3002 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3004 gst_element_set_state(tee, GST_STATE_PAUSED);
3007 srcpad = gst_element_get_request_pad(tee, "src_%u");
3008 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3009 LOGE("ERROR : stereo queue create error\n");
3013 g_object_set(G_OBJECT(stereo_queue),
3014 "max-size-buffers", 10,
3015 "max-size-bytes", 0,
3016 "max-size-time", (guint64)0,
3019 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3020 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3023 gst_object_unref(GST_OBJECT(srcpad));
3027 srcpad = gst_element_get_request_pad(tee, "src_%u");
3029 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3030 LOGE("ERROR : mono queue create error\n");
3034 g_object_set(G_OBJECT(mono_queue),
3035 "max-size-buffers", 10,
3036 "max-size-bytes", 0,
3037 "max-size-time", (guint64)0,
3040 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3041 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3043 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3044 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3047 srcpad = gst_element_get_static_pad(mono_queue, "src");
3048 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3049 LOGE("ERROR : audioconvert create error\n");
3053 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3054 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3058 gst_object_unref(GST_OBJECT(srcpad));
3061 srcpad = gst_element_get_static_pad(conv, "src");
3063 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3064 LOGE("ERROR : capsfilter create error\n");
3068 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3069 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3071 caps = gst_caps_from_string("audio/x-raw-int, "
3072 "width = (int) 16, "
3073 "depth = (int) 16, "
3074 "channels = (int) 2");
3076 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3077 gst_caps_unref(caps);
3079 gst_element_set_state(conv, GST_STATE_PAUSED);
3080 gst_element_set_state(filter, GST_STATE_PAUSED);
3084 gst_object_unref(GST_OBJECT(srcpad));
3087 srcpad = gst_element_get_static_pad(filter, "src");
3089 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3090 LOGE("ERROR : deinterleave create error\n");
3094 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3096 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3097 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3099 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3100 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3102 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3103 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3106 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3107 if (selector == NULL) {
3108 LOGE("ERROR : audio-selector create error\n");
3112 g_object_set(selector, "sync-streams", TRUE, NULL);
3113 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3115 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3116 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3118 selector_srcpad = gst_element_get_static_pad(selector, "src");
3120 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3122 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3123 __mmplayer_gst_selector_blocked, NULL, NULL);
3126 gst_object_unref(GST_OBJECT(srcpad));
3130 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3131 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3133 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3134 LOGW("failed to link queue_stereo - selector\n");
3138 player->audio_mode.total_track_num++;
3140 g_object_set(selector, "active-pad", sinkpad, NULL);
3141 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3142 gst_element_set_state(selector, GST_STATE_PAUSED);
3144 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3148 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3149 if (block_id != 0) {
3150 gst_pad_remove_probe(selector_srcpad, block_id);
3155 gst_object_unref(GST_OBJECT(sinkpad));
3160 gst_object_unref(GST_OBJECT(srcpad));
3164 if (selector_srcpad) {
3165 gst_object_unref(GST_OBJECT(selector_srcpad));
3166 selector_srcpad = NULL;
3174 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3176 mm_player_t* player = NULL;
3177 GstPad* srcpad = NULL;
3178 GstElement* video_selector = NULL;
3179 GstElement* audio_selector = NULL;
3180 GstElement* text_selector = NULL;
3181 MMHandleType attrs = 0;
3182 gint active_index = 0;
3183 gint64 dur_bytes = 0L;
3185 player = (mm_player_t*) data;
3187 LOGD("no-more-pad signal handling\n");
3189 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3190 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3191 LOGW("no need to go more");
3193 if (player->gapless.reconfigure) {
3194 player->gapless.reconfigure = FALSE;
3195 MMPLAYER_PLAYBACK_UNLOCK(player);
3201 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3202 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3203 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3204 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3205 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3207 if (NULL == player->streamer) {
3208 LOGW("invalid state for buffering");
3212 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3213 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3215 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3216 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3218 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3220 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3221 LOGE("fail to get duration.\n");
3223 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3224 * use file information was already set on Q2 when it was created. */
3225 __mm_player_streaming_set_queue2(player->streamer,
3226 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3227 TRUE, /* use_buffering */
3229 init_buffering_time,
3230 1.0, /* low percent */
3231 player->ini.http_buffering_limit, /* high percent */
3232 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
3234 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3237 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3238 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3239 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3240 if (video_selector) {
3241 // [link] input-selector :: videobin
3242 srcpad = gst_element_get_static_pad(video_selector, "src");
3244 LOGE("failed to get srcpad from video selector\n");
3248 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3249 if (!text_selector && !audio_selector)
3250 player->no_more_pad = TRUE;
3252 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3254 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3256 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3257 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3261 if (audio_selector) {
3262 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3263 if ((active_index != DEFAULT_TRACK) &&
3264 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3265 LOGW("failed to change audio track\n");
3266 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3269 // [link] input-selector :: audiobin
3270 srcpad = gst_element_get_static_pad(audio_selector, "src");
3272 LOGE("failed to get srcpad from selector\n");
3276 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3278 player->no_more_pad = TRUE;
3280 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3281 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3282 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3283 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3284 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3287 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3289 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3291 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3292 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3293 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3294 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3298 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3300 attrs = MMPLAYER_GET_ATTRS(player);
3302 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3303 if (mmf_attrs_commit(attrs))
3304 LOGE("failed to commit.\n");
3306 LOGE("cannot get content attribute");
3308 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3309 LOGD("There is no audio track : remove audiobin");
3311 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3312 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3314 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3315 MMPLAYER_FREEIF(player->pipeline->audiobin);
3318 if (player->num_dynamic_pad == 0)
3319 __mmplayer_pipeline_complete(NULL, player);
3322 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3324 __mmplayer_handle_text_decode_path(player, text_selector);
3331 gst_object_unref(GST_OBJECT(srcpad));
3335 if (player->gapless.reconfigure) {
3336 player->gapless.reconfigure = FALSE;
3337 MMPLAYER_PLAYBACK_UNLOCK(player);
3342 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3344 mm_player_t* player = NULL;
3345 MMHandleType attrs = 0;
3346 GstElement* pipeline = NULL;
3347 GstCaps* caps = NULL;
3348 gchar* caps_str = NULL;
3349 GstStructure* str = NULL;
3350 const gchar* name = NULL;
3351 GstPad* sinkpad = NULL;
3352 GstElement* sinkbin = NULL;
3353 gboolean reusing = FALSE;
3354 GstElement *text_selector = NULL;
3357 player = (mm_player_t*) data;
3359 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3360 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3362 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3364 attrs = MMPLAYER_GET_ATTRS(player);
3366 LOGE("cannot get content attribute\n");
3370 /* get mimetype from caps */
3371 caps = gst_pad_query_caps(pad, NULL);
3373 LOGE("cannot get caps from pad.\n");
3376 caps_str = gst_caps_to_string(caps);
3378 str = gst_caps_get_structure(caps, 0);
3380 LOGE("cannot get structure from caps.\n");
3384 name = gst_structure_get_name(str);
3386 LOGE("cannot get mimetype from structure.\n");
3390 //LOGD("detected mimetype : %s\n", name);
3392 if (strstr(name, "audio")) {
3393 if (player->pipeline->audiobin == NULL) {
3394 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3395 LOGE("failed to create audiobin. continuing without audio\n");
3399 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3400 LOGD("creating audiosink bin success\n");
3403 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3404 LOGD("reusing audiobin\n");
3405 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3408 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3409 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3411 player->audiosink_linked = 1;
3413 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3415 LOGE("failed to get pad from sinkbin\n");
3418 } else if (strstr(name, "video")) {
3419 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3420 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3421 player->set_mode.video_zc = TRUE;
3423 if (player->pipeline->videobin == NULL) {
3424 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3425 /* get video surface type */
3426 int surface_type = 0;
3427 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3428 LOGD("display_surface_type(%d)\n", surface_type);
3430 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3431 LOGD("not make videobin because it dose not want\n");
3435 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3436 /* mark video overlay for acquire */
3437 if (player->video_overlay_resource == NULL) {
3438 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3439 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3440 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3441 &player->video_overlay_resource)
3442 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3443 LOGE("could not mark video_overlay resource for acquire\n");
3449 player->interrupted_by_resource = FALSE;
3450 /* acquire resources for video overlay */
3451 if (mm_resource_manager_commit(player->resource_manager) !=
3452 MM_RESOURCE_MANAGER_ERROR_NONE) {
3453 LOGE("could not acquire resources for video playing\n");
3457 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3458 LOGE("failed to create videobin. continuing without video\n");
3462 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3463 LOGD("creating videosink bin success\n");
3466 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3467 LOGD("re-using videobin\n");
3468 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3471 player->videosink_linked = 1;
3473 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3475 LOGE("failed to get pad from sinkbin\n");
3478 } else if (strstr(name, "text")) {
3479 if (player->pipeline->textbin == NULL) {
3480 MMPlayerGstElement* mainbin = NULL;
3482 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3483 LOGE("failed to create text sink bin. continuing without text\n");
3487 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3488 LOGD("creating textsink bin success\n");
3490 /* FIXIT : track number shouldn't be hardcoded */
3491 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3493 player->textsink_linked = 1;
3494 LOGI("player->textsink_linked set to 1\n");
3496 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3498 LOGE("failed to get pad from sinkbin\n");
3502 mainbin = player->pipeline->mainbin;
3504 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3505 /* input selector */
3506 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3507 if (!text_selector) {
3508 LOGE("failed to create subtitle input selector element\n");
3511 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3513 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3514 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3517 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3518 LOGE("failed to set state(READY) to sinkbin\n");
3522 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3523 LOGW("failed to add subtitle input selector\n");
3527 LOGD("created element input-selector");
3530 LOGD("already having subtitle input selector");
3531 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3534 if (!player->textsink_linked) {
3535 LOGD("re-using textbin\n");
3538 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3540 player->textsink_linked = 1;
3541 LOGI("player->textsink_linked set to 1\n");
3543 LOGD("ignoring internal subtutle since external subtitle is available");
3546 LOGW("unknown type of elementary stream!ignoring it...\n");
3553 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3554 LOGE("failed to set state(READY) to sinkbin\n");
3558 /* Added for multi audio support to avoid adding audio bin again*/
3560 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3561 LOGE("failed to add sinkbin to pipeline\n");
3567 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3568 LOGE("failed to get pad from sinkbin\n");
3574 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3575 LOGE("failed to set state(PAUSED) to sinkbin\n");
3579 if (text_selector) {
3580 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3581 LOGE("failed to set state(PAUSED) to sinkbin\n");
3587 gst_object_unref(sinkpad);
3591 LOGD("[handle: %p] linking sink bin success", player);
3593 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3594 * streaming task. if the task blocked, then buffer will not flow to the next element
3595 *(autoplugging element). so this is special hack for streaming. please try to remove it
3597 /* dec stream count. we can remove fakesink if it's zero */
3598 if (player->num_dynamic_pad)
3599 player->num_dynamic_pad--;
3601 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3603 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3604 __mmplayer_pipeline_complete(NULL, player);
3608 MMPLAYER_FREEIF(caps_str);
3611 gst_caps_unref(caps);
3614 gst_object_unref(GST_OBJECT(sinkpad));
3616 /* flusing out new attributes */
3617 if (mmf_attrs_commit(attrs))
3618 LOGE("failed to comit attributes\n");
3624 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3626 int pro_value = 0; // in the case of expection, default will be returned.
3627 int dest_angle = rotation_angle;
3628 int rotation_type = -1;
3630 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3631 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3632 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3634 if (rotation_angle >= 360)
3635 dest_angle = rotation_angle - 360;
3637 /* chech if supported or not */
3638 if (dest_angle % 90) {
3639 LOGD("not supported rotation angle = %d", rotation_angle);
3645 * custom_convert - none (B)
3646 * videoflip - none (C)
3648 if (player->set_mode.video_zc) {
3649 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3650 rotation_type = ROTATION_USING_CUSTOM;
3652 rotation_type = ROTATION_USING_SINK;
3654 int surface_type = 0;
3655 rotation_type = ROTATION_USING_FLIP;
3657 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3658 LOGD("check display surface type attribute: %d", surface_type);
3660 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3661 rotation_type = ROTATION_USING_SINK;
3663 rotation_type = ROTATION_USING_FLIP; //C
3665 LOGD("using %d type for rotation", rotation_type);
3668 /* get property value for setting */
3669 switch (rotation_type) {
3670 case ROTATION_USING_SINK: // tizenwlsink
3672 switch (dest_angle) {
3676 pro_value = 3; // clockwise 90
3682 pro_value = 1; // counter-clockwise 90
3687 case ROTATION_USING_CUSTOM:
3689 gchar *ename = NULL;
3690 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3692 if (g_strrstr(ename, "fimcconvert")) {
3693 switch (dest_angle) {
3697 pro_value = 90; // clockwise 90
3703 pro_value = 270; // counter-clockwise 90
3709 case ROTATION_USING_FLIP: // videoflip
3711 switch (dest_angle) {
3715 pro_value = 1; // clockwise 90
3721 pro_value = 3; // counter-clockwise 90
3728 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3736 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3738 /* check video sinkbin is created */
3739 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3741 player->pipeline->videobin &&
3742 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3743 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3744 MM_ERROR_PLAYER_NOT_INITIALIZED);
3746 return MM_ERROR_NONE;
3750 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3752 int rotation_value = 0;
3753 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3757 /* check video sinkbin is created */
3758 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3761 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3763 /* get rotation value to set */
3764 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3765 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3766 LOGD("set video param : rotate %d", rotation_value);
3770 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3772 MMHandleType attrs = 0;
3776 /* check video sinkbin is created */
3777 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3780 attrs = MMPLAYER_GET_ATTRS(player);
3781 MMPLAYER_RETURN_IF_FAIL(attrs);
3783 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3784 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3785 LOGD("set video param : visible %d", visible);
3789 __mmplayer_video_param_set_display_method(mm_player_t* player)
3791 MMHandleType attrs = 0;
3792 int display_method = 0;
3795 /* check video sinkbin is created */
3796 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3799 attrs = MMPLAYER_GET_ATTRS(player);
3800 MMPLAYER_RETURN_IF_FAIL(attrs);
3802 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3803 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3804 LOGD("set video param : method %d", display_method);
3808 __mmplayer_video_param_set_roi_area(mm_player_t* player)
3810 MMHandleType attrs = 0;
3811 void *handle = NULL;
3815 int win_roi_width = 0;
3816 int win_roi_height = 0;
3819 /* check video sinkbin is created */
3820 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3823 attrs = MMPLAYER_GET_ATTRS(player);
3824 MMPLAYER_RETURN_IF_FAIL(attrs);
3826 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3829 /* It should be set after setting window */
3830 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
3831 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
3832 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
3833 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
3835 /* After setting window handle, set display roi area */
3836 gst_video_overlay_set_display_roi_area(
3837 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3838 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3839 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
3840 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
3845 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3847 MMHandleType attrs = 0;
3848 void *handle = NULL;
3850 /* check video sinkbin is created */
3851 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3854 attrs = MMPLAYER_GET_ATTRS(player);
3855 MMPLAYER_RETURN_IF_FAIL(attrs);
3857 /* common case if using overlay surface */
3858 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3861 /* default is using wl_surface_id */
3862 unsigned int wl_surface_id = 0;
3863 wl_surface_id = *(int*)handle;
3864 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3865 gst_video_overlay_set_wl_window_wl_surface_id(
3866 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3869 /* FIXIT : is it error case? */
3870 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3875 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3877 bool update_all_param = FALSE;
3880 /* check video sinkbin is created */
3881 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3882 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3884 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3885 LOGE("can not find tizenwlsink");
3886 return MM_ERROR_PLAYER_INTERNAL;
3889 LOGD("param_name : %s", param_name);
3890 if (!g_strcmp0(param_name, "update_all_param"))
3891 update_all_param = TRUE;
3893 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3894 __mmplayer_video_param_set_display_overlay(player);
3895 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3896 __mmplayer_video_param_set_display_method(player);
3897 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3898 __mmplayer_video_param_set_display_visible(player);
3899 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3900 __mmplayer_video_param_set_display_rotation(player);
3901 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
3902 __mmplayer_video_param_set_roi_area(player);
3904 return MM_ERROR_NONE;
3908 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3910 MMHandleType attrs = 0;
3911 int surface_type = 0;
3912 int ret = MM_ERROR_NONE;
3916 /* check video sinkbin is created */
3917 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3918 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3920 attrs = MMPLAYER_GET_ATTRS(player);
3922 LOGE("cannot get content attribute");
3923 return MM_ERROR_PLAYER_INTERNAL;
3925 LOGD("param_name : %s", param_name);
3927 /* update display surface */
3928 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3929 LOGD("check display surface type attribute: %d", surface_type);
3931 /* configuring display */
3932 switch (surface_type) {
3933 case MM_DISPLAY_SURFACE_OVERLAY:
3935 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3936 if (ret != MM_ERROR_NONE)
3944 return MM_ERROR_NONE;
3948 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3950 gboolean disable_overlay = FALSE;
3951 mm_player_t* player = (mm_player_t*) hplayer;
3952 int ret = MM_ERROR_NONE;
3955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3956 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3957 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3958 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3960 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3961 LOGW("Display control is not supported");
3962 return MM_ERROR_PLAYER_INTERNAL;
3965 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3967 if (audio_only == (bool)disable_overlay) {
3968 LOGE("It's the same with current setting: (%d)", audio_only);
3969 return MM_ERROR_NONE;
3973 LOGE("disable overlay");
3974 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3976 /* release overlay resource */
3977 if (player->video_overlay_resource != NULL) {
3978 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3979 player->video_overlay_resource);
3980 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3981 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3984 player->video_overlay_resource = NULL;
3987 ret = mm_resource_manager_commit(player->resource_manager);
3988 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3993 /* mark video overlay for acquire */
3994 if (player->video_overlay_resource == NULL) {
3995 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3996 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3997 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3998 &player->video_overlay_resource);
3999 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4000 LOGE("could not prepare for video_overlay resource\n");
4005 player->interrupted_by_resource = FALSE;
4006 /* acquire resources for video overlay */
4007 ret = mm_resource_manager_commit(player->resource_manager);
4008 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4009 LOGE("could not acquire resources for video playing\n");
4013 LOGD("enable overlay");
4014 __mmplayer_video_param_set_display_overlay(player);
4015 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4020 return MM_ERROR_NONE;
4024 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4026 mm_player_t* player = (mm_player_t*) hplayer;
4027 gboolean disable_overlay = FALSE;
4031 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4032 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4033 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4034 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4035 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4037 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4038 LOGW("Display control is not supported");
4039 return MM_ERROR_PLAYER_INTERNAL;
4042 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4044 *paudio_only = (bool)(disable_overlay);
4046 LOGD("audio_only : %d", *paudio_only);
4050 return MM_ERROR_NONE;
4054 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4056 GList* bucket = element_bucket;
4057 MMPlayerGstElement* element = NULL;
4058 MMPlayerGstElement* prv_element = NULL;
4059 gint successful_link_count = 0;
4063 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4065 prv_element = (MMPlayerGstElement*)bucket->data;
4066 bucket = bucket->next;
4068 for (; bucket; bucket = bucket->next) {
4069 element = (MMPlayerGstElement*)bucket->data;
4071 if (element && element->gst) {
4072 /* If next element is audio appsrc then make a separate audio pipeline */
4073 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4074 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4075 prv_element = element;
4079 if (prv_element && prv_element->gst) {
4080 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4081 LOGD("linking [%s] to [%s] success\n",
4082 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4083 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4084 successful_link_count++;
4086 LOGD("linking [%s] to [%s] failed\n",
4087 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4088 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4094 prv_element = element;
4099 return successful_link_count;
4103 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4105 GList* bucket = element_bucket;
4106 MMPlayerGstElement* element = NULL;
4107 int successful_add_count = 0;
4111 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4112 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4114 for (; bucket; bucket = bucket->next) {
4115 element = (MMPlayerGstElement*)bucket->data;
4117 if (element && element->gst) {
4118 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4119 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4120 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4121 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4124 successful_add_count++;
4130 return successful_add_count;
4133 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4135 mm_player_t* player = (mm_player_t*) data;
4136 GstCaps *caps = NULL;
4137 GstStructure *str = NULL;
4142 MMPLAYER_RETURN_IF_FAIL(pad)
4143 MMPLAYER_RETURN_IF_FAIL(unused)
4144 MMPLAYER_RETURN_IF_FAIL(data)
4146 caps = gst_pad_get_current_caps(pad);
4150 str = gst_caps_get_structure(caps, 0);
4154 name = gst_structure_get_name(str);
4158 LOGD("name = %s\n", name);
4160 if (strstr(name, "audio")) {
4161 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4163 if (player->audio_stream_changed_cb) {
4164 LOGE("call the audio stream changed cb\n");
4165 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4167 } else if (strstr(name, "video")) {
4168 if ((name = gst_structure_get_string(str, "format")))
4169 player->set_mode.video_zc = name[0] == 'S';
4171 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4173 if (player->video_stream_changed_cb) {
4174 LOGE("call the video stream changed cb\n");
4175 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4182 gst_caps_unref(caps);
4192 * This function is to create audio pipeline for playing.
4194 * @param player [in] handle of player
4196 * @return This function returns zero on success.
4198 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4200 /* macro for code readability. just for sinkbin-creation functions */
4201 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4203 x_bin[x_id].id = x_id;\
4204 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4205 if (!x_bin[x_id].gst) {\
4206 LOGE("failed to create %s \n", x_factory);\
4209 if (x_player->ini.set_dump_element_flag)\
4210 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4213 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4217 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4222 MMPLAYER_RETURN_IF_FAIL(player);
4224 if (player->audio_stream_buff_list) {
4225 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4226 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4229 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4230 __mmplayer_audio_stream_send_data(player, tmp);
4233 g_free(tmp->pcm_data);
4237 g_list_free(player->audio_stream_buff_list);
4238 player->audio_stream_buff_list = NULL;
4245 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4247 MMPlayerAudioStreamDataType audio_stream = { 0, };
4250 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4252 audio_stream.bitrate = a_buffer->bitrate;
4253 audio_stream.channel = a_buffer->channel;
4254 audio_stream.depth = a_buffer->depth;
4255 audio_stream.is_little_endian = a_buffer->is_little_endian;
4256 audio_stream.channel_mask = a_buffer->channel_mask;
4257 audio_stream.data_size = a_buffer->data_size;
4258 audio_stream.data = a_buffer->pcm_data;
4260 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4261 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4267 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4269 mm_player_t* player = (mm_player_t*) data;
4274 gint endianness = 0;
4275 guint64 channel_mask = 0;
4276 void *a_data = NULL;
4278 mm_player_audio_stream_buff_t *a_buffer = NULL;
4279 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4283 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4285 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4286 a_data = mapinfo.data;
4287 a_size = mapinfo.size;
4289 GstCaps *caps = gst_pad_get_current_caps(pad);
4290 GstStructure *structure = gst_caps_get_structure(caps, 0);
4292 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4293 gst_structure_get_int(structure, "rate", &rate);
4294 gst_structure_get_int(structure, "channels", &channel);
4295 gst_structure_get_int(structure, "depth", &depth);
4296 gst_structure_get_int(structure, "endianness", &endianness);
4297 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4298 gst_caps_unref(GST_CAPS(caps));
4300 /* In case of the sync is false, use buffer list. *
4301 * The num of buffer list depends on the num of audio channels */
4302 if (player->audio_stream_buff_list) {
4303 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4304 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4306 if (channel_mask == tmp->channel_mask) {
4307 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4308 if (tmp->data_size + a_size < tmp->buff_size) {
4309 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4310 tmp->data_size += a_size;
4312 /* send data to client */
4313 __mmplayer_audio_stream_send_data(player, tmp);
4315 if (a_size > tmp->buff_size) {
4316 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4317 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4318 if (tmp->pcm_data == NULL) {
4319 LOGE("failed to realloc data.");
4322 tmp->buff_size = a_size;
4324 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4325 memcpy(tmp->pcm_data, a_data, a_size);
4326 tmp->data_size = a_size;
4331 LOGE("data is empty in list.");
4337 /* create new audio stream data */
4338 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4339 if (a_buffer == NULL) {
4340 LOGE("failed to alloc data.");
4343 a_buffer->bitrate = rate;
4344 a_buffer->channel = channel;
4345 a_buffer->depth = depth;
4346 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4347 a_buffer->channel_mask = channel_mask;
4348 a_buffer->data_size = a_size;
4350 if (!player->audio_stream_sink_sync) {
4351 /* If sync is FALSE, use buffer list to reduce the IPC. */
4352 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4353 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4354 if (a_buffer->pcm_data == NULL) {
4355 LOGE("failed to alloc data.");
4359 memcpy(a_buffer->pcm_data, a_data, a_size);
4360 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4361 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4363 /* If sync is TRUE, send data directly. */
4364 a_buffer->pcm_data = a_data;
4365 __mmplayer_audio_stream_send_data(player, a_buffer);
4370 gst_buffer_unmap(buffer, &mapinfo);
4375 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4377 mm_player_t* player = (mm_player_t*)data;
4378 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4379 GstPad* sinkpad = NULL;
4380 GstElement *queue = NULL, *sink = NULL;
4383 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4385 queue = gst_element_factory_make("queue", NULL);
4386 if (queue == NULL) {
4387 LOGD("fail make queue\n");
4391 sink = gst_element_factory_make("fakesink", NULL);
4393 LOGD("fail make fakesink\n");
4397 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4399 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4400 LOGW("failed to link queue & sink\n");
4404 sinkpad = gst_element_get_static_pad(queue, "sink");
4406 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4407 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4411 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4413 gst_object_unref(sinkpad);
4414 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4415 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4417 gst_element_set_state(sink, GST_STATE_PAUSED);
4418 gst_element_set_state(queue, GST_STATE_PAUSED);
4420 MMPLAYER_SIGNAL_CONNECT(player,
4422 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4424 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4431 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4433 gst_object_unref(GST_OBJECT(queue));
4437 gst_object_unref(GST_OBJECT(sink));
4441 gst_object_unref(GST_OBJECT(sinkpad));
4448 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4450 #define MAX_PROPS_LEN 128
4451 gint latency_mode = 0;
4452 gchar *stream_type = NULL;
4453 gchar *latency = NULL;
4455 gchar stream_props[MAX_PROPS_LEN] = {0,};
4456 GstStructure *props = NULL;
4459 * It should be set after player creation through attribute.
4460 * But, it can not be changed during playing.
4463 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4464 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4467 LOGE("stream_type is null.\n");
4469 if (player->sound.focus_id)
4470 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4471 stream_type, stream_id, player->sound.focus_id);
4473 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4474 stream_type, stream_id);
4475 props = gst_structure_from_string(stream_props, NULL);
4476 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4477 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4478 stream_type, stream_id, player->sound.focus_id, stream_props);
4479 gst_structure_free(props);
4482 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4484 switch (latency_mode) {
4485 case AUDIO_LATENCY_MODE_LOW:
4486 latency = g_strndup("low", 3);
4488 case AUDIO_LATENCY_MODE_MID:
4489 latency = g_strndup("mid", 3);
4491 case AUDIO_LATENCY_MODE_HIGH:
4492 latency = g_strndup("high", 4);
4496 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4500 LOGD("audiosink property - latency=%s \n", latency);
4508 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4510 MMPlayerGstElement* first_element = NULL;
4511 MMPlayerGstElement* audiobin = NULL;
4512 MMHandleType attrs = 0;
4514 GstPad *ghostpad = NULL;
4515 GList* element_bucket = NULL;
4516 gboolean link_audio_sink_now = TRUE;
4522 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4525 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4527 LOGE("failed to allocate memory for audiobin\n");
4528 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4531 attrs = MMPLAYER_GET_ATTRS(player);
4534 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4535 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4536 if (!audiobin[MMPLAYER_A_BIN].gst) {
4537 LOGE("failed to create audiobin\n");
4542 player->pipeline->audiobin = audiobin;
4544 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4546 /* Adding audiotp plugin for reverse trickplay feature */
4547 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4550 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4552 /* replaygain volume */
4553 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4554 if (player->sound.rg_enable)
4555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4560 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4562 if (player->set_mode.pcm_extraction) {
4563 // pcm extraction only and no sound output
4564 if (player->audio_stream_render_cb_ex) {
4565 char *caps_str = NULL;
4566 GstCaps* caps = NULL;
4567 gchar *format = NULL;
4570 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4572 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4574 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4576 caps = gst_caps_new_simple("audio/x-raw",
4577 "format", G_TYPE_STRING, format,
4578 "rate", G_TYPE_INT, player->pcm_samplerate,
4579 "channels", G_TYPE_INT, player->pcm_channel,
4581 caps_str = gst_caps_to_string(caps);
4582 LOGD("new caps : %s\n", caps_str);
4584 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4587 gst_caps_unref(caps);
4588 MMPLAYER_FREEIF(caps_str);
4590 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4593 /* raw pad handling signal */
4594 MMPLAYER_SIGNAL_CONNECT(player,
4595 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4596 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4597 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4599 int dst_samplerate = 0;
4600 int dst_channels = 0;
4602 char *caps_str = NULL;
4603 GstCaps* caps = NULL;
4605 /* get conf. values */
4606 mm_attrs_multiple_get(player->attrs,
4608 "pcm_extraction_samplerate", &dst_samplerate,
4609 "pcm_extraction_channels", &dst_channels,
4610 "pcm_extraction_depth", &dst_depth,
4614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4615 caps = gst_caps_new_simple("audio/x-raw",
4616 "rate", G_TYPE_INT, dst_samplerate,
4617 "channels", G_TYPE_INT, dst_channels,
4618 "depth", G_TYPE_INT, dst_depth,
4620 caps_str = gst_caps_to_string(caps);
4621 LOGD("new caps : %s\n", caps_str);
4623 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4626 gst_caps_unref(caps);
4627 MMPLAYER_FREEIF(caps_str);
4630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4637 //GstCaps* caps = NULL;
4640 /* for logical volume control */
4641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4644 if (player->sound.mute) {
4645 LOGD("mute enabled\n");
4646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4652 caps = gst_caps_from_string("audio/x-raw-int, "
4653 "endianness = (int) LITTLE_ENDIAN, "
4654 "signed = (boolean) true, "
4655 "width = (int) 16, "
4656 "depth = (int) 16");
4657 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4658 gst_caps_unref(caps);
4661 /* check if multi-channels */
4662 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4663 GstPad *srcpad = NULL;
4664 GstCaps *caps = NULL;
4666 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4667 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4668 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4669 GstStructure *str = gst_caps_get_structure(caps, 0);
4671 gst_structure_get_int(str, "channels", &channels);
4672 gst_caps_unref(caps);
4674 gst_object_unref(srcpad);
4678 /* audio effect element. if audio effect is enabled */
4679 if ((strcmp(player->ini.audioeffect_element, ""))
4681 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4684 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4686 if ((!player->bypass_audio_effect)
4687 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4688 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4689 if (!_mmplayer_audio_effect_custom_apply(player))
4690 LOGI("apply audio effect(custom) setting success\n");
4694 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4695 && (player->set_mode.rich_audio))
4696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4699 /* create audio sink */
4700 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4701 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4702 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4704 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4705 if (player->is_360_feature_enabled &&
4706 player->is_content_spherical &&
4708 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4709 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4710 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4712 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4717 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4719 gst_caps_unref(acaps);
4721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4723 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4726 player->is_openal_plugin_used = TRUE;
4728 if (player->video360_yaw_radians <= M_PI &&
4729 player->video360_yaw_radians >= -M_PI &&
4730 player->video360_pitch_radians <= M_PI_2 &&
4731 player->video360_pitch_radians >= -M_PI_2) {
4732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4733 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4734 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4735 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4736 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4737 "source-orientation-y", player->video360_metadata.init_view_heading,
4738 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4741 if (player->is_360_feature_enabled && player->is_content_spherical)
4742 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4751 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4752 (player->videodec_linked && player->ini.use_system_clock)) {
4753 LOGD("system clock will be used.\n");
4754 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4757 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4758 __mmplayer_gst_set_audiosink_property(player, attrs);
4761 if (audiobin[MMPLAYER_A_SINK].gst) {
4762 GstPad *sink_pad = NULL;
4763 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4764 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4765 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4766 gst_object_unref(GST_OBJECT(sink_pad));
4769 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4771 /* adding created elements to bin */
4772 LOGD("adding created elements to bin\n");
4773 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4774 LOGE("failed to add elements\n");
4778 /* linking elements in the bucket by added order. */
4779 LOGD("Linking elements in the bucket by added order.\n");
4780 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4781 LOGE("failed to link elements\n");
4785 /* get first element's sinkpad for creating ghostpad */
4786 first_element = (MMPlayerGstElement *)element_bucket->data;
4787 if (!first_element) {
4788 LOGE("failed to get first elem\n");
4792 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4794 LOGE("failed to get pad from first element of audiobin\n");
4798 ghostpad = gst_ghost_pad_new("sink", pad);
4800 LOGE("failed to create ghostpad\n");
4804 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4805 LOGE("failed to add ghostpad to audiobin\n");
4809 gst_object_unref(pad);
4811 g_list_free(element_bucket);
4814 return MM_ERROR_NONE;
4818 LOGD("ERROR : releasing audiobin\n");
4821 gst_object_unref(GST_OBJECT(pad));
4824 gst_object_unref(GST_OBJECT(ghostpad));
4827 g_list_free(element_bucket);
4829 /* release element which are not added to bin */
4830 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4831 /* NOTE : skip bin */
4832 if (audiobin[i].gst) {
4833 GstObject* parent = NULL;
4834 parent = gst_element_get_parent(audiobin[i].gst);
4837 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4838 audiobin[i].gst = NULL;
4840 gst_object_unref(GST_OBJECT(parent));
4844 /* release audiobin with it's childs */
4845 if (audiobin[MMPLAYER_A_BIN].gst)
4846 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4848 MMPLAYER_FREEIF(audiobin);
4850 player->pipeline->audiobin = NULL;
4852 return MM_ERROR_PLAYER_INTERNAL;
4855 static GstPadProbeReturn
4856 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4858 mm_player_t* player = (mm_player_t*) u_data;
4859 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4860 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4862 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4864 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4865 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4867 return GST_PAD_PROBE_OK;
4870 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4872 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4875 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4877 int ret = MM_ERROR_NONE;
4879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4882 MMPLAYER_VIDEO_BO_LOCK(player);
4884 if (player->video_bo_list) {
4885 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4886 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887 if (tmp && tmp->bo == bo) {
4889 LOGD("release bo %p", bo);
4890 tbm_bo_unref(tmp->bo);
4891 MMPLAYER_VIDEO_BO_UNLOCK(player);
4892 MMPLAYER_VIDEO_BO_SIGNAL(player);
4897 /* hw codec is running or the list was reset for DRC. */
4898 LOGW("there is no bo list.");
4900 MMPLAYER_VIDEO_BO_UNLOCK(player);
4902 LOGW("failed to find bo %p", bo);
4907 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4912 MMPLAYER_RETURN_IF_FAIL(player);
4914 MMPLAYER_VIDEO_BO_LOCK(player);
4915 if (player->video_bo_list) {
4916 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4917 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4918 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4921 tbm_bo_unref(tmp->bo);
4925 g_list_free(player->video_bo_list);
4926 player->video_bo_list = NULL;
4928 player->video_bo_size = 0;
4929 MMPLAYER_VIDEO_BO_UNLOCK(player);
4936 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4939 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4940 gboolean ret = TRUE;
4942 /* check DRC, if it is, destroy the prev bo list to create again */
4943 if (player->video_bo_size != size) {
4944 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4945 __mmplayer_video_stream_destroy_bo_list(player);
4946 player->video_bo_size = size;
4949 MMPLAYER_VIDEO_BO_LOCK(player);
4951 if ((!player->video_bo_list) ||
4952 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4954 /* create bo list */
4956 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4958 if (player->video_bo_list) {
4959 /* if bo list did not created all, try it again. */
4960 idx = g_list_length(player->video_bo_list);
4961 LOGD("bo list exist(len: %d)", idx);
4964 for (; idx < player->ini.num_of_video_bo; idx++) {
4965 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4967 LOGE("Fail to alloc bo_info.");
4970 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4972 LOGE("Fail to tbm_bo_alloc.");
4976 bo_info->using = FALSE;
4977 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4980 /* update video num buffers */
4981 player->video_num_buffers = idx;
4982 if (idx == player->ini.num_of_video_bo)
4983 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4986 MMPLAYER_VIDEO_BO_UNLOCK(player);
4990 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4994 /* get bo from list*/
4995 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4996 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4997 if (tmp && (tmp->using == FALSE)) {
4998 LOGD("found bo %p to use", tmp->bo);
5000 MMPLAYER_VIDEO_BO_UNLOCK(player);
5001 return tbm_bo_ref(tmp->bo);
5005 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5006 MMPLAYER_VIDEO_BO_UNLOCK(player);
5010 if (player->ini.video_bo_timeout <= 0) {
5011 MMPLAYER_VIDEO_BO_WAIT(player);
5013 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5014 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5021 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5023 mm_player_t* player = (mm_player_t*)data;
5025 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5027 /* send prerolled pkt */
5028 player->video_stream_prerolled = FALSE;
5030 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5032 /* not to send prerolled pkt again */
5033 player->video_stream_prerolled = TRUE;
5037 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5039 mm_player_t* player = (mm_player_t*)data;
5040 GstCaps *caps = NULL;
5041 MMPlayerVideoStreamDataType *stream = NULL;
5042 MMVideoBuffer *video_buffer = NULL;
5043 GstMemory *dataBlock = NULL;
5044 GstMemory *metaBlock = NULL;
5045 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5046 GstStructure *structure = NULL;
5047 const gchar *string_format = NULL;
5048 unsigned int fourcc = 0;
5051 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5053 if (player->video_stream_prerolled) {
5054 player->video_stream_prerolled = FALSE;
5055 LOGD("skip the prerolled pkt not to send it again");
5059 caps = gst_pad_get_current_caps(pad);
5061 LOGE("Caps is NULL.");
5065 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5067 /* clear stream data structure */
5068 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5070 LOGE("failed to alloc mem for video data");
5074 structure = gst_caps_get_structure(caps, 0);
5075 gst_structure_get_int(structure, "width", &(stream->width));
5076 gst_structure_get_int(structure, "height", &(stream->height));
5077 string_format = gst_structure_get_string(structure, "format");
5079 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5080 stream->format = util_get_pixtype(fourcc);
5081 gst_caps_unref(caps);
5084 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5087 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5088 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5091 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5092 LOGE("Wrong condition!!");
5096 /* set size and timestamp */
5097 dataBlock = gst_buffer_peek_memory(buffer, 0);
5098 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5099 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5101 /* check zero-copy */
5102 if (player->set_mode.video_zc &&
5103 player->set_mode.media_packet_video_stream &&
5104 gst_buffer_n_memory(buffer) > 1) {
5105 metaBlock = gst_buffer_peek_memory(buffer, 1);
5106 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5107 video_buffer = (MMVideoBuffer *)mapinfo.data;
5110 if (video_buffer) { /* hw codec */
5112 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5115 /* copy pointer of tbm bo, stride, elevation */
5116 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5117 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5121 LOGE("Not support video buffer format");
5124 memcpy(stream->stride, video_buffer->stride_width,
5125 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5126 memcpy(stream->elevation, video_buffer->stride_height,
5127 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5129 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5130 stream->internal_buffer = gst_buffer_ref(buffer);
5131 } else { /* sw codec */
5135 int ret = TBM_SURFACE_ERROR_NONE;
5136 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5137 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5139 unsigned char *src = NULL;
5140 unsigned char *dest = NULL;
5141 tbm_bo_handle thandle;
5142 tbm_surface_h surface;
5143 tbm_surface_info_s info;
5146 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5148 LOGE("fail to gst_memory_map");
5153 if (stream->format == MM_PIXEL_FORMAT_I420) {
5154 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5156 ret = tbm_surface_get_info(surface, &info);
5158 if (ret != TBM_SURFACE_ERROR_NONE) {
5159 tbm_surface_destroy(surface);
5162 tbm_surface_destroy(surface);
5164 src_stride[0] = GST_ROUND_UP_4(stream->width);
5165 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5166 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5167 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5168 stream->stride[0] = info.planes[0].stride;
5169 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5170 stream->stride[1] = info.planes[1].stride;
5171 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5172 stream->stride[2] = info.planes[2].stride;
5173 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5174 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5175 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5176 stream->stride[0] = stream->width * 4;
5177 stream->elevation[0] = stream->height;
5178 size = stream->stride[0] * stream->height;
5180 LOGE("Not support format %d", stream->format);
5184 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5185 if (!stream->bo[0]) {
5186 LOGE("Fail to tbm_bo_alloc!!");
5190 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5191 if (thandle.ptr && mapinfo.data) {
5192 if (stream->format == MM_PIXEL_FORMAT_I420) {
5193 for (i = 0; i < 3; i++) {
5194 src = mapinfo.data + src_offset[i];
5195 dest = thandle.ptr + info.planes[i].offset;
5198 for (j = 0; j < stream->height>>k; j++) {
5199 memcpy(dest, src, stream->width>>k);
5200 src += src_stride[i];
5201 dest += stream->stride[i];
5204 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5205 memcpy(thandle.ptr, mapinfo.data, size);
5207 LOGE("Not support format %d", stream->format);
5211 LOGE("data pointer is wrong. dest : %p, src : %p",
5212 thandle.ptr, mapinfo.data);
5215 tbm_bo_unmap(stream->bo[0]);
5218 if (player->video_stream_cb) { /* This has been already checked at the entry */
5219 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5220 LOGE("failed to send video stream data.");
5226 gst_memory_unmap(metaBlock, &mapinfo);
5228 gst_memory_unmap(dataBlock, &mapinfo);
5233 LOGE("release video stream resource.");
5236 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5238 tbm_bo_unref(stream->bo[i]);
5240 gst_memory_unmap(metaBlock, &mapinfo);
5242 /* unref gst buffer */
5243 if (stream->internal_buffer)
5244 gst_buffer_unref(stream->internal_buffer);
5245 } else if (dataBlock) {
5247 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5248 gst_memory_unmap(dataBlock, &mapinfo);
5256 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5258 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5259 GList* element_bucket = NULL;
5261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5265 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5266 LOGD("do not need to add video filters.");
5267 return MM_ERROR_NONE;
5270 /* in case of sw codec except 360 playback,
5271 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5272 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5273 LOGD("using video converter: %s", video_csc);
5275 /* set video rotator */
5276 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5278 *bucket = element_bucket;
5280 return MM_ERROR_NONE;
5282 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5283 g_list_free(element_bucket);
5287 return MM_ERROR_PLAYER_INTERNAL;
5291 * This function is to create video pipeline.
5293 * @param player [in] handle of player
5294 * caps [in] src caps of decoder
5295 * surface_type [in] surface type for video rendering
5297 * @return This function returns zero on success.
5299 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5303 * - video overlay surface(arm/x86) : tizenwlsink
5306 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5310 GList*element_bucket = NULL;
5311 MMPlayerGstElement* first_element = NULL;
5312 MMPlayerGstElement* videobin = NULL;
5313 gchar *videosink_element = NULL;
5317 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5320 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5322 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5324 player->pipeline->videobin = videobin;
5326 attrs = MMPLAYER_GET_ATTRS(player);
5328 LOGE("cannot get content attribute");
5329 return MM_ERROR_PLAYER_INTERNAL;
5333 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5334 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5335 if (!videobin[MMPLAYER_V_BIN].gst) {
5336 LOGE("failed to create videobin");
5340 int enable_video_decoded_cb = 0;
5341 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5343 if (player->is_360_feature_enabled && player->is_content_spherical) {
5344 LOGD("video360 elem will be added.");
5346 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5347 "video-360", TRUE, player);
5349 /* Set spatial media metadata and/or user settings to the element.
5351 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5352 "projection-type", player->video360_metadata.projection_type, NULL);
5354 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5357 if (player->video360_metadata.full_pano_width_pixels &&
5358 player->video360_metadata.full_pano_height_pixels &&
5359 player->video360_metadata.cropped_area_image_width &&
5360 player->video360_metadata.cropped_area_image_height) {
5361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5362 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5363 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5364 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5365 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5366 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5367 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5371 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5372 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5373 "horizontal-fov", player->video360_horizontal_fov,
5374 "vertical-fov", player->video360_vertical_fov, NULL);
5377 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5378 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5379 "zoom", 1.0f / player->video360_zoom, NULL);
5382 if (player->video360_yaw_radians <= M_PI &&
5383 player->video360_yaw_radians >= -M_PI &&
5384 player->video360_pitch_radians <= M_PI_2 &&
5385 player->video360_pitch_radians >= -M_PI_2) {
5386 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5387 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5388 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5389 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5391 "pose-yaw", player->video360_metadata.init_view_heading,
5392 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5395 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5396 "passthrough", !player->is_video360_enabled, NULL);
5399 /* set video sink */
5400 switch (surface_type) {
5401 case MM_DISPLAY_SURFACE_OVERLAY:
5402 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5404 if (strlen(player->ini.videosink_element_overlay) > 0)
5405 videosink_element = player->ini.videosink_element_overlay;
5409 case MM_DISPLAY_SURFACE_NULL:
5410 if (strlen(player->ini.videosink_element_fake) > 0)
5411 videosink_element = player->ini.videosink_element_fake;
5415 case MM_DISPLAY_SURFACE_REMOTE:
5416 if (strlen(player->ini.videosink_element_fake) > 0)
5417 videosink_element = player->ini.videosink_element_fake;
5422 LOGE("unidentified surface type");
5425 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5427 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5429 /* additional setting for sink plug-in */
5430 switch (surface_type) {
5431 case MM_DISPLAY_SURFACE_OVERLAY:
5433 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5435 LOGD("selected videosink name: %s", videosink_element);
5437 /* support shard memory with S/W codec on HawkP */
5438 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5439 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5440 "use-tbm", use_tbm, NULL);
5446 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5449 LOGD("disable last-sample");
5450 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5454 if (player->set_mode.media_packet_video_stream) {
5456 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5458 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5460 MMPLAYER_SIGNAL_CONNECT(player,
5461 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5462 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5464 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5467 MMPLAYER_SIGNAL_CONNECT(player,
5468 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5469 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5471 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5476 case MM_DISPLAY_SURFACE_REMOTE:
5478 if (player->set_mode.media_packet_video_stream) {
5479 LOGE("add data probe at videosink");
5480 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5481 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5483 MMPLAYER_SIGNAL_CONNECT(player,
5484 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5485 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5487 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5490 MMPLAYER_SIGNAL_CONNECT(player,
5491 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5492 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5494 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5499 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5502 LOGD("disable last-sample");
5503 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5513 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5516 if (videobin[MMPLAYER_V_SINK].gst) {
5517 GstPad *sink_pad = NULL;
5518 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5520 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5521 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5522 gst_object_unref(GST_OBJECT(sink_pad));
5524 LOGW("failed to get sink pad from videosink\n");
5527 /* store it as it's sink element */
5528 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5530 /* adding created elements to bin */
5531 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5532 LOGE("failed to add elements\n");
5536 /* Linking elements in the bucket by added order */
5537 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5538 LOGE("failed to link elements\n");
5542 /* get first element's sinkpad for creating ghostpad */
5544 first_element = (MMPlayerGstElement *)element_bucket->data;
5545 if (!first_element) {
5546 LOGE("failed to get first element from bucket\n");
5550 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5552 LOGE("failed to get pad from first element\n");
5556 /* create ghostpad */
5557 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5558 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5559 LOGE("failed to add ghostpad to videobin\n");
5562 gst_object_unref(pad);
5564 /* done. free allocated variables */
5566 g_list_free(element_bucket);
5570 return MM_ERROR_NONE;
5573 LOGE("ERROR : releasing videobin\n");
5575 g_list_free(element_bucket);
5578 gst_object_unref(GST_OBJECT(pad));
5580 /* release videobin with it's childs */
5581 if (videobin[MMPLAYER_V_BIN].gst)
5582 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5585 MMPLAYER_FREEIF(videobin);
5587 player->pipeline->videobin = NULL;
5589 return MM_ERROR_PLAYER_INTERNAL;
5592 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5594 GList *element_bucket = NULL;
5595 MMPlayerGstElement *textbin = player->pipeline->textbin;
5597 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5598 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5599 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5600 "signal-handoffs", FALSE,
5603 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5604 MMPLAYER_SIGNAL_CONNECT(player,
5605 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5606 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5608 G_CALLBACK(__mmplayer_update_subtitle),
5611 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5612 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5614 if (!player->play_subtitle) {
5615 LOGD("add textbin sink as sink element of whole pipeline.\n");
5616 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5619 /* adding created elements to bin */
5620 LOGD("adding created elements to bin\n");
5621 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5622 LOGE("failed to add elements\n");
5626 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5627 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5628 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5630 /* linking elements in the bucket by added order. */
5631 LOGD("Linking elements in the bucket by added order.\n");
5632 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5633 LOGE("failed to link elements\n");
5637 /* done. free allocated variables */
5638 g_list_free(element_bucket);
5640 if (textbin[MMPLAYER_T_QUEUE].gst) {
5642 GstPad *ghostpad = NULL;
5644 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5646 LOGE("failed to get sink pad of text queue");
5650 ghostpad = gst_ghost_pad_new("text_sink", pad);
5651 gst_object_unref(pad);
5654 LOGE("failed to create ghostpad of textbin\n");
5658 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5659 LOGE("failed to add ghostpad to textbin\n");
5660 gst_object_unref(ghostpad);
5665 return MM_ERROR_NONE;
5668 g_list_free(element_bucket);
5670 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5671 LOGE("remove textbin sink from sink list");
5672 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5675 /* release element at __mmplayer_gst_create_text_sink_bin */
5676 return MM_ERROR_PLAYER_INTERNAL;
5679 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5681 MMPlayerGstElement *textbin = NULL;
5682 GList *element_bucket = NULL;
5683 int surface_type = 0;
5688 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5691 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5693 LOGE("failed to allocate memory for textbin\n");
5694 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5698 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5699 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5700 if (!textbin[MMPLAYER_T_BIN].gst) {
5701 LOGE("failed to create textbin\n");
5706 player->pipeline->textbin = textbin;
5709 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5710 LOGD("surface type for subtitle : %d", surface_type);
5711 switch (surface_type) {
5712 case MM_DISPLAY_SURFACE_OVERLAY:
5713 case MM_DISPLAY_SURFACE_NULL:
5714 case MM_DISPLAY_SURFACE_REMOTE:
5715 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5716 LOGE("failed to make plain text elements\n");
5727 return MM_ERROR_NONE;
5731 LOGD("ERROR : releasing textbin\n");
5733 g_list_free(element_bucket);
5735 /* release signal */
5736 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5738 /* release element which are not added to bin */
5739 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5740 /* NOTE : skip bin */
5741 if (textbin[i].gst) {
5742 GstObject* parent = NULL;
5743 parent = gst_element_get_parent(textbin[i].gst);
5746 gst_object_unref(GST_OBJECT(textbin[i].gst));
5747 textbin[i].gst = NULL;
5749 gst_object_unref(GST_OBJECT(parent));
5754 /* release textbin with it's childs */
5755 if (textbin[MMPLAYER_T_BIN].gst)
5756 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5758 MMPLAYER_FREEIF(player->pipeline->textbin);
5759 player->pipeline->textbin = NULL;
5762 return MM_ERROR_PLAYER_INTERNAL;
5767 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5769 MMPlayerGstElement* mainbin = NULL;
5770 MMPlayerGstElement* textbin = NULL;
5771 MMHandleType attrs = 0;
5772 GstElement *subsrc = NULL;
5773 GstElement *subparse = NULL;
5774 gchar *subtitle_uri = NULL;
5775 const gchar *charset = NULL;
5781 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5783 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5785 mainbin = player->pipeline->mainbin;
5787 attrs = MMPLAYER_GET_ATTRS(player);
5789 LOGE("cannot get content attribute\n");
5790 return MM_ERROR_PLAYER_INTERNAL;
5793 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5794 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5795 LOGE("subtitle uri is not proper filepath.\n");
5796 return MM_ERROR_PLAYER_INVALID_URI;
5799 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5800 LOGE("failed to get storage info of subtitle path");
5801 return MM_ERROR_PLAYER_INVALID_URI;
5804 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5806 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5807 player->subtitle_language_list = NULL;
5808 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5810 /* create the subtitle source */
5811 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5813 LOGE("failed to create filesrc element\n");
5816 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5818 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5819 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5821 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5822 LOGW("failed to add queue\n");
5823 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5824 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5825 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5830 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5832 LOGE("failed to create subparse element\n");
5836 charset = util_get_charset(subtitle_uri);
5838 LOGD("detected charset is %s\n", charset);
5839 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5842 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5843 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5845 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5846 LOGW("failed to add subparse\n");
5847 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5848 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5849 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5853 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5854 LOGW("failed to link subsrc and subparse\n");
5858 player->play_subtitle = TRUE;
5859 player->adjust_subtitle_pos = 0;
5861 LOGD("play subtitle using subtitle file\n");
5863 if (player->pipeline->textbin == NULL) {
5864 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5865 LOGE("failed to create text sink bin. continuing without text\n");
5869 textbin = player->pipeline->textbin;
5871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5872 LOGW("failed to add textbin\n");
5874 /* release signal */
5875 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5877 /* release textbin with it's childs */
5878 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5879 MMPLAYER_FREEIF(player->pipeline->textbin);
5880 player->pipeline->textbin = textbin = NULL;
5884 LOGD("link text input selector and textbin ghost pad");
5886 player->textsink_linked = 1;
5887 player->external_text_idx = 0;
5888 LOGI("player->textsink_linked set to 1\n");
5890 textbin = player->pipeline->textbin;
5891 LOGD("text bin has been created. reuse it.");
5892 player->external_text_idx = 1;
5895 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5896 LOGW("failed to link subparse and textbin\n");
5900 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5902 LOGE("failed to get sink pad from textsink to probe data");
5906 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5907 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5909 gst_object_unref(pad);
5912 /* create dot. for debugging */
5913 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5916 return MM_ERROR_NONE;
5919 /* release text pipeline resource */
5920 player->textsink_linked = 0;
5922 /* release signal */
5923 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5925 if (player->pipeline->textbin) {
5926 LOGE("remove textbin");
5928 /* release textbin with it's childs */
5929 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5930 MMPLAYER_FREEIF(player->pipeline->textbin);
5931 player->pipeline->textbin = NULL;
5935 /* release subtitle elem */
5936 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5937 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5939 return MM_ERROR_PLAYER_INTERNAL;
5943 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5945 mm_player_t* player = (mm_player_t*) data;
5946 MMMessageParamType msg = {0, };
5947 GstClockTime duration = 0;
5948 gpointer text = NULL;
5949 guint text_size = 0;
5950 gboolean ret = TRUE;
5951 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5955 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5956 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5958 if (player->is_subtitle_force_drop) {
5959 LOGW("subtitle is dropped forcedly.");
5963 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5964 text = mapinfo.data;
5965 text_size = mapinfo.size;
5966 duration = GST_BUFFER_DURATION(buffer);
5968 if (player->set_mode.subtitle_off) {
5969 LOGD("subtitle is OFF.\n");
5973 if (!text || (text_size == 0)) {
5974 LOGD("There is no subtitle to be displayed.\n");
5978 msg.data = (void *) text;
5979 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5981 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5983 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5984 gst_buffer_unmap(buffer, &mapinfo);
5991 static GstPadProbeReturn
5992 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5994 mm_player_t *player = (mm_player_t *) u_data;
5995 GstClockTime cur_timestamp = 0;
5996 gint64 adjusted_timestamp = 0;
5997 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5999 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6001 if (player->set_mode.subtitle_off) {
6002 LOGD("subtitle is OFF.\n");
6006 if (player->adjust_subtitle_pos == 0) {
6007 LOGD("nothing to do");
6011 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6012 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6014 if (adjusted_timestamp < 0) {
6015 LOGD("adjusted_timestamp under zero");
6020 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6021 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6022 GST_TIME_ARGS(cur_timestamp),
6023 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6025 return GST_PAD_PROBE_OK;
6027 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6031 /* check player and subtitlebin are created */
6032 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6033 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6035 if (position == 0) {
6036 LOGD("nothing to do\n");
6038 return MM_ERROR_NONE;
6042 case MM_PLAYER_POS_FORMAT_TIME:
6044 /* check current postion */
6045 player->adjust_subtitle_pos = position;
6047 LOGD("save adjust_subtitle_pos in player") ;
6053 LOGW("invalid format.\n");
6055 return MM_ERROR_INVALID_ARGUMENT;
6061 return MM_ERROR_NONE;
6065 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6067 GstElement *appsrc = element;
6068 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6069 GstBuffer *buffer = NULL;
6070 GstFlowReturn ret = GST_FLOW_OK;
6073 MMPLAYER_RETURN_IF_FAIL(element);
6074 MMPLAYER_RETURN_IF_FAIL(buf);
6076 buffer = gst_buffer_new();
6078 if (buf->offset >= buf->len) {
6079 LOGD("call eos appsrc\n");
6080 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6084 if (buf->len - buf->offset < size)
6085 len = buf->len - buf->offset;
6087 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6088 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6089 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6091 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6092 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6098 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6100 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6102 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6104 buf->offset = (int)size;
6109 static GstBusSyncReply
6110 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6112 mm_player_t *player = (mm_player_t *)data;
6113 GstBusSyncReply reply = GST_BUS_DROP;
6115 if (!(player->pipeline && player->pipeline->mainbin)) {
6116 LOGE("player pipeline handle is null");
6117 return GST_BUS_PASS;
6120 if (!__mmplayer_check_useful_message(player, message)) {
6121 gst_message_unref(message);
6122 return GST_BUS_DROP;
6125 switch (GST_MESSAGE_TYPE(message)) {
6126 case GST_MESSAGE_STATE_CHANGED:
6127 /* post directly for fast launch */
6128 if (player->sync_handler) {
6129 __mmplayer_gst_callback(message, player);
6130 reply = GST_BUS_DROP;
6132 reply = GST_BUS_PASS;
6134 case GST_MESSAGE_TAG:
6135 __mmplayer_gst_extract_tag_from_msg(player, message);
6139 GstTagList *tags = NULL;
6141 gst_message_parse_tag(message, &tags);
6143 LOGE("TAGS received from element \"%s\".\n",
6144 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6146 gst_tag_list_foreach(tags, print_tag, NULL);
6147 gst_tag_list_free(tags);
6155 case GST_MESSAGE_DURATION_CHANGED:
6156 __mmplayer_gst_handle_duration(player, message);
6158 case GST_MESSAGE_ASYNC_DONE:
6159 /* NOTE:Don't call gst_callback directly
6160 * because previous frame can be showed even though this message is received for seek.
6163 reply = GST_BUS_PASS;
6167 if (reply == GST_BUS_DROP)
6168 gst_message_unref(message);
6174 __mmplayer_gst_create_decoder(mm_player_t *player,
6175 MMPlayerTrackType track,
6177 enum MainElementID elemId,
6180 gboolean ret = TRUE;
6181 GstPad *sinkpad = NULL;
6185 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6187 player->pipeline->mainbin, FALSE);
6188 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6189 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6190 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6192 GstElement *decodebin = NULL;
6193 GstCaps *dec_caps = NULL;
6195 /* create decodebin */
6196 decodebin = gst_element_factory_make("decodebin", name);
6199 LOGE("error : fail to create decodebin for %d decoder\n", track);
6204 /* raw pad handling signal */
6205 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6206 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6208 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6209 before looking for any elements that can handle that stream.*/
6210 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6211 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6213 /* This signal is emitted when a element is added to the bin.*/
6214 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6215 G_CALLBACK(__mmplayer_gst_element_added), player);
6217 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6218 LOGE("failed to add new decodebin\n");
6223 dec_caps = gst_pad_query_caps(srcpad, NULL);
6225 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6226 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6227 gst_caps_unref(dec_caps);
6230 player->pipeline->mainbin[elemId].id = elemId;
6231 player->pipeline->mainbin[elemId].gst = decodebin;
6233 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6235 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6236 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6237 gst_object_unref(GST_OBJECT(decodebin));
6240 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6241 LOGE("failed to sync second level decodebin state with parent\n");
6243 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6247 gst_object_unref(GST_OBJECT(sinkpad));
6256 * This function is to create audio or video pipeline for playing.
6258 * @param player [in] handle of player
6260 * @return This function returns zero on success.
6265 __mmplayer_gst_create_pipeline(mm_player_t* player)
6268 MMPlayerGstElement *mainbin = NULL;
6269 MMHandleType attrs = 0;
6270 GstElement* element = NULL;
6271 GstElement* elem_src_audio = NULL;
6272 GstElement* elem_src_subtitle = NULL;
6273 GstElement* es_video_queue = NULL;
6274 GstElement* es_audio_queue = NULL;
6275 GstElement* es_subtitle_queue = NULL;
6276 GList* element_bucket = NULL;
6277 gboolean need_state_holder = TRUE;
6279 #ifdef SW_CODEC_ONLY
6280 int surface_type = 0;
6284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6286 /* get profile attribute */
6287 attrs = MMPLAYER_GET_ATTRS(player);
6289 LOGE("cannot get content attribute\n");
6293 /* create pipeline handles */
6294 if (player->pipeline) {
6295 LOGW("pipeline should be released before create new one\n");
6299 player->video360_metadata.is_spherical = -1;
6300 player->is_openal_plugin_used = FALSE;
6302 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6303 if (player->pipeline == NULL)
6306 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6308 /* create mainbin */
6309 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6310 if (mainbin == NULL)
6313 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6315 /* create pipeline */
6316 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6317 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6318 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6319 LOGE("failed to create pipeline\n");
6322 player->demux_pad_index = 0;
6323 player->subtitle_language_list = NULL;
6325 player->is_subtitle_force_drop = FALSE;
6326 player->last_multiwin_status = FALSE;
6328 _mmplayer_track_initialize(player);
6329 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6331 /* create source element */
6332 switch (player->profile.uri_type) {
6333 /* rtsp streamming */
6334 case MM_PLAYER_URI_TYPE_URL_RTSP:
6338 element = gst_element_factory_make("rtspsrc", "rtsp source");
6341 LOGE("failed to create streaming source element\n");
6349 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6351 SECURE_LOGD("user_agent : %s\n", user_agent);
6353 /* setting property to streaming source */
6354 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6356 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6358 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6359 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6360 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6361 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6366 case MM_PLAYER_URI_TYPE_URL_HTTP:
6368 gchar *user_agent, *cookies, **cookie_list;
6369 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6370 user_agent = cookies = NULL;
6372 gint mode = MM_PLAYER_PD_MODE_NONE;
6374 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6376 player->pd_mode = mode;
6378 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6380 if (!MMPLAYER_IS_HTTP_PD(player)) {
6381 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6383 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6386 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6389 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6390 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6392 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6393 LOGD("get timeout from ini\n");
6394 http_timeout = player->ini.http_timeout;
6398 SECURE_LOGD("location : %s\n", player->profile.uri);
6399 SECURE_LOGD("cookies : %s\n", cookies);
6400 SECURE_LOGD("user_agent : %s\n", user_agent);
6401 LOGD("timeout : %d\n", http_timeout);
6403 /* setting property to streaming source */
6404 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6405 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6406 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6408 /* parsing cookies */
6409 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6410 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6411 g_strfreev(cookie_list);
6414 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6416 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6417 LOGW("it's dash. and it's still experimental feature.");
6419 // progressive download
6420 gchar* location = NULL;
6422 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6425 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6427 MMPLAYER_FREEIF(player->pd_file_save_path);
6429 LOGD("PD Location : %s\n", path);
6432 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6433 LOGE("failed to get storage info");
6436 player->pd_file_save_path = g_strdup(path);
6438 LOGE("can't find pd location so, it should be set \n");
6443 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6445 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6449 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6450 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6452 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6453 g_object_get(element, "location", &location, NULL);
6454 LOGD("PD_LOCATION [%s].\n", location);
6462 case MM_PLAYER_URI_TYPE_FILE:
6464 LOGD("using filesrc for 'file://' handler.\n");
6465 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6466 LOGE("failed to get storage info");
6470 element = gst_element_factory_make("filesrc", "source");
6472 LOGE("failed to create filesrc\n");
6476 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6480 case MM_PLAYER_URI_TYPE_SS:
6482 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6483 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6485 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6489 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6490 LOGD("get timeout from ini\n");
6491 http_timeout = player->ini.http_timeout;
6494 /* setting property to streaming source */
6495 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6496 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6499 case MM_PLAYER_URI_TYPE_MS_BUFF:
6501 LOGD("MS buff src is selected\n");
6503 if (player->v_stream_caps) {
6504 element = gst_element_factory_make("appsrc", "video_appsrc");
6506 LOGF("failed to create video app source element[appsrc].\n");
6510 if (player->a_stream_caps) {
6511 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6512 if (!elem_src_audio) {
6513 LOGF("failed to create audio app source element[appsrc].\n");
6517 } else if (player->a_stream_caps) {
6518 /* no video, only audio pipeline*/
6519 element = gst_element_factory_make("appsrc", "audio_appsrc");
6521 LOGF("failed to create audio app source element[appsrc].\n");
6526 if (player->s_stream_caps) {
6527 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6528 if (!elem_src_subtitle) {
6529 LOGF("failed to create subtitle app source element[appsrc].\n");
6534 LOGD("setting app sources properties.\n");
6535 LOGD("location : %s\n", player->profile.uri);
6537 if (player->v_stream_caps && element) {
6538 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6539 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6540 "caps", player->v_stream_caps, NULL);
6542 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6544 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6545 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6547 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6548 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6549 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6550 G_CALLBACK(__gst_seek_video_data), player);
6552 if (player->a_stream_caps && elem_src_audio) {
6553 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6554 "caps", player->a_stream_caps, NULL);
6556 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6558 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6559 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6561 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6562 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6563 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6564 G_CALLBACK(__gst_seek_audio_data), player);
6566 } else if (player->a_stream_caps && element) {
6567 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6568 "caps", player->a_stream_caps, NULL);
6570 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6572 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6573 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6575 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6576 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6577 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6578 G_CALLBACK(__gst_seek_audio_data), player);
6581 if (player->s_stream_caps && elem_src_subtitle) {
6582 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6583 "caps", player->s_stream_caps, NULL);
6585 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6587 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6588 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6590 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6592 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6593 G_CALLBACK(__gst_seek_subtitle_data), player);
6596 if (player->v_stream_caps && element) {
6597 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6599 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6600 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6602 if (player->a_stream_caps && elem_src_audio) {
6603 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6604 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6605 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6606 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6608 } else if (player->a_stream_caps && element) {
6609 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6611 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6612 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6615 if (player->s_stream_caps && elem_src_subtitle)
6616 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6617 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6619 need_state_holder = FALSE;
6621 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6622 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6623 LOGE("failed to commit\n");
6627 case MM_PLAYER_URI_TYPE_MEM:
6629 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6631 LOGD("mem src is selected\n");
6633 element = gst_element_factory_make("appsrc", "mem-source");
6635 LOGE("failed to create appsrc element\n");
6639 g_object_set(element, "stream-type", stream_type, NULL);
6640 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6641 g_object_set(element, "blocksize", (guint64)20480, NULL);
6643 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6644 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6645 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6646 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6649 case MM_PLAYER_URI_TYPE_URL:
6652 case MM_PLAYER_URI_TYPE_TEMP:
6655 case MM_PLAYER_URI_TYPE_NONE:
6660 /* check source element is OK */
6662 LOGE("no source element was created.\n");
6666 /* take source element */
6667 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6668 mainbin[MMPLAYER_M_SRC].gst = element;
6669 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6671 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6672 player->streamer = __mm_player_streaming_create();
6673 __mm_player_streaming_initialize(player->streamer);
6676 if (MMPLAYER_IS_HTTP_PD(player)) {
6677 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6679 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6680 element = gst_element_factory_make("queue2", "queue2");
6682 LOGE("failed to create http streaming buffer element\n");
6687 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6688 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6689 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6691 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6693 player->streamer->is_pd_mode = TRUE;
6695 __mm_player_streaming_set_queue2(player->streamer,
6698 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6701 player->ini.http_buffering_limit,
6702 MUXED_BUFFER_TYPE_MEM_QUEUE,
6706 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6707 if (player->v_stream_caps) {
6708 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6709 if (!es_video_queue) {
6710 LOGE("create es_video_queue for es player failed\n");
6713 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6714 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6715 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6716 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6718 /* Adding audio appsrc to bucket */
6719 if (player->a_stream_caps && elem_src_audio) {
6720 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6721 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6722 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6724 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6725 if (!es_audio_queue) {
6726 LOGE("create es_audio_queue for es player failed\n");
6729 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6731 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6732 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6733 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6735 } else if (player->a_stream_caps) {
6736 /* Only audio stream, no video */
6737 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6738 if (!es_audio_queue) {
6739 LOGE("create es_audio_queue for es player failed\n");
6742 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6743 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6744 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6747 if (player->s_stream_caps && elem_src_subtitle) {
6748 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6749 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6750 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6752 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6753 if (!es_subtitle_queue) {
6754 LOGE("create es_subtitle_queue for es player failed\n");
6757 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6758 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6759 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6763 /* create autoplugging element if src element is not a rtsp src */
6764 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6765 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6767 enum MainElementID elemId = MMPLAYER_M_NUM;
6769 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6770 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6771 elemId = MMPLAYER_M_AUTOPLUG;
6772 element = __mmplayer_create_decodebin(player);
6774 /* default size of mq in decodebin is 2M
6775 * but it can cause blocking issue during seeking depends on content. */
6776 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6778 need_state_holder = FALSE;
6780 elemId = MMPLAYER_M_TYPEFIND;
6781 element = gst_element_factory_make("typefind", "typefinder");
6782 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6783 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6786 /* check autoplug element is OK */
6788 LOGE("can not create element(%d)\n", elemId);
6792 mainbin[elemId].id = elemId;
6793 mainbin[elemId].gst = element;
6795 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6798 /* add elements to pipeline */
6799 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6800 LOGE("Failed to add elements to pipeline\n");
6805 /* linking elements in the bucket by added order. */
6806 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6807 LOGE("Failed to link some elements\n");
6812 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6813 if (need_state_holder) {
6815 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6816 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6818 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6819 LOGE("fakesink element could not be created\n");
6822 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6824 /* take ownership of fakesink. we are reusing it */
6825 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6828 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6829 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6830 LOGE("failed to add fakesink to bin\n");
6835 /* now we have completed mainbin. take it */
6836 player->pipeline->mainbin = mainbin;
6838 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6839 GstPad *srcpad = NULL;
6841 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6842 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6844 __mmplayer_gst_create_decoder(player,
6845 MM_PLAYER_TRACK_TYPE_VIDEO,
6847 MMPLAYER_M_AUTOPLUG_V_DEC,
6850 gst_object_unref(GST_OBJECT(srcpad));
6855 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6856 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6858 __mmplayer_gst_create_decoder(player,
6859 MM_PLAYER_TRACK_TYPE_AUDIO,
6861 MMPLAYER_M_AUTOPLUG_A_DEC,
6864 gst_object_unref(GST_OBJECT(srcpad));
6869 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6870 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6873 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6874 if (__mmplayer_check_subtitle(player)) {
6875 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6876 LOGE("fail to create text pipeline");
6879 /* connect bus callback */
6880 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6882 LOGE("cannot get bus from pipeline.\n");
6886 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6888 player->context.thread_default = g_main_context_get_thread_default();
6890 if (player->context.thread_default == NULL) {
6891 player->context.thread_default = g_main_context_default();
6892 LOGD("thread-default context is the global default context");
6894 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6896 /* set sync handler to get tag synchronously */
6897 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6900 gst_object_unref(GST_OBJECT(bus));
6901 g_list_free(element_bucket);
6903 /* create gst bus_msb_cb thread */
6904 g_mutex_init(&player->bus_msg_thread_mutex);
6905 g_cond_init(&player->bus_msg_thread_cond);
6906 player->bus_msg_thread_exit = FALSE;
6907 player->bus_msg_thread =
6908 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6909 if (!player->bus_msg_thread) {
6910 LOGE("failed to create gst BUS msg thread");
6911 g_mutex_clear(&player->bus_msg_thread_mutex);
6912 g_cond_clear(&player->bus_msg_thread_cond);
6918 return MM_ERROR_NONE;
6921 __mmplayer_gst_destroy_pipeline(player);
6922 g_list_free(element_bucket);
6925 /* release element which are not added to bin */
6926 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6927 /* NOTE : skip pipeline */
6928 if (mainbin[i].gst) {
6929 GstObject* parent = NULL;
6930 parent = gst_element_get_parent(mainbin[i].gst);
6933 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6934 mainbin[i].gst = NULL;
6936 gst_object_unref(GST_OBJECT(parent));
6940 /* release pipeline with it's childs */
6941 if (mainbin[MMPLAYER_M_PIPE].gst)
6942 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6944 MMPLAYER_FREEIF(mainbin);
6947 MMPLAYER_FREEIF(player->pipeline);
6948 return MM_ERROR_PLAYER_INTERNAL;
6952 __mmplayer_reset_gapless_state(mm_player_t* player)
6955 MMPLAYER_RETURN_IF_FAIL(player
6957 && player->pipeline->audiobin
6958 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6960 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6967 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6970 int ret = MM_ERROR_NONE;
6974 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6976 /* cleanup stuffs */
6977 MMPLAYER_FREEIF(player->type);
6978 player->have_dynamic_pad = FALSE;
6979 player->no_more_pad = FALSE;
6980 player->num_dynamic_pad = 0;
6981 player->demux_pad_index = 0;
6982 player->use_deinterleave = FALSE;
6983 player->max_audio_channels = 0;
6984 player->video_share_api_delta = 0;
6985 player->video_share_clock_delta = 0;
6986 player->video_hub_download_mode = 0;
6988 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6989 player->subtitle_language_list = NULL;
6990 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6992 __mmplayer_reset_gapless_state(player);
6994 if (player->streamer) {
6995 __mm_player_streaming_deinitialize(player->streamer);
6996 __mm_player_streaming_destroy(player->streamer);
6997 player->streamer = NULL;
7000 /* cleanup unlinked mime type */
7001 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7002 MMPLAYER_FREEIF(player->unlinked_video_mime);
7003 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7005 /* cleanup running stuffs */
7006 __mmplayer_cancel_eos_timer(player);
7008 /* cleanup gst stuffs */
7009 if (player->pipeline) {
7010 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7011 GstTagList* tag_list = player->pipeline->tag_list;
7013 /* first we need to disconnect all signal hander */
7014 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7017 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7018 MMPlayerGstElement* videobin = player->pipeline->videobin;
7019 MMPlayerGstElement* textbin = player->pipeline->textbin;
7020 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7021 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7022 gst_object_unref(bus);
7024 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7025 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7026 if (ret != MM_ERROR_NONE) {
7027 LOGE("fail to change state to NULL\n");
7028 return MM_ERROR_PLAYER_INTERNAL;
7031 LOGW("succeeded in chaning state to NULL\n");
7033 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7036 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7037 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7039 /* free avsysaudiosink
7040 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7041 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7043 MMPLAYER_FREEIF(audiobin);
7044 MMPLAYER_FREEIF(videobin);
7045 MMPLAYER_FREEIF(textbin);
7046 MMPLAYER_FREEIF(mainbin);
7050 gst_tag_list_free(tag_list);
7052 MMPLAYER_FREEIF(player->pipeline);
7054 MMPLAYER_FREEIF(player->album_art);
7056 if (player->v_stream_caps) {
7057 gst_caps_unref(player->v_stream_caps);
7058 player->v_stream_caps = NULL;
7060 if (player->a_stream_caps) {
7061 gst_caps_unref(player->a_stream_caps);
7062 player->a_stream_caps = NULL;
7065 if (player->s_stream_caps) {
7066 gst_caps_unref(player->s_stream_caps);
7067 player->s_stream_caps = NULL;
7069 _mmplayer_track_destroy(player);
7071 if (player->sink_elements)
7072 g_list_free(player->sink_elements);
7073 player->sink_elements = NULL;
7075 if (player->bufmgr) {
7076 tbm_bufmgr_deinit(player->bufmgr);
7077 player->bufmgr = NULL;
7080 LOGW("finished destroy pipeline\n");
7087 static void __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
7089 MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
7091 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
7093 audiobin = player->pipeline->audiobin; /* can be null */
7094 videobin = player->pipeline->videobin; /* can be null */
7095 textbin = player->pipeline->textbin; /* can be null */
7097 LOGD("Async will be set to %d about 0x%X type sink", async, type);
7099 if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
7100 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
7102 if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
7103 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
7105 if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
7106 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
7111 static int __gst_realize(mm_player_t* player)
7114 int ret = MM_ERROR_NONE;
7118 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7120 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7122 ret = __mmplayer_gst_create_pipeline(player);
7124 LOGE("failed to create pipeline\n");
7128 /* set pipeline state to READY */
7129 /* NOTE : state change to READY must be performed sync. */
7130 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7131 ret = __mmplayer_gst_set_state(player,
7132 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7134 if (ret != MM_ERROR_NONE) {
7135 /* return error if failed to set state */
7136 LOGE("failed to set READY state");
7140 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7142 /* create dot before error-return. for debugging */
7143 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7150 static int __gst_unrealize(mm_player_t* player)
7152 int ret = MM_ERROR_NONE;
7156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7158 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7159 MMPLAYER_PRINT_STATE(player);
7161 /* release miscellaneous information */
7162 __mmplayer_release_misc(player);
7164 /* destroy pipeline */
7165 ret = __mmplayer_gst_destroy_pipeline(player);
7166 if (ret != MM_ERROR_NONE) {
7167 LOGE("failed to destory pipeline\n");
7171 /* release miscellaneous information.
7172 these info needs to be released after pipeline is destroyed. */
7173 __mmplayer_release_misc_post(player);
7175 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7182 static int __gst_pending_seek(mm_player_t* player)
7184 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7185 int ret = MM_ERROR_NONE;
7189 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7191 if (!player->pending_seek.is_pending) {
7192 LOGD("pending seek is not reserved. nothing to do.\n");
7196 /* check player state if player could pending seek or not. */
7197 current_state = MMPLAYER_CURRENT_STATE(player);
7199 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7200 LOGW("try to pending seek in %s state, try next time. \n",
7201 MMPLAYER_STATE_GET_NAME(current_state));
7205 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7207 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7209 if (MM_ERROR_NONE != ret)
7210 LOGE("failed to seek pending postion. just keep staying current position.\n");
7212 player->pending_seek.is_pending = FALSE;
7219 static int __gst_start(mm_player_t* player)
7221 int ret = MM_ERROR_NONE;
7222 gboolean async = FALSE;
7226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7228 /* NOTE : if SetPosition was called before Start. do it now */
7229 /* streaming doesn't support it. so it should be always sync */
7230 /* !!create one more api to check if there is pending seek rather than checking variables */
7231 if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
7232 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7233 ret = __gst_pause(player, FALSE);
7234 if (ret != MM_ERROR_NONE) {
7235 LOGE("failed to set state to PAUSED for pending seek");
7239 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7240 if (__gst_pending_seek(player) != MM_ERROR_NONE)
7241 LOGW("failed to seek pending postion. starting from the begin of content");
7244 LOGD("current state before doing transition");
7245 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7246 MMPLAYER_PRINT_STATE(player);
7248 /* set pipeline state to PLAYING */
7249 ret = __mmplayer_gst_set_state(player,
7250 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7252 if (ret == MM_ERROR_NONE) {
7253 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7255 LOGE("failed to set state to PLAYING");
7259 /* generating debug info before returning error */
7260 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7267 static int __gst_stop(mm_player_t* player)
7269 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7270 MMHandleType attrs = 0;
7271 gboolean rewind = FALSE;
7273 int ret = MM_ERROR_NONE;
7277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7280 LOGD("current state before doing transition");
7281 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7282 MMPLAYER_PRINT_STATE(player);
7284 attrs = MMPLAYER_GET_ATTRS(player);
7286 LOGE("cannot get content attribute\n");
7287 return MM_ERROR_PLAYER_INTERNAL;
7290 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7291 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7293 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7294 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7297 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7298 /* disable the async state transition because there could be no data in the pipeline */
7299 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
7303 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
7305 if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
7306 /* enable the async state transition as default operation */
7307 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
7310 /* return if set_state has failed */
7311 if (ret != MM_ERROR_NONE) {
7312 LOGE("failed to set state.\n");
7318 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7319 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7320 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7321 LOGW("failed to rewind\n");
7322 ret = MM_ERROR_PLAYER_SEEK;
7327 player->sent_bos = FALSE;
7329 if (player->es_player_push_mode) //for cloudgame
7332 /* wait for seek to complete */
7333 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7334 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7335 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7337 LOGE("fail to stop player.\n");
7338 ret = MM_ERROR_PLAYER_INTERNAL;
7339 __mmplayer_dump_pipeline_state(player);
7342 /* generate dot file if enabled */
7343 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7350 int __gst_pause(mm_player_t* player, gboolean async)
7352 int ret = MM_ERROR_NONE;
7356 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7357 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7359 LOGD("current state before doing transition");
7360 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7361 MMPLAYER_PRINT_STATE(player);
7363 /* set pipeline status to PAUSED */
7364 ret = __mmplayer_gst_set_state(player,
7365 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7367 if (FALSE == async) {
7368 if (ret != MM_ERROR_NONE) {
7369 GstMessage *msg = NULL;
7370 GTimer *timer = NULL;
7371 gdouble MAX_TIMEOUT_SEC = 3;
7373 LOGE("failed to set state to PAUSED");
7375 if (player->msg_posted) {
7376 LOGE("error msg is already posted.");
7380 timer = g_timer_new();
7381 g_timer_start(timer);
7383 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7386 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7388 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7389 GError *error = NULL;
7391 /* parse error code */
7392 gst_message_parse_error(msg, &error, NULL);
7394 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7395 /* Note : the streaming error from the streaming source is handled
7396 * using __mmplayer_handle_streaming_error.
7398 __mmplayer_handle_streaming_error(player, msg);
7401 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7403 if (error->domain == GST_STREAM_ERROR)
7404 ret = __gst_handle_stream_error(player, error, msg);
7405 else if (error->domain == GST_RESOURCE_ERROR)
7406 ret = __gst_handle_resource_error(player, error->code, NULL);
7407 else if (error->domain == GST_LIBRARY_ERROR)
7408 ret = __gst_handle_library_error(player, error->code);
7409 else if (error->domain == GST_CORE_ERROR)
7410 ret = __gst_handle_core_error(player, error->code);
7412 g_error_free(error);
7414 player->msg_posted = TRUE;
7416 gst_message_unref(msg);
7418 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7420 gst_object_unref(bus);
7421 g_timer_stop(timer);
7422 g_timer_destroy(timer);
7426 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7427 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7429 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7431 } else if (ret == MM_ERROR_NONE) {
7433 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7437 /* generate dot file before returning error */
7438 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7445 int __gst_resume(mm_player_t* player, gboolean async)
7447 int ret = MM_ERROR_NONE;
7452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7453 MM_ERROR_PLAYER_NOT_INITIALIZED);
7455 LOGD("current state before doing transition");
7456 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7457 MMPLAYER_PRINT_STATE(player);
7460 LOGD("do async state transition to PLAYING");
7462 /* set pipeline state to PLAYING */
7463 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7465 ret = __mmplayer_gst_set_state(player,
7466 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7467 if (ret != MM_ERROR_NONE) {
7468 LOGE("failed to set state to PLAYING");
7472 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7476 /* generate dot file */
7477 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7485 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7487 gint64 dur_nsec = 0;
7488 gint64 pos_nsec = 0;
7489 gboolean ret = TRUE;
7490 gboolean accurated = FALSE;
7491 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7494 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7495 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7497 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7498 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7501 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7502 /* check duration */
7503 /* NOTE : duration cannot be zero except live streaming.
7504 * Since some element could have some timing problemn with quering duration, try again.
7506 if (player->duration == 0) {
7507 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7508 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7509 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7510 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7511 player->pending_seek.is_pending = TRUE;
7512 player->pending_seek.format = format;
7513 player->pending_seek.pos = position;
7514 player->seek_state = MMPLAYER_SEEK_NONE;
7515 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7516 return MM_ERROR_NONE;
7521 player->duration = dur_nsec;
7524 LOGD("playback rate: %f\n", player->playback_rate);
7526 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7528 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7530 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7534 case MM_PLAYER_POS_FORMAT_TIME:
7536 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7537 GstQuery *query = NULL;
7538 gboolean seekable = FALSE;
7540 /* check position is valid or not */
7541 if (position > player->duration)
7544 query = gst_query_new_seeking(GST_FORMAT_TIME);
7545 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7546 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7547 gst_query_unref(query);
7550 LOGW("non-seekable content");
7551 player->seek_state = MMPLAYER_SEEK_NONE;
7552 return MM_ERROR_PLAYER_NO_OP;
7555 LOGW("failed to get seeking query");
7556 gst_query_unref(query); /* keep seeking operation */
7559 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7561 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7562 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7563 This causes problem is position calculation during normal pause resume scenarios also.
7564 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7565 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7566 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7567 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7568 LOGW("getting current position failed in seek\n");
7570 player->last_position = pos_nsec;
7571 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7574 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7575 LOGD("not completed seek");
7576 return MM_ERROR_PLAYER_DOING_SEEK;
7580 if (!internal_called)
7581 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7583 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7584 gint64 cur_time = 0;
7586 /* get current position */
7587 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7590 GstEvent *event = gst_event_new_seek(1.0,
7592 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7593 GST_SEEK_TYPE_SET, cur_time,
7594 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7596 __gst_send_event_to_sink(player, event);
7598 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7599 __gst_pause(player, FALSE);
7602 pos_nsec = position;
7604 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7605 that's why set position through property. */
7606 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7607 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7608 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7609 (!player->videodec_linked) && (!player->audiodec_linked)) {
7611 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7612 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7613 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7614 player->seek_state = MMPLAYER_SEEK_NONE;
7615 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7617 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7618 GST_FORMAT_TIME, seek_flags,
7619 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7623 LOGE("failed to set position.");
7629 case MM_PLAYER_POS_FORMAT_PERCENT:
7631 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7633 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7634 LOGD("not completed seek");
7635 return MM_ERROR_PLAYER_DOING_SEEK;
7638 if (!internal_called)
7639 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7641 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7642 pos_nsec = (gint64)((position * player->duration) / 100);
7643 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7644 GST_FORMAT_TIME, seek_flags,
7645 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7647 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7657 /* NOTE : store last seeking point to overcome some bad operation
7658 * (returning zero when getting current position) of some elements
7660 player->last_position = pos_nsec;
7662 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7663 if (player->playback_rate > 1.0)
7664 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7666 if ((!internal_called) &&
7667 (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7668 LOGD("buffering should be reset after seeking");
7669 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7670 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
7674 return MM_ERROR_NONE;
7677 player->pending_seek.is_pending = TRUE;
7678 player->pending_seek.format = format;
7679 player->pending_seek.pos = position;
7681 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7682 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7683 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7684 player->pending_seek.pos);
7686 return MM_ERROR_NONE;
7689 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7690 return MM_ERROR_INVALID_ARGUMENT;
7693 player->seek_state = MMPLAYER_SEEK_NONE;
7694 return MM_ERROR_PLAYER_SEEK;
7697 #define TRICKPLAY_OFFSET GST_MSECOND
7700 __gst_get_position(mm_player_t* player, int format, gint64* position)
7702 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7703 gint64 pos_nsec = 0;
7704 gboolean ret = TRUE;
7706 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7707 MM_ERROR_PLAYER_NOT_INITIALIZED);
7709 current_state = MMPLAYER_CURRENT_STATE(player);
7711 /* NOTE : query position except paused state to overcome some bad operation
7712 * please refer to below comments in details
7714 if (current_state != MM_PLAYER_STATE_PAUSED)
7715 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7717 /* NOTE : get last point to overcome some bad operation of some elements
7718 *(returning zero when getting current position in paused state
7719 * and when failed to get postion during seeking
7721 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7722 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7724 if (player->playback_rate < 0.0)
7725 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7727 pos_nsec = player->last_position;
7730 pos_nsec = player->last_position;
7732 player->last_position = pos_nsec;
7734 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7737 if (player->duration > 0 && pos_nsec > player->duration)
7738 pos_nsec = player->duration;
7740 player->last_position = pos_nsec;
7744 case MM_PLAYER_POS_FORMAT_TIME:
7745 *position = pos_nsec;
7748 case MM_PLAYER_POS_FORMAT_PERCENT:
7750 if (player->duration <= 0) {
7751 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7754 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7755 *position = (gint64)(pos_nsec * 100 / player->duration);
7760 return MM_ERROR_PLAYER_INTERNAL;
7763 return MM_ERROR_NONE;
7767 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7769 #define STREAMING_IS_FINISHED 0
7770 #define BUFFERING_MAX_PER 100
7771 #define DEFAULT_PER_VALUE -1
7772 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7774 MMPlayerGstElement *mainbin = NULL;
7775 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7776 gint64 buffered_total = 0;
7777 gint64 position = 0;
7778 gint buffered_sec = -1;
7779 GstBufferingMode mode = GST_BUFFERING_STREAM;
7780 gint64 content_size_time = player->duration;
7781 guint64 content_size_bytes = player->http_content_size;
7783 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7785 player->pipeline->mainbin,
7786 MM_ERROR_PLAYER_NOT_INITIALIZED);
7788 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7793 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7794 /* and rtsp is not ready yet. */
7795 LOGW("it's only used for http streaming case.\n");
7796 return MM_ERROR_PLAYER_NO_OP;
7799 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7800 LOGW("Time format is not supported yet.\n");
7801 return MM_ERROR_INVALID_ARGUMENT;
7804 if (content_size_time <= 0 || content_size_bytes <= 0) {
7805 LOGW("there is no content size.");
7806 return MM_ERROR_NONE;
7809 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7810 LOGW("fail to get current position.");
7811 return MM_ERROR_NONE;
7814 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7815 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7817 mainbin = player->pipeline->mainbin;
7818 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7820 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7821 GstQuery *query = NULL;
7822 gint byte_in_rate = 0, byte_out_rate = 0;
7823 gint64 estimated_total = 0;
7825 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7826 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7827 LOGW("fail to get buffering query from queue2");
7829 gst_query_unref(query);
7830 return MM_ERROR_NONE;
7833 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7834 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7836 if (mode == GST_BUFFERING_STREAM) {
7837 /* using only queue in case of push mode(ts / mp3) */
7838 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7839 GST_FORMAT_BYTES, &buffered_total)) {
7840 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7841 stop_per = 100 * buffered_total / content_size_bytes;
7844 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7846 guint num_of_ranges = 0;
7847 gint64 start_byte = 0, stop_byte = 0;
7849 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7850 if (estimated_total != STREAMING_IS_FINISHED) {
7851 /* buffered size info from queue2 */
7852 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7853 for (idx = 0; idx < num_of_ranges; idx++) {
7854 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7855 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7857 buffered_total += (stop_byte - start_byte);
7860 stop_per = BUFFERING_MAX_PER;
7862 gst_query_unref(query);
7865 if (stop_per == DEFAULT_PER_VALUE) {
7866 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7868 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7870 /* buffered size info from multiqueue */
7871 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7872 guint curr_size_bytes = 0;
7873 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7874 "curr-size-bytes", &curr_size_bytes, NULL);
7875 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7876 buffered_total += curr_size_bytes;
7879 if (avg_byterate > 0)
7880 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7881 else if (player->total_maximum_bitrate > 0)
7882 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7883 else if (player->total_bitrate > 0)
7884 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7886 if (buffered_sec >= 0)
7887 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7891 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7892 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7894 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7895 buffered_total, buffered_sec, *start_pos, *stop_pos);
7897 return MM_ERROR_NONE;
7901 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7906 LOGW("set_message_callback is called with invalid player handle\n");
7907 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7910 player->msg_cb = callback;
7911 player->msg_cb_param = user_param;
7913 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7917 return MM_ERROR_NONE;
7920 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7922 int ret = MM_ERROR_PLAYER_INVALID_URI;
7927 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7928 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7929 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7931 memset(data, 0, sizeof(MMPlayerParseProfile));
7933 if ((path = strstr(uri, "es_buff://"))) {
7935 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7936 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7937 ret = MM_ERROR_NONE;
7939 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7941 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7942 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7943 ret = MM_ERROR_NONE;
7945 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7948 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7949 tmp = g_ascii_strdown(uri, strlen(uri));
7951 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7952 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7954 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7956 ret = MM_ERROR_NONE;
7959 } else if ((path = strstr(uri, "rtspu://"))) {
7961 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7962 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7963 ret = MM_ERROR_NONE;
7965 } else if ((path = strstr(uri, "rtspr://"))) {
7966 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7967 char *separater = strstr(path, "*");
7971 char *urgent = separater + strlen("*");
7973 if ((urgent_len = strlen(urgent))) {
7974 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7975 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7976 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7977 ret = MM_ERROR_NONE;
7980 } else if ((path = strstr(uri, "mms://"))) {
7982 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7983 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7984 ret = MM_ERROR_NONE;
7986 } else if ((path = strstr(uri, "mem://"))) {
7989 char *buffer = NULL;
7990 char *seperator = strchr(path, ',');
7991 char ext[100] = {0,}, size[100] = {0,};
7994 if ((buffer = strstr(path, "ext="))) {
7995 buffer += strlen("ext=");
7997 if (strlen(buffer)) {
7998 strncpy(ext, buffer, 99);
8000 if ((seperator = strchr(ext, ','))
8001 || (seperator = strchr(ext, ' '))
8002 || (seperator = strchr(ext, '\0'))) {
8003 seperator[0] = '\0';
8008 if ((buffer = strstr(path, "size="))) {
8009 buffer += strlen("size=");
8011 if (strlen(buffer) > 0) {
8012 strncpy(size, buffer, 99);
8014 if ((seperator = strchr(size, ','))
8015 || (seperator = strchr(size, ' '))
8016 || (seperator = strchr(size, '\0'))) {
8017 seperator[0] = '\0';
8020 mem_size = atoi(size);
8025 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8026 if (mem_size && param) {
8027 if (data->input_mem.buf)
8028 free(data->input_mem.buf);
8029 data->input_mem.buf = malloc(mem_size);
8031 if (data->input_mem.buf) {
8032 memcpy(data->input_mem.buf, param, mem_size);
8033 data->input_mem.len = mem_size;
8034 ret = MM_ERROR_NONE;
8036 LOGE("failed to alloc mem %d", mem_size);
8037 ret = MM_ERROR_PLAYER_INTERNAL;
8040 data->input_mem.offset = 0;
8041 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8045 gchar *location = NULL;
8048 if ((path = strstr(uri, "file://"))) {
8050 location = g_filename_from_uri(uri, NULL, &err);
8052 if (!location || (err != NULL)) {
8053 LOGE("Invalid URI '%s' for filesrc: %s", path,
8054 (err != NULL) ? err->message : "unknown error");
8056 if (err) g_error_free(err);
8057 if (location) g_free(location);
8059 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8063 LOGD("path from uri: %s", location);
8066 path = (location != NULL) ? (location) : ((char*)uri);
8067 int file_stat = MM_ERROR_NONE;
8069 file_stat = util_exist_file_path(path);
8071 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8072 if (file_stat == MM_ERROR_NONE) {
8073 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8075 if (util_is_sdp_file(path)) {
8076 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8077 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8079 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8081 ret = MM_ERROR_NONE;
8082 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8083 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8085 LOGE("invalid uri, could not play..\n");
8086 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8089 if (location) g_free(location);
8093 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8094 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8095 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8096 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8098 /* dump parse result */
8099 SECURE_LOGW("incomming uri : %s\n", uri);
8100 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8101 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8109 __mmplayer_can_do_interrupt(mm_player_t *player)
8111 if (!player || !player->pipeline || !player->attrs) {
8112 LOGW("not initialized");
8116 if (player->set_mode.pcm_extraction) {
8117 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8121 /* check if seeking */
8122 if (player->seek_state != MMPLAYER_SEEK_NONE) {
8123 MMMessageParamType msg_param;
8124 memset(&msg_param, 0, sizeof(MMMessageParamType));
8125 msg_param.code = MM_ERROR_PLAYER_SEEK;
8126 player->seek_state = MMPLAYER_SEEK_NONE;
8127 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8131 /* check other thread */
8132 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8133 LOGW("locked already, cmd state : %d", player->cmd);
8135 /* check application command */
8136 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8137 LOGW("playing.. should wait cmd lock then, will be interrupted");
8139 /* lock will be released at mrp_resource_release_cb() */
8140 MMPLAYER_CMD_LOCK(player);
8143 LOGW("nothing to do");
8146 LOGW("can interrupt immediately");
8150 FAILED: /* with CMD UNLOCKED */
8153 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8158 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8161 mm_player_t *player = NULL;
8165 if (user_data == NULL) {
8166 LOGE("- user_data is null\n");
8169 player = (mm_player_t *)user_data;
8171 /* do something to release resource here.
8172 * player stop and interrupt forwarding */
8173 if (!__mmplayer_can_do_interrupt(player)) {
8174 LOGW("no need to interrupt, so leave");
8176 MMMessageParamType msg = {0, };
8179 player->interrupted_by_resource = TRUE;
8181 /* get last play position */
8182 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8183 LOGW("failed to get play position.");
8185 msg.union_type = MM_MSG_UNION_TIME;
8186 msg.time.elapsed = pos;
8187 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8189 LOGD("video resource conflict so, resource will be freed by unrealizing");
8190 if (_mmplayer_unrealize((MMHandleType)player))
8191 LOGW("failed to unrealize");
8193 /* lock is called in __mmplayer_can_do_interrupt() */
8194 MMPLAYER_CMD_UNLOCK(player);
8197 if (res == player->video_overlay_resource)
8198 player->video_overlay_resource = FALSE;
8200 player->video_decoder_resource = FALSE;
8208 _mmplayer_create_player(MMHandleType handle)
8210 int ret = MM_ERROR_PLAYER_INTERNAL;
8211 bool enabled = false;
8213 mm_player_t* player = MM_PLAYER_CAST(handle);
8217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8219 /* initialize player state */
8220 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8221 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8222 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8223 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8225 /* check current state */
8226 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8228 /* construct attributes */
8229 player->attrs = _mmplayer_construct_attribute(handle);
8231 if (!player->attrs) {
8232 LOGE("Failed to construct attributes\n");
8236 /* initialize gstreamer with configured parameter */
8237 if (!__mmplayer_init_gstreamer(player)) {
8238 LOGE("Initializing gstreamer failed\n");
8239 _mmplayer_deconstruct_attribute(handle);
8243 /* create lock. note that g_tread_init() has already called in gst_init() */
8244 g_mutex_init(&player->fsink_lock);
8246 /* create update tag lock */
8247 g_mutex_init(&player->update_tag_lock);
8249 /* create next play mutex */
8250 g_mutex_init(&player->next_play_thread_mutex);
8252 /* create next play cond */
8253 g_cond_init(&player->next_play_thread_cond);
8255 /* create next play thread */
8256 player->next_play_thread =
8257 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8258 if (!player->next_play_thread) {
8259 LOGE("failed to create next play thread");
8260 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8261 g_mutex_clear(&player->next_play_thread_mutex);
8262 g_cond_clear(&player->next_play_thread_cond);
8266 player->bus_msg_q = g_queue_new();
8267 if (!player->bus_msg_q) {
8268 LOGE("failed to create queue for bus_msg");
8269 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8273 ret = _mmplayer_initialize_video_capture(player);
8274 if (ret != MM_ERROR_NONE) {
8275 LOGE("failed to initialize video capture\n");
8279 /* initialize resource manager */
8280 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8281 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8282 &player->resource_manager)) {
8283 LOGE("failed to initialize resource manager\n");
8287 if (MMPLAYER_IS_HTTP_PD(player)) {
8288 player->pd_downloader = NULL;
8289 player->pd_file_save_path = NULL;
8292 /* create video bo lock and cond */
8293 g_mutex_init(&player->video_bo_mutex);
8294 g_cond_init(&player->video_bo_cond);
8296 /* create media stream callback mutex */
8297 g_mutex_init(&player->media_stream_cb_lock);
8299 /* create subtitle info lock and cond */
8300 g_mutex_init(&player->subtitle_info_mutex);
8301 g_cond_init(&player->subtitle_info_cond);
8303 player->streaming_type = STREAMING_SERVICE_NONE;
8305 /* give default value of audio effect setting */
8306 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8307 player->sound.rg_enable = false;
8308 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8310 player->play_subtitle = FALSE;
8311 player->use_deinterleave = FALSE;
8312 player->max_audio_channels = 0;
8313 player->video_share_api_delta = 0;
8314 player->video_share_clock_delta = 0;
8315 player->has_closed_caption = FALSE;
8316 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8317 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8318 player->pending_resume = FALSE;
8319 if (player->ini.dump_element_keyword[0][0] == '\0')
8320 player->ini.set_dump_element_flag = FALSE;
8322 player->ini.set_dump_element_flag = TRUE;
8324 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8325 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8326 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8328 /* Set video360 settings to their defaults for just-created player.
8331 player->is_360_feature_enabled = FALSE;
8332 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8333 LOGI("spherical feature info: %d", enabled);
8335 player->is_360_feature_enabled = TRUE;
8337 LOGE("failed to get spherical feature info");
8340 player->is_content_spherical = FALSE;
8341 player->is_video360_enabled = TRUE;
8342 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8343 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8344 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8345 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8346 player->video360_zoom = 1.0f;
8347 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8348 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8350 /* set player state to null */
8351 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8352 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8354 return MM_ERROR_NONE;
8358 g_mutex_clear(&player->fsink_lock);
8360 /* free update tag lock */
8361 g_mutex_clear(&player->update_tag_lock);
8363 g_queue_free(player->bus_msg_q);
8365 /* free next play thread */
8366 if (player->next_play_thread) {
8367 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8368 player->next_play_thread_exit = TRUE;
8369 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8370 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8372 g_thread_join(player->next_play_thread);
8373 player->next_play_thread = NULL;
8375 g_mutex_clear(&player->next_play_thread_mutex);
8376 g_cond_clear(&player->next_play_thread_cond);
8379 /* release attributes */
8380 _mmplayer_deconstruct_attribute(handle);
8388 __mmplayer_init_gstreamer(mm_player_t* player)
8390 static gboolean initialized = FALSE;
8391 static const int max_argc = 50;
8393 gchar** argv = NULL;
8394 gchar** argv2 = NULL;
8400 LOGD("gstreamer already initialized.\n");
8405 argc = malloc(sizeof(int));
8406 argv = malloc(sizeof(gchar*) * max_argc);
8407 argv2 = malloc(sizeof(gchar*) * max_argc);
8409 if (!argc || !argv || !argv2)
8412 memset(argv, 0, sizeof(gchar*) * max_argc);
8413 memset(argv2, 0, sizeof(gchar*) * max_argc);
8417 argv[0] = g_strdup("mmplayer");
8420 for (i = 0; i < 5; i++) {
8421 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8422 if (strlen(player->ini.gst_param[i]) > 0) {
8423 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8428 /* we would not do fork for scanning plugins */
8429 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8432 /* check disable registry scan */
8433 if (player->ini.skip_rescan) {
8434 argv[*argc] = g_strdup("--gst-disable-registry-update");
8438 /* check disable segtrap */
8439 if (player->ini.disable_segtrap) {
8440 argv[*argc] = g_strdup("--gst-disable-segtrap");
8444 LOGD("initializing gstreamer with following parameter\n");
8445 LOGD("argc : %d\n", *argc);
8448 for (i = 0; i < arg_count; i++) {
8450 LOGD("argv[%d] : %s\n", i, argv2[i]);
8453 /* initializing gstreamer */
8454 if (!gst_init_check(argc, &argv, &err)) {
8455 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8462 for (i = 0; i < arg_count; i++) {
8463 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8464 MMPLAYER_FREEIF(argv2[i]);
8467 MMPLAYER_FREEIF(argv);
8468 MMPLAYER_FREEIF(argv2);
8469 MMPLAYER_FREEIF(argc);
8479 for (i = 0; i < arg_count; i++) {
8480 LOGD("free[%d] : %s\n", i, argv2[i]);
8481 MMPLAYER_FREEIF(argv2[i]);
8484 MMPLAYER_FREEIF(argv);
8485 MMPLAYER_FREEIF(argv2);
8486 MMPLAYER_FREEIF(argc);
8492 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8496 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8497 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8498 MMPLAYER_FREEIF(player->pd_file_save_path);
8501 return MM_ERROR_NONE;
8505 __mmplayer_check_async_state_transition(mm_player_t* player)
8507 GstState element_state = GST_STATE_VOID_PENDING;
8508 GstState element_pending_state = GST_STATE_VOID_PENDING;
8509 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8510 GstElement * element = NULL;
8511 gboolean async = FALSE;
8513 /* check player handle */
8514 MMPLAYER_RETURN_IF_FAIL(player &&
8516 player->pipeline->mainbin &&
8517 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8520 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8522 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8523 LOGD("don't need to check the pipeline state");
8527 MMPLAYER_PRINT_STATE(player);
8529 /* wait for state transition */
8530 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8531 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8533 if (ret == GST_STATE_CHANGE_FAILURE) {
8534 LOGE(" [%s] state : %s pending : %s \n",
8535 GST_ELEMENT_NAME(element),
8536 gst_element_state_get_name(element_state),
8537 gst_element_state_get_name(element_pending_state));
8539 /* dump state of all element */
8540 __mmplayer_dump_pipeline_state(player);
8545 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8550 _mmplayer_destroy(MMHandleType handle)
8552 mm_player_t* player = MM_PLAYER_CAST(handle);
8556 /* check player handle */
8557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8559 /* destroy can called at anytime */
8560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8562 /* check async state transition */
8563 __mmplayer_check_async_state_transition(player);
8565 __mmplayer_destroy_streaming_ext(player);
8567 /* release next play thread */
8568 if (player->next_play_thread) {
8569 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8570 player->next_play_thread_exit = TRUE;
8571 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8572 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8574 LOGD("waitting for next play thread exit\n");
8575 g_thread_join(player->next_play_thread);
8576 g_mutex_clear(&player->next_play_thread_mutex);
8577 g_cond_clear(&player->next_play_thread_cond);
8578 LOGD("next play thread released\n");
8581 _mmplayer_release_video_capture(player);
8583 /* de-initialize resource manager */
8584 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8585 player->resource_manager))
8586 LOGE("failed to deinitialize resource manager\n");
8588 /* release pipeline */
8589 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8590 LOGE("failed to destory pipeline\n");
8591 return MM_ERROR_PLAYER_INTERNAL;
8594 g_queue_free(player->bus_msg_q);
8596 /* release subtitle info lock and cond */
8597 g_mutex_clear(&player->subtitle_info_mutex);
8598 g_cond_clear(&player->subtitle_info_cond);
8600 __mmplayer_release_dump_list(player->dump_list);
8602 /* release miscellaneous information */
8603 __mmplayer_release_misc(player);
8605 /* release miscellaneous information.
8606 these info needs to be released after pipeline is destroyed. */
8607 __mmplayer_release_misc_post(player);
8609 /* release attributes */
8610 _mmplayer_deconstruct_attribute(handle);
8613 g_mutex_clear(&player->fsink_lock);
8616 g_mutex_clear(&player->update_tag_lock);
8618 /* release video bo lock and cond */
8619 g_mutex_clear(&player->video_bo_mutex);
8620 g_cond_clear(&player->video_bo_cond);
8622 /* release media stream callback lock */
8623 g_mutex_clear(&player->media_stream_cb_lock);
8627 return MM_ERROR_NONE;
8631 __mmplayer_realize_streaming_ext(mm_player_t* player)
8633 int ret = MM_ERROR_NONE;
8636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8638 if (MMPLAYER_IS_HTTP_PD(player)) {
8639 gboolean bret = FALSE;
8641 player->pd_downloader = _mmplayer_create_pd_downloader();
8642 if (!player->pd_downloader) {
8643 LOGE("Unable to create PD Downloader...");
8644 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8647 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8649 if (FALSE == bret) {
8650 LOGE("Unable to create PD Downloader...");
8651 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8660 _mmplayer_realize(MMHandleType hplayer)
8662 mm_player_t* player = (mm_player_t*)hplayer;
8665 MMHandleType attrs = 0;
8666 int ret = MM_ERROR_NONE;
8670 /* check player handle */
8671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8673 /* check current state */
8674 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8676 attrs = MMPLAYER_GET_ATTRS(player);
8678 LOGE("fail to get attributes.\n");
8679 return MM_ERROR_PLAYER_INTERNAL;
8681 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8682 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8684 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8685 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8687 if (ret != MM_ERROR_NONE) {
8688 LOGE("failed to parse profile\n");
8693 if (uri && (strstr(uri, "es_buff://"))) {
8694 if (strstr(uri, "es_buff://push_mode"))
8695 player->es_player_push_mode = TRUE;
8697 player->es_player_push_mode = FALSE;
8700 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8701 LOGW("mms protocol is not supported format.\n");
8702 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8705 if (MMPLAYER_IS_STREAMING(player))
8706 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8708 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8710 player->smooth_streaming = FALSE;
8711 player->videodec_linked = 0;
8712 player->videosink_linked = 0;
8713 player->audiodec_linked = 0;
8714 player->audiosink_linked = 0;
8715 player->textsink_linked = 0;
8716 player->is_external_subtitle_present = FALSE;
8717 player->is_external_subtitle_added_now = FALSE;
8718 /* set the subtitle ON default */
8719 player->is_subtitle_off = FALSE;
8721 /* realize pipeline */
8722 ret = __gst_realize(player);
8723 if (ret != MM_ERROR_NONE)
8724 LOGE("fail to realize the player.\n");
8726 ret = __mmplayer_realize_streaming_ext(player);
8728 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8736 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8741 /* destroy can called at anytime */
8742 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8743 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8746 return MM_ERROR_NONE;
8750 _mmplayer_unrealize(MMHandleType hplayer)
8752 mm_player_t* player = (mm_player_t*)hplayer;
8753 int ret = MM_ERROR_NONE;
8757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8759 MMPLAYER_CMD_UNLOCK(player);
8760 /* destroy the gst bus msg thread which is created during realize.
8761 this funct have to be called before getting cmd lock. */
8762 _mmplayer_bus_msg_thread_destroy(player);
8763 MMPLAYER_CMD_LOCK(player);
8765 /* check current state */
8766 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8768 /* check async state transition */
8769 __mmplayer_check_async_state_transition(player);
8771 __mmplayer_unrealize_streaming_ext(player);
8773 /* unrealize pipeline */
8774 ret = __gst_unrealize(player);
8776 /* set asm stop if success */
8777 if (MM_ERROR_NONE == ret) {
8778 if (!player->interrupted_by_resource) {
8779 if (player->video_decoder_resource != NULL) {
8780 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8781 player->video_decoder_resource);
8782 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8783 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8785 player->video_decoder_resource = NULL;
8788 if (player->video_overlay_resource != NULL) {
8789 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8790 player->video_overlay_resource);
8791 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8792 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8794 player->video_overlay_resource = NULL;
8797 ret = mm_resource_manager_commit(player->resource_manager);
8798 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8799 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8802 LOGE("failed and don't change asm state to stop");
8810 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8812 mm_player_t* player = (mm_player_t*)hplayer;
8814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8816 return __gst_set_message_callback(player, callback, user_param);
8820 _mmplayer_get_state(MMHandleType hplayer, int* state)
8822 mm_player_t *player = (mm_player_t*)hplayer;
8824 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8826 *state = MMPLAYER_CURRENT_STATE(player);
8828 return MM_ERROR_NONE;
8833 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8835 mm_player_t* player = (mm_player_t*) hplayer;
8836 GstElement* vol_element = NULL;
8841 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843 LOGD("volume [L]=%f:[R]=%f\n",
8844 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8846 /* invalid factor range or not */
8847 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8848 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8849 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8850 return MM_ERROR_INVALID_ARGUMENT;
8854 /* not support to set other value into each channel */
8855 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8856 return MM_ERROR_INVALID_ARGUMENT;
8858 /* Save volume to handle. Currently the first array element will be saved. */
8859 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8861 /* check pipeline handle */
8862 if (!player->pipeline || !player->pipeline->audiobin) {
8863 LOGD("audiobin is not created yet\n");
8864 LOGD("but, current stored volume will be set when it's created.\n");
8866 /* NOTE : stored volume will be used in create_audiobin
8867 * returning MM_ERROR_NONE here makes application to able to
8868 * set volume at anytime.
8870 return MM_ERROR_NONE;
8873 /* setting volume to volume element */
8874 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8877 LOGD("volume is set [%f]\n", player->sound.volume);
8878 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8883 return MM_ERROR_NONE;
8888 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8890 mm_player_t* player = (mm_player_t*) hplayer;
8895 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8896 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8898 /* returning stored volume */
8899 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8900 volume->level[i] = player->sound.volume;
8904 return MM_ERROR_NONE;
8908 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8910 mm_player_t* player = (mm_player_t*) hplayer;
8911 GstElement* vol_element = NULL;
8915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8917 /* mute value shoud 0 or 1 */
8918 if (mute != 0 && mute != 1) {
8919 LOGE("bad mute value\n");
8921 /* FIXIT : definitly, we need _BAD_PARAM error code */
8922 return MM_ERROR_INVALID_ARGUMENT;
8925 player->sound.mute = mute;
8927 /* just hold mute value if pipeline is not ready */
8928 if (!player->pipeline || !player->pipeline->audiobin) {
8929 LOGD("pipeline is not ready. holding mute value\n");
8930 return MM_ERROR_NONE;
8933 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8935 /* NOTE : volume will only created when the bt is enabled */
8937 LOGD("mute : %d\n", mute);
8938 g_object_set(vol_element, "mute", mute, NULL);
8940 LOGD("volume elemnet is not created. using volume in audiosink\n");
8944 return MM_ERROR_NONE;
8948 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8950 mm_player_t* player = (mm_player_t*) hplayer;
8954 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8955 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8957 /* just hold mute value if pipeline is not ready */
8958 if (!player->pipeline || !player->pipeline->audiobin) {
8959 LOGD("pipeline is not ready. returning stored value\n");
8960 *pmute = player->sound.mute;
8961 return MM_ERROR_NONE;
8964 *pmute = player->sound.mute;
8968 return MM_ERROR_NONE;
8972 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8974 mm_player_t* player = (mm_player_t*) hplayer;
8978 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8980 player->video_stream_changed_cb = callback;
8981 player->video_stream_changed_cb_user_param = user_param;
8982 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8986 return MM_ERROR_NONE;
8990 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8992 mm_player_t* player = (mm_player_t*) hplayer;
8996 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8998 player->audio_stream_changed_cb = callback;
8999 player->audio_stream_changed_cb_user_param = user_param;
9000 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9004 return MM_ERROR_NONE;
9008 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9010 mm_player_t* player = (mm_player_t*) hplayer;
9014 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9016 player->audio_stream_render_cb_ex = callback;
9017 player->audio_stream_cb_user_param = user_param;
9018 player->audio_stream_sink_sync = sync;
9019 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);
9023 return MM_ERROR_NONE;
9027 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9029 mm_player_t* player = (mm_player_t*) hplayer;
9033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9035 if (callback && !player->bufmgr)
9036 player->bufmgr = tbm_bufmgr_init(-1);
9038 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9039 player->video_stream_cb = callback;
9040 player->video_stream_cb_user_param = user_param;
9042 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9046 return MM_ERROR_NONE;
9050 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9052 mm_player_t* player = (mm_player_t*) hplayer;
9056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9058 player->audio_stream_cb = callback;
9059 player->audio_stream_cb_user_param = user_param;
9060 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9064 return MM_ERROR_NONE;
9068 __mmplayer_start_streaming_ext(mm_player_t *player)
9070 gint ret = MM_ERROR_NONE;
9073 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9075 if (MMPLAYER_IS_HTTP_PD(player)) {
9076 if (!player->pd_downloader) {
9077 ret = __mmplayer_realize_streaming_ext(player);
9079 if (ret != MM_ERROR_NONE) {
9080 LOGE("failed to realize streaming ext\n");
9085 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9086 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9088 LOGE("ERROR while starting PD...\n");
9089 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9091 ret = MM_ERROR_NONE;
9100 _mmplayer_start(MMHandleType hplayer)
9102 mm_player_t* player = (mm_player_t*) hplayer;
9103 gint ret = MM_ERROR_NONE;
9107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9109 /* check current state */
9110 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9112 /* PD - start streaming */
9113 ret = __mmplayer_start_streaming_ext(player);
9114 if (ret != MM_ERROR_NONE) {
9115 LOGE("failed to start streaming ext 0x%X", ret);
9119 /* start pipeline */
9120 ret = __gst_start(player);
9121 if (ret != MM_ERROR_NONE)
9122 LOGE("failed to start player.\n");
9124 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9125 LOGD("force playing start even during buffering");
9126 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9134 /* NOTE: post "not supported codec message" to application
9135 * when one codec is not found during AUTOPLUGGING in MSL.
9136 * So, it's separated with error of __mmplayer_gst_callback().
9137 * And, if any codec is not found, don't send message here.
9138 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9141 __mmplayer_handle_missed_plugin(mm_player_t* player)
9143 MMMessageParamType msg_param;
9144 memset(&msg_param, 0, sizeof(MMMessageParamType));
9145 gboolean post_msg_direct = FALSE;
9149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9151 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9152 player->not_supported_codec, player->can_support_codec);
9154 if (player->not_found_demuxer) {
9155 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9156 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9158 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9159 MMPLAYER_FREEIF(msg_param.data);
9161 return MM_ERROR_NONE;
9164 if (player->not_supported_codec) {
9165 if (player->can_support_codec) {
9166 // There is one codec to play
9167 post_msg_direct = TRUE;
9169 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9170 post_msg_direct = TRUE;
9173 if (post_msg_direct) {
9174 MMMessageParamType msg_param;
9175 memset(&msg_param, 0, sizeof(MMMessageParamType));
9177 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9178 LOGW("not found AUDIO codec, posting error code to application.\n");
9180 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9181 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9182 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9183 LOGW("not found VIDEO codec, posting error code to application.\n");
9185 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9186 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9189 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9191 MMPLAYER_FREEIF(msg_param.data);
9193 return MM_ERROR_NONE;
9195 // no any supported codec case
9196 LOGW("not found any codec, posting error code to application.\n");
9198 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9199 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9200 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9202 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9203 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9206 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9208 MMPLAYER_FREEIF(msg_param.data);
9214 return MM_ERROR_NONE;
9217 static void __mmplayer_check_pipeline(mm_player_t* player)
9219 GstState element_state = GST_STATE_VOID_PENDING;
9220 GstState element_pending_state = GST_STATE_VOID_PENDING;
9222 int ret = MM_ERROR_NONE;
9224 if (player->gapless.reconfigure) {
9225 LOGW("pipeline is under construction.\n");
9227 MMPLAYER_PLAYBACK_LOCK(player);
9228 MMPLAYER_PLAYBACK_UNLOCK(player);
9230 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9232 /* wait for state transition */
9233 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9235 if (ret == GST_STATE_CHANGE_FAILURE)
9236 LOGE("failed to change pipeline state within %d sec\n", timeout);
9240 /* NOTE : it should be able to call 'stop' anytime*/
9242 _mmplayer_stop(MMHandleType hplayer)
9244 mm_player_t* player = (mm_player_t*)hplayer;
9245 int ret = MM_ERROR_NONE;
9249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9251 /* check current state */
9252 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9254 /* check pipline building state */
9255 __mmplayer_check_pipeline(player);
9256 __mmplayer_reset_gapless_state(player);
9258 /* NOTE : application should not wait for EOS after calling STOP */
9259 __mmplayer_cancel_eos_timer(player);
9261 __mmplayer_unrealize_streaming_ext(player);
9264 player->seek_state = MMPLAYER_SEEK_NONE;
9267 ret = __gst_stop(player);
9269 if (ret != MM_ERROR_NONE)
9270 LOGE("failed to stop player.\n");
9278 _mmplayer_pause(MMHandleType hplayer)
9280 mm_player_t* player = (mm_player_t*)hplayer;
9281 gint64 pos_nsec = 0;
9282 gboolean async = FALSE;
9283 gint ret = MM_ERROR_NONE;
9287 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9289 /* check current state */
9290 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9292 /* check pipline building state */
9293 __mmplayer_check_pipeline(player);
9295 switch (MMPLAYER_CURRENT_STATE(player)) {
9296 case MM_PLAYER_STATE_READY:
9298 /* check prepare async or not.
9299 * In the case of streaming playback, it's recommned to avoid blocking wait.
9301 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9302 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9304 /* Changing back sync of rtspsrc to async */
9305 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9306 LOGD("async prepare working mode for rtsp");
9312 case MM_PLAYER_STATE_PLAYING:
9314 /* NOTE : store current point to overcome some bad operation
9315 *(returning zero when getting current position in paused state) of some
9318 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9319 LOGW("getting current position failed in paused\n");
9321 player->last_position = pos_nsec;
9323 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9324 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9325 This causes problem is position calculation during normal pause resume scenarios also.
9326 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9327 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9328 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9329 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9335 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9336 LOGD("doing async pause in case of ms buff src");
9340 /* pause pipeline */
9341 ret = __gst_pause(player, async);
9343 if (ret != MM_ERROR_NONE)
9344 LOGE("failed to pause player. ret : 0x%x\n", ret);
9346 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9347 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9348 LOGE("failed to update display_rotation");
9357 _mmplayer_resume(MMHandleType hplayer)
9359 mm_player_t* player = (mm_player_t*)hplayer;
9360 int ret = MM_ERROR_NONE;
9361 gboolean async = FALSE;
9365 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9367 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9368 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
9369 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
9373 /* Changing back sync mode rtspsrc to async */
9374 LOGD("async resume for rtsp case");
9378 /* check current state */
9379 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9381 ret = __gst_resume(player, async);
9382 if (ret != MM_ERROR_NONE)
9383 LOGE("failed to resume player.\n");
9385 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9386 LOGD("force resume even during buffering");
9387 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9396 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9398 mm_player_t* player = (mm_player_t*)hplayer;
9399 gint64 pos_nsec = 0;
9400 int ret = MM_ERROR_NONE;
9402 signed long long start = 0, stop = 0;
9403 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9407 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9409 /* The sound of video is not supported under 0.0 and over 2.0. */
9410 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9411 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9414 _mmplayer_set_mute(hplayer, mute);
9416 if (player->playback_rate == rate)
9417 return MM_ERROR_NONE;
9419 /* If the position is reached at start potion during fast backward, EOS is posted.
9420 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9422 player->playback_rate = rate;
9424 current_state = MMPLAYER_CURRENT_STATE(player);
9426 if (current_state != MM_PLAYER_STATE_PAUSED)
9427 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9429 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9431 if ((current_state == MM_PLAYER_STATE_PAUSED)
9432 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9433 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9434 pos_nsec = player->last_position;
9439 stop = GST_CLOCK_TIME_NONE;
9441 start = GST_CLOCK_TIME_NONE;
9445 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9446 player->playback_rate,
9448 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9449 GST_SEEK_TYPE_SET, start,
9450 GST_SEEK_TYPE_SET, stop)) {
9451 LOGE("failed to set speed playback\n");
9452 return MM_ERROR_PLAYER_SEEK;
9455 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9459 return MM_ERROR_NONE;;
9463 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9465 mm_player_t* player = (mm_player_t*)hplayer;
9466 int ret = MM_ERROR_NONE;
9470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9472 /* check pipline building state */
9473 __mmplayer_check_pipeline(player);
9475 ret = __gst_set_position(player, format, position, FALSE);
9483 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9485 mm_player_t* player = (mm_player_t*)hplayer;
9486 int ret = MM_ERROR_NONE;
9488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9490 ret = __gst_get_position(player, format, position);
9496 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9498 mm_player_t* player = (mm_player_t*)hplayer;
9499 int ret = MM_ERROR_NONE;
9501 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9502 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9504 *duration = player->duration;
9509 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9511 mm_player_t* player = (mm_player_t*)hplayer;
9512 int ret = MM_ERROR_NONE;
9514 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9516 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9522 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9524 mm_player_t* player = (mm_player_t*)hplayer;
9525 int ret = MM_ERROR_NONE;
9529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9531 ret = __gst_adjust_subtitle_position(player, format, position);
9539 __mmplayer_is_midi_type(gchar* str_caps)
9541 if ((g_strrstr(str_caps, "audio/midi")) ||
9542 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9543 (g_strrstr(str_caps, "application/x-smaf")) ||
9544 (g_strrstr(str_caps, "audio/x-imelody")) ||
9545 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9546 (g_strrstr(str_caps, "audio/xmf")) ||
9547 (g_strrstr(str_caps, "audio/mxmf"))) {
9556 __mmplayer_is_only_mp3_type(gchar *str_caps)
9558 if (g_strrstr(str_caps, "application/x-id3") ||
9559 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9565 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9567 GstStructure* caps_structure = NULL;
9568 gint samplerate = 0;
9572 MMPLAYER_RETURN_IF_FAIL(player && caps);
9574 caps_structure = gst_caps_get_structure(caps, 0);
9576 /* set stream information */
9577 gst_structure_get_int(caps_structure, "rate", &samplerate);
9578 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9580 gst_structure_get_int(caps_structure, "channels", &channels);
9581 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9583 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9587 __mmplayer_update_content_type_info(mm_player_t* player)
9590 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9592 if (__mmplayer_is_midi_type(player->type)) {
9593 player->bypass_audio_effect = TRUE;
9594 } else if (g_strrstr(player->type, "application/x-hls")) {
9595 /* If it can't know exact type when it parses uri because of redirection case,
9596 * it will be fixed by typefinder or when doing autoplugging.
9598 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9599 if (player->streamer) {
9600 player->streamer->is_adaptive_streaming = TRUE;
9601 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9602 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9604 } else if (g_strrstr(player->type, "application/dash+xml")) {
9605 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9606 if (player->streamer) {
9607 player->streamer->is_adaptive_streaming = TRUE;
9608 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9612 LOGD("uri type : %d", player->profile.uri_type);
9617 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9618 GstCaps *caps, gpointer data)
9620 mm_player_t* player = (mm_player_t*)data;
9625 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9627 /* store type string */
9628 MMPLAYER_FREEIF(player->type);
9629 player->type = gst_caps_to_string(caps);
9631 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9632 player, player->type, probability, gst_caps_get_size(caps));
9635 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9636 (g_strrstr(player->type, "audio/x-raw-int"))) {
9637 LOGE("not support media format\n");
9639 if (player->msg_posted == FALSE) {
9640 MMMessageParamType msg_param;
9641 memset(&msg_param, 0, sizeof(MMMessageParamType));
9643 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9644 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9646 /* don't post more if one was sent already */
9647 player->msg_posted = TRUE;
9652 __mmplayer_update_content_type_info(player);
9654 pad = gst_element_get_static_pad(tf, "src");
9656 LOGE("fail to get typefind src pad.\n");
9660 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9661 gboolean async = FALSE;
9662 LOGE("failed to autoplug %s\n", player->type);
9664 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9666 if (async && player->msg_posted == FALSE)
9667 __mmplayer_handle_missed_plugin(player);
9673 gst_object_unref(GST_OBJECT(pad));
9681 __mmplayer_create_decodebin(mm_player_t* player)
9683 GstElement *decodebin = NULL;
9687 /* create decodebin */
9688 decodebin = gst_element_factory_make("decodebin", NULL);
9691 LOGE("fail to create decodebin\n");
9695 /* raw pad handling signal */
9696 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9697 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9699 /* no-more-pad pad handling signal */
9700 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9701 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9703 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9704 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9706 /* This signal is emitted when a pad for which there is no further possible
9707 decoding is added to the decodebin.*/
9708 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9709 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9711 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9712 before looking for any elements that can handle that stream.*/
9713 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9714 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9716 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9717 before looking for any elements that can handle that stream.*/
9718 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9719 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9721 /* This signal is emitted once decodebin has finished decoding all the data.*/
9722 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9723 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9725 /* This signal is emitted when a element is added to the bin.*/
9726 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9727 G_CALLBACK(__mmplayer_gst_element_added), player);
9734 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9736 MMPlayerGstElement* mainbin = NULL;
9737 GstElement* decodebin = NULL;
9738 GstElement* queue2 = NULL;
9739 GstPad* sinkpad = NULL;
9740 GstPad* qsrcpad = NULL;
9741 gint64 dur_bytes = 0L;
9743 guint max_buffer_size_bytes = 0;
9744 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9747 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9749 mainbin = player->pipeline->mainbin;
9751 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9752 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9753 LOGD("creating http streaming buffering queue(queue2)\n");
9755 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9756 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9758 queue2 = gst_element_factory_make("queue2", "queue2");
9760 LOGE("failed to create buffering queue element\n");
9764 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9765 LOGE("failed to add buffering queue\n");
9769 sinkpad = gst_element_get_static_pad(queue2, "sink");
9770 qsrcpad = gst_element_get_static_pad(queue2, "src");
9772 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9773 LOGE("failed to link buffering queue");
9777 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9778 LOGE("fail to get duration");
9780 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9782 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9784 if (dur_bytes > 0) {
9785 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9786 type = MUXED_BUFFER_TYPE_FILE;
9788 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9789 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9795 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9796 * skip the pull mode(file or ring buffering) setting. */
9797 if (!g_strrstr(player->type, "video/mpegts")) {
9798 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9799 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9801 __mm_player_streaming_set_queue2(player->streamer,
9804 max_buffer_size_bytes,
9805 player->ini.http_buffering_time,
9806 1.0, /* no meaning */
9807 player->ini.http_buffering_limit, /* no meaning */
9809 player->http_file_buffering_path,
9810 (guint64)dur_bytes);
9813 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9814 LOGE("failed to sync queue2 state with parent\n");
9820 gst_object_unref(GST_OBJECT(sinkpad));
9822 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9823 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9827 /* create decodebin */
9828 decodebin = __mmplayer_create_decodebin(player);
9831 LOGE("can not create autoplug element\n");
9835 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9836 LOGE("failed to add decodebin\n");
9840 /* to force caps on the decodebin element and avoid reparsing stuff by
9841 * typefind. It also avoids a deadlock in the way typefind activates pads in
9842 * the state change */
9843 g_object_set(decodebin, "sink-caps", caps, NULL);
9845 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9847 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9848 LOGE("failed to link decodebin\n");
9852 gst_object_unref(GST_OBJECT(sinkpad));
9854 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9855 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9857 /* set decodebin property about buffer in streaming playback. *
9858 * in case of HLS/DASH, it does not need to have big buffer *
9859 * because it is kind of adaptive streaming. */
9860 if (!MMPLAYER_IS_HTTP_PD(player) &&
9861 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9862 gdouble high_percent = 0.0;
9864 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9865 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9867 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9868 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9870 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9871 "high-percent", (gint)high_percent,
9872 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9873 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9874 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9875 "max-size-buffers", 0, NULL); // disable or automatic
9878 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9879 LOGE("failed to sync decodebin state with parent\n");
9890 gst_object_unref(GST_OBJECT(sinkpad));
9893 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9894 * You need to explicitly set elements to the NULL state before
9895 * dropping the final reference, to allow them to clean up.
9897 gst_element_set_state(queue2, GST_STATE_NULL);
9899 /* And, it still has a parent "player".
9900 * You need to let the parent manage the object instead of unreffing the object directly.
9902 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9903 gst_object_unref(queue2);
9908 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9909 * You need to explicitly set elements to the NULL state before
9910 * dropping the final reference, to allow them to clean up.
9912 gst_element_set_state(decodebin, GST_STATE_NULL);
9914 /* And, it still has a parent "player".
9915 * You need to let the parent manage the object instead of unreffing the object directly.
9918 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9919 gst_object_unref(decodebin);
9927 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9931 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9932 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9934 LOGD("class : %s, mime : %s \n", factory_class, mime);
9936 /* add missing plugin */
9937 /* NOTE : msl should check missing plugin for image mime type.
9938 * Some motion jpeg clips can have playable audio track.
9939 * So, msl have to play audio after displaying popup written video format not supported.
9941 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9942 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9943 LOGD("not found demuxer\n");
9944 player->not_found_demuxer = TRUE;
9945 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9951 if (!g_strrstr(factory_class, "Demuxer")) {
9952 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9953 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9954 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9956 /* check that clip have multi tracks or not */
9957 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9958 LOGD("video plugin is already linked\n");
9960 LOGW("add VIDEO to missing plugin\n");
9961 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9962 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9964 } else if (g_str_has_prefix(mime, "audio")) {
9965 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9966 LOGD("audio plugin is already linked\n");
9968 LOGW("add AUDIO to missing plugin\n");
9969 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9970 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9978 return MM_ERROR_NONE;
9983 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9985 mm_player_t* player = (mm_player_t*)data;
9989 MMPLAYER_RETURN_IF_FAIL(player);
9991 /* remove fakesink. */
9992 if (!__mmplayer_gst_remove_fakesink(player,
9993 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9994 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9995 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9996 * source element are not same. To overcome this situation, this function will called
9997 * several places and several times. Therefore, this is not an error case.
10002 LOGD("[handle: %p] pipeline has completely constructed", player);
10004 if ((player->ini.async_start) &&
10005 (player->msg_posted == FALSE) &&
10006 (player->cmd >= MMPLAYER_COMMAND_START))
10007 __mmplayer_handle_missed_plugin(player);
10009 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10013 __mmplayer_verify_next_play_path(mm_player_t *player)
10015 MMHandleType attrs = 0;
10016 MMPlayerParseProfile profile;
10017 gint uri_idx = 0, check_cnt = 0;
10019 gint mode = MM_PLAYER_PD_MODE_NONE;
10023 guint num_of_list = 0;
10024 static int profile_tv = -1;
10028 LOGD("checking for gapless play");
10030 if (player->pipeline->textbin) {
10031 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10035 attrs = MMPLAYER_GET_ATTRS(player);
10037 LOGE("fail to get attributes.\n");
10041 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10043 if (__builtin_expect(profile_tv == -1, 0)) {
10045 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10046 switch (*profileName) {
10056 /* gapless playback is not supported in case of video at TV profile. */
10057 if (profile_tv && video) {
10058 LOGW("not support video gapless playback");
10062 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10063 if (mode == TRUE) {
10069 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10070 LOGE("can not get play count\n");
10072 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10073 LOGE("can not get gapless mode\n");
10075 if (video && !gapless) {
10076 LOGW("not enabled video gapless playback");
10080 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10084 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10088 num_of_list = g_list_length(player->uri_info.uri_list);
10090 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10092 if (num_of_list == 0) {
10093 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10094 LOGE("can not get profile_uri\n");
10099 LOGE("uri list is empty.\n");
10103 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10104 LOGD("add original path : %s ", uri);
10110 uri_idx = player->uri_info.uri_idx;
10115 if (check_cnt > num_of_list) {
10116 LOGE("there is no valid uri.");
10120 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10122 if (uri_idx < num_of_list-1) {
10125 if ((count <= 1) && (count != -1)) {
10126 LOGD("no repeat.");
10128 } else if (count > 1) {
10129 /* decrease play count */
10130 /* we succeeded to rewind. update play count and then wait for next EOS */
10133 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10135 /* commit attribute */
10136 if (mmf_attrs_commit(attrs))
10137 LOGE("failed to commit attribute\n");
10140 /* count < 0 : repeat continually */
10144 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10145 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10148 LOGW("next uri does not exist\n");
10152 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10153 LOGE("failed to parse profile\n");
10157 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10158 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10159 LOGW("uri type is not supported(%d).", profile.uri_type);
10166 player->uri_info.uri_idx = uri_idx;
10167 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10169 if (mmf_attrs_commit(player->attrs)) {
10170 LOGE("failed to commit.\n");
10174 LOGD("next uri %s(%d)\n", uri, uri_idx);
10180 LOGE("unable to play next path. EOS will be posted soon.\n");
10185 __mmplayer_initialize_next_play(mm_player_t *player)
10191 player->smooth_streaming = FALSE;
10192 player->videodec_linked = 0;
10193 player->audiodec_linked = 0;
10194 player->videosink_linked = 0;
10195 player->audiosink_linked = 0;
10196 player->textsink_linked = 0;
10197 player->is_external_subtitle_present = FALSE;
10198 player->is_external_subtitle_added_now = FALSE;
10199 player->not_supported_codec = MISSING_PLUGIN_NONE;
10200 player->can_support_codec = FOUND_PLUGIN_NONE;
10201 player->pending_seek.is_pending = FALSE;
10202 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10203 player->pending_seek.pos = 0;
10204 player->msg_posted = FALSE;
10205 player->has_many_types = FALSE;
10206 player->no_more_pad = FALSE;
10207 player->not_found_demuxer = 0;
10208 player->seek_state = MMPLAYER_SEEK_NONE;
10209 player->max_audio_channels = 0;
10210 player->is_subtitle_force_drop = FALSE;
10211 player->play_subtitle = FALSE;
10212 player->adjust_subtitle_pos = 0;
10214 player->total_bitrate = 0;
10215 player->total_maximum_bitrate = 0;
10217 _mmplayer_track_initialize(player);
10218 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10220 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10221 player->bitrate[i] = 0;
10222 player->maximum_bitrate[i] = 0;
10225 if (player->v_stream_caps) {
10226 gst_caps_unref(player->v_stream_caps);
10227 player->v_stream_caps = NULL;
10230 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10232 /* clean found parsers */
10233 if (player->parsers) {
10234 GList *parsers = player->parsers;
10235 for (; parsers; parsers = g_list_next(parsers)) {
10236 gchar *name = parsers->data;
10237 MMPLAYER_FREEIF(name);
10239 g_list_free(player->parsers);
10240 player->parsers = NULL;
10243 /* clean found audio decoders */
10244 if (player->audio_decoders) {
10245 GList *a_dec = player->audio_decoders;
10246 for (; a_dec; a_dec = g_list_next(a_dec)) {
10247 gchar *name = a_dec->data;
10248 MMPLAYER_FREEIF(name);
10250 g_list_free(player->audio_decoders);
10251 player->audio_decoders = NULL;
10258 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10260 MMPlayerGstElement *mainbin = NULL;
10261 MMMessageParamType msg_param = {0,};
10262 GstElement *element = NULL;
10263 MMHandleType attrs = 0;
10265 enum MainElementID elemId = MMPLAYER_M_NUM;
10269 if ((player == NULL) ||
10270 (player->pipeline == NULL) ||
10271 (player->pipeline->mainbin == NULL)) {
10272 LOGE("player is null.\n");
10276 mainbin = player->pipeline->mainbin;
10277 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10279 attrs = MMPLAYER_GET_ATTRS(player);
10281 LOGE("fail to get attributes.\n");
10285 /* Initialize Player values */
10286 __mmplayer_initialize_next_play(player);
10288 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10290 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10291 LOGE("failed to parse profile\n");
10292 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10296 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10297 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10298 LOGE("it's dash or hls. not support.");
10299 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10304 switch (player->profile.uri_type) {
10306 case MM_PLAYER_URI_TYPE_FILE:
10308 LOGD("using filesrc for 'file://' handler.\n");
10309 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10310 LOGE("failed to get storage info");
10314 element = gst_element_factory_make("filesrc", "source");
10317 LOGE("failed to create filesrc\n");
10321 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10324 case MM_PLAYER_URI_TYPE_URL_HTTP:
10326 gchar *user_agent, *cookies, **cookie_list;
10327 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10328 user_agent = cookies = NULL;
10329 cookie_list = NULL;
10331 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10333 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10336 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10338 /* get attribute */
10339 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10340 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10342 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10343 LOGD("get timeout from ini\n");
10344 http_timeout = player->ini.http_timeout;
10347 /* get attribute */
10348 SECURE_LOGD("location : %s\n", player->profile.uri);
10349 SECURE_LOGD("cookies : %s\n", cookies);
10350 SECURE_LOGD("user_agent : %s\n", user_agent);
10351 LOGD("timeout : %d\n", http_timeout);
10353 /* setting property to streaming source */
10354 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10355 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10356 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10358 /* parsing cookies */
10359 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10360 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10362 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10366 LOGE("not support uri type %d\n", player->profile.uri_type);
10371 LOGE("no source element was created.\n");
10375 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10376 LOGE("failed to add source element to pipeline\n");
10377 gst_object_unref(GST_OBJECT(element));
10382 /* take source element */
10383 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10384 mainbin[MMPLAYER_M_SRC].gst = element;
10388 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10389 if (player->streamer == NULL) {
10390 player->streamer = __mm_player_streaming_create();
10391 __mm_player_streaming_initialize(player->streamer);
10394 elemId = MMPLAYER_M_TYPEFIND;
10395 element = gst_element_factory_make("typefind", "typefinder");
10396 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10397 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10399 elemId = MMPLAYER_M_AUTOPLUG;
10400 element = __mmplayer_create_decodebin(player);
10403 /* check autoplug element is OK */
10405 LOGE("can not create element(%d)\n", elemId);
10409 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10410 LOGE("failed to add sinkbin to pipeline\n");
10411 gst_object_unref(GST_OBJECT(element));
10416 mainbin[elemId].id = elemId;
10417 mainbin[elemId].gst = element;
10419 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10420 LOGE("Failed to link src - autoplug(or typefind)\n");
10424 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10425 LOGE("Failed to change state of src element\n");
10429 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10430 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10431 LOGE("Failed to change state of decodebin\n");
10435 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10436 LOGE("Failed to change state of src element\n");
10441 player->gapless.stream_changed = TRUE;
10442 player->gapless.running = TRUE;
10448 MMPLAYER_PLAYBACK_UNLOCK(player);
10450 if (!player->msg_posted) {
10451 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10452 player->msg_posted = TRUE;
10459 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10461 mm_player_selector_t *selector = &player->selector[type];
10462 MMPlayerGstElement *sinkbin = NULL;
10463 enum MainElementID selectorId = MMPLAYER_M_NUM;
10464 enum MainElementID sinkId = MMPLAYER_M_NUM;
10465 GstPad *srcpad = NULL;
10466 GstPad *sinkpad = NULL;
10467 gboolean send_notice = FALSE;
10470 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10472 LOGD("type %d", type);
10475 case MM_PLAYER_TRACK_TYPE_AUDIO:
10476 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10477 sinkId = MMPLAYER_A_BIN;
10478 sinkbin = player->pipeline->audiobin;
10480 case MM_PLAYER_TRACK_TYPE_VIDEO:
10481 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10482 sinkId = MMPLAYER_V_BIN;
10483 sinkbin = player->pipeline->videobin;
10484 send_notice = TRUE;
10486 case MM_PLAYER_TRACK_TYPE_TEXT:
10487 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10488 sinkId = MMPLAYER_T_BIN;
10489 sinkbin = player->pipeline->textbin;
10492 LOGE("requested type is not supportable");
10497 if (player->pipeline->mainbin[selectorId].gst) {
10500 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10502 if (selector->event_probe_id != 0)
10503 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10504 selector->event_probe_id = 0;
10506 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10507 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10509 if (srcpad && sinkpad) {
10510 /* after getting drained signal there is no data flows, so no need to do pad_block */
10511 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10512 gst_pad_unlink(srcpad, sinkpad);
10514 /* send custom event to sink pad to handle it at video sink */
10516 LOGD("send custom event to sinkpad");
10517 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10518 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10519 gst_pad_send_event(sinkpad, event);
10523 gst_object_unref(sinkpad);
10526 gst_object_unref(srcpad);
10529 LOGD("selector release");
10531 /* release and unref requests pad from the selector */
10532 for (n = 0; n < selector->channels->len; n++) {
10533 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10534 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10536 g_ptr_array_set_size(selector->channels, 0);
10538 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10539 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10541 player->pipeline->mainbin[selectorId].gst = NULL;
10549 __mmplayer_deactivate_old_path(mm_player_t *player)
10552 MMPLAYER_RETURN_IF_FAIL(player);
10554 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10555 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10556 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10557 LOGE("deactivate selector error");
10561 _mmplayer_track_destroy(player);
10562 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10564 if (player->streamer) {
10565 __mm_player_streaming_deinitialize(player->streamer);
10566 __mm_player_streaming_destroy(player->streamer);
10567 player->streamer = NULL;
10570 MMPLAYER_PLAYBACK_LOCK(player);
10571 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10578 if (!player->msg_posted) {
10579 MMMessageParamType msg = {0,};
10582 msg.code = MM_ERROR_PLAYER_INTERNAL;
10583 LOGE("next_uri_play> deactivate error");
10585 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10586 player->msg_posted = TRUE;
10591 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10593 int result = MM_ERROR_NONE;
10594 mm_player_t* player = (mm_player_t*) hplayer;
10597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10600 player->http_file_buffering_path = (gchar*)file_path;
10601 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10607 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10609 int result = MM_ERROR_NONE;
10610 mm_player_t* player = (mm_player_t*) hplayer;
10613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10615 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10616 if (mmf_attrs_commit(player->attrs)) {
10617 LOGE("failed to commit the original uri.\n");
10618 result = MM_ERROR_PLAYER_INTERNAL;
10620 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10621 LOGE("failed to add the original uri in the uri list.\n");
10628 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10630 mm_player_t* player = (mm_player_t*) hplayer;
10631 guint num_of_list = 0;
10635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10636 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10638 if (player->pipeline && player->pipeline->textbin) {
10639 LOGE("subtitle path is enabled.\n");
10640 return MM_ERROR_PLAYER_INVALID_STATE;
10643 num_of_list = g_list_length(player->uri_info.uri_list);
10645 if (is_first_path == TRUE) {
10646 if (num_of_list == 0) {
10647 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10648 LOGD("add original path : %s", uri);
10650 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10651 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10653 LOGD("change original path : %s", uri);
10656 MMHandleType attrs = 0;
10657 attrs = MMPLAYER_GET_ATTRS(player);
10659 if (num_of_list == 0) {
10660 char *original_uri = NULL;
10663 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10665 if (!original_uri) {
10666 LOGE("there is no original uri.");
10667 return MM_ERROR_PLAYER_INVALID_STATE;
10670 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10671 player->uri_info.uri_idx = 0;
10673 LOGD("add original path at first : %s(%d)", original_uri);
10677 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10678 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10682 return MM_ERROR_NONE;
10685 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10687 mm_player_t* player = (mm_player_t*) hplayer;
10688 char *next_uri = NULL;
10689 guint num_of_list = 0;
10692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10694 num_of_list = g_list_length(player->uri_info.uri_list);
10696 if (num_of_list > 0) {
10697 gint uri_idx = player->uri_info.uri_idx;
10699 if (uri_idx < num_of_list-1)
10704 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10705 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10707 *uri = g_strdup(next_uri);
10711 return MM_ERROR_NONE;
10715 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10716 GstCaps *caps, gpointer data)
10718 mm_player_t* player = (mm_player_t*)data;
10719 const gchar* klass = NULL;
10720 const gchar* mime = NULL;
10721 gchar* caps_str = NULL;
10723 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10724 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10725 caps_str = gst_caps_to_string(caps);
10727 LOGW("unknown type of caps : %s from %s",
10728 caps_str, GST_ELEMENT_NAME(elem));
10730 MMPLAYER_FREEIF(caps_str);
10732 /* There is no available codec. */
10733 __mmplayer_check_not_supported_codec(player, klass, mime);
10737 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10738 GstCaps * caps, gpointer data)
10740 mm_player_t* player = (mm_player_t*)data;
10741 const char* mime = NULL;
10742 gboolean ret = TRUE;
10744 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10745 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10747 if (g_str_has_prefix(mime, "audio")) {
10748 GstStructure* caps_structure = NULL;
10749 gint samplerate = 0;
10751 gchar *caps_str = NULL;
10753 caps_structure = gst_caps_get_structure(caps, 0);
10754 gst_structure_get_int(caps_structure, "rate", &samplerate);
10755 gst_structure_get_int(caps_structure, "channels", &channels);
10757 if ((channels > 0 && samplerate == 0)) {
10758 LOGD("exclude audio...");
10762 caps_str = gst_caps_to_string(caps);
10763 /* set it directly because not sent by TAG */
10764 if (g_strrstr(caps_str, "mobile-xmf"))
10765 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10766 MMPLAYER_FREEIF(caps_str);
10767 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10768 MMMessageParamType msg_param;
10769 memset(&msg_param, 0, sizeof(MMMessageParamType));
10770 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10771 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10772 LOGD("video file is not supported on this device");
10774 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10775 LOGD("already video linked");
10778 LOGD("found new stream");
10785 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10787 int ret = MM_ERROR_NONE;
10789 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10791 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10792 GstStructure* str = NULL;
10794 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10796 LOGD("audio codec type: %d", codec_type);
10797 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10798 /* sw codec will be skipped */
10799 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10800 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10801 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10802 ret = MM_ERROR_PLAYER_INTERNAL;
10806 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10807 /* hw codec will be skipped */
10808 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10809 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10810 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10811 ret = MM_ERROR_PLAYER_INTERNAL;
10816 str = gst_caps_get_structure(caps, 0);
10818 gst_structure_get_int(str, "channels", &channels);
10820 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10821 if (player->max_audio_channels < channels)
10822 player->max_audio_channels = channels;
10824 /* set stream information */
10825 if (!player->audiodec_linked)
10826 __mmplayer_set_audio_attrs(player, caps);
10828 /* update codec info */
10829 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10830 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10831 player->audiodec_linked = 1;
10833 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10835 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10837 LOGD("video codec type: %d", codec_type);
10838 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10839 /* sw codec is skipped */
10840 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10841 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10842 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10843 ret = MM_ERROR_PLAYER_INTERNAL;
10847 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10848 /* hw codec is skipped */
10849 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10850 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10851 ret = MM_ERROR_PLAYER_INTERNAL;
10856 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10857 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10859 /* mark video decoder for acquire */
10860 if (player->video_decoder_resource == NULL) {
10861 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10862 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10863 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10864 &player->video_decoder_resource)
10865 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10866 LOGE("could not mark video_decoder resource for acquire");
10867 ret = MM_ERROR_PLAYER_INTERNAL;
10871 LOGW("video decoder resource is already acquired, skip it.");
10872 ret = MM_ERROR_PLAYER_INTERNAL;
10876 player->interrupted_by_resource = FALSE;
10877 /* acquire resources for video playing */
10878 if (mm_resource_manager_commit(player->resource_manager)
10879 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10880 LOGE("could not acquire resources for video decoding\n");
10881 ret = MM_ERROR_PLAYER_INTERNAL;
10886 /* update codec info */
10887 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10888 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10889 player->videodec_linked = 1;
10897 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10898 GstCaps* caps, GstElementFactory* factory, gpointer data)
10900 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10901 We are defining our own and will be removed when it actually exposed */
10903 GST_AUTOPLUG_SELECT_TRY,
10904 GST_AUTOPLUG_SELECT_EXPOSE,
10905 GST_AUTOPLUG_SELECT_SKIP
10906 } GstAutoplugSelectResult;
10908 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10909 mm_player_t* player = (mm_player_t*)data;
10911 gchar* factory_name = NULL;
10912 gchar* caps_str = NULL;
10913 const gchar* klass = NULL;
10916 factory_name = GST_OBJECT_NAME(factory);
10917 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10918 caps_str = gst_caps_to_string(caps);
10920 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10922 /* store type string */
10923 if (player->type == NULL) {
10924 player->type = gst_caps_to_string(caps);
10925 __mmplayer_update_content_type_info(player);
10928 /* filtering exclude keyword */
10929 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10930 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10931 LOGW("skipping [%s] by exculde keyword [%s]\n",
10932 factory_name, player->ini.exclude_element_keyword[idx]);
10934 result = GST_AUTOPLUG_SELECT_SKIP;
10939 /* exclude webm format */
10940 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10941 * because webm format is not supportable.
10942 * If webm is disabled in "autoplug-continue", there is no state change
10943 * failure or error because the decodebin will expose the pad directly.
10944 * It make MSL invoke _prepare_async_callback.
10945 * So, we need to disable webm format in "autoplug-select" */
10946 if (caps_str && strstr(caps_str, "webm")) {
10947 LOGW("webm is not supported");
10948 result = GST_AUTOPLUG_SELECT_SKIP;
10952 /* check factory class for filtering */
10953 /* NOTE : msl don't need to use image plugins.
10954 * So, those plugins should be skipped for error handling.
10956 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10957 LOGD("skipping [%s] by not required\n", factory_name);
10958 result = GST_AUTOPLUG_SELECT_SKIP;
10962 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10963 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10964 // TO CHECK : subtitle if needed, add subparse exception.
10965 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10966 result = GST_AUTOPLUG_SELECT_SKIP;
10970 if (g_strrstr(factory_name, "mpegpsdemux")) {
10971 LOGD("skipping PS container - not support\n");
10972 result = GST_AUTOPLUG_SELECT_SKIP;
10976 if (g_strrstr(factory_name, "mssdemux"))
10977 player->smooth_streaming = TRUE;
10979 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10980 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10983 GstStructure *str = NULL;
10984 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10986 /* don't make video because of not required */
10987 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10988 (player->set_mode.media_packet_video_stream == FALSE)) {
10989 LOGD("no video because it's not required. -> return expose");
10990 result = GST_AUTOPLUG_SELECT_EXPOSE;
10994 /* get w/h for omx state-tune */
10995 /* FIXME: deprecated? */
10996 str = gst_caps_get_structure(caps, 0);
10997 gst_structure_get_int(str, "width", &width);
11000 if (player->v_stream_caps) {
11001 gst_caps_unref(player->v_stream_caps);
11002 player->v_stream_caps = NULL;
11005 player->v_stream_caps = gst_caps_copy(caps);
11006 LOGD("take caps for video state tune");
11007 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11011 if (g_strrstr(klass, "Codec/Decoder")) {
11012 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11013 LOGD("skipping %s codec", factory_name);
11014 result = GST_AUTOPLUG_SELECT_SKIP;
11020 MMPLAYER_FREEIF(caps_str);
11026 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11029 //mm_player_t* player = (mm_player_t*)data;
11030 GstCaps* caps = NULL;
11032 LOGD("[Decodebin2] pad-removed signal\n");
11034 caps = gst_pad_query_caps(new_pad, NULL);
11036 gchar* caps_str = NULL;
11037 caps_str = gst_caps_to_string(caps);
11039 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11041 MMPLAYER_FREEIF(caps_str);
11042 gst_caps_unref(caps);
11047 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11049 mm_player_t* player = (mm_player_t*)data;
11050 GstIterator *iter = NULL;
11051 GValue item = { 0, };
11052 GstPad *pad = NULL;
11053 gboolean done = FALSE;
11054 gboolean is_all_drained = TRUE;
11057 MMPLAYER_RETURN_IF_FAIL(player);
11059 LOGD("__mmplayer_gst_decode_drained");
11061 if (player->use_deinterleave == TRUE) {
11062 LOGD("group playing mode.");
11066 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11067 LOGW("Fail to get cmd lock");
11071 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11072 !__mmplayer_verify_next_play_path(player)) {
11073 LOGD("decoding is finished.");
11074 __mmplayer_reset_gapless_state(player);
11075 MMPLAYER_CMD_UNLOCK(player);
11079 player->gapless.reconfigure = TRUE;
11081 /* check decodebin src pads whether they received EOS or not */
11082 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11085 switch (gst_iterator_next(iter, &item)) {
11086 case GST_ITERATOR_OK:
11087 pad = g_value_get_object(&item);
11088 if (pad && !GST_PAD_IS_EOS(pad)) {
11089 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11090 is_all_drained = FALSE;
11093 g_value_reset(&item);
11095 case GST_ITERATOR_RESYNC:
11096 gst_iterator_resync(iter);
11098 case GST_ITERATOR_ERROR:
11099 case GST_ITERATOR_DONE:
11104 g_value_unset(&item);
11105 gst_iterator_free(iter);
11107 if (!is_all_drained) {
11108 LOGD("Wait util the all pads get EOS.");
11109 MMPLAYER_CMD_UNLOCK(player);
11114 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11115 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11117 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11118 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11119 __mmplayer_deactivate_old_path(player);
11120 MMPLAYER_CMD_UNLOCK(player);
11126 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11128 mm_player_t* player = (mm_player_t*)data;
11129 const gchar* klass = NULL;
11130 gchar* factory_name = NULL;
11132 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11133 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11135 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11137 if (__mmplayer_add_dump_buffer_probe(player, element))
11138 LOGD("add buffer probe");
11141 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11142 gchar* selected = NULL;
11143 selected = g_strdup(GST_ELEMENT_NAME(element));
11144 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11148 if (g_strrstr(klass, "Parser")) {
11149 gchar* selected = NULL;
11151 selected = g_strdup(factory_name);
11152 player->parsers = g_list_append(player->parsers, selected);
11155 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11156 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11157 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11159 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11160 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11162 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11163 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11164 "max-video-width", player->adaptive_info.limit.width,
11165 "max-video-height", player->adaptive_info.limit.height, NULL);
11167 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11168 /* FIXIT : first value will be overwritten if there's more
11169 * than 1 demuxer/parser
11172 //LOGD("plugged element is demuxer. take it\n");
11173 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11174 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11176 /*Added for multi audio support */ // Q. del?
11177 if (g_strrstr(klass, "Demux")) {
11178 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11179 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11183 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11184 int surface_type = 0;
11186 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11189 // to support trust-zone only
11190 if (g_strrstr(factory_name, "asfdemux")) {
11191 LOGD("set file-location %s\n", player->profile.uri);
11192 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11194 if (player->video_hub_download_mode == TRUE)
11195 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11196 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11197 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11198 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11199 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11200 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11201 (__mmplayer_is_only_mp3_type(player->type))) {
11202 LOGD("[mpegaudioparse] set streaming pull mode.");
11203 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11205 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11206 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11209 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11210 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11211 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11213 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11214 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11216 if (!MMPLAYER_IS_HTTP_PD(player) &&
11217 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11218 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11219 (MMPLAYER_IS_DASH_STREAMING(player)))) {
11220 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11221 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11222 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11230 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11233 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11235 if (MMPLAYER_IS_STREAMING(player))
11238 /* This callback can be set to music player only. */
11239 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11240 LOGW("audio callback is not supported for video");
11244 if (player->audio_stream_cb) {
11245 GstPad *pad = NULL;
11247 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11250 LOGE("failed to get sink pad from audiosink to probe data\n");
11253 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11254 __mmplayer_audio_stream_probe, player, NULL);
11256 gst_object_unref(pad);
11260 LOGE("There is no audio callback to configure.\n");
11270 __mmplayer_release_misc(mm_player_t* player)
11273 bool cur_mode = player->set_mode.rich_audio;
11276 MMPLAYER_RETURN_IF_FAIL(player);
11278 player->video_stream_cb = NULL;
11279 player->video_stream_cb_user_param = NULL;
11280 player->video_stream_prerolled = FALSE;
11282 player->audio_stream_cb = NULL;
11283 player->audio_stream_render_cb_ex = NULL;
11284 player->audio_stream_cb_user_param = NULL;
11285 player->audio_stream_sink_sync = false;
11287 player->video_stream_changed_cb = NULL;
11288 player->video_stream_changed_cb_user_param = NULL;
11290 player->audio_stream_changed_cb = NULL;
11291 player->audio_stream_changed_cb_user_param = NULL;
11293 player->sent_bos = FALSE;
11294 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11296 player->seek_state = MMPLAYER_SEEK_NONE;
11298 player->total_bitrate = 0;
11299 player->total_maximum_bitrate = 0;
11301 player->not_found_demuxer = 0;
11303 player->last_position = 0;
11304 player->duration = 0;
11305 player->http_content_size = 0;
11306 player->not_supported_codec = MISSING_PLUGIN_NONE;
11307 player->can_support_codec = FOUND_PLUGIN_NONE;
11308 player->pending_seek.is_pending = FALSE;
11309 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11310 player->pending_seek.pos = 0;
11311 player->msg_posted = FALSE;
11312 player->has_many_types = FALSE;
11313 player->max_audio_channels = 0;
11314 player->video_share_api_delta = 0;
11315 player->video_share_clock_delta = 0;
11316 player->is_subtitle_force_drop = FALSE;
11317 player->play_subtitle = FALSE;
11318 player->adjust_subtitle_pos = 0;
11319 player->last_multiwin_status = FALSE;
11320 player->has_closed_caption = FALSE;
11321 player->set_mode.media_packet_video_stream = FALSE;
11322 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11323 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11325 player->set_mode.rich_audio = cur_mode;
11327 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11328 player->bitrate[i] = 0;
11329 player->maximum_bitrate[i] = 0;
11332 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11334 /* remove media stream cb(appsrc cb) */
11335 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11336 player->media_stream_buffer_status_cb[i] = NULL;
11337 player->media_stream_seek_data_cb[i] = NULL;
11338 player->buffer_cb_user_param[i] = NULL;
11339 player->seek_cb_user_param[i] = NULL;
11341 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11343 /* free memory related to audio effect */
11344 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11346 if (player->adaptive_info.var_list) {
11347 g_list_free_full(player->adaptive_info.var_list, g_free);
11348 player->adaptive_info.var_list = NULL;
11351 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11352 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11353 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11355 /* Reset video360 settings to their defaults in case if the pipeline is to be
11358 player->video360_metadata.is_spherical = -1;
11359 player->is_openal_plugin_used = FALSE;
11361 player->is_content_spherical = FALSE;
11362 player->is_video360_enabled = TRUE;
11363 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11364 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11365 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11366 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11367 player->video360_zoom = 1.0f;
11368 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11369 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11371 player->sound.rg_enable = false;
11377 __mmplayer_release_misc_post(mm_player_t* player)
11379 char *original_uri = NULL;
11382 /* player->pipeline is already released before. */
11384 MMPLAYER_RETURN_IF_FAIL(player);
11386 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11388 /* clean found parsers */
11389 if (player->parsers) {
11390 GList *parsers = player->parsers;
11391 for (; parsers; parsers = g_list_next(parsers)) {
11392 gchar *name = parsers->data;
11393 MMPLAYER_FREEIF(name);
11395 g_list_free(player->parsers);
11396 player->parsers = NULL;
11399 /* clean found audio decoders */
11400 if (player->audio_decoders) {
11401 GList *a_dec = player->audio_decoders;
11402 for (; a_dec; a_dec = g_list_next(a_dec)) {
11403 gchar *name = a_dec->data;
11404 MMPLAYER_FREEIF(name);
11406 g_list_free(player->audio_decoders);
11407 player->audio_decoders = NULL;
11410 /* clean the uri list except original uri */
11411 if (player->uri_info.uri_list) {
11412 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11414 if (player->attrs) {
11415 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11416 LOGD("restore original uri = %s\n", original_uri);
11418 if (mmf_attrs_commit(player->attrs))
11419 LOGE("failed to commit the original uri.\n");
11422 GList *uri_list = player->uri_info.uri_list;
11423 for (; uri_list; uri_list = g_list_next(uri_list)) {
11424 gchar *uri = uri_list->data;
11425 MMPLAYER_FREEIF(uri);
11427 g_list_free(player->uri_info.uri_list);
11428 player->uri_info.uri_list = NULL;
11431 /* clear the audio stream buffer list */
11432 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11434 /* clear the video stream bo list */
11435 __mmplayer_video_stream_destroy_bo_list(player);
11436 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11438 if (player->profile.input_mem.buf) {
11439 free(player->profile.input_mem.buf);
11440 player->profile.input_mem.buf = NULL;
11442 player->profile.input_mem.len = 0;
11443 player->profile.input_mem.offset = 0;
11445 player->uri_info.uri_idx = 0;
11449 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11451 GstElement *element = NULL;
11454 LOGD("creating %s to plug\n", name);
11456 element = gst_element_factory_make(name, NULL);
11458 LOGE("failed to create queue\n");
11462 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11463 LOGE("failed to set state READY to %s\n", name);
11464 gst_object_unref(element);
11468 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11469 LOGE("failed to add %s\n", name);
11470 gst_object_unref(element);
11474 sinkpad = gst_element_get_static_pad(element, "sink");
11476 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11477 LOGE("failed to link %s\n", name);
11478 gst_object_unref(sinkpad);
11479 gst_object_unref(element);
11483 LOGD("linked %s to pipeline successfully\n", name);
11485 gst_object_unref(sinkpad);
11491 __mmplayer_check_subtitle(mm_player_t* player)
11493 MMHandleType attrs = 0;
11494 char *subtitle_uri = NULL;
11498 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11500 /* get subtitle attribute */
11501 attrs = MMPLAYER_GET_ATTRS(player);
11505 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11506 if (!subtitle_uri || !strlen(subtitle_uri))
11509 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11510 player->is_external_subtitle_present = TRUE;
11518 __mmplayer_can_extract_pcm(mm_player_t* player)
11520 MMHandleType attrs = 0;
11521 gboolean sound_extraction = FALSE;
11523 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11525 attrs = MMPLAYER_GET_ATTRS(player);
11527 LOGE("fail to get attributes.");
11531 /* get sound_extraction property */
11532 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11534 if (!sound_extraction) {
11535 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11543 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11546 MMMessageParamType msg_param;
11547 gchar *msg_src_element = NULL;
11548 GstStructure *s = NULL;
11549 guint error_id = 0;
11550 gchar *error_string = NULL;
11554 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11555 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11557 s = gst_structure_copy(gst_message_get_structure(message));
11560 if (!gst_structure_get_uint(s, "error_id", &error_id))
11561 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11563 switch (error_id) {
11564 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11565 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11567 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11568 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11570 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11571 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11573 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11574 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11576 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11577 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11579 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11580 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11582 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11583 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11585 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11586 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11588 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11589 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11591 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11592 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11594 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11595 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11597 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11598 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11600 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11601 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11603 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11604 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11606 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11607 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11609 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11610 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11612 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11613 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11615 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11616 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11618 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11619 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11621 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11622 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11624 case MMPLAYER_STREAMING_ERROR_GONE:
11625 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11627 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11628 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11630 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11631 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11633 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11634 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11636 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11637 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11639 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11640 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11642 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11643 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11645 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11646 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11648 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11649 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11651 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11652 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11654 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11655 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11657 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11658 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11660 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11661 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11663 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11664 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11666 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11667 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11669 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11670 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11672 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11673 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11675 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11676 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11678 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11679 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11681 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11682 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11684 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11685 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11687 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11688 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11690 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11691 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11693 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11694 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11696 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11697 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11701 gst_structure_free(s);
11702 return MM_ERROR_PLAYER_STREAMING_FAIL;
11706 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11708 msg_param.data = (void *) error_string;
11710 if (message->src) {
11711 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11713 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11714 msg_src_element, msg_param.code, (char*)msg_param.data);
11717 /* post error to application */
11718 if (!player->msg_posted) {
11719 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11721 /* don't post more if one was sent already */
11722 player->msg_posted = TRUE;
11724 LOGD("skip error post because it's sent already.\n");
11726 gst_structure_free(s);
11728 g_free(error_string);
11735 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11737 MMPLAYER_RETURN_IF_FAIL(player);
11739 /* post now if delay is zero */
11740 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11741 LOGD("eos delay is zero. posting EOS now\n");
11742 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11744 if (player->set_mode.pcm_extraction)
11745 __mmplayer_cancel_eos_timer(player);
11750 /* cancel if existing */
11751 __mmplayer_cancel_eos_timer(player);
11753 /* init new timeout */
11754 /* NOTE : consider give high priority to this timer */
11755 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11757 player->eos_timer = g_timeout_add(delay_in_ms,
11758 __mmplayer_eos_timer_cb, player);
11760 player->context.global_default = g_main_context_default();
11761 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11763 /* check timer is valid. if not, send EOS now */
11764 if (player->eos_timer == 0) {
11765 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11766 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11771 __mmplayer_cancel_eos_timer(mm_player_t* player)
11773 MMPLAYER_RETURN_IF_FAIL(player);
11775 if (player->eos_timer) {
11776 LOGD("cancel eos timer");
11777 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11778 player->eos_timer = 0;
11785 __mmplayer_eos_timer_cb(gpointer u_data)
11787 mm_player_t* player = NULL;
11788 MMHandleType attrs = 0;
11791 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11793 player = (mm_player_t*) u_data;
11794 attrs = MMPLAYER_GET_ATTRS(player);
11796 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11799 gint ret_value = 0;
11800 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11801 if (ret_value != MM_ERROR_NONE)
11802 LOGE("seeking to 0 failed in repeat play");
11805 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11808 /* we are returning FALSE as we need only one posting */
11812 /* sending event to one of sinkelements */
11814 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11816 GstEvent * event2 = NULL;
11817 GList *sinks = NULL;
11818 gboolean res = FALSE;
11821 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11822 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11824 /* While adding subtitles in live feeds seek is getting called.
11825 Adding defensive check in framework layer.*/
11826 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11827 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11828 LOGE("Should not send seek event during live playback");
11833 if (player->play_subtitle)
11834 event2 = gst_event_copy((const GstEvent *)event);
11836 sinks = player->sink_elements;
11838 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11840 if (GST_IS_ELEMENT(sink)) {
11841 /* keep ref to the event */
11842 gst_event_ref(event);
11844 if ((res = gst_element_send_event(sink, event))) {
11845 LOGD("sending event[%s] to sink element [%s] success!\n",
11846 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11848 /* rtsp case, asyn_done is not called after seek during pause state */
11849 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11850 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11851 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11852 LOGD("RTSP seek completed, after pause state..\n");
11853 player->seek_state = MMPLAYER_SEEK_NONE;
11854 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11860 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11861 sinks = g_list_next(sinks);
11868 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11869 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11872 sinks = g_list_next(sinks);
11875 /* Note : Textbin is not linked to the video or audio bin.
11876 * It needs to send the event to the text sink seperatelly.
11878 if (player->play_subtitle && player->pipeline) {
11879 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11881 if (GST_IS_ELEMENT(text_sink)) {
11882 /* keep ref to the event */
11883 gst_event_ref(event2);
11885 if ((res = gst_element_send_event(text_sink, event2)))
11886 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11887 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11889 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11890 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11892 gst_event_unref(event2);
11896 gst_event_unref(event);
11904 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11908 MMPLAYER_RETURN_IF_FAIL(player);
11909 MMPLAYER_RETURN_IF_FAIL(sink);
11911 player->sink_elements =
11912 g_list_append(player->sink_elements, sink);
11918 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11922 MMPLAYER_RETURN_IF_FAIL(player);
11923 MMPLAYER_RETURN_IF_FAIL(sink);
11925 player->sink_elements =
11926 g_list_remove(player->sink_elements, sink);
11932 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11933 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11934 gint64 cur, GstSeekType stop_type, gint64 stop)
11936 GstEvent* event = NULL;
11937 gboolean result = FALSE;
11941 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11943 if (player->pipeline && player->pipeline->textbin)
11944 __mmplayer_drop_subtitle(player, FALSE);
11946 event = gst_event_new_seek(rate, format, flags, cur_type,
11947 cur, stop_type, stop);
11949 result = __gst_send_event_to_sink(player, event);
11956 /* NOTE : be careful with calling this api. please refer to below glib comment
11957 * glib comment : Note that there is a bug in GObject that makes this function much
11958 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11959 * will no longer be called, but, the signal handler is not currently disconnected.
11960 * If the instance is itself being freed at the same time than this doesn't matter,
11961 * since the signal will automatically be removed, but if instance persists,
11962 * then the signal handler will leak. You should not remove the signal yourself
11963 * because in a future versions of GObject, the handler will automatically be
11966 * It's possible to work around this problem in a way that will continue to work
11967 * with future versions of GObject by checking that the signal handler is still
11968 * connected before disconnected it:
11970 * if (g_signal_handler_is_connected(instance, id))
11971 * g_signal_handler_disconnect(instance, id);
11974 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11976 GList* sig_list = NULL;
11977 MMPlayerSignalItem* item = NULL;
11981 MMPLAYER_RETURN_IF_FAIL(player);
11983 LOGD("release signals type : %d", type);
11985 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11986 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11987 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11988 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11989 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11990 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11994 sig_list = player->signals[type];
11996 for (; sig_list; sig_list = sig_list->next) {
11997 item = sig_list->data;
11999 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12000 if (g_signal_handler_is_connected(item->obj, item->sig))
12001 g_signal_handler_disconnect(item->obj, item->sig);
12004 MMPLAYER_FREEIF(item);
12007 g_list_free(player->signals[type]);
12008 player->signals[type] = NULL;
12015 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12017 mm_player_t* player = 0;
12018 int prev_display_surface_type = 0;
12019 void *prev_display_overlay = NULL;
12020 const gchar *klass = NULL;
12021 gchar *cur_videosink_name = NULL;
12024 int num_of_dec = 2; /* DEC1, DEC2 */
12028 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12029 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12031 player = MM_PLAYER_CAST(handle);
12033 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12034 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12036 return MM_ERROR_INVALID_ARGUMENT;
12039 /* load previous attributes */
12040 if (player->attrs) {
12041 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12042 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12043 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12044 if (prev_display_surface_type == surface_type) {
12045 LOGD("incoming display surface type is same as previous one, do nothing..");
12047 return MM_ERROR_NONE;
12050 LOGE("failed to load attributes");
12052 return MM_ERROR_PLAYER_INTERNAL;
12055 /* check videosink element is created */
12056 if (!player->pipeline || !player->pipeline->videobin ||
12057 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12058 LOGD("videosink element is not yet ready");
12060 /* videobin is not created yet, so we just set attributes related to display surface */
12061 LOGD("store display attribute for given surface type(%d)", surface_type);
12062 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12063 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12064 if (mmf_attrs_commit(player->attrs)) {
12065 LOGE("failed to commit attribute");
12067 return MM_ERROR_PLAYER_INTERNAL;
12070 return MM_ERROR_NONE;
12072 /* get player command status */
12073 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12074 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12076 return MM_ERROR_PLAYER_INVALID_STATE;
12079 /* surface change */
12080 for (i = 0 ; i < num_of_dec ; i++) {
12081 if (player->pipeline->mainbin &&
12082 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12083 GstElementFactory *decfactory;
12084 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12086 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12087 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12088 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12089 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12093 LOGW("success to changing display surface(%d)", surface_type);
12095 return MM_ERROR_NONE;
12097 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12098 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12102 LOGW("success to changing display surface(%d)", surface_type);
12104 return MM_ERROR_NONE;
12107 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12108 ret = MM_ERROR_PLAYER_INTERNAL;
12117 /* rollback to previous attributes */
12118 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12119 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12120 if (mmf_attrs_commit(player->attrs)) {
12121 LOGE("failed to commit attributes to rollback");
12123 return MM_ERROR_PLAYER_INTERNAL;
12129 /* NOTE : It does not support some use cases, eg using colorspace converter */
12131 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12133 GstPad *src_pad_dec = NULL;
12134 GstPad *sink_pad_videosink = NULL;
12135 GstPad *sink_pad_videobin = NULL;
12136 GstClock *clock = NULL;
12137 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12138 int ret = MM_ERROR_NONE;
12139 gboolean is_audiobin_created = TRUE;
12143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12144 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12145 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12147 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12148 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12150 /* get information whether if audiobin is created */
12151 if (!player->pipeline->audiobin ||
12152 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12153 LOGW("audiobin is null, this video content may not have audio data");
12154 is_audiobin_created = FALSE;
12157 /* get current state of player */
12158 previous_state = MMPLAYER_CURRENT_STATE(player);
12159 LOGD("previous state(%d)", previous_state);
12162 /* get src pad of decoder and block it */
12163 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12164 if (!src_pad_dec) {
12165 LOGE("failed to get src pad from decode in mainbin");
12166 return MM_ERROR_PLAYER_INTERNAL;
12169 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12170 LOGW("trying to block pad(video)");
12171 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12172 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12175 LOGE("failed to set block pad(video)");
12176 return MM_ERROR_PLAYER_INTERNAL;
12178 LOGW("pad is blocked(video)");
12180 /* no data flows, so no need to do pad_block */
12181 if (player->seek_state != MMPLAYER_SEEK_NONE)
12182 LOGW("not completed seek(%d), do nothing", player->seek_state);
12184 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12188 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12189 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12190 LOGE("failed to remove previous ghost_pad for videobin");
12191 return MM_ERROR_PLAYER_INTERNAL;
12194 /* change state of videobin to NULL */
12195 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12196 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12197 if (ret != GST_STATE_CHANGE_SUCCESS) {
12198 LOGE("failed to change state of videobin to NULL");
12199 return MM_ERROR_PLAYER_INTERNAL;
12202 /* unlink between decoder and videobin and remove previous videosink from videobin */
12203 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12204 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12205 LOGE("failed to remove former videosink from videobin");
12206 return MM_ERROR_PLAYER_INTERNAL;
12209 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12211 /* create a new videosink and add it to videobin */
12212 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12213 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12214 LOGE("failed to create videosink element\n");
12216 return MM_ERROR_PLAYER_INTERNAL;
12218 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12219 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12220 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12222 /* save attributes */
12223 if (player->attrs) {
12224 /* set a new display surface type */
12225 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12226 /* set a new diplay overlay */
12227 switch (surface_type) {
12228 case MM_DISPLAY_SURFACE_OVERLAY:
12229 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12230 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12233 LOGE("invalid type(%d) for changing display surface", surface_type);
12235 return MM_ERROR_INVALID_ARGUMENT;
12237 if (mmf_attrs_commit(player->attrs)) {
12238 LOGE("failed to commit");
12240 return MM_ERROR_PLAYER_INTERNAL;
12243 LOGE("player->attrs is null, failed to save attributes");
12245 return MM_ERROR_PLAYER_INTERNAL;
12248 /* update video param */
12249 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12250 LOGE("failed to update video param");
12251 return MM_ERROR_PLAYER_INTERNAL;
12254 /* change state of videobin to READY */
12255 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12256 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12257 if (ret != GST_STATE_CHANGE_SUCCESS) {
12258 LOGE("failed to change state of videobin to READY");
12259 return MM_ERROR_PLAYER_INTERNAL;
12262 /* change ghostpad */
12263 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12264 if (!sink_pad_videosink) {
12265 LOGE("failed to get sink pad from videosink element");
12266 return MM_ERROR_PLAYER_INTERNAL;
12268 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12269 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12270 LOGE("failed to set active to ghost_pad");
12271 return MM_ERROR_PLAYER_INTERNAL;
12273 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12274 LOGE("failed to change ghostpad for videobin");
12275 return MM_ERROR_PLAYER_INTERNAL;
12277 gst_object_unref(sink_pad_videosink);
12279 /* link decoder with videobin */
12280 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12281 if (!sink_pad_videobin) {
12282 LOGE("failed to get sink pad from videobin");
12283 return MM_ERROR_PLAYER_INTERNAL;
12285 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12286 LOGE("failed to link");
12287 return MM_ERROR_PLAYER_INTERNAL;
12289 gst_object_unref(sink_pad_videobin);
12291 /* clock setting for a new videosink plugin */
12292 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12293 so we set it from audiosink plugin or pipeline(system clock) */
12294 if (!is_audiobin_created) {
12295 LOGW("audiobin is not created, get clock from pipeline..");
12296 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12298 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12302 GstClockTime base_time;
12303 LOGD("set the clock to videosink");
12304 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12305 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12307 LOGD("got clock of videosink");
12308 now = gst_clock_get_time(clock);
12309 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12310 LOGD("at time %" GST_TIME_FORMAT ", base %"
12311 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12313 LOGE("failed to get clock of videosink after setting clock");
12314 return MM_ERROR_PLAYER_INTERNAL;
12317 LOGW("failed to get clock, maybe it is the time before first playing");
12319 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12320 /* change state of videobin to PAUSED */
12321 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12322 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12323 if (ret != GST_STATE_CHANGE_FAILURE) {
12324 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12326 LOGE("failed to change state of videobin to PLAYING");
12327 return MM_ERROR_PLAYER_INTERNAL;
12330 /* release blocked and unref src pad of video decoder */
12332 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12333 LOGE("failed to set pad blocked FALSE(video)");
12334 return MM_ERROR_PLAYER_INTERNAL;
12337 LOGW("pad is unblocked(video)");
12339 if (player->seek_state != MMPLAYER_SEEK_NONE)
12340 LOGW("not completed seek(%d)", player->seek_state);
12341 /* change state of videobin to PAUSED */
12342 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12343 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12344 if (ret != GST_STATE_CHANGE_FAILURE) {
12345 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12347 LOGE("failed to change state of videobin to PLAYING");
12348 return MM_ERROR_PLAYER_INTERNAL;
12351 /* already skipped pad block */
12352 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12355 /* do get/set position for new videosink plugin */
12357 gint64 position = 0;
12359 LOGD("do get/set position for new videosink plugin");
12360 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12361 LOGE("failed to get position");
12362 return MM_ERROR_PLAYER_INTERNAL;
12364 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12365 /* accurate seek */
12366 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12367 LOGE("failed to set position");
12368 return MM_ERROR_PLAYER_INTERNAL;
12371 /* key unit seek */
12372 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12373 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12374 GST_SEEK_TYPE_SET, position,
12375 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12377 LOGE("failed to set position");
12378 return MM_ERROR_PLAYER_INTERNAL;
12384 gst_object_unref(src_pad_dec);
12385 LOGD("success to change sink");
12389 return MM_ERROR_NONE;
12393 /* Note : if silent is true, then subtitle would not be displayed. :*/
12394 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12396 mm_player_t* player = (mm_player_t*) hplayer;
12400 /* check player handle */
12401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12403 player->set_mode.subtitle_off = silent;
12405 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12409 return MM_ERROR_NONE;
12412 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12414 MMPlayerGstElement* mainbin = NULL;
12415 MMPlayerGstElement* textbin = NULL;
12416 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12417 GstState current_state = GST_STATE_VOID_PENDING;
12418 GstState element_state = GST_STATE_VOID_PENDING;
12419 GstState element_pending_state = GST_STATE_VOID_PENDING;
12421 GstEvent *event = NULL;
12422 int result = MM_ERROR_NONE;
12424 GstClock *curr_clock = NULL;
12425 GstClockTime base_time, start_time, curr_time;
12430 /* check player handle */
12431 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12432 player->pipeline &&
12433 player->pipeline->mainbin &&
12434 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12436 mainbin = player->pipeline->mainbin;
12437 textbin = player->pipeline->textbin;
12439 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12441 // sync clock with current pipeline
12442 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12443 curr_time = gst_clock_get_time(curr_clock);
12445 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12446 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12448 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12449 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12451 if (current_state > GST_STATE_READY) {
12452 // sync state with current pipeline
12453 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12454 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12455 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12457 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12458 if (GST_STATE_CHANGE_FAILURE == ret) {
12459 LOGE("fail to state change.\n");
12460 result = MM_ERROR_PLAYER_INTERNAL;
12465 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12466 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12469 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12470 gst_object_unref(curr_clock);
12473 // seek to current position
12474 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12475 result = MM_ERROR_PLAYER_INVALID_STATE;
12476 LOGE("gst_element_query_position failed, invalid state\n");
12480 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12481 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);
12483 __gst_send_event_to_sink(player, event);
12485 result = MM_ERROR_PLAYER_INTERNAL;
12486 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12490 /* sync state with current pipeline */
12491 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12492 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12493 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12495 return MM_ERROR_NONE;
12498 /* release text pipeline resource */
12499 player->textsink_linked = 0;
12501 /* release signal */
12502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12504 /* release textbin with it's childs */
12505 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12506 MMPLAYER_FREEIF(player->pipeline->textbin);
12507 player->pipeline->textbin = NULL;
12509 /* release subtitle elem */
12510 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12511 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12517 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12519 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12520 GstState current_state = GST_STATE_VOID_PENDING;
12522 MMHandleType attrs = 0;
12523 MMPlayerGstElement* mainbin = NULL;
12524 MMPlayerGstElement* textbin = NULL;
12526 gchar* subtitle_uri = NULL;
12527 int result = MM_ERROR_NONE;
12528 const gchar *charset = NULL;
12532 /* check player handle */
12533 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12534 player->pipeline &&
12535 player->pipeline->mainbin &&
12536 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12537 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12539 mainbin = player->pipeline->mainbin;
12540 textbin = player->pipeline->textbin;
12542 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12543 if (current_state < GST_STATE_READY) {
12544 result = MM_ERROR_PLAYER_INVALID_STATE;
12545 LOGE("Pipeline is not in proper state\n");
12549 attrs = MMPLAYER_GET_ATTRS(player);
12551 LOGE("cannot get content attribute\n");
12552 result = MM_ERROR_PLAYER_INTERNAL;
12556 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12557 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12558 LOGE("subtitle uri is not proper filepath\n");
12559 result = MM_ERROR_PLAYER_INVALID_URI;
12563 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12564 LOGE("failed to get storage info of subtitle path");
12565 result = MM_ERROR_PLAYER_INVALID_URI;
12569 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12570 LOGD("new subtitle file path is [%s]\n", filepath);
12572 if (!strcmp(filepath, subtitle_uri)) {
12573 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12576 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12577 if (mmf_attrs_commit(player->attrs)) {
12578 LOGE("failed to commit.\n");
12583 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12584 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12585 player->subtitle_language_list = NULL;
12586 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12588 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12589 if (ret != GST_STATE_CHANGE_SUCCESS) {
12590 LOGE("failed to change state of textbin to READY");
12591 result = MM_ERROR_PLAYER_INTERNAL;
12595 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12596 if (ret != GST_STATE_CHANGE_SUCCESS) {
12597 LOGE("failed to change state of subparse to READY");
12598 result = MM_ERROR_PLAYER_INTERNAL;
12602 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12603 if (ret != GST_STATE_CHANGE_SUCCESS) {
12604 LOGE("failed to change state of filesrc to READY");
12605 result = MM_ERROR_PLAYER_INTERNAL;
12609 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12611 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12613 charset = util_get_charset(filepath);
12615 LOGD("detected charset is %s\n", charset);
12616 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12619 result = _mmplayer_sync_subtitle_pipeline(player);
12626 /* API to switch between external subtitles */
12627 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12629 int result = MM_ERROR_NONE;
12630 mm_player_t* player = (mm_player_t*)hplayer;
12635 /* check player handle */
12636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12638 /* filepath can be null in idle state */
12640 /* check file path */
12641 if ((path = strstr(filepath, "file://")))
12642 result = util_exist_file_path(path + 7);
12644 result = util_exist_file_path(filepath);
12646 if (result != MM_ERROR_NONE) {
12647 LOGE("invalid subtitle path 0x%X", result);
12648 return result; /* file not found or permission denied */
12652 if (!player->pipeline) {
12654 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12655 if (mmf_attrs_commit(player->attrs)) {
12656 LOGE("failed to commit"); /* subtitle path will not be created */
12657 return MM_ERROR_PLAYER_INTERNAL;
12660 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12661 /* check filepath */
12662 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12664 if (!__mmplayer_check_subtitle(player)) {
12665 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12666 if (mmf_attrs_commit(player->attrs)) {
12667 LOGE("failed to commit");
12668 return MM_ERROR_PLAYER_INTERNAL;
12671 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12672 LOGE("fail to create text pipeline");
12673 return MM_ERROR_PLAYER_INTERNAL;
12676 result = _mmplayer_sync_subtitle_pipeline(player);
12678 result = __mmplayer_change_external_subtitle_language(player, filepath);
12681 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12682 player->is_external_subtitle_added_now = TRUE;
12684 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12685 if (!player->subtitle_language_list) {
12686 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12687 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12688 LOGW("subtitle language list is not updated yet");
12690 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12698 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12700 int result = MM_ERROR_NONE;
12701 gchar* change_pad_name = NULL;
12702 GstPad* sinkpad = NULL;
12703 MMPlayerGstElement* mainbin = NULL;
12704 enum MainElementID elemId = MMPLAYER_M_NUM;
12705 GstCaps* caps = NULL;
12706 gint total_track_num = 0;
12710 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12711 MM_ERROR_PLAYER_NOT_INITIALIZED);
12713 LOGD("Change Track(%d) to %d\n", type, index);
12715 mainbin = player->pipeline->mainbin;
12717 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12718 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12719 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12720 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12722 /* Changing Video Track is not supported. */
12723 LOGE("Track Type Error\n");
12727 if (mainbin[elemId].gst == NULL) {
12728 result = MM_ERROR_PLAYER_NO_OP;
12729 LOGD("Req track doesn't exist\n");
12733 total_track_num = player->selector[type].total_track_num;
12734 if (total_track_num <= 0) {
12735 result = MM_ERROR_PLAYER_NO_OP;
12736 LOGD("Language list is not available \n");
12740 if ((index < 0) || (index >= total_track_num)) {
12741 result = MM_ERROR_INVALID_ARGUMENT;
12742 LOGD("Not a proper index : %d \n", index);
12746 /*To get the new pad from the selector*/
12747 change_pad_name = g_strdup_printf("sink_%u", index);
12748 if (change_pad_name == NULL) {
12749 result = MM_ERROR_PLAYER_INTERNAL;
12750 LOGD("Pad does not exists\n");
12754 LOGD("new active pad name: %s\n", change_pad_name);
12756 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12757 if (sinkpad == NULL) {
12758 LOGD("sinkpad is NULL");
12759 result = MM_ERROR_PLAYER_INTERNAL;
12763 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12764 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12766 caps = gst_pad_get_current_caps(sinkpad);
12767 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12770 gst_object_unref(sinkpad);
12772 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12773 __mmplayer_set_audio_attrs(player, caps);
12777 MMPLAYER_FREEIF(change_pad_name);
12781 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12783 int result = MM_ERROR_NONE;
12784 mm_player_t* player = NULL;
12785 MMPlayerGstElement* mainbin = NULL;
12787 gint current_active_index = 0;
12789 GstState current_state = GST_STATE_VOID_PENDING;
12790 GstEvent* event = NULL;
12795 player = (mm_player_t*)hplayer;
12796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12798 if (!player->pipeline) {
12799 LOGE("Track %d pre setting -> %d\n", type, index);
12801 player->selector[type].active_pad_index = index;
12805 mainbin = player->pipeline->mainbin;
12807 current_active_index = player->selector[type].active_pad_index;
12809 /*If index is same as running index no need to change the pad*/
12810 if (current_active_index == index)
12813 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12814 result = MM_ERROR_PLAYER_INVALID_STATE;
12818 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12819 if (current_state < GST_STATE_PAUSED) {
12820 result = MM_ERROR_PLAYER_INVALID_STATE;
12821 LOGW("Pipeline not in porper state\n");
12825 result = __mmplayer_change_selector_pad(player, type, index);
12826 if (result != MM_ERROR_NONE) {
12827 LOGE("change selector pad error\n");
12831 player->selector[type].active_pad_index = index;
12833 if (current_state == GST_STATE_PLAYING) {
12834 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);
12836 __gst_send_event_to_sink(player, event);
12838 result = MM_ERROR_PLAYER_INTERNAL;
12847 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12849 mm_player_t* player = (mm_player_t*) hplayer;
12853 /* check player handle */
12854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12856 *silent = player->set_mode.subtitle_off;
12858 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12862 return MM_ERROR_NONE;
12866 __is_ms_buff_src(mm_player_t* player)
12868 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12870 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12874 __has_suffix(mm_player_t* player, const gchar* suffix)
12876 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12877 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12879 gboolean ret = FALSE;
12880 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12881 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12883 if (g_str_has_suffix(player->profile.uri, suffix))
12886 MMPLAYER_FREEIF(t_url);
12887 MMPLAYER_FREEIF(t_suffix);
12893 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12895 mm_player_t* player = (mm_player_t*) hplayer;
12897 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12899 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12900 MMPLAYER_PRINT_STATE(player);
12901 LOGE("wrong-state : can't set the download mode to parse");
12902 return MM_ERROR_PLAYER_INVALID_STATE;
12905 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12906 player->video_hub_download_mode = mode;
12908 return MM_ERROR_NONE;
12912 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12914 mm_player_t* player = (mm_player_t*) hplayer;
12916 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12918 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12919 player->sync_handler = enable;
12921 return MM_ERROR_NONE;
12925 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12926 gint64 video_time, gint64 media_clock, gint64 audio_time)
12928 mm_player_t* player = (mm_player_t*) hplayer;
12929 MMPlayerGstElement* mainbin = NULL;
12930 GstClockTime start_time_audio = 0, start_time_video = 0;
12931 GstClockTimeDiff base_time = 0, new_base_time = 0;
12932 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12933 gint64 api_delta = 0;
12934 gint64 position = 0, position_delta = 0;
12935 gint64 adj_base_time = 0;
12936 GstClock *curr_clock = NULL;
12937 GstClockTime curr_time = 0;
12938 gboolean query_ret = TRUE;
12939 int result = MM_ERROR_NONE;
12943 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12944 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12945 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12947 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12948 clock, clock_delta, video_time, media_clock, audio_time); */
12950 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
12951 LOGD("skip setting master clock. %lld", video_time);
12955 mainbin = player->pipeline->mainbin;
12957 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12958 curr_time = gst_clock_get_time(curr_clock);
12960 current_state = MMPLAYER_CURRENT_STATE(player);
12962 if (current_state == MM_PLAYER_STATE_PLAYING)
12963 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12965 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12967 position = player->last_position;
12968 LOGD("query fail. %"G_GINT64_FORMAT, position);
12971 clock *= GST_USECOND;
12972 clock_delta *= GST_USECOND;
12974 api_delta = clock - curr_time;
12975 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12976 player->video_share_api_delta = api_delta;
12978 clock_delta += (api_delta - player->video_share_api_delta);
12980 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12981 player->video_share_clock_delta = (gint64)clock_delta;
12983 position_delta = (position/GST_USECOND) - video_time;
12984 position_delta *= GST_USECOND;
12986 adj_base_time = position_delta;
12987 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
12990 gint64 new_play_time = 0;
12991 gint64 network_delay = 0;
12993 video_time *= GST_USECOND;
12995 network_delay = clock_delta - player->video_share_clock_delta;
12996 new_play_time = video_time + network_delay;
12998 adj_base_time = position - new_play_time;
13000 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13001 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13002 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13005 /* Adjust Current Stream Time with base_time of sink
13006 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13007 * 2. Set new base time
13008 * if adj_base_time is positive value, the stream time will be decreased.
13009 * 3. If seek event is occurred, the start time will be reset. */
13010 if ((player->pipeline->audiobin) &&
13011 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13012 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13014 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13015 LOGD("audio sink : gst_element_set_start_time -> NONE");
13016 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13019 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13022 if ((player->pipeline->videobin) &&
13023 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13024 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13026 if (start_time_video != GST_CLOCK_TIME_NONE) {
13027 LOGD("video sink : gst_element_set_start_time -> NONE");
13028 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13031 // if videobin exist, get base_time from videobin.
13032 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13035 new_base_time = base_time + adj_base_time;
13037 if ((player->pipeline->audiobin) &&
13038 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13039 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13041 if ((player->pipeline->videobin) &&
13042 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13043 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13052 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13054 mm_player_t* player = (mm_player_t*) hplayer;
13055 MMPlayerGstElement* mainbin = NULL;
13056 GstClock *curr_clock = NULL;
13057 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13058 gint64 position = 0;
13059 gboolean query_ret = TRUE;
13063 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13064 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13065 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13067 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13068 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13069 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13071 mainbin = player->pipeline->mainbin;
13073 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13075 current_state = MMPLAYER_CURRENT_STATE(player);
13077 if (current_state != MM_PLAYER_STATE_PAUSED)
13078 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13080 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13082 position = player->last_position;
13084 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13086 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13089 gst_object_unref(curr_clock);
13093 return MM_ERROR_NONE;
13097 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13099 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13100 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13102 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13103 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13107 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13108 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13109 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13110 mm_player_dump_t *dump_s;
13111 dump_s = g_malloc(sizeof(mm_player_dump_t));
13113 if (dump_s == NULL) {
13114 LOGE("malloc fail");
13118 dump_s->dump_element_file = NULL;
13119 dump_s->dump_pad = NULL;
13120 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13122 if (dump_s->dump_pad) {
13123 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13124 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]);
13125 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13126 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);
13127 /* add list for removed buffer probe and close FILE */
13128 player->dump_list = g_list_append(player->dump_list, dump_s);
13129 LOGD("%s sink pad added buffer probe for dump", factory_name);
13134 LOGE("failed to get %s sink pad added", factory_name);
13143 static GstPadProbeReturn
13144 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13146 FILE *dump_data = (FILE *) u_data;
13147 // int written = 0;
13148 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13149 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13151 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13153 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13155 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13157 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13159 return GST_PAD_PROBE_OK;
13163 __mmplayer_release_dump_list(GList *dump_list)
13166 GList *d_list = dump_list;
13167 for (; d_list; d_list = g_list_next(d_list)) {
13168 mm_player_dump_t *dump_s = d_list->data;
13169 if (dump_s->dump_pad) {
13170 if (dump_s->probe_handle_id)
13171 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13173 if (dump_s->dump_element_file) {
13174 fclose(dump_s->dump_element_file);
13175 dump_s->dump_element_file = NULL;
13177 MMPLAYER_FREEIF(dump_s);
13179 g_list_free(dump_list);
13185 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13187 mm_player_t* player = (mm_player_t*) hplayer;
13191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13192 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13194 *exist = player->has_closed_caption;
13198 return MM_ERROR_NONE;
13201 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13205 // LOGD("unref internal gst buffer %p", buffer);
13206 gst_buffer_unref((GstBuffer *)buffer);
13213 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13215 mm_player_t *player = (mm_player_t*)user_data;
13216 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13217 guint64 current_level_bytes = 0;
13219 MMPLAYER_RETURN_IF_FAIL(player);
13221 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13223 LOGI("app-src: feed audio(%llu)", current_level_bytes);
13224 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13226 if (player->media_stream_buffer_status_cb[type])
13227 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13228 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13233 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13235 mm_player_t *player = (mm_player_t*)user_data;
13236 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13237 guint64 current_level_bytes = 0;
13239 MMPLAYER_RETURN_IF_FAIL(player);
13241 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13243 LOGI("app-src: feed video(%llu)", current_level_bytes);
13245 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13246 if (player->media_stream_buffer_status_cb[type])
13247 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13248 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13252 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13254 mm_player_t *player = (mm_player_t*)user_data;
13255 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13256 guint64 current_level_bytes = 0;
13258 MMPLAYER_RETURN_IF_FAIL(player);
13260 LOGI("app-src: feed subtitle");
13262 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13264 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13265 if (player->media_stream_buffer_status_cb[type])
13266 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13268 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13272 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13274 mm_player_t *player = (mm_player_t*)user_data;
13275 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13276 guint64 current_level_bytes = 0;
13278 MMPLAYER_RETURN_IF_FAIL(player);
13280 LOGI("app-src: audio buffer is full");
13282 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13284 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13286 if (player->media_stream_buffer_status_cb[type])
13287 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13289 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13293 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13295 mm_player_t *player = (mm_player_t*)user_data;
13296 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13297 guint64 current_level_bytes = 0;
13299 MMPLAYER_RETURN_IF_FAIL(player);
13301 LOGI("app-src: video buffer is full");
13303 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13305 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13306 if (player->media_stream_buffer_status_cb[type])
13307 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13309 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13313 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13315 mm_player_t *player = (mm_player_t*)user_data;
13316 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13318 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13320 LOGD("app-src: seek audio data %llu", position);
13321 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13323 if (player->media_stream_seek_data_cb[type])
13324 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13325 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13331 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13333 mm_player_t *player = (mm_player_t*)user_data;
13334 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13336 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13338 LOGD("app-src: seek video data %llu", position);
13339 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13340 if (player->media_stream_seek_data_cb[type])
13341 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13342 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13348 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13350 mm_player_t *player = (mm_player_t*)user_data;
13351 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13353 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13355 LOGD("app-src: seek subtitle data");
13356 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13358 if (player->media_stream_seek_data_cb[type])
13359 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13360 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13366 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13368 mm_player_t* player = (mm_player_t*) hplayer;
13372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13374 player->pcm_samplerate = samplerate;
13375 player->pcm_channel = channel;
13378 return MM_ERROR_NONE;
13381 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13383 mm_player_t* player = (mm_player_t*) hplayer;
13387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13388 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13390 if (MMPLAYER_IS_HTTP_PD(player))
13391 *timeout = player->ini.live_state_change_timeout*2;
13392 else if (MMPLAYER_IS_STREAMING(player))
13393 *timeout = player->ini.live_state_change_timeout;
13395 *timeout = player->ini.localplayback_state_change_timeout;
13397 LOGD("timeout = %d\n", *timeout);
13400 return MM_ERROR_NONE;
13403 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13405 mm_player_t* player = (mm_player_t*) hplayer;
13409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13410 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13412 *num = player->video_num_buffers;
13413 *extra_num = player->video_extra_num_buffers;
13415 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13418 return MM_ERROR_NONE;
13422 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13426 MMPLAYER_RETURN_IF_FAIL(player);
13428 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13430 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13431 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13432 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13433 player->storage_info[i].id = -1;
13434 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13436 if (path_type != MMPLAYER_PATH_MAX)
13444 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13446 int ret = MM_ERROR_NONE;
13447 mm_player_t* player = (mm_player_t*)hplayer;
13448 MMMessageParamType msg_param = {0, };
13451 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13453 LOGW("state changed storage %d:%d", id, state);
13455 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13456 return MM_ERROR_NONE;
13458 /* FIXME: text path should be handled seperately. */
13459 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13460 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13461 LOGW("external storage is removed");
13463 if (player->msg_posted == FALSE) {
13464 memset(&msg_param, 0, sizeof(MMMessageParamType));
13465 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13466 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13467 player->msg_posted = TRUE;
13470 /* unrealize the player */
13471 ret = _mmplayer_unrealize(hplayer);
13472 if (ret != MM_ERROR_NONE)
13473 LOGE("failed to unrealize");
13480 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13482 int ret = MM_ERROR_NONE;
13483 mm_player_t* player = (mm_player_t*) hplayer;
13484 int idx = 0, total = 0;
13485 gchar *result = NULL, *tmp = NULL;
13488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13489 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13491 total = *num = g_list_length(player->adaptive_info.var_list);
13493 LOGW("There is no stream variant info.");
13497 result = g_strdup("");
13498 for (idx = 0 ; idx < total ; idx++) {
13499 VariantData *v_data = NULL;
13500 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13503 gchar data[64] = {0};
13504 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13506 tmp = g_strconcat(result, data, NULL);
13510 LOGW("There is no variant data in %d", idx);
13515 *var_info = (char *)result;
13517 LOGD("variant info %d:%s", *num, *var_info);
13522 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13524 int ret = MM_ERROR_NONE;
13525 mm_player_t* player = (mm_player_t*) hplayer;
13528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13530 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13532 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13533 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13534 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13536 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13537 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13538 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13539 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13541 /* FIXME: seek to current position for applying new variant limitation */
13549 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13551 int ret = MM_ERROR_NONE;
13552 mm_player_t* player = (mm_player_t*) hplayer;
13555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13556 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13558 *bandwidth = player->adaptive_info.limit.bandwidth;
13559 *width = player->adaptive_info.limit.width;
13560 *height = player->adaptive_info.limit.height;
13562 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13568 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13570 int ret = MM_ERROR_NONE;
13571 mm_player_t* player = (mm_player_t*) hplayer;
13574 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13576 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13577 LOGW("buffer_ms will not be applied.");
13580 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13582 if (player->streamer == NULL) {
13583 player->streamer = __mm_player_streaming_create();
13584 __mm_player_streaming_initialize(player->streamer);
13587 if (buffer_ms >= 0)
13588 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13590 if (rebuffer_ms >= 0)
13591 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13598 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13600 int ret = MM_ERROR_NONE;
13601 mm_player_t* player = (mm_player_t*) hplayer;
13604 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13605 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13607 if (player->streamer == NULL) {
13608 player->streamer = __mm_player_streaming_create();
13609 __mm_player_streaming_initialize(player->streamer);
13612 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13613 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13615 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13621 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13623 #define IDX_FIRST_SW_CODEC 0
13624 mm_player_t* player = (mm_player_t*) hplayer;
13625 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13626 MMHandleType attrs = 0;
13629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13631 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13632 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13633 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13635 switch (stream_type) {
13636 case MM_PLAYER_STREAM_TYPE_AUDIO:
13637 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13638 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13639 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13640 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13641 LOGE("There is no a codec for codec_type %d", codec_type);
13642 return MM_ERROR_PLAYER_NO_OP;
13645 case MM_PLAYER_STREAM_TYPE_VIDEO:
13646 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13647 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13648 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13649 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13650 LOGE("There is no v codec for codec_type %d", codec_type);
13651 return MM_ERROR_PLAYER_NO_OP;
13656 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13657 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13661 LOGD("update %s codec_type to %d", attr_name, codec_type);
13663 attrs = MMPLAYER_GET_ATTRS(player);
13664 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13666 if (mmf_attrs_commit(player->attrs)) {
13667 LOGE("failed to commit codec_type attributes");
13668 return MM_ERROR_PLAYER_INTERNAL;
13672 return MM_ERROR_NONE;
13676 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13678 mm_player_t* player = (mm_player_t*) hplayer;
13679 GstElement* rg_vol_element = NULL;
13683 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13685 player->sound.rg_enable = enabled;
13687 /* just hold rgvolume enable value if pipeline is not ready */
13688 if (!player->pipeline || !player->pipeline->audiobin) {
13689 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13690 return MM_ERROR_NONE;
13693 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13695 if (!rg_vol_element) {
13696 LOGD("rgvolume element is not created");
13697 return MM_ERROR_PLAYER_INTERNAL;
13701 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13703 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13707 return MM_ERROR_NONE;
13711 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13713 mm_player_t* player = (mm_player_t*) hplayer;
13714 GstElement* rg_vol_element = NULL;
13715 gboolean enable = FALSE;
13719 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13720 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13722 /* just hold enable_rg value if pipeline is not ready */
13723 if (!player->pipeline || !player->pipeline->audiobin) {
13724 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13725 *enabled = player->sound.rg_enable;
13726 return MM_ERROR_NONE;
13729 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13731 if (!rg_vol_element) {
13732 LOGD("rgvolume element is not created");
13733 return MM_ERROR_PLAYER_INTERNAL;
13736 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13741 return MM_ERROR_NONE;