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>, YoungHwan An <younghwan_.an@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*===========================================================================================
26 ========================================================================================== */
29 #include <gst/app/gstappsrc.h>
30 #include <gst/interfaces/xoverlay.h>
38 #include <mm_attrs_private.h>
41 #include "mm_player_priv.h"
42 #include "mm_player_ini.h"
43 #include "mm_player_attrs.h"
44 #include "mm_player_capture.h"
46 /*===========================================================================================
48 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
50 ========================================================================================== */
52 /*---------------------------------------------------------------------------
53 | GLOBAL CONSTANT DEFINITIONS: |
54 ---------------------------------------------------------------------------*/
56 /*---------------------------------------------------------------------------
57 | IMPORTED VARIABLE DECLARATIONS: |
58 ---------------------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------
61 | IMPORTED FUNCTION DECLARATIONS: |
62 ---------------------------------------------------------------------------*/
64 /*---------------------------------------------------------------------------
66 ---------------------------------------------------------------------------*/
67 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
68 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
70 #define MM_VOLUME_FACTOR_DEFAULT 1.0
71 #define MM_VOLUME_FACTOR_MIN 0
72 #define MM_VOLUME_FACTOR_MAX 1.0
74 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 700000 // 700 msec
76 #define MM_PLAYER_MPEG_VNAME "mpegversion"
77 #define MM_PLAYER_DIVX_VNAME "divxversion"
78 #define MM_PLAYER_WMV_VNAME "wmvversion"
79 #define MM_PLAYER_WMA_VNAME "wmaversion"
81 #define DEFAULT_PLAYBACK_RATE 1.0
83 #define GST_QUEUE_DEFAULT_TIME 2
84 #define GST_QUEUE_HLS_TIME 8
86 /* video capture callback*/
87 gulong ahs_appsrc_cb_probe_id = 0;
89 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && (PLAYER_INI()->http_file_buffer_path) && (strlen(PLAYER_INI()->http_file_buffer_path) > 0) )
90 #define MMPLAYER_PLAY_SUBTITLE(player) ((player)->play_subtitle)
92 #define LAZY_PAUSE_TIMEOUT_MSEC 700
94 /*---------------------------------------------------------------------------
95 | LOCAL CONSTANT DEFINITIONS: |
96 ---------------------------------------------------------------------------*/
98 /*---------------------------------------------------------------------------
99 | LOCAL DATA TYPE DEFINITIONS: |
100 ---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------
103 | GLOBAL VARIABLE DEFINITIONS: |
104 ---------------------------------------------------------------------------*/
106 /*---------------------------------------------------------------------------
107 | LOCAL VARIABLE DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL FUNCTION PROTOTYPES: |
112 ---------------------------------------------------------------------------*/
113 static gboolean __mmplayer_set_state(mm_player_t* player, int state);
114 static int __mmplayer_get_state(mm_player_t* player);
115 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
116 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
117 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
118 static int __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player);
119 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
120 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
121 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
123 static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
124 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
126 static void __mmplayer_typefind_have_type( GstElement *tf, guint probability, GstCaps *caps, gpointer data);
127 static gboolean __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps);
128 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
129 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
130 static gboolean __mmplayer_is_amr_type (gchar *str_caps);
131 static gboolean __mmplayer_is_only_mp3_type (gchar *str_caps);
133 static gboolean __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement, const char *padname, const GList *templlist);
134 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data);
135 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data);
137 static void __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data);
138 static void __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data);
139 static gboolean __mmplayer_update_stream_service_type( mm_player_t* player );
140 static gboolean __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
143 static void __mmplayer_init_factories(mm_player_t* player);
144 static void __mmplayer_release_factories(mm_player_t* player);
145 static void __mmplayer_release_misc(mm_player_t* player);
146 static gboolean __mmplayer_gstreamer_init(void);
148 static int __mmplayer_gst_set_state (mm_player_t* player, GstElement * pipeline, GstState state, gboolean async, gint timeout );
149 gboolean __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param);
150 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
151 int __mmplayer_switch_audio_sink (mm_player_t* player);
152 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
153 static int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
154 static gboolean __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data);
156 static gboolean __mmplayer_dump_pipeline_state( mm_player_t* player );
157 static gboolean __mmplayer_check_subtitle( mm_player_t* player );
158 static gboolean __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error );
159 static gboolean __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message );
160 static void __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms );
161 static void __mmplayer_cancel_delayed_eos( mm_player_t* player );
162 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
163 static gboolean __mmplayer_link_decoder( mm_player_t* player,GstPad *srcpad);
164 static gboolean __mmplayer_link_sink( mm_player_t* player,GstPad *srcpad);
165 static int __mmplayer_post_missed_plugin(mm_player_t* player);
166 static int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime);
167 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
168 static void __mmplayer_add_sink( mm_player_t* player, GstElement* sink);
169 static void __mmplayer_del_sink( mm_player_t* player, GstElement* sink);
170 static void __mmplayer_release_signal_connection(mm_player_t* player);
171 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force);
172 static gpointer __mmplayer_repeat_thread(gpointer data);
173 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count);
175 static int __gst_realize(mm_player_t* player);
176 static int __gst_unrealize(mm_player_t* player);
177 static int __gst_start(mm_player_t* player);
178 static int __gst_stop(mm_player_t* player);
179 int __gst_pause(mm_player_t* player, gboolean async);
180 int __gst_resume(mm_player_t* player, gboolean async);
181 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
182 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
183 gint64 cur, GstSeekType stop_type, gint64 stop );
184 static int __gst_pending_seek ( mm_player_t* player );
186 static int __gst_set_position(mm_player_t* player, int format, unsigned long position);
187 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
188 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
189 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
190 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
191 static void __gst_set_async_state_change(mm_player_t* player, gboolean async);
193 static gint __gst_handle_core_error( mm_player_t* player, int code );
194 static gint __gst_handle_library_error( mm_player_t* player, int code );
195 static gint __gst_handle_resource_error( mm_player_t* player, int code );
196 static gint __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message );
197 static gint __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error);
198 static gboolean __gst_send_event_to_sink( mm_player_t* player, GstEvent* event );
200 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
201 static gboolean __mmplayer_can_extract_pcm( mm_player_t* player );
204 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time);
205 static void __mmplayer_undo_sound_fadedown(mm_player_t* player);
207 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data);
208 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps);
211 const gchar * __get_state_name ( int state );
212 static gboolean __is_streaming( mm_player_t* player );
213 static gboolean __is_rtsp_streaming( mm_player_t* player );
214 static gboolean __is_live_streaming ( mm_player_t* player );
215 static gboolean __is_http_streaming( mm_player_t* player );
216 static gboolean __is_http_live_streaming( mm_player_t* player );
217 static gboolean __is_http_progressive_down(mm_player_t* player);
219 static gboolean __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory);
220 static GstBusSyncReply __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data);
222 /*===========================================================================================
224 | FUNCTION DEFINITIONS |
226 ========================================================================================== */
228 /* implementing player FSM */
229 /* FIXIT : We need to handle state transition also at here since start api is no more sync */
231 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
233 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
234 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
235 MMPlayerStateType target_state = MM_PLAYER_STATE_NUM;
236 MMPlayerStateType prev_state = MM_PLAYER_STATE_NUM;
240 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
242 //debug_log("incomming command : %d \n", command );
244 current_state = MMPLAYER_CURRENT_STATE(player);
245 pending_state = MMPLAYER_PENDING_STATE(player);
246 target_state = MMPLAYER_TARGET_STATE(player);
247 prev_state = MMPLAYER_PREV_STATE(player);
249 MMPLAYER_PRINT_STATE(player);
253 case MMPLAYER_COMMAND_CREATE:
255 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
257 if ( current_state == MM_PLAYER_STATE_NULL ||
258 current_state == MM_PLAYER_STATE_READY ||
259 current_state == MM_PLAYER_STATE_PAUSED ||
260 current_state == MM_PLAYER_STATE_PLAYING )
265 case MMPLAYER_COMMAND_DESTROY:
267 /* destroy can called anytime */
269 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
273 case MMPLAYER_COMMAND_REALIZE:
275 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
277 if ( pending_state != MM_PLAYER_STATE_NONE )
283 /* need ready state to realize */
284 if ( current_state == MM_PLAYER_STATE_READY )
287 if ( current_state != MM_PLAYER_STATE_NULL )
293 case MMPLAYER_COMMAND_UNREALIZE:
295 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
297 if ( current_state == MM_PLAYER_STATE_NULL )
302 case MMPLAYER_COMMAND_START:
304 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
306 if ( pending_state == MM_PLAYER_STATE_NONE )
308 if ( current_state == MM_PLAYER_STATE_PLAYING )
310 else if ( current_state != MM_PLAYER_STATE_READY &&
311 current_state != MM_PLAYER_STATE_PAUSED )
314 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
318 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
320 debug_log("player is going to paused state, just change the pending state as playing");
329 case MMPLAYER_COMMAND_STOP:
331 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
333 if ( current_state == MM_PLAYER_STATE_READY )
336 /* need playing/paused state to stop */
337 if ( current_state != MM_PLAYER_STATE_PLAYING &&
338 current_state != MM_PLAYER_STATE_PAUSED )
343 case MMPLAYER_COMMAND_PAUSE:
345 if ( MMPLAYER_IS_LIVE_STREAMING( player ) )
348 if (player->doing_seek)
349 goto NOT_COMPLETED_SEEK;
351 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
353 if ( pending_state == MM_PLAYER_STATE_NONE )
355 if ( current_state == MM_PLAYER_STATE_PAUSED )
357 else if ( current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY ) // support loading state of broswer
360 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
364 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
366 if ( current_state == MM_PLAYER_STATE_PAUSED ) {
367 debug_log("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
375 case MMPLAYER_COMMAND_RESUME:
377 if ( MMPLAYER_IS_LIVE_STREAMING(player) )
380 if (player->doing_seek)
381 goto NOT_COMPLETED_SEEK;
383 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
385 if ( pending_state == MM_PLAYER_STATE_NONE )
387 if ( current_state == MM_PLAYER_STATE_PLAYING )
389 else if ( current_state != MM_PLAYER_STATE_PAUSED )
392 else if ( pending_state == MM_PLAYER_STATE_PLAYING )
396 else if ( pending_state == MM_PLAYER_STATE_PAUSED )
398 debug_log("player is going to paused state, just change the pending state as playing");
410 player->cmd = command;
413 return MM_ERROR_NONE;
416 debug_warning("since player is in wrong state(%s). it's not able to apply the command(%d)",
417 MMPLAYER_STATE_GET_NAME(current_state), command);
418 return MM_ERROR_PLAYER_INVALID_STATE;
421 debug_warning("not completed seek");
422 return MM_ERROR_PLAYER_DOING_SEEK;
425 debug_warning("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
426 return MM_ERROR_PLAYER_NO_OP;
429 debug_warning("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
430 return MM_ERROR_PLAYER_NO_OP;
434 __mmplayer_gst_set_state (mm_player_t* player, GstElement * element, GstState state, gboolean async, gint timeout) // @
436 GstState element_state = GST_STATE_VOID_PENDING;
437 GstState element_pending_state = GST_STATE_VOID_PENDING;
438 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
442 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
443 return_val_if_fail ( element, MM_ERROR_INVALID_ARGUMENT );
445 debug_log("setting [%s] element state to : %d\n", GST_ELEMENT_NAME(element), state);
448 ret = gst_element_set_state(element, state);
450 if ( ret == GST_STATE_CHANGE_FAILURE )
452 debug_error("failed to set [%s] state to [%d]\n", GST_ELEMENT_NAME(element), state);
453 return MM_ERROR_PLAYER_INTERNAL;
456 /* return here so state transition to be done in async mode */
459 debug_log("async state transition. not waiting for state complete.\n");
460 return MM_ERROR_NONE;
463 /* wait for state transition */
464 ret = gst_element_get_state( element, &element_state, &element_pending_state, timeout * GST_SECOND );
466 if ( ret == GST_STATE_CHANGE_FAILURE || ( state != element_state ) )
468 debug_error("failed to change [%s] element state to [%s] within %d sec\n",
469 GST_ELEMENT_NAME(element),
470 gst_element_state_get_name(state), timeout );
472 debug_error(" [%s] state : %s pending : %s \n",
473 GST_ELEMENT_NAME(element),
474 gst_element_state_get_name(element_state),
475 gst_element_state_get_name(element_pending_state) );
477 return MM_ERROR_PLAYER_INTERNAL;
480 debug_log("[%s] element state has changed to %s \n",
481 GST_ELEMENT_NAME(element),
482 gst_element_state_get_name(element_state));
486 return MM_ERROR_NONE;
491 __mmplayer_videostream_cb(GstElement *element, void *stream,
492 int width, int height, gpointer data) // @
494 mm_player_t* player = (mm_player_t*)data;
497 return_if_fail ( player );
499 if (player->video_stream_cb )
501 length = width * height * 4; // for rgb 32bit
502 player->video_stream_cb(stream, length, player->video_stream_cb_user_param, width, height);
507 _mmplayer_update_content_attrs(mm_player_t* player) // @
509 GstFormat fmt = GST_FORMAT_TIME;
511 GstStructure* p = NULL;
512 MMHandleType attrs = 0;
513 gint retry_count = 0;
514 gint retry_count_max = 10;
518 return_val_if_fail ( player, FALSE );
520 if ( ! player->need_update_content_attrs )
522 debug_log("content attributes are already updated");
526 /* get content attribute first */
527 attrs = MMPLAYER_GET_ATTRS(player);
530 debug_error("cannot get content attribute");
535 * NOTE : we need to wait for a while until is possible to get duration from pipeline
536 * as getting duration timing is depends on behavier of demuxers ( or etc ).
537 * we set timeout 100ms * 10 as initial value. fix it if needed.
539 if ( player->need_update_content_dur )
541 while ( retry_count < retry_count_max)
543 if ( FALSE == gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
546 /* retry if failed */
547 debug_warning("failed to get duraton. waiting 100ms and then retrying...");
553 if ( dur_nsec == 0 && ( !MMPLAYER_IS_LIVE_STREAMING( player ) ) )
555 /* retry if duration is zero in case of not live stream */
556 debug_warning("returned duration is zero. but it's not an live stream. retrying...");
565 player->duration = dur_nsec;
566 debug_log("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
568 /* try to get streaming service type */
569 __mmplayer_update_stream_service_type( player );
571 /* check duration is OK */
572 if ( dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING( player ) )
574 /* FIXIT : find another way to get duration here. */
575 debug_error("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
579 player->need_update_content_dur = FALSE;
583 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
587 debug_log("not ready to get duration or already updated");
590 /* update rate, channels */
591 if ( player->pipeline->audiobin &&
592 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
594 GstCaps *caps_a = NULL;
596 gint samplerate = 0, channels = 0;
598 pad = gst_element_get_static_pad(
599 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink" );
603 caps_a = gst_pad_get_negotiated_caps( pad );
607 p = gst_caps_get_structure (caps_a, 0);
609 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
610 if ( ! samplerate ) // check if update already or not
612 gst_structure_get_int (p, "rate", &samplerate);
613 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
615 gst_structure_get_int (p, "channels", &channels);
616 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
618 debug_log("samplerate : %d channels : %d", samplerate, channels);
620 gst_caps_unref( caps_a );
625 debug_warning("not ready to get audio caps");
628 gst_object_unref( pad );
632 debug_warning("failed to get pad from audiosink");
636 /* update width, height, framerate */
637 if ( player->pipeline->videobin &&
638 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
640 GstCaps *caps_v = NULL;
645 pad = gst_element_get_static_pad( player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink" );
648 caps_v = gst_pad_get_negotiated_caps( pad );
651 p = gst_caps_get_structure (caps_v, 0);
652 gst_structure_get_int (p, "width", &width);
653 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
655 gst_structure_get_int (p, "height", &height);
656 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
658 gst_structure_get_fraction (p, "framerate", &tmpNu, &tmpDe);
660 debug_log("width : %d height : %d", width, height );
662 gst_caps_unref( caps_v );
667 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
668 debug_log("fps : %d", tmpNu / tmpDe);
673 debug_warning("failed to get negitiated caps from videosink");
675 gst_object_unref( pad );
680 debug_warning("failed to get pad from videosink");
684 if (player->duration)
686 guint64 data_size = 0;
688 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO))
690 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
692 if (stat(path, &sb) == 0)
694 data_size = (guint64)sb.st_size;
697 else if (MMPLAYER_IS_HTTP_STREAMING(player))
699 data_size = player->http_content_size;
705 guint64 msec_dur = 0;
707 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
708 bitrate = data_size * 8 * 1000 / msec_dur;
709 debug_log("file size : %u, video bitrate = %llu", data_size, bitrate);
710 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
716 if ( mmf_attrs_commit ( attrs ) )
718 debug_error("failed to update attributes\n");
722 player->need_update_content_attrs = FALSE;
727 gboolean __mmplayer_update_stream_service_type( mm_player_t* player )
729 MMHandleType attrs = 0;
730 gint streaming_type = STREAMING_SERVICE_NONE;
734 return_val_if_fail ( player &&
736 player->pipeline->mainbin &&
737 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
740 /* streaming service type if streaming */
741 if ( ! MMPLAYER_IS_STREAMING(player) );
744 if (MMPLAYER_IS_RTSP_STREAMING(player))
746 /* get property from rtspsrc element */
747 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "service_type", &streaming_type, NULL);
749 else if (MMPLAYER_IS_HTTP_STREAMING(player))
751 if ( player->duration <= 0)
752 streaming_type = STREAMING_SERVICE_LIVE;
754 streaming_type = STREAMING_SERVICE_VOD;
757 player->streaming_type = streaming_type;
759 if ( player->streaming_type == STREAMING_SERVICE_LIVE)
761 debug_log("It's live streaming. pause/resume/seek are not working.\n");
763 else if (player->streaming_type == STREAMING_SERVICE_LIVE)
765 debug_log("It's vod streaming. pause/resume/seek are working.\n");
769 debug_warning("fail to determine streaming type. pause/resume/seek may not working properly if stream is live stream\n");
772 /* get profile attribute */
773 attrs = MMPLAYER_GET_ATTRS(player);
776 debug_error("cannot get content attribute\n");
780 mm_attrs_set_int_by_name ( attrs, "streaming_type", streaming_type );
782 if ( mmf_attrs_commit ( attrs ) )
784 debug_warning("updating streaming service type failed. pause/resume/seek may not working properly if stream is live stream\n");
794 /* this function sets the player state and also report
795 * it to applicaton by calling callback function
798 __mmplayer_set_state(mm_player_t* player, int state) // @
800 MMMessageParamType msg = {0, };
801 int asm_result = MM_ERROR_NONE;
804 return_val_if_fail ( player, FALSE );
806 if ( MMPLAYER_CURRENT_STATE(player) == state )
808 debug_warning("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
809 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
813 /* post message to application */
814 if (MMPLAYER_TARGET_STATE(player) == state)
816 /* fill the message with state of player */
817 msg.state.previous = MMPLAYER_CURRENT_STATE(player);
818 msg.state.current = state;
820 /* state changed by asm callback */
821 if ( player->sm.by_asm_cb )
823 msg.union_type = MM_MSG_UNION_CODE;
824 msg.code = player->sm.event_src;
825 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg );
827 /* state changed by usecase */
830 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_CHANGED, &msg );
833 debug_log ("player reach the target state, then do something in each state(%s).\n",
834 MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
838 debug_log ("intermediate state, do nothing.\n");
839 MMPLAYER_PRINT_STATE(player);
844 /* update player states */
845 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
846 MMPLAYER_CURRENT_STATE(player) = state;
847 if ( MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player) )
848 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
851 MMPLAYER_PRINT_STATE(player);
853 switch ( MMPLAYER_TARGET_STATE(player) )
855 case MM_PLAYER_STATE_NULL:
856 case MM_PLAYER_STATE_READY:
858 if (player->cmd == MMPLAYER_COMMAND_STOP)
860 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_STOP);
861 if ( asm_result != MM_ERROR_NONE )
863 debug_error("failed to set asm state to stop\n");
870 case MM_PLAYER_STATE_PAUSED:
872 /* special care for local playback. normaly we can get some content attribute
873 * when the demuxer is changed to PAUSED. so we are trying it. it will be tried again
874 * when PLAYING state has signalled if failed.
875 * note that this is only happening pause command has come before the state of pipeline
876 * reach to the PLAYING.
878 player->need_update_content_dur = TRUE;
879 _mmplayer_update_content_attrs( player );
881 /* add audio callback probe if condition is satisfied */
882 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
883 __mmplayer_configure_audio_callback(player);
885 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PAUSE);
888 debug_error("failed to set asm state to PAUSE\n");
894 case MM_PLAYER_STATE_PLAYING:
896 /* update attributes which are only available on playing status */
897 player->need_update_content_attrs = TRUE;
898 _mmplayer_update_content_attrs ( player );
900 if ( player->cmd == MMPLAYER_COMMAND_START && !player->sent_bos )
902 __mmplayer_post_missed_plugin ( player );
904 /* update video resource status */
905 if ( ( player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO )
907 asm_result = _mmplayer_asm_set_state((MMHandleType)player, ASM_STATE_PLAYING);
910 MMMessageParamType msg = {0, };
912 debug_error("failed to go ahead because of video conflict\n");
914 msg.union_type = MM_MSG_UNION_CODE;
915 msg.code = MM_ERROR_POLICY_INTERRUPTED;
916 MMPLAYER_POST_MSG( player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
918 _mmplayer_unrealize((MMHandleType)player);
925 if ( player->resumed_by_rewind && player->playback_rate < 0.0 )
927 /* initialize because auto resume is done well. */
928 player->resumed_by_rewind = FALSE;
929 player->playback_rate = 1.0;
932 if ( !player->sent_bos )
934 /* check audio codec field is set or not
935 * we can get it from typefinder or codec's caps.
937 gchar *audio_codec = NULL;
938 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
940 /* The codec format can't be sent for audio only case like amr, mid etc.
941 * Because, parser don't make related TAG.
942 * So, if it's not set yet, fill it with found data.
946 if ( g_strrstr(player->type, "audio/midi"))
948 audio_codec = g_strdup("MIDI");
951 else if ( g_strrstr(player->type, "audio/x-amr"))
953 audio_codec = g_strdup("AMR");
955 else if ( g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion=(int)1"))
957 audio_codec = g_strdup("AAC");
961 audio_codec = g_strdup("unknown");
963 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
965 MMPLAYER_FREEIF(audio_codec);
966 mmf_attrs_commit(player->attrs);
967 debug_log("set audio codec type with caps\n");
970 MMTA_ACUM_ITEM_END("[KPI] start media player service", FALSE);
971 MMTA_ACUM_ITEM_END("[KPI] media player service create->playing", FALSE);
973 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BEGIN_OF_STREAM, NULL );
974 player->sent_bos = TRUE;
979 case MM_PLAYER_STATE_NONE:
981 debug_warning("invalid target state, there is nothing to do.\n");
992 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param) // @
994 return_val_if_fail( player, FALSE );
998 if ( !player->msg_cb )
1000 debug_warning("no msg callback. can't post\n");
1004 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
1006 player->msg_cb(msgtype, param, player->msg_cb_param);
1015 __mmplayer_get_state(mm_player_t* player) // @
1017 int state = MM_PLAYER_STATE_NONE;
1021 return_val_if_fail ( player, MM_PLAYER_STATE_NONE );
1023 state = MMPLAYER_CURRENT_STATE(player);
1025 debug_log("player state is %s.\n", MMPLAYER_STATE_GET_NAME(state));
1033 __gst_set_async_state_change(mm_player_t* player, gboolean async)
1036 return_if_fail( player && player->pipeline && player->pipeline->mainbin );
1038 /* need only when we are using decodebin */
1039 if ( ! PLAYER_INI()->use_decodebin )
1043 if ( player->pipeline->audiobin &&
1044 player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
1046 debug_log("audiosink async : %d\n", async);
1047 g_object_set (G_OBJECT (player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "async", async, NULL);
1051 if ( player->pipeline->videobin &&
1052 player->pipeline->videobin[MMPLAYER_V_SINK].gst )
1054 debug_log("videosink async : %d\n", async);
1055 g_object_set (G_OBJECT (player->pipeline->videobin[MMPLAYER_V_SINK].gst), "async", async, NULL);
1058 /* decodebin if enabled */
1059 if ( PLAYER_INI()->use_decodebin )
1061 debug_log("decodebin async : %d\n", async);
1062 g_object_set (G_OBJECT (player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst), "async-handling", async, NULL);
1068 static gpointer __mmplayer_repeat_thread(gpointer data)
1070 mm_player_t* player = (mm_player_t*) data;
1071 gboolean ret_value = FALSE;
1072 MMHandleType attrs = 0;
1075 return_val_if_fail ( player, NULL );
1077 while ( ! player->repeat_thread_exit )
1079 debug_log("repeat thread started. waiting for signal.\n");
1080 g_cond_wait( player->repeat_thread_cond, player->repeat_thread_mutex );
1082 if ( player->repeat_thread_exit )
1084 debug_log("exiting repeat thread\n");
1089 MMPLAYER_CMD_LOCK( player );
1091 return_val_if_fail( player, NULL );
1093 attrs = MMPLAYER_GET_ATTRS(player);
1095 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
1097 debug_error("can not get play count\n");
1101 if ( player->section_repeat )
1103 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1107 if ( player->playback_rate < 0.0 )
1109 player->resumed_by_rewind = TRUE;
1110 _mmplayer_set_mute((MMHandleType)player, 0);
1111 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1114 ret_value = __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
1115 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
1116 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
1119 player->sent_bos = FALSE;
1124 debug_error("failed to set position to zero for rewind\n");
1128 /* decrease play count */
1131 /* we successeded to rewind. update play count and then wait for next EOS */
1134 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1136 /* commit attribute */
1137 if ( mmf_attrs_commit ( attrs ) )
1139 debug_error("failed to commit attribute\n");
1144 MMPLAYER_CMD_UNLOCK( player );
1151 __mmplayer_handle_buffering_message ( mm_player_t* player )
1153 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1154 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1155 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1156 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1158 return_if_fail ( player );
1160 prev_state = MMPLAYER_PREV_STATE(player),
1161 current_state = MMPLAYER_CURRENT_STATE(player);
1162 target_state = MMPLAYER_TARGET_STATE(player);
1163 pending_state = MMPLAYER_PENDING_STATE(player);
1165 if ( MMPLAYER_IS_RTSP_STREAMING(player) )
1168 if ( !player->streamer->is_buffering )
1170 debug_log( "player state : prev %s, current %s, pending %s, target %s \n",
1171 MMPLAYER_STATE_GET_NAME(prev_state),
1172 MMPLAYER_STATE_GET_NAME(current_state),
1173 MMPLAYER_STATE_GET_NAME(pending_state),
1174 MMPLAYER_STATE_GET_NAME(target_state));
1176 /* NOTE : if buffering has done, player has to go to target state. */
1177 switch ( target_state )
1179 case MM_PLAYER_STATE_PAUSED :
1181 switch ( pending_state )
1183 case MM_PLAYER_STATE_PLAYING:
1185 __gst_pause ( player, TRUE );
1189 case MM_PLAYER_STATE_PAUSED:
1191 debug_log("player is already going to paused state, there is nothing to do.\n");
1195 case MM_PLAYER_STATE_NONE:
1196 case MM_PLAYER_STATE_NULL:
1197 case MM_PLAYER_STATE_READY:
1200 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1207 case MM_PLAYER_STATE_PLAYING :
1209 switch ( pending_state )
1211 case MM_PLAYER_STATE_NONE:
1213 if (current_state != MM_PLAYER_STATE_PLAYING)
1214 __gst_resume ( player, TRUE );
1218 case MM_PLAYER_STATE_PAUSED:
1220 __gst_resume ( player, TRUE );
1224 case MM_PLAYER_STATE_PLAYING:
1226 debug_log("player is already going to playing state, there is nothing to do.\n");
1230 case MM_PLAYER_STATE_NULL:
1231 case MM_PLAYER_STATE_READY:
1234 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1241 case MM_PLAYER_STATE_NULL :
1242 case MM_PLAYER_STATE_READY :
1243 case MM_PLAYER_STATE_NONE :
1246 debug_warning("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state) );
1253 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1254 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
1256 switch ( pending_state )
1258 case MM_PLAYER_STATE_NONE:
1260 if (current_state != MM_PLAYER_STATE_PAUSED)
1261 __gst_pause ( player, TRUE );
1265 case MM_PLAYER_STATE_PLAYING:
1267 __gst_pause ( player, TRUE );
1271 case MM_PLAYER_STATE_PAUSED:
1273 debug_log("player is already going to paused state, there is nothing to do.\n");
1277 case MM_PLAYER_STATE_NULL:
1278 case MM_PLAYER_STATE_READY:
1281 debug_warning("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state) );
1289 __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data) // @
1291 mm_player_t* player = (mm_player_t*) data;
1292 gboolean ret = TRUE;
1293 static gboolean async_done = FALSE;
1295 return_val_if_fail ( player, FALSE );
1296 return_val_if_fail ( msg && GST_IS_MESSAGE(msg), FALSE );
1298 switch ( GST_MESSAGE_TYPE( msg ) )
1300 case GST_MESSAGE_UNKNOWN:
1301 debug_warning("unknown message received\n");
1304 case GST_MESSAGE_EOS:
1306 MMHandleType attrs = 0;
1309 debug_log("GST_MESSAGE_EOS received\n");
1311 /* NOTE : EOS event is comming multiple time. watch out it */
1312 /* check state. we only process EOS when pipeline state goes to PLAYING */
1313 if ( ! (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) )
1315 debug_warning("EOS received on non-playing state. ignoring it\n");
1319 if ( (player->audio_stream_cb) && (player->is_sound_extraction) )
1323 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1325 debug_error("release audio callback\n");
1327 /* release audio callback */
1328 gst_pad_remove_buffer_probe (pad, player->audio_cb_probe_id);
1329 player->audio_cb_probe_id = 0;
1330 /* audio callback should be free because it can be called even though probe remove.*/
1331 player->audio_stream_cb = NULL;
1332 player->audio_stream_cb_user_param = NULL;
1336 /* rewind if repeat count is greater then zero */
1337 /* get play count */
1338 attrs = MMPLAYER_GET_ATTRS(player);
1342 gboolean smooth_repeat = FALSE;
1344 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1345 mm_attrs_get_int_by_name(attrs, "profile_smooth_repeat", &smooth_repeat);
1347 debug_log("remaining play count: %d, playback rate: %f\n", count, player->playback_rate);
1349 if ( count > 1 || count == -1 || player->playback_rate < 0.0 ) /* default value is 1 */
1351 if ( smooth_repeat )
1353 debug_log("smooth repeat enabled. seeking operation will be excuted in new thread\n");
1355 g_cond_signal( player->repeat_thread_cond );
1363 if ( player->section_repeat )
1365 ret_value = _mmplayer_activate_section_repeat((MMHandleType)player, player->section_repeat_start, player->section_repeat_end);
1370 if ( player->playback_rate < 0.0 )
1372 player->resumed_by_rewind = TRUE;
1373 _mmplayer_set_mute((MMHandleType)player, 0);
1374 MMPLAYER_POST_MSG( player, MM_MESSAGE_RESUMED_BY_REW, NULL );
1377 ret_value = __gst_set_position( player, MM_PLAYER_POS_FORMAT_TIME, 0 );
1380 player->sent_bos = FALSE;
1383 if ( MM_ERROR_NONE != ret_value )
1385 debug_error("failed to set position to zero for rewind\n");
1391 /* we successeded to rewind. update play count and then wait for next EOS */
1394 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
1396 if ( mmf_attrs_commit ( attrs ) )
1397 debug_error("failed to commit attrs\n");
1406 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-eos" );
1408 /* post eos message to application */
1409 __mmplayer_post_delayed_eos( player, PLAYER_INI()->eos_delay );
1411 /* reset last position */
1412 player->last_position = 0;
1416 case GST_MESSAGE_ERROR:
1418 GError *error = NULL;
1419 gchar* debug = NULL;
1420 gchar *msg_src_element = NULL;
1422 /* generating debug info before returning error */
1423 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-error" );
1425 /* get error code */
1426 gst_message_parse_error( msg, &error, &debug );
1428 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( msg->src ) );
1429 if ( gst_structure_has_name ( msg->structure, "streaming_error" ) )
1431 /* Note : the streaming error from the streaming source is handled
1432 * using __mmplayer_handle_streaming_error.
1434 __mmplayer_handle_streaming_error ( player, msg );
1436 /* dump state of all element */
1437 __mmplayer_dump_pipeline_state( player );
1441 /* traslate gst error code to msl error code. then post it
1442 * to application if needed
1444 __mmplayer_handle_gst_error( player, msg, error );
1446 /* dump state of all element */
1447 __mmplayer_dump_pipeline_state( player );
1451 if (MMPLAYER_IS_HTTP_PD(player))
1453 _mmplayer_pd_stop ((MMHandleType)player);
1456 MMPLAYER_FREEIF( debug );
1457 g_error_free( error );
1461 case GST_MESSAGE_WARNING:
1464 GError* error = NULL;
1466 gst_message_parse_warning(msg, &error, &debug);
1468 debug_warning("warning : %s\n", error->message);
1469 debug_warning("debug : %s\n", debug);
1471 MMPLAYER_POST_MSG( player, MM_MESSAGE_WARNING, NULL );
1473 MMPLAYER_FREEIF( debug );
1474 g_error_free( error );
1478 case GST_MESSAGE_INFO: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1480 case GST_MESSAGE_TAG:
1482 debug_log("GST_MESSAGE_TAG\n");
1483 if ( ! __mmplayer_gst_extract_tag_from_msg( player, msg ) )
1485 debug_warning("failed to extract tags from gstmessage\n");
1490 case GST_MESSAGE_BUFFERING:
1492 MMMessageParamType msg_param = {0, };
1493 gboolean update_buffering_percent = TRUE;
1495 if ( !MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) // pure hlsdemux case, don't consider buffering of msl currently
1498 __mm_player_streaming_buffering (player->streamer, msg);
1500 __mmplayer_handle_buffering_message ( player );
1502 update_buffering_percent = player->pipeline_is_constructed || MMPLAYER_IS_RTSP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player);
1503 if (update_buffering_percent)
1505 msg_param.connection.buffering = player->streamer->buffering_percent;
1506 MMPLAYER_POST_MSG ( player, MM_MESSAGE_BUFFERING, &msg_param );
1511 case GST_MESSAGE_STATE_CHANGED:
1513 MMPlayerGstElement *mainbin;
1514 const GValue *voldstate, *vnewstate, *vpending;
1515 GstState oldstate, newstate, pending;
1517 if ( ! ( player->pipeline && player->pipeline->mainbin ) )
1519 debug_error("player pipeline handle is null");
1524 mainbin = player->pipeline->mainbin;
1526 /* get state info from msg */
1527 voldstate = gst_structure_get_value (msg->structure, "old-state");
1528 vnewstate = gst_structure_get_value (msg->structure, "new-state");
1529 vpending = gst_structure_get_value (msg->structure, "pending-state");
1531 oldstate = (GstState)voldstate->data[0].v_int;
1532 newstate = (GstState)vnewstate->data[0].v_int;
1533 pending = (GstState)vpending->data[0].v_int;
1535 if (oldstate == newstate)
1538 debug_log("state changed [%s] : %s ---> %s final : %s\n",
1539 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1540 gst_element_state_get_name( (GstState)oldstate ),
1541 gst_element_state_get_name( (GstState)newstate ),
1542 gst_element_state_get_name( (GstState)pending ) );
1544 /* we only handle messages from pipeline */
1545 if( msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst )
1550 case GST_STATE_VOID_PENDING:
1553 case GST_STATE_NULL:
1556 case GST_STATE_READY:
1559 case GST_STATE_PAUSED:
1561 if ( ! player->audio_cb_probe_id && player->is_sound_extraction )
1562 __mmplayer_configure_audio_callback(player);
1565 if ( MMPLAYER_IS_STREAMING(player) )
1567 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
1569 __mm_player_streaming_set_content_bitrate(player->streamer, player->total_maximum_bitrate, player->total_bitrate);
1571 /* check pending seek and do now */
1572 if ( player->pending_seek.is_pending )
1573 __gst_pending_seek ( player );
1576 player->need_update_content_dur = TRUE;
1580 case GST_STATE_PLAYING:
1583 gboolean is_async = FALSE;
1585 if (player->doing_seek && async_done)
1587 player->doing_seek = FALSE;
1589 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1592 /* It should be called in case of async start only.
1593 * don't need to call in the case of resume and sync start (currently, resume is sync.)
1595 mm_attrs_get_int_by_name(player->attrs,"profile_async_start", &is_async);
1596 if (is_async && player->cmd == MMPLAYER_COMMAND_START)
1597 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
1607 case GST_MESSAGE_STATE_DIRTY: debug_log("GST_MESSAGE_STATE_DIRTY\n"); break;
1608 case GST_MESSAGE_STEP_DONE: debug_log("GST_MESSAGE_STEP_DONE\n"); break;
1609 case GST_MESSAGE_CLOCK_PROVIDE: debug_log("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1611 case GST_MESSAGE_CLOCK_LOST:
1613 GstClock *clock = NULL;
1614 gst_message_parse_clock_lost (msg, &clock);
1615 debug_log("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1616 g_print ("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1618 if (PLAYER_INI()->provide_clock)
1620 debug_log ("Provide clock is TRUE, do pause->resume\n");
1621 __gst_pause(player, FALSE);
1622 __gst_resume(player, FALSE);
1627 case GST_MESSAGE_NEW_CLOCK:
1629 GstClock *clock = NULL;
1630 gst_message_parse_new_clock (msg, &clock);
1631 debug_log("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
1635 case GST_MESSAGE_STRUCTURE_CHANGE: debug_log("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1636 case GST_MESSAGE_STREAM_STATUS: debug_log("GST_MESSAGE_STREAM_STATUS\n"); break;
1637 case GST_MESSAGE_APPLICATION: debug_log("GST_MESSAGE_APPLICATION\n"); break;
1639 case GST_MESSAGE_ELEMENT:
1641 debug_log("GST_MESSAGE_ELEMENT\n");
1645 case GST_MESSAGE_SEGMENT_START: debug_log("GST_MESSAGE_SEGMENT_START\n"); break;
1646 case GST_MESSAGE_SEGMENT_DONE: debug_log("GST_MESSAGE_SEGMENT_DONE\n"); break;
1648 case GST_MESSAGE_DURATION:
1650 debug_log("GST_MESSAGE_DURATION\n");
1654 case GST_MESSAGE_LATENCY: debug_log("GST_MESSAGE_LATENCY\n"); break;
1655 case GST_MESSAGE_ASYNC_START: debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg))); break;
1657 case GST_MESSAGE_ASYNC_DONE:
1659 debug_log("GST_MESSAGE_ASYNC_DONE : %s\n", gst_element_get_name(GST_MESSAGE_SRC(msg)));
1661 if (player->doing_seek)
1663 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED)
1665 player->doing_seek = FALSE;
1666 MMPLAYER_POST_MSG ( player, MM_MESSAGE_SEEK_COMPLETED, NULL );
1668 else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING)
1676 case GST_MESSAGE_REQUEST_STATE: debug_log("GST_MESSAGE_REQUEST_STATE\n"); break;
1677 case GST_MESSAGE_STEP_START: debug_log("GST_MESSAGE_STEP_START\n"); break;
1678 case GST_MESSAGE_QOS: debug_log("GST_MESSAGE_QOS\n"); break;
1679 case GST_MESSAGE_PROGRESS: debug_log("GST_MESSAGE_PROGRESS\n"); break;
1680 case GST_MESSAGE_ANY: debug_log("GST_MESSAGE_ANY\n"); break;
1683 debug_warning("unhandled message\n");
1687 /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
1688 * gst_element_post_message api takes ownership of the message.
1690 //gst_message_unref( msg );
1696 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg) // @
1699 /* macro for better code readability */
1700 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1701 if (gst_tag_list_get_string(tag_list, gsttag, &string)) \
1703 if (string != NULL)\
1705 debug_log ( "update tag string : %s\n", string); \
1706 mm_attrs_set_string_by_name(attribute, playertag, string); \
1712 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1713 value = gst_tag_list_get_value_index(tag_list, gsttag, index); \
1716 buffer = gst_value_get_buffer (value); \
1717 debug_log ( "update album cover data : %p, size : %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1718 player->album_art = (gchar *)g_malloc(GST_BUFFER_SIZE(buffer)); \
1719 if (player->album_art); \
1721 memcpy(player->album_art, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); \
1722 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, GST_BUFFER_SIZE(buffer)); \
1726 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1727 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint))\
1731 if(gsttag==GST_TAG_BITRATE)\
1733 if (player->updated_bitrate_count == 0) \
1734 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1735 if (player->updated_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1737 player->bitrate[player->updated_bitrate_count] = v_uint;\
1738 player->total_bitrate += player->bitrate[player->updated_maximum_bitrate_count]; \
1739 player->updated_bitrate_count++; \
1740 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate);\
1741 debug_log ( "update bitrate %d[bps] of stream #%d.\n", v_uint, player->updated_bitrate_count);\
1744 else if (gsttag==GST_TAG_MAXIMUM_BITRATE)\
1746 if (player->updated_maximum_bitrate_count<MM_PLAYER_STREAM_COUNT_MAX) \
1748 player->maximum_bitrate[player->updated_maximum_bitrate_count] = v_uint;\
1749 player->total_maximum_bitrate += player->maximum_bitrate[player->updated_maximum_bitrate_count]; \
1750 player->updated_maximum_bitrate_count++; \
1751 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate); \
1752 debug_log ( "update maximum bitrate %d[bps] of stream #%d\n", v_uint, player->updated_maximum_bitrate_count);\
1757 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1763 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1764 if (gst_tag_list_get_date(tag_list, gsttag, &date))\
1768 string = g_strdup_printf("%d", g_date_get_year(date));\
1769 mm_attrs_set_string_by_name(attribute, playertag, string);\
1770 debug_log ( "metainfo year : %s\n", string);\
1771 MMPLAYER_FREEIF(string);\
1776 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1777 if(gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64))\
1781 /* FIXIT : don't know how to store date */\
1787 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1788 if(gst_tag_list_get_double(tag_list, gsttag, &v_double))\
1792 /* FIXIT : don't know how to store date */\
1798 /* function start */
1799 GstTagList* tag_list = NULL;
1801 MMHandleType attrs = 0;
1803 char *string = NULL;
1807 GstBuffer *buffer = NULL;
1809 const GValue *value;
1811 /* currently not used. but those are needed for above macro */
1812 //guint64 v_uint64 = 0;
1813 //gdouble v_double = 0;
1815 return_val_if_fail( player && msg, FALSE );
1817 attrs = MMPLAYER_GET_ATTRS(player);
1819 return_val_if_fail( attrs, FALSE );
1821 /* get tag list from gst message */
1822 gst_message_parse_tag(msg, &tag_list);
1824 /* store tags to player attributes */
1825 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1826 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1827 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1828 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1829 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1830 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1831 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1832 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1833 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1834 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1835 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1836 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1837 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1838 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1839 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1840 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1841 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1842 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1843 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1844 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1845 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1846 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1847 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1848 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1849 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1850 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1851 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1852 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1853 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1854 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1855 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1856 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1857 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1858 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1859 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1860 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1861 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1862 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1863 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1864 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1865 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1866 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1867 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1868 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1869 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1871 if ( mmf_attrs_commit ( attrs ) )
1872 debug_error("failed to commit.\n");
1874 gst_tag_list_free(tag_list);
1880 __mmplayer_gst_rtp_no_more_pads (GstElement *element, gpointer data) // @
1882 mm_player_t* player = (mm_player_t*) data;
1886 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
1887 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
1888 * num_dynamic_pad. and this is no-more-pad situation which means mo more pad will be added.
1889 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1891 * [1] audio and video will be dumped with filesink.
1892 * [2] autoplugging is done by just using pad caps.
1893 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1894 * and the video will be dumped via filesink.
1896 if ( player->num_dynamic_pad == 0 )
1898 debug_log("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1900 if ( ! __mmplayer_gst_remove_fakesink( player,
1901 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) );
1904 /* create dot before error-return. for debugging */
1905 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-no-more-pad" );
1907 /* NOTE : if rtspsrc goes to PLAYING before adding it's src pads, a/v sink elements will
1908 * not goes to PLAYING. they will just remain in PAUSED state. simply we are giving
1909 * PLAYING state again.
1911 __mmplayer_gst_set_state(player,
1912 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, TRUE, 5000 );
1914 player->no_more_pad = TRUE;
1920 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink) // @
1922 GstElement* parent = NULL;
1924 return_val_if_fail(player && player->pipeline && fakesink, FALSE);
1927 g_mutex_lock( player->fsink_lock );
1929 if ( ! fakesink->gst )
1934 /* get parent of fakesink */
1935 parent = (GstElement*)gst_object_get_parent( (GstObject*)fakesink->gst );
1938 debug_log("fakesink already removed\n");
1942 gst_element_set_locked_state( fakesink->gst, TRUE );
1944 /* setting the state to NULL never returns async
1945 * so no need to wait for completion of state transiton
1947 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (fakesink->gst, GST_STATE_NULL) )
1949 debug_error("fakesink state change failure!\n");
1951 /* FIXIT : should I return here? or try to proceed to next? */
1955 /* remove fakesink from it's parent */
1956 if ( ! gst_bin_remove( GST_BIN( parent ), fakesink->gst ) )
1958 debug_error("failed to remove fakesink\n");
1960 gst_object_unref( parent );
1965 gst_object_unref( parent );
1967 /* FIXIT : releasing fakesink takes too much time (around 700ms)
1968 * we need to figure out the reason why. just for now, fakesink will be released
1969 * in __mmplayer_gst_destroy_pipeline()
1971 // gst_object_unref ( fakesink->gst );
1972 // fakesink->gst = NULL;
1974 debug_log("state-holder removed\n");
1976 gst_element_set_locked_state( fakesink->gst, FALSE );
1978 g_mutex_unlock( player->fsink_lock );
1982 if ( fakesink->gst )
1984 gst_element_set_locked_state( fakesink->gst, FALSE );
1987 g_mutex_unlock( player->fsink_lock );
1993 __mmplayer_gst_rtp_dynamic_pad (GstElement *element, GstPad *pad, gpointer data) // @
1995 GstPad *sinkpad = NULL;
1996 GstCaps* caps = NULL;
1997 GstElement* new_element = NULL;
1998 enum MainElementID element_id = MMPLAYER_M_NUM;
2000 mm_player_t* player = (mm_player_t*) data;
2004 return_if_fail( element && pad );
2005 return_if_fail( player &&
2007 player->pipeline->mainbin );
2010 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2011 * num_dynamic_pad will decreased after creating a sinkbin.
2013 player->num_dynamic_pad++;
2014 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
2016 /* perform autoplugging if dump is disabled */
2017 if ( PLAYER_INI()->rtsp_do_typefinding )
2019 /* create typefind */
2020 new_element = gst_element_factory_make( "typefind", NULL );
2021 if ( ! new_element )
2023 debug_error("failed to create typefind\n");
2027 MMPLAYER_SIGNAL_CONNECT( player,
2028 G_OBJECT(new_element),
2030 G_CALLBACK(__mmplayer_typefind_have_type),
2033 /* FIXIT : try to remove it */
2034 player->have_dynamic_pad = FALSE;
2036 else /* NOTE : use pad's caps directely. if enabled. what I am assuming is there's no elemnt has dynamic pad */
2038 debug_log("using pad caps to autopluging instead of doing typefind\n");
2040 caps = gst_pad_get_caps( pad );
2042 MMPLAYER_CHECK_NULL( caps );
2044 /* clear previous result*/
2045 player->have_dynamic_pad = FALSE;
2047 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
2049 debug_error("failed to autoplug for caps : %s\n", gst_caps_to_string( caps ) );
2053 /* check if there's dynamic pad*/
2054 if( player->have_dynamic_pad )
2056 debug_error("using pad caps assums there's no dynamic pad !\n");
2057 debug_error("try with enalbing rtsp_do_typefinding\n");
2061 gst_caps_unref( caps );
2065 /* excute new_element if created*/
2068 debug_log("adding new element to pipeline\n");
2070 /* set state to READY before add to bin */
2071 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_READY );
2073 /* add new element to the pipeline */
2074 if ( FALSE == gst_bin_add( GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element) )
2076 debug_error("failed to add autoplug element to bin\n");
2080 /* get pad from element */
2081 sinkpad = gst_element_get_static_pad ( GST_ELEMENT(new_element), "sink" );
2084 debug_error("failed to get sinkpad from autoplug element\n");
2089 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2091 debug_error("failed to link autoplug element\n");
2095 gst_object_unref (sinkpad);
2098 /* run. setting PLAYING here since streamming source is live source */
2099 MMPLAYER_ELEMENT_SET_STATE( new_element, GST_STATE_PLAYING );
2102 /* store handle to futher manipulation */
2103 player->pipeline->mainbin[element_id].id = element_id;
2104 player->pipeline->mainbin[element_id].gst = new_element;
2110 STATE_CHANGE_FAILED:
2112 /* FIXIT : take care if new_element has already added to pipeline */
2114 gst_object_unref(GST_OBJECT(new_element));
2117 gst_object_unref(GST_OBJECT(sinkpad));
2120 gst_object_unref(GST_OBJECT(caps));
2122 /* FIXIT : how to inform this error to MSL ????? */
2123 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2124 * then post an error to application
2130 __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) // @
2132 mm_player_t* player = NULL;
2133 MMHandleType attrs = 0;
2134 GstElement* pipeline = NULL;
2135 GstCaps* caps = NULL;
2136 GstStructure* str = NULL;
2137 const gchar* name = NULL;
2138 GstPad* sinkpad = NULL;
2139 GstElement* sinkbin = NULL;
2142 player = (mm_player_t*) data;
2144 return_if_fail( decodebin && pad );
2145 return_if_fail(player && player->pipeline && player->pipeline->mainbin);
2147 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2149 attrs = MMPLAYER_GET_ATTRS(player);
2152 debug_error("cannot get content attribute\n");
2156 /* get mimetype from caps */
2157 caps = gst_pad_get_caps( pad );
2160 debug_error("cannot get caps from pad.\n");
2164 str = gst_caps_get_structure( caps, 0 );
2167 debug_error("cannot get structure from capse.\n");
2171 name = gst_structure_get_name(str);
2174 debug_error("cannot get mimetype from structure.\n");
2178 debug_log("detected mimetype : %s\n", name);
2180 if (strstr(name, "audio"))
2182 if (player->pipeline->audiobin == NULL)
2184 __ta__("__mmplayer_gst_create_audio_pipeline",
2185 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player))
2187 debug_error("failed to create audiobin. continuing without audio\n");
2192 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2193 debug_log("creating audiosink bin success\n");
2197 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2198 debug_log("re-using audiobin\n");
2201 /* FIXIT : track number shouldn't be hardcoded */
2202 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2204 player->audiosink_linked = 1;
2205 debug_msg("player->audsink_linked set to 1\n");
2208 else if (strstr(name, "video"))
2210 if (player->pipeline->videobin == NULL)
2212 /* NOTE : not make videobin because application dose not want to play it even though file has video stream.
2215 /* get video surface type */
2216 int surface_type = 0;
2217 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2218 debug_log("check display surface type attribute: %d", surface_type);
2219 if (surface_type == MM_DISPLAY_SURFACE_NULL)
2221 debug_log("not make videobin because it dose not want\n");
2225 __ta__("__mmplayer_gst_create_video_pipeline",
2226 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type) )
2228 debug_error("failed to create videobin. continuing without video\n");
2233 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2234 debug_log("creating videosink bin success\n");
2238 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2239 debug_log("re-using videobin\n");
2242 /* FIXIT : track number shouldn't be hardcoded */
2243 mm_attrs_set_int_by_name(attrs, "content_video_track_num", 1);
2245 player->videosink_linked = 1;
2246 debug_msg("player->videosink_linked set to 1\n");
2249 else if (strstr(name, "text"))
2251 if (player->pipeline->textbin == NULL)
2253 __ta__("__mmplayer_gst_create_text_pipeline",
2254 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
2256 debug_error("failed to create textbin. continuing without text\n");
2261 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2262 debug_log("creating textink bin success\n");
2266 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2267 debug_log("re-using textbin\n");
2270 /* FIXIT : track number shouldn't be hardcoded */
2271 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2273 player->textsink_linked = 1;
2274 debug_msg("player->textsink_linked set to 1\n");
2278 debug_warning("unknown type of elementary stream! ignoring it...\n");
2285 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_READY ) )
2287 debug_error("failed to set state(READY) to sinkbin\n");
2292 if ( FALSE == gst_bin_add( GST_BIN(pipeline), sinkbin ) )
2294 debug_error("failed to add sinkbin to pipeline\n");
2298 sinkpad = gst_element_get_static_pad( GST_ELEMENT(sinkbin), "sink" );
2302 debug_error("failed to get pad from sinkbin\n");
2307 if ( GST_PAD_LINK_OK != GST_PAD_LINK(pad, sinkpad) )
2309 debug_error("failed to get pad from sinkbin\n");
2314 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state( sinkbin, GST_STATE_PAUSED ) )
2316 debug_error("failed to set state(PLAYING) to sinkbin\n");
2320 gst_object_unref( sinkpad );
2324 /* update track number attributes */
2325 if ( mmf_attrs_commit ( attrs ) )
2326 debug_error("failed to commit attrs\n");
2328 debug_log("linking sink bin success\n");
2331 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2332 * streaming task. if the task blocked, then buffer will not flow to the next element
2333 * ( autoplugging element ). so this is special hack for streaming. please try to remove it
2335 /* dec stream count. we can remove fakesink if it's zero */
2336 player->num_dynamic_pad--;
2338 debug_log("stream count dec : %d (num of dynamic pad)\n", player->num_dynamic_pad);
2340 if ( ( player->no_more_pad ) && ( player->num_dynamic_pad == 0 ) )
2342 __mmplayer_pipeline_complete( NULL, player );
2347 gst_caps_unref( caps );
2350 gst_object_unref(GST_OBJECT(sinkpad));
2356 _mmplayer_update_video_param(mm_player_t* player) // @
2358 MMHandleType attrs = 0;
2359 MMDisplaySurfaceType surface_type = 0;
2363 /* check video sinkbin is created */
2364 return_val_if_fail ( player &&
2366 player->pipeline->videobin &&
2367 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2368 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2369 MM_ERROR_PLAYER_NOT_INITIALIZED );
2371 attrs = MMPLAYER_GET_ATTRS(player);
2374 debug_error("cannot get content attribute");
2375 return MM_ERROR_PLAYER_INTERNAL;
2378 /* update display surface */
2379 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &surface_type);
2380 debug_log("check display surface type attribute: %d", surface_type);
2382 /* check video stream callback is used */
2383 if( player->use_video_stream )
2385 int rotate, width, height, orientation;
2387 rotate = width = height = orientation = 0;
2389 debug_log("using video stream callback with memsink. player handle : [%p]", player);
2391 mm_attrs_get_int_by_name(attrs, "display_width", &width);
2392 mm_attrs_get_int_by_name(attrs, "display_height", &height);
2393 mm_attrs_get_int_by_name(attrs, "display_rotation", &rotate);
2394 mm_attrs_get_int_by_name(attrs, "display_orientation", &orientation);
2396 if (rotate < MM_DISPLAY_ROTATION_NONE || rotate > MM_DISPLAY_ROTATION_270)
2401 if(orientation == 1) rotate = 90;
2402 else if(orientation == 2) rotate = 180;
2403 else if(orientation == 3) rotate = 270;
2406 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "width", width, NULL);
2409 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "height", height, NULL);
2411 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotate,NULL);
2413 return MM_ERROR_NONE;
2416 /* configuring display */
2417 switch ( surface_type )
2419 case MM_DISPLAY_SURFACE_X:
2421 /* ximagesink or xvimagesink */
2425 int display_method = 0;
2430 int force_aspect_ratio = 0;
2432 gboolean visible = TRUE;
2434 /* common case if using x surface */
2435 mm_attrs_get_data_by_name(attrs, "display_overlay", &xid);
2438 debug_log("set video param : xid %d", *(int*)xid);
2439 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY( player->pipeline->videobin[MMPLAYER_V_SINK].gst ), *(int*)xid );
2443 /* FIXIT : is it error case? */
2444 debug_warning("still we don't have xid on player attribute. create it's own surface.");
2447 /* if xvimagesink */
2448 if (!strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2450 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2451 mm_attrs_get_int_by_name(attrs, "display_zoom", &zoom);
2452 mm_attrs_get_int_by_name(attrs, "display_rotation", °ree);
2453 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2454 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2455 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2456 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2457 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2458 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2460 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2461 "force-aspect-ratio", force_aspect_ratio,
2464 "handle-events", TRUE,
2465 "display-geometry-method", display_method,
2466 "draw-borders", FALSE,
2474 debug_log("set video param : zoom %d", zoom);
2475 debug_log("set video param : rotate %d", degree);
2476 debug_log("set video param : method %d", display_method);
2477 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2478 roi_x, roi_y, roi_w, roi_h );
2479 debug_log("set video param : visible %d", visible);
2480 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2484 case MM_DISPLAY_SURFACE_EVAS:
2486 void *object = NULL;
2488 gboolean visible = TRUE;
2490 /* common case if using evas surface */
2491 mm_attrs_get_data_by_name(attrs, "display_overlay", &object);
2492 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2493 mm_attrs_get_int_by_name(attrs, "display_evas_do_scaling", &scaling);
2496 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2497 "evas-object", object,
2500 debug_log("set video param : evas-object %x", object);
2501 debug_log("set video param : visible %d", visible);
2505 debug_error("no evas object");
2506 return MM_ERROR_PLAYER_INTERNAL;
2509 /* if evaspixmapsink */
2510 if (!strcmp(PLAYER_INI()->videosink_element_evas,"evaspixmapsink"))
2512 int display_method = 0;
2517 int force_aspect_ratio = 0;
2518 int origin_size = !scaling;
2520 mm_attrs_get_int_by_name(attrs, "display_force_aspect_ration", &force_aspect_ratio);
2521 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2522 mm_attrs_get_int_by_name(attrs, "display_roi_x", &roi_x);
2523 mm_attrs_get_int_by_name(attrs, "display_roi_y", &roi_y);
2524 mm_attrs_get_int_by_name(attrs, "display_roi_width", &roi_w);
2525 mm_attrs_get_int_by_name(attrs, "display_roi_height", &roi_h);
2527 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2528 "force-aspect-ratio", force_aspect_ratio,
2529 "origin-size", origin_size,
2534 "display-geometry-method", display_method,
2537 debug_log("set video param : method %d", display_method);
2538 debug_log("set video param : dst-roi-x: %d, dst-roi-y: %d, dst-roi-w: %d, dst-roi-h: %d",
2539 roi_x, roi_y, roi_w, roi_h );
2540 debug_log("set video param : force aspect ratio %d", force_aspect_ratio);
2541 debug_log("set video param : display_evas_do_scaling %d (origin-size %d)", scaling, origin_size);
2545 case MM_DISPLAY_SURFACE_X_EXT: /* NOTE : this surface type is for the video texture(canvas texture) */
2547 void *pixmap_id_cb = NULL;
2548 void *pixmap_id_cb_user_data = NULL;
2551 int display_method = 0;
2556 int force_aspect_ratio = 0;
2557 gboolean visible = TRUE;
2559 /* if xvimagesink */
2560 if (strcmp(PLAYER_INI()->videosink_element_x,"xvimagesink"))
2562 debug_error("videosink is not xvimagesink");
2563 return MM_ERROR_PLAYER_INTERNAL;
2566 /* get information from attributes */
2567 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
2568 mm_attrs_get_data_by_name(attrs, "display_overlay_user_data", &pixmap_id_cb_user_data);
2569 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2573 debug_log("set video param : display_overlay(0x%x)", pixmap_id_cb);
2574 if (pixmap_id_cb_user_data)
2576 debug_log("set video param : display_overlay_user_data(0x%x)", pixmap_id_cb_user_data);
2581 debug_error("failed to set pixmap-id-callback");
2582 return MM_ERROR_PLAYER_INTERNAL;
2584 debug_log("set video param : method %d", display_method);
2585 debug_log("set video param : visible %d", visible);
2587 /* set properties of videosink plugin */
2588 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2589 "display-geometry-method", display_method,
2590 "draw-borders", FALSE,
2592 "pixmap-id-callback", pixmap_id_cb,
2593 "pixmap-id-callback-userdata", pixmap_id_cb_user_data,
2597 case MM_DISPLAY_SURFACE_NULL:
2606 return MM_ERROR_NONE;
2610 __mmplayer_gst_element_link_bucket(GList* element_bucket) // @
2612 GList* bucket = element_bucket;
2613 MMPlayerGstElement* element = NULL;
2614 MMPlayerGstElement* prv_element = NULL;
2615 gint successful_link_count = 0;
2619 return_val_if_fail(element_bucket, -1);
2621 prv_element = (MMPlayerGstElement*)bucket->data;
2622 bucket = bucket->next;
2624 for ( ; bucket; bucket = bucket->next )
2626 element = (MMPlayerGstElement*)bucket->data;
2628 if ( element && element->gst )
2630 if ( GST_ELEMENT_LINK(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst)) )
2632 debug_log("linking [%s] to [%s] success\n",
2633 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2634 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2635 successful_link_count ++;
2639 debug_log("linking [%s] to [%s] failed\n",
2640 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2641 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) );
2647 prv_element = element;
2652 return successful_link_count;
2656 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket) // @
2658 GList* bucket = element_bucket;
2659 MMPlayerGstElement* element = NULL;
2660 int successful_add_count = 0;
2664 return_val_if_fail(element_bucket, 0);
2665 return_val_if_fail(bin, 0);
2667 for ( ; bucket; bucket = bucket->next )
2669 element = (MMPlayerGstElement*)bucket->data;
2671 if ( element && element->gst )
2673 if( !gst_bin_add(bin, GST_ELEMENT(element->gst)) )
2675 debug_log("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2676 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2677 GST_ELEMENT_NAME(GST_ELEMENT(bin) ) );
2680 successful_add_count ++;
2686 return successful_add_count;
2692 * This function is to create audio pipeline for playing.
2694 * @param player [in] handle of player
2696 * @return This function returns zero on success.
2698 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2700 #define MMPLAYER_CREATEONLY_ELEMENT(x_bin, x_id, x_factory, x_name) \
2701 x_bin[x_id].id = x_id;\
2702 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2703 if ( ! x_bin[x_id].gst )\
2705 debug_critical("failed to create %s \n", x_factory);\
2709 /* macro for code readability. just for sinkbin-creation functions */
2710 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket) \
2713 x_bin[x_id].id = x_id;\
2714 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2715 if ( ! x_bin[x_id].gst )\
2717 debug_critical("failed to create %s \n", x_factory);\
2720 if ( x_add_bucket )\
2721 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2727 * - Local playback : audioconvert !volume ! capsfilter ! dnse ! audiosink
2728 * - Streaming : audioconvert !volume ! audiosink
2729 * - PCM extraction : audioconvert ! audioresample ! capsfilter ! fakesink
2732 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
2734 MMPlayerGstElement* first_element = NULL;
2735 MMPlayerGstElement* audiobin = NULL;
2736 MMHandleType attrs = 0;
2738 GstPad *ghostpad = NULL;
2739 GList* element_bucket = NULL;
2740 char *device_name = NULL;
2741 gboolean link_audio_sink_now = TRUE;
2746 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
2749 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2750 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2753 debug_error("failed to allocate memory for audiobin\n");
2754 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2757 attrs = MMPLAYER_GET_ATTRS(player);
2760 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2761 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2762 if ( !audiobin[MMPLAYER_A_BIN].gst )
2764 debug_critical("failed to create audiobin\n");
2769 player->pipeline->audiobin = audiobin;
2771 player->is_sound_extraction = __mmplayer_can_extract_pcm(player);
2773 /* Adding audiotp plugin for reverse trickplay feature */
2774 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audiotrickplay", TRUE);
2777 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audioconverter", TRUE);
2779 if ( ! player->is_sound_extraction )
2781 GstCaps* caps = NULL;
2783 /* for logical volume control */
2784 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE);
2785 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2787 if (player->sound.mute)
2789 debug_log("mute enabled\n");
2790 g_object_set(G_OBJECT (audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2794 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
2796 caps = gst_caps_from_string( "audio/x-raw-int, "
2797 "endianness = (int) LITTLE_ENDIAN, "
2798 "signed = (boolean) true, "
2799 "width = (int) 16, "
2800 "depth = (int) 16" );
2802 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
2804 gst_caps_unref( caps );
2806 /* audio filter. if enabled */
2807 if ( PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom )
2809 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, "soundalive", "audiofilter", TRUE);
2812 /* create audio sink */
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, PLAYER_INI()->name_of_audiosink,
2814 "audiosink", link_audio_sink_now);
2817 if (MMPLAYER_IS_RTSP_STREAMING(player))
2818 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL); /* sync off */
2820 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL); /* sync on */
2823 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2825 /* FIXIT : using system clock. isn't there another way? */
2826 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "provide-clock", PLAYER_INI()->provide_clock, NULL);
2828 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
2830 if(player->audio_buffer_cb)
2832 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-handle", player->audio_buffer_cb_user_param, NULL);
2833 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "audio-callback", player->audio_buffer_cb, NULL);
2836 if ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink") )
2838 gint volume_type = 0;
2839 gint audio_route = 0;
2840 gint sound_priority = FALSE;
2841 gint is_spk_out_only = 0;
2844 * It should be set after player creation through attribute.
2845 * But, it can not be changed during playing.
2847 mm_attrs_get_int_by_name(attrs, "sound_volume_type", &volume_type);
2848 mm_attrs_get_int_by_name(attrs, "sound_route", &audio_route);
2849 mm_attrs_get_int_by_name(attrs, "sound_priority", &sound_priority);
2850 mm_attrs_get_int_by_name(attrs, "sound_spk_out_only", &is_spk_out_only);
2852 /* hook sound_type if emergency case */
2853 if ( player->sm.event == ASM_EVENT_EMERGENCY)
2855 debug_log ("This is emergency session, hook sound_type from [%d] to [%d]\n", volume_type, MM_SOUND_VOLUME_TYPE_EMERGENCY);
2856 volume_type = MM_SOUND_VOLUME_TYPE_EMERGENCY;
2859 g_object_set(audiobin[MMPLAYER_A_SINK].gst,
2860 "volumetype", volume_type,
2861 "audio-route", audio_route,
2862 "priority", sound_priority,
2863 "user-route", is_spk_out_only,
2866 debug_log("audiosink property status...volume type:%d, route:%d, priority=%d, user-route=%d\n",
2867 volume_type, audio_route, sound_priority, is_spk_out_only);
2870 /* Antishock can be enabled when player is resumed by soundCM.
2871 * But, it's not used in MMS, setting and etc.
2872 * Because, player start seems like late.
2874 __mmplayer_set_antishock( player , FALSE );
2876 else // pcm extraction only and no sound output
2878 int dst_samplerate = 0;
2879 int dst_channels = 0;
2881 char *caps_type = NULL;
2882 GstCaps* caps = NULL;
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, "audioresample", "resampler", TRUE);
2887 /* get conf. values */
2888 mm_attrs_multiple_get(player->attrs,
2890 "pcm_extraction_samplerate", &dst_samplerate,
2891 "pcm_extraction_channels", &dst_channels,
2892 "pcm_extraction_depth", &dst_depth,
2895 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE);
2897 caps = gst_caps_new_simple ("audio/x-raw-int",
2898 "rate", G_TYPE_INT, dst_samplerate,
2899 "channels", G_TYPE_INT, dst_channels,
2900 "depth", G_TYPE_INT, dst_depth,
2903 caps_type = gst_caps_to_string(caps);
2904 debug_log("resampler new caps : %s\n", caps_type);
2906 g_object_set (GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL );
2909 gst_caps_unref( caps );
2910 MMPLAYER_FREEIF( caps_type );
2913 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE);
2916 g_object_set (G_OBJECT (audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
2918 __mmplayer_add_sink( player, audiobin[MMPLAYER_A_SINK].gst );
2921 /* adding created elements to bin */
2922 debug_log("adding created elements to bin\n");
2923 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket ))
2925 debug_error("failed to add elements\n");
2929 /* linking elements in the bucket by added order. */
2930 debug_log("Linking elements in the bucket by added order.\n");
2931 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
2933 debug_error("failed to link elements\n");
2937 /* get first element's sinkpad for creating ghostpad */
2938 first_element = (MMPlayerGstElement *)element_bucket->data;
2940 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2943 debug_error("failed to get pad from first element of audiobin\n");
2947 ghostpad = gst_ghost_pad_new("sink", pad);
2950 debug_error("failed to create ghostpad\n");
2954 if ( FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad) )
2956 debug_error("failed to add ghostpad to audiobin\n");
2960 gst_object_unref(pad);
2962 if ( !player->bypass_sound_effect && (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
2964 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
2966 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
2968 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
2971 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
2973 if (!_mmplayer_sound_filter_custom_apply(player))
2975 debug_msg("apply sound effect(custom) setting success\n");
2980 /* done. free allocated variables */
2981 MMPLAYER_FREEIF( device_name );
2982 g_list_free(element_bucket);
2984 mm_attrs_set_int_by_name(attrs, "content_audio_found", TRUE);
2985 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
2986 debug_error("failed to commit attribute ""content_audio_found"".\n");
2990 return MM_ERROR_NONE;
2994 debug_log("ERROR : releasing audiobin\n");
2996 MMPLAYER_FREEIF( device_name );
2999 gst_object_unref(GST_OBJECT(pad));
3002 gst_object_unref(GST_OBJECT(ghostpad));
3004 g_list_free( element_bucket );
3007 /* release element which are not added to bin */
3008 for ( i = 1; i < MMPLAYER_A_NUM; i++ ) /* NOTE : skip bin */
3010 if ( audiobin[i].gst )
3012 GstObject* parent = NULL;
3013 parent = gst_element_get_parent( audiobin[i].gst );
3017 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3018 audiobin[i].gst = NULL;
3022 gst_object_unref(GST_OBJECT(parent));
3027 /* release audiobin with it's childs */
3028 if ( audiobin[MMPLAYER_A_BIN].gst )
3030 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3033 MMPLAYER_FREEIF( audiobin );
3035 player->pipeline->audiobin = NULL;
3037 return MM_ERROR_PLAYER_INTERNAL;
3041 __mmplayer_audio_stream_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3043 mm_player_t* player = (mm_player_t*) u_data;
3047 data = GST_BUFFER_DATA(buffer);
3048 size = GST_BUFFER_SIZE(buffer);
3050 if (player->audio_stream_cb && size && data)
3051 player->audio_stream_cb((void *)data, size, player->audio_stream_cb_user_param);
3057 __mmplayer_ahs_appsrc_probe (GstPad *pad, GstBuffer *buffer, gpointer u_data)
3059 mm_player_t* player = (mm_player_t*) u_data;
3061 //g_print ("appsrc buf : timestamp = %"GST_TIME_FORMAT", duration = %"GST_TIME_FORMAT"\n",
3062 // GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION(buffer)));
3064 if (ahs_check_allow_cache (player->ahs_player))
3066 ahs_store_media_presentation (player->ahs_player, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
3072 * This function is to create video pipeline.
3074 * @param player [in] handle of player
3075 * caps [in] src caps of decoder
3076 * surface_type [in] surface type for video rendering
3078 * @return This function returns zero on success.
3080 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3084 * - x surface (arm/x86) : xvimagesink
3085 * - evas surface (arm) : ffmpegcolorspace ! evasimagesink
3086 * - evas surface (x86) : videoconvertor ! evasimagesink
3089 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3093 GList*element_bucket = NULL;
3094 MMPlayerGstElement* first_element = NULL;
3095 MMPlayerGstElement* videobin = NULL;
3096 gchar* vconv_factory = NULL;
3097 gchar *videosink_element = NULL;
3101 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3104 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3106 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3108 player->pipeline->videobin = videobin;
3110 attrs = MMPLAYER_GET_ATTRS(player);
3113 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3114 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3115 if ( !videobin[MMPLAYER_V_BIN].gst )
3117 debug_critical("failed to create videobin");
3121 if( player->use_video_stream ) // video stream callack, so send raw video data to application
3123 GstStructure *str = NULL;
3127 debug_log("using memsink\n");
3129 /* first, create colorspace convert */
3130 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3132 vconv_factory = PLAYER_INI()->name_of_video_converter;
3137 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3140 /* then, create video scale to resize if needed */
3141 str = gst_caps_get_structure (caps, 0);
3145 debug_error("cannot get structure\n");
3149 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3151 ret = gst_structure_get_fourcc (str, "format", &fourcc);
3154 debug_log("not fixed format at this point, and not consider this case\n")
3156 /* NOTE : if the width of I420 format is not multiple of 8, it should be resize before colorspace conversion.
3157 * so, video scale is required for this case only.
3159 if ( GST_MAKE_FOURCC ('I', '4', '2', '0') == fourcc )
3161 gint width = 0; //width of video
3162 gint height = 0; //height of video
3163 gint framerate_n = 0; //numerator of frame rate
3164 gint framerate_d = 0; //denominator of frame rate
3165 GstCaps* video_caps = NULL;
3169 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscale", TRUE);
3171 /*to limit width as multiple of 8 */
3172 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CAPS, "capsfilter", "videocapsfilter", TRUE);
3174 /* get video stream caps parsed by demuxer */
3175 str = gst_caps_get_structure (player->v_stream_caps, 0);
3178 debug_error("cannot get structure\n");
3182 /* check the width if it's a multiple of 8 or not */
3183 ret = gst_structure_get_int (str, "width", &width);
3186 debug_error("cannot get width\n");
3189 width = GST_ROUND_UP_8(width);
3191 ret = gst_structure_get_int(str, "height", &height);
3194 debug_error("cannot get height\n");
3198 fps = gst_structure_get_value (str, "framerate");
3201 debug_error("cannot get fps\n");
3204 framerate_n = gst_value_get_fraction_numerator (fps);
3205 framerate_d = gst_value_get_fraction_denominator (fps);
3207 video_caps = gst_caps_new_simple( "video/x-raw-yuv",
3208 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
3209 "width", G_TYPE_INT, width,
3210 "height", G_TYPE_INT, height,
3211 "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d,
3214 g_object_set (GST_ELEMENT(videobin[MMPLAYER_V_CAPS].gst), "caps", video_caps, NULL );
3216 gst_caps_unref( video_caps );
3219 /* finally, create video sink. its oupput should be BGRX8888 for application like cario surface. */
3220 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, "avsysmemsink", "videosink", TRUE);
3222 MMPLAYER_SIGNAL_CONNECT( player,
3223 videobin[MMPLAYER_V_SINK].gst,
3225 G_CALLBACK(__mmplayer_videostream_cb),
3228 else // render video data using sink pugin like xvimagesink
3230 debug_log("using videosink");
3232 /*set video converter */
3233 if (strlen(PLAYER_INI()->name_of_video_converter) > 0)
3235 vconv_factory = PLAYER_INI()->name_of_video_converter;
3238 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_CONV, vconv_factory, "video converter", TRUE);
3239 debug_log("using video converter: %s", vconv_factory);
3243 /* videoscaler */ /* NOTE : ini parsing method seems to be more suitable rather than define method */
3244 #if !defined(__arm__)
3245 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SCALE, "videoscale", "videoscaler", TRUE);
3248 /* set video sink */
3249 switch (surface_type)
3251 case MM_DISPLAY_SURFACE_X:
3252 if (strlen(PLAYER_INI()->videosink_element_x) > 0)
3253 videosink_element = PLAYER_INI()->videosink_element_x;
3257 case MM_DISPLAY_SURFACE_EVAS:
3258 if (strlen(PLAYER_INI()->videosink_element_evas) > 0)
3259 videosink_element = PLAYER_INI()->videosink_element_evas;
3263 case MM_DISPLAY_SURFACE_X_EXT:
3265 void *pixmap_id_cb = NULL;
3266 mm_attrs_get_data_by_name(attrs, "display_overlay", &pixmap_id_cb);
3267 if (pixmap_id_cb) /* this is for the video textue(canvas texture) */
3269 videosink_element = PLAYER_INI()->videosink_element_x;
3270 debug_warning("video texture usage");
3274 debug_error("something wrong.. callback function for getting pixmap id is null");
3279 case MM_DISPLAY_SURFACE_NULL:
3280 if (strlen(PLAYER_INI()->videosink_element_fake) > 0)
3281 videosink_element = PLAYER_INI()->videosink_element_fake;
3286 debug_error("unidentified surface type");
3290 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, videosink_element, TRUE);
3291 debug_log("selected videosink name: %s", videosink_element);
3294 if ( _mmplayer_update_video_param(player) != MM_ERROR_NONE)
3298 g_object_set (G_OBJECT (videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
3300 /* store it as it's sink element */
3301 __mmplayer_add_sink( player, videobin[MMPLAYER_V_SINK].gst );
3303 /* adding created elements to bin */
3304 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket) )
3306 debug_error("failed to add elements\n");
3310 /* Linking elements in the bucket by added order */
3311 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3313 debug_error("failed to link elements\n");
3317 /* get first element's sinkpad for creating ghostpad */
3318 first_element = (MMPlayerGstElement *)element_bucket->data;
3319 if ( !first_element )
3321 debug_error("failed to get first element from bucket\n");
3325 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3328 debug_error("failed to get pad from first element\n");
3332 /* create ghostpad */
3333 if ( FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, gst_ghost_pad_new("sink", pad)) )
3335 debug_error("failed to add ghostpad to videobin\n");
3338 gst_object_unref(pad);
3340 /* done. free allocated variables */
3341 g_list_free(element_bucket);
3343 mm_attrs_set_int_by_name(attrs, "content_video_found", TRUE);
3344 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
3345 debug_error("failed to commit attribute ""content_video_found"".\n");
3349 return MM_ERROR_NONE;
3352 debug_error("ERROR : releasing videobin\n");
3354 g_list_free( element_bucket );
3357 gst_object_unref(GST_OBJECT(pad));
3359 /* release videobin with it's childs */
3360 if ( videobin[MMPLAYER_V_BIN].gst )
3362 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3366 MMPLAYER_FREEIF( videobin );
3368 player->pipeline->videobin = NULL;
3370 return MM_ERROR_PLAYER_INTERNAL;
3373 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3375 MMPlayerGstElement* first_element = NULL;
3376 MMPlayerGstElement* textbin = NULL;
3377 GList* element_bucket = NULL;
3379 GstPad *ghostpad = NULL;
3384 return_val_if_fail( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
3387 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3390 debug_error("failed to allocate memory for textbin\n");
3391 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3395 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3396 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3397 if ( !textbin[MMPLAYER_T_BIN].gst )
3399 debug_critical("failed to create textbin\n");
3404 player->pipeline->textbin = textbin;
3407 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_SINK, "fakesink", "text_sink", TRUE);
3409 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "sync", TRUE, NULL);
3410 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "async", FALSE, NULL);
3411 g_object_set (G_OBJECT (textbin[MMPLAYER_T_SINK].gst), "signal-handoffs", TRUE, NULL);
3413 MMPLAYER_SIGNAL_CONNECT( player,
3414 G_OBJECT(textbin[MMPLAYER_T_SINK].gst),
3416 G_CALLBACK(__mmplayer_update_subtitle),
3419 __mmplayer_add_sink (player, GST_ELEMENT(textbin[MMPLAYER_T_SINK].gst));
3421 /* adding created elements to bin */
3422 debug_log("adding created elements to bin\n");
3423 if( !__mmplayer_gst_element_add_bucket_to_bin( GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket ))
3425 debug_error("failed to add elements\n");
3429 /* linking elements in the bucket by added order. */
3430 debug_log("Linking elements in the bucket by added order.\n");
3431 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3433 debug_error("failed to link elements\n");
3437 /* get first element's sinkpad for creating ghostpad */
3438 first_element = (MMPlayerGstElement *)element_bucket->data;
3440 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3443 debug_error("failed to get pad from first element of textbin\n");
3447 ghostpad = gst_ghost_pad_new("sink", pad);
3450 debug_error("failed to create ghostpad\n");
3454 if ( FALSE == gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad) )
3456 debug_error("failed to add ghostpad to textbin\n");
3460 gst_object_unref(pad);
3463 /* done. free allocated variables */
3464 g_list_free(element_bucket);
3468 return MM_ERROR_NONE;
3472 debug_log("ERROR : releasing textbin\n");
3475 gst_object_unref(GST_OBJECT(pad));
3478 gst_object_unref(GST_OBJECT(ghostpad));
3480 g_list_free( element_bucket );
3483 /* release element which are not added to bin */
3484 for ( i = 1; i < MMPLAYER_T_NUM; i++ ) /* NOTE : skip bin */
3486 if ( textbin[i].gst )
3488 GstObject* parent = NULL;
3489 parent = gst_element_get_parent( textbin[i].gst );
3493 gst_object_unref(GST_OBJECT(textbin[i].gst));
3494 textbin[i].gst = NULL;
3498 gst_object_unref(GST_OBJECT(parent));
3503 /* release textbin with it's childs */
3504 if ( textbin[MMPLAYER_T_BIN].gst )
3506 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3509 MMPLAYER_FREEIF( textbin );
3511 player->pipeline->textbin = NULL;
3513 return MM_ERROR_PLAYER_INTERNAL;
3518 __mmplayer_gst_create_subtitle_pipeline(mm_player_t* player)
3520 MMPlayerGstElement* subtitlebin = NULL;
3521 MMHandleType attrs = 0;
3522 gchar *subtitle_uri =NULL;
3523 GList*element_bucket = NULL;
3525 #define USE_MESSAGE_FOR_PLAYING_SUBTITLE
3526 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3528 gint width =0, height = 0;
3529 gboolean silent=FALSE;
3535 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3537 attrs = MMPLAYER_GET_ATTRS(player);
3540 debug_error("cannot get content attribute\n");
3541 return MM_ERROR_PLAYER_INTERNAL;
3544 mm_attrs_get_string_by_name ( attrs, "subtitle_uri", &subtitle_uri );
3545 if ( !subtitle_uri || strlen(subtitle_uri) < 1)
3547 debug_error("subtitle uri is not proper filepath.\n");
3548 return MM_ERROR_PLAYER_INVALID_URI;
3550 debug_log("subtitle file path is [%s].\n", subtitle_uri);
3554 subtitlebin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_SUB_NUM);
3557 debug_error("failed to allocate memory\n");
3558 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3562 subtitlebin[MMPLAYER_SUB_PIPE].id = MMPLAYER_SUB_PIPE;
3563 subtitlebin[MMPLAYER_SUB_PIPE].gst = gst_pipeline_new("subtitlebin");
3564 if ( !subtitlebin[MMPLAYER_SUB_PIPE].gst )
3566 debug_error("failed to create text pipeline\n");
3569 player->pipeline->subtitlebin = subtitlebin;
3571 /* create the text file source */
3572 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SRC, "filesrc", "subtitle_source", TRUE);
3573 g_object_set(G_OBJECT (subtitlebin[MMPLAYER_SUB_SRC].gst), "location", subtitle_uri, NULL);
3576 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_QUEUE, "queue", NULL, TRUE);
3579 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SUBPARSE, "subparse", "subtitle_parser", TRUE);
3581 #ifndef USE_MESSAGE_FOR_PLAYING_SUBTITLE
3583 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_TEXTRENDER, "textrender", "subtitle_render", TRUE);
3585 mm_attrs_get_int_by_name(attrs,"width", &width);
3586 mm_attrs_get_int_by_name(attrs,"height", &height);
3587 mm_attrs_get_int_by_name(attrs,"silent", &silent);
3588 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"width", width, NULL);
3589 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"height", height, NULL);
3590 g_object_set ( G_OBJECT (subtitlebin[MMPLAYER_SUB_TEXTRENDER].gst),"silent", silent, NULL);
3592 debug_log ( "subtitle winow size is [%dX%d].\n", width, height );
3593 debug_log ( "subtitle silent is [%d].\n", silent );
3596 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV1, "ffmpegcolorspace", "subtitle_converter1", TRUE);
3599 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_FLIP, "videoflip", "subtitle_fliper", TRUE);
3602 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_CONV2, "ffmpegcolorspace", "subtitle_converter2", TRUE);
3605 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "ximagesink", "subtitle_sink", TRUE);
3607 mm_attrs_get_data_by_name(attrs, "xid", &xid);
3610 debug_log("setting subtitle xid = %d\n", *(int*)xid);
3611 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(subtitlebin[MMPLAYER_SUB_SINK].gst), *(int*)xid);
3615 /* FIXIT : is it error case? */
3616 debug_warning("still we don't have xid on player attribute. create it's own surface.\n");
3620 MMPLAYER_CREATE_ELEMENT(subtitlebin, MMPLAYER_SUB_SINK, "fakesink", "subtitle_sink", TRUE);
3622 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "sync", TRUE, NULL);
3623 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "async", FALSE, NULL);
3624 g_object_set (G_OBJECT (subtitlebin[MMPLAYER_SUB_SINK].gst), "signal-handoffs", TRUE, NULL);
3626 MMPLAYER_SIGNAL_CONNECT( player,
3627 G_OBJECT(subtitlebin[MMPLAYER_SUB_SINK].gst),
3629 G_CALLBACK(__mmplayer_update_subtitle),
3633 /* adding created elements to bin */
3634 if( ! __mmplayer_gst_element_add_bucket_to_bin(GST_BIN(subtitlebin[MMPLAYER_SUB_PIPE].gst), element_bucket) )
3636 debug_error("failed to add elements\n");
3640 /* Linking elements in the bucket by added order */
3641 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
3643 debug_error("failed to link elements\n");
3647 /* done. free allocated variables */
3648 g_list_free(element_bucket);
3650 player->play_subtitle = TRUE;
3654 return MM_ERROR_NONE;
3658 debug_error("ERROR : releasing text pipeline\n");
3660 g_list_free( element_bucket );
3662 /* release subtitlebin with it's childs */
3663 if ( subtitlebin[MMPLAYER_SUB_PIPE].gst )
3665 gst_object_unref(GST_OBJECT(subtitlebin[MMPLAYER_SUB_PIPE].gst));
3668 MMPLAYER_FREEIF( subtitlebin );
3670 player->pipeline->subtitlebin = NULL;
3672 return MM_ERROR_PLAYER_INTERNAL;
3676 __mmplayer_update_subtitle( GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3678 mm_player_t* player = (mm_player_t*) data;
3679 MMMessageParamType msg = {0, };
3680 GstClockTime duration = 0;
3681 guint8 *text = NULL;
3682 gboolean ret = TRUE;
3686 return_val_if_fail ( player, FALSE );
3687 return_val_if_fail ( buffer, FALSE );
3689 text = GST_BUFFER_DATA(buffer);
3690 duration = GST_BUFFER_DURATION(buffer);
3692 if ( player->is_subtitle_off )
3694 debug_log("subtitle is OFF.\n" );
3700 debug_log("There is no subtitle to be displayed.\n" );
3704 msg.data = (void *) text;
3705 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3707 debug_warning("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data );
3709 MMPLAYER_POST_MSG( player, MM_MESSAGE_UPDATE_SUBTITLE, &msg );
3717 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3719 GstEvent* event = NULL;
3720 gint64 current_pos = 0;
3721 gint64 adusted_pos = 0;
3722 gboolean ret = TRUE;
3726 /* check player and subtitlebin are created */
3727 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
3728 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
3732 debug_log("adjusted values is 0, no need to adjust subtitle position.\n");
3733 return MM_ERROR_NONE;
3738 case MM_PLAYER_POS_FORMAT_TIME:
3740 /* check current postion */
3741 ret = gst_element_query_position( GST_ELEMENT(player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst), &format, ¤t_pos );
3744 debug_warning("fail to query current postion.\n");
3745 return MM_ERROR_PLAYER_SEEK;
3749 adusted_pos = current_pos + ((gint64)position * G_GINT64_CONSTANT(1000000));
3750 if (adusted_pos < 0)
3751 adusted_pos = G_GINT64_CONSTANT(0);
3752 debug_log("adjust subtitle postion : %lu -> %lu [msec]\n", GST_TIME_AS_MSECONDS(current_pos), GST_TIME_AS_MSECONDS(adusted_pos));
3755 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
3756 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
3757 GST_SEEK_TYPE_SET, adusted_pos,
3758 GST_SEEK_TYPE_SET, -1);
3762 case MM_PLAYER_POS_FORMAT_PERCENT:
3764 debug_warning("percent format is not supported yet.\n");
3765 return MM_ERROR_INVALID_ARGUMENT;
3771 debug_warning("invalid format.\n");
3772 return MM_ERROR_INVALID_ARGUMENT;
3776 /* keep ref to the event */
3777 gst_event_ref (event);
3779 debug_log("sending event[%s] to sink element [%s]\n",
3780 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
3782 if ( ret = gst_element_send_event (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst, event) )
3784 debug_log("sending event[%s] to sink element [%s] success!\n",
3785 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst) );
3788 /* unref to the event */
3789 gst_event_unref (event);
3794 return MM_ERROR_NONE;
3799 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data) // @
3801 GstElement *appsrc = element;
3802 tBuffer *buf = (tBuffer *)user_data;
3803 GstBuffer *buffer = NULL;
3804 GstFlowReturn ret = GST_FLOW_OK;
3807 return_if_fail ( element );
3808 return_if_fail ( buf );
3810 buffer = gst_buffer_new ();
3812 if (buf->offset >= buf->len)
3814 debug_log("call eos appsrc\n");
3815 g_signal_emit_by_name (appsrc, "end-of-stream", &ret);
3819 if ( buf->len - buf->offset < size)
3821 len = buf->len - buf->offset + buf->offset;
3824 GST_BUFFER_DATA(buffer) = (guint8*)(buf->buf + buf->offset);
3825 GST_BUFFER_SIZE(buffer) = len;
3826 GST_BUFFER_OFFSET(buffer) = buf->offset;
3827 GST_BUFFER_OFFSET_END(buffer) = buf->offset + len;
3829 debug_log("feed buffer %p, offset %u-%u length %u\n", buffer, buf->offset, buf->len,len);
3830 g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
3836 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data) // @
3838 tBuffer *buf = (tBuffer *)user_data;
3840 return_val_if_fail ( buf, FALSE );
3842 buf->offset = (int)size;
3848 __gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) // @
3850 mm_player_t *player = (mm_player_t*)user_data;
3852 return_if_fail ( player );
3854 debug_msg("app-src: feed data\n");
3856 if(player->need_data_cb)
3857 player->need_data_cb(size, player->buffer_cb_user_param);
3861 __gst_appsrc_seek_data(GstElement *element, guint64 offset, gpointer user_data) // @
3863 mm_player_t *player = (mm_player_t*)user_data;
3865 return_val_if_fail ( player, FALSE );
3867 debug_msg("app-src: seek data\n");
3869 if(player->seek_data_cb)
3870 player->seek_data_cb(offset, player->buffer_cb_user_param);
3877 __gst_appsrc_enough_data(GstElement *element, gpointer user_data) // @
3879 mm_player_t *player = (mm_player_t*)user_data;
3881 return_val_if_fail ( player, FALSE );
3883 debug_msg("app-src: enough data:%p\n", player->enough_data_cb);
3885 if(player->enough_data_cb)
3886 player->enough_data_cb(player->buffer_cb_user_param);
3892 _mmplayer_push_buffer(MMHandleType hplayer, unsigned char *buf, int size) // @
3894 mm_player_t* player = (mm_player_t*)hplayer;
3895 GstBuffer *buffer = NULL;
3896 GstFlowReturn gst_ret = GST_FLOW_OK;
3897 int ret = MM_ERROR_NONE;
3901 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
3903 /* check current state */
3904 // MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
3907 /* NOTE : we should check and create pipeline again if not created as we destroy
3908 * whole pipeline when stopping in streamming playback
3910 if ( ! player->pipeline )
3912 if ( MM_ERROR_NONE != __gst_realize( player ) )
3914 debug_error("failed to realize before starting. only in streamming\n");
3915 return MM_ERROR_PLAYER_INTERNAL;
3919 debug_msg("app-src: pushing data\n");
3923 debug_error("buf is null\n");
3924 return MM_ERROR_NONE;
3927 buffer = gst_buffer_new ();
3931 debug_log("call eos appsrc\n");
3932 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "end-of-stream", &gst_ret);
3933 return MM_ERROR_NONE;
3936 GST_BUFFER_DATA(buffer) = (guint8*)(buf);
3937 GST_BUFFER_SIZE(buffer) = size;
3939 debug_log("feed buffer %p, length %u\n", buf, size);
3940 g_signal_emit_by_name (player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "push-buffer", buffer, &gst_ret);
3947 static GstBusSyncReply
3948 __mmplayer_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
3950 mm_player_t *player = (mm_player_t *)data;
3951 GstElement *sender = (GstElement *) GST_MESSAGE_SRC (message);
3952 const gchar *name = gst_element_get_name (sender);
3954 switch (GST_MESSAGE_TYPE (message))
3956 case GST_MESSAGE_TAG:
3957 __mmplayer_gst_extract_tag_from_msg(player, message);
3960 case GST_MESSAGE_DURATION:
3961 if (MMPLAYER_IS_STREAMING(player))
3966 gst_message_parse_duration (message, &format, &bytes);
3967 if (format == GST_FORMAT_BYTES)
3969 debug_log("data total size of http content: %lld", bytes);
3970 player->http_content_size = bytes;
3975 player->need_update_content_attrs = TRUE;
3976 _mmplayer_update_content_attrs(player);
3979 return GST_BUS_PASS;
3981 gst_message_unref (message);
3983 return GST_BUS_DROP;
3987 * This function is to create audio or video pipeline for playing.
3989 * @param player [in] handle of player
3991 * @return This function returns zero on success.
3996 __mmplayer_gst_create_pipeline(mm_player_t* player) // @
3999 MMPlayerGstElement *mainbin = NULL;
4000 MMHandleType attrs = 0;
4001 GstElement* element = NULL;
4002 GList* element_bucket = NULL;
4003 gboolean need_state_holder = TRUE;
4008 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4010 /* get profile attribute */
4011 attrs = MMPLAYER_GET_ATTRS(player);
4014 debug_error("cannot get content attribute\n");
4018 /* create pipeline handles */
4019 if ( player->pipeline )
4021 debug_warning("pipeline should be released before create new one\n");
4025 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0( sizeof(MMPlayerGstPipelineInfo) );
4026 if (player->pipeline == NULL)
4029 memset( player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo) );
4032 /* create mainbin */
4033 mainbin = (MMPlayerGstElement*) g_malloc0( sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM );
4034 if (mainbin == NULL)
4037 memset( mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4040 /* create pipeline */
4041 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4042 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4043 if ( ! mainbin[MMPLAYER_M_PIPE].gst )
4045 debug_error("failed to create pipeline\n");
4050 /* create source element */
4051 switch ( player->profile.uri_type )
4053 /* rtsp streamming */
4054 case MM_PLAYER_URI_TYPE_URL_RTSP:
4056 gint network_bandwidth;
4057 gchar *user_agent, *wap_profile;
4059 element = gst_element_factory_make(PLAYER_INI()->name_of_rtspsrc, "streaming_source");
4063 debug_critical("failed to create streaming source element\n");
4067 debug_log("using streamming source [%s].\n", PLAYER_INI()->name_of_rtspsrc);
4070 network_bandwidth = 0;
4071 user_agent = wap_profile = NULL;
4074 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4075 mm_attrs_get_string_by_name ( attrs,"streaming_wap_profile", &wap_profile );
4076 mm_attrs_get_int_by_name ( attrs, "streaming_network_bandwidth", &network_bandwidth );
4078 debug_log("setting streaming source ----------------\n");
4079 debug_log("user_agent : %s\n", user_agent);
4080 debug_log("wap_profile : %s\n", wap_profile);
4081 debug_log("network_bandwidth : %d\n", network_bandwidth);
4082 debug_log("buffering time : %d\n", PLAYER_INI()->rtsp_buffering_time);
4083 debug_log("rebuffering time : %d\n", PLAYER_INI()->rtsp_rebuffering_time);
4084 debug_log("-----------------------------------------\n");
4086 /* setting property to streaming source */
4087 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4088 g_object_set(G_OBJECT(element), "bandwidth", network_bandwidth, NULL);
4089 g_object_set(G_OBJECT(element), "buffering_time", PLAYER_INI()->rtsp_buffering_time, NULL);
4090 g_object_set(G_OBJECT(element), "rebuffering_time", PLAYER_INI()->rtsp_rebuffering_time, NULL);
4092 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4094 g_object_set(G_OBJECT(element), "wap_profile", wap_profile, NULL);
4096 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "pad-added",
4097 G_CALLBACK (__mmplayer_gst_rtp_dynamic_pad), player );
4098 MMPLAYER_SIGNAL_CONNECT ( player, G_OBJECT(element), "no-more-pads",
4099 G_CALLBACK (__mmplayer_gst_rtp_no_more_pads), player );
4101 player->no_more_pad = FALSE;
4102 player->num_dynamic_pad = 0;
4104 /* NOTE : we cannot determine it yet. this filed will be filled by
4105 * _mmplayer_update_content_attrs() after START.
4107 player->streaming_type = STREAMING_SERVICE_NONE;
4112 case MM_PLAYER_URI_TYPE_URL_HTTP:
4114 gchar *user_agent, *proxy, *cookies, **cookie_list;
4115 user_agent = proxy = cookies = NULL;
4117 gint mode = MM_PLAYER_PD_MODE_NONE;
4119 mm_attrs_get_int_by_name ( attrs, "pd_mode", &mode );
4121 player->pd_mode = mode;
4123 debug_log("http playback, PD mode : %d\n", player->pd_mode);
4125 if ( ! MMPLAYER_IS_HTTP_PD(player) )
4127 element = gst_element_factory_make(PLAYER_INI()->name_of_httpsrc, "http_streaming_source");
4130 debug_critical("failed to create http streaming source element[%s].\n", PLAYER_INI()->name_of_httpsrc);
4133 debug_log("using http streamming source [%s].\n", PLAYER_INI()->name_of_httpsrc);
4136 mm_attrs_get_string_by_name ( attrs, "streaming_cookie", &cookies );
4137 mm_attrs_get_string_by_name ( attrs, "streaming_user_agent", &user_agent );
4138 mm_attrs_get_string_by_name ( attrs, "streaming_proxy", &proxy );
4141 debug_log("setting http streaming source ----------------\n");
4142 debug_log("location : %s\n", player->profile.uri);
4143 debug_log("cookies : %s\n", cookies);
4144 debug_log("proxy : %s\n", proxy);
4145 debug_log("user_agent : %s\n", user_agent);
4146 debug_log("timeout : %d\n", PLAYER_INI()->http_timeout);
4147 debug_log("-----------------------------------------\n");
4149 /* setting property to streaming source */
4150 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
4151 g_object_set(G_OBJECT(element), "timeout", PLAYER_INI()->http_timeout, NULL);
4152 /* check if prosy is vailid or not */
4153 if ( util_check_valid_url ( proxy ) )
4154 g_object_set(G_OBJECT(element), "proxy", proxy, NULL);
4155 /* parsing cookies */
4156 if ( ( cookie_list = util_get_cookie_list ((const char*)cookies) ) )
4157 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
4159 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
4161 else // progressive download
4163 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
4167 mm_attrs_get_string_by_name ( attrs, "pd_location", &path );
4169 MMPLAYER_FREEIF(player->pd_file_location);
4171 debug_log("PD Location : %s\n", path);
4175 player->pd_file_location = g_strdup(path);
4179 debug_error("can't find pd location so, it should be set \n");
4180 return MM_ERROR_PLAYER_FILE_NOT_FOUND;
4184 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
4187 debug_critical("failed to create PD push source element[%s].\n", "pdpushsrc");
4191 g_object_set(G_OBJECT(element), "location", player->pd_file_location, NULL);
4194 player->streaming_type = STREAMING_SERVICE_NONE;
4199 case MM_PLAYER_URI_TYPE_FILE:
4201 char* drmsrc = PLAYER_INI()->name_of_drmsrc;
4203 debug_log("using [%s] for 'file://' handler.\n", drmsrc);
4205 element = gst_element_factory_make(drmsrc, "source");
4208 debug_critical("failed to create %s\n", drmsrc);
4212 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
4213 //g_object_set(G_OBJECT(element), "use-mmap", TRUE, NULL);
4217 #ifdef NO_USE_GST_HLSDEMUX
4218 case MM_PLAYER_URI_TYPE_HLS:
4220 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4222 debug_log("hsl src is selected\n");
4224 element = gst_element_factory_make("appsrc", "hls-source");
4227 debug_critical("failed to create appsrc element\n");
4230 g_object_set( element, "stream-type", stream_type, NULL );
4232 // TODO: need to set time based limit instead of bytes (or) remove constraint.... need to investigate more
4233 g_object_set( element, "max-bytes", 500000, NULL ); // Naveen made queue as un-limited
4238 case MM_PLAYER_URI_TYPE_BUFF:
4240 guint64 stream_type = GST_APP_STREAM_TYPE_STREAM;
4242 debug_log("mem src is selected\n");
4244 element = gst_element_factory_make("appsrc", "buff-source");
4247 debug_critical("failed to create appsrc element\n");
4251 g_object_set( element, "stream-type", stream_type, NULL );
4252 //g_object_set( element, "size", player->mem_buf.len, NULL );
4253 //g_object_set( element, "blocksize", (guint64)20480, NULL );
4255 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4256 G_CALLBACK(__gst_appsrc_seek_data), player);
4257 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4258 G_CALLBACK(__gst_appsrc_feed_data), player);
4259 MMPLAYER_SIGNAL_CONNECT( player, element, "enough-data",
4260 G_CALLBACK(__gst_appsrc_enough_data), player);
4265 case MM_PLAYER_URI_TYPE_MEM:
4267 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
4269 debug_log("mem src is selected\n");
4271 element = gst_element_factory_make("appsrc", "mem-source");
4274 debug_critical("failed to create appsrc element\n");
4278 g_object_set( element, "stream-type", stream_type, NULL );
4279 g_object_set( element, "size", player->mem_buf.len, NULL );
4280 g_object_set( element, "blocksize", (guint64)20480, NULL );
4282 MMPLAYER_SIGNAL_CONNECT( player, element, "seek-data",
4283 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->mem_buf );
4284 MMPLAYER_SIGNAL_CONNECT( player, element, "need-data",
4285 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->mem_buf );
4288 case MM_PLAYER_URI_TYPE_URL:
4291 case MM_PLAYER_URI_TYPE_TEMP:
4294 case MM_PLAYER_URI_TYPE_NONE:
4299 /* check source element is OK */
4302 debug_critical("no source element was created.\n");
4306 /* take source element */
4307 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4308 mainbin[MMPLAYER_M_SRC].gst = element;
4309 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
4311 if (MMPLAYER_IS_STREAMING(player) || (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS))
4313 player->streamer = __mm_player_streaming_create();
4314 __mm_player_streaming_initialize(player->streamer);
4317 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS )
4319 debug_log ("adding appsrc's pad probe...\n");
4321 pad = gst_element_get_static_pad(mainbin[MMPLAYER_M_SRC].gst, "src" );
4323 /* register probe */
4324 ahs_appsrc_cb_probe_id = gst_pad_add_buffer_probe (pad,
4325 G_CALLBACK (__mmplayer_ahs_appsrc_probe), player);
4327 gst_object_unref(pad);
4331 if ( MMPLAYER_IS_HTTP_PD(player) )
4333 debug_log ("Picked queue2 element....\n");
4334 element = gst_element_factory_make("queue2", "hls_stream_buffer");
4337 debug_critical ( "failed to create http streaming buffer element\n" );
4342 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
4343 mainbin[MMPLAYER_M_S_BUFFER].gst = element;
4344 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
4346 __mm_player_streaming_set_buffer(player->streamer,
4349 PLAYER_INI()->http_max_size_bytes,
4351 PLAYER_INI()->http_buffering_limit,
4352 PLAYER_INI()->http_buffering_time,
4358 /* create autoplugging element if src element is not a streamming src */
4359 if ( player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP )
4363 if( PLAYER_INI()->use_decodebin )
4365 /* create decodebin */
4366 element = gst_element_factory_make("decodebin", "decodebin");
4368 g_object_set(G_OBJECT(element), "async-handling", TRUE, NULL);
4370 /* set signal handler */
4371 MMPLAYER_SIGNAL_CONNECT( player, G_OBJECT(element), "new-decoded-pad",
4372 G_CALLBACK(__mmplayer_gst_decode_callback), player);
4374 /* we don't need state holder, bcz decodebin is doing well by itself */
4375 need_state_holder = FALSE;
4379 element = gst_element_factory_make("typefind", "typefinder");
4380 MMPLAYER_SIGNAL_CONNECT( player, element, "have-type",
4381 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player );
4384 /* check autoplug element is OK */
4387 debug_critical("can not create autoplug element\n");
4391 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
4392 mainbin[MMPLAYER_M_AUTOPLUG].gst = element;
4394 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_AUTOPLUG]);
4398 /* add elements to pipeline */
4399 if( !__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket))
4401 debug_error("Failed to add elements to pipeline\n");
4406 /* linking elements in the bucket by added order. */
4407 if ( __mmplayer_gst_element_link_bucket(element_bucket) == -1 )
4409 debug_error("Failed to link some elements\n");
4414 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4415 if ( need_state_holder )
4418 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4419 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make ("fakesink", "state-holder");
4421 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4423 debug_error ("fakesink element could not be created\n");
4426 GST_OBJECT_FLAG_UNSET (mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_IS_SINK);
4428 /* take ownership of fakesink. we are reusing it */
4429 gst_object_ref( mainbin[MMPLAYER_M_SRC_FAKESINK].gst );
4432 if ( FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
4433 mainbin[MMPLAYER_M_SRC_FAKESINK].gst) )
4435 debug_error("failed to add fakesink to bin\n");
4440 /* now we have completed mainbin. take it */
4441 player->pipeline->mainbin = mainbin;
4443 /* connect bus callback */
4444 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4447 debug_error ("cannot get bus from pipeline.\n");
4450 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
4452 /* Note : check whether subtitle atrribute uri is set. If uri is set, then create the text pipeline */
4453 if ( __mmplayer_check_subtitle ( player ) )
4455 debug_log("try to create subtitle pipeline \n");
4457 if ( MM_ERROR_NONE != __mmplayer_gst_create_subtitle_pipeline(player) )
4458 debug_error("fail to create subtitle pipeline")
4460 debug_log("subtitle pipeline is created successfully\n");
4463 /* set sync handler to get tag synchronously */
4464 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player);
4468 gst_object_unref(GST_OBJECT(bus));
4469 g_list_free(element_bucket);
4473 return MM_ERROR_NONE;
4477 __mmplayer_gst_destroy_pipeline(player);
4478 g_list_free(element_bucket);
4480 /* release element which are not added to bin */
4481 for ( i = 1; i < MMPLAYER_M_NUM; i++ ) /* NOTE : skip pipeline */
4483 if ( mainbin[i].gst )
4485 GstObject* parent = NULL;
4486 parent = gst_element_get_parent( mainbin[i].gst );
4490 gst_object_unref(GST_OBJECT(mainbin[i].gst));
4491 mainbin[i].gst = NULL;
4495 gst_object_unref(GST_OBJECT(parent));
4500 /* release pipeline with it's childs */
4501 if ( mainbin[MMPLAYER_M_PIPE].gst )
4503 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4506 MMPLAYER_FREEIF( player->pipeline );
4507 MMPLAYER_FREEIF( mainbin );
4509 return MM_ERROR_PLAYER_INTERNAL;
4514 __mmplayer_gst_destroy_pipeline(mm_player_t* player) // @
4517 int ret = MM_ERROR_NONE;
4521 return_val_if_fail ( player, MM_ERROR_INVALID_HANDLE );
4523 /* cleanup stuffs */
4524 MMPLAYER_FREEIF(player->type);
4525 player->have_dynamic_pad = FALSE;
4526 player->no_more_pad = FALSE;
4527 player->num_dynamic_pad = 0;
4528 player->last_position = 0;
4529 player->duration = 0;
4530 player->http_content_size = 0;
4531 player->not_supported_codec = MISSING_PLUGIN_NONE;
4532 player->can_support_codec = FOUND_PLUGIN_NONE;
4533 player->not_found_demuxer = 0;
4534 if (player->v_stream_caps)
4536 gst_caps_unref(player->v_stream_caps);
4537 player->v_stream_caps = NULL;
4540 player->need_update_content_dur = FALSE;
4542 player->pending_seek.is_pending = FALSE;
4543 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
4544 player->pending_seek.pos = 0;
4546 if (ahs_appsrc_cb_probe_id )
4549 pad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "src" );
4551 gst_pad_remove_buffer_probe (pad, ahs_appsrc_cb_probe_id);
4552 gst_object_unref(pad);
4554 ahs_appsrc_cb_probe_id = 0;
4557 if ( player->sink_elements )
4558 g_list_free ( player->sink_elements );
4559 player->sink_elements = NULL;
4561 /* cleanup unlinked mime type */
4562 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4563 MMPLAYER_FREEIF(player->unlinked_video_mime);
4564 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4566 /* cleanup running stuffs */
4567 __mmplayer_cancel_delayed_eos( player );
4569 /* cleanup gst stuffs */
4570 if ( player->pipeline )
4572 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4573 GstTagList* tag_list = player->pipeline->tag_list;
4574 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mainbin[MMPLAYER_M_PIPE].gst));
4576 /* first we need to disconnect all signal hander */
4577 __mmplayer_release_signal_connection( player );
4579 /* disconnecting bus watch */
4580 if ( player->bus_watcher )
4581 g_source_remove( player->bus_watcher );
4582 player->bus_watcher = 0;
4584 gst_bus_set_sync_handler (bus, NULL, NULL);
4588 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4589 MMPlayerGstElement* videobin = player->pipeline->videobin;
4590 MMPlayerGstElement* textbin = player->pipeline->textbin;
4591 MMPlayerGstElement* subtitlebin = player->pipeline->subtitlebin;
4593 debug_log("pipeline status before set state to NULL\n");
4594 __mmplayer_dump_pipeline_state( player );
4596 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4597 ret = __mmplayer_gst_set_state ( player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout );
4598 if ( ret != MM_ERROR_NONE )
4600 debug_error("fail to change state to NULL\n");
4601 return MM_ERROR_PLAYER_INTERNAL;
4604 debug_log("pipeline status before unrefering pipeline\n");
4605 __mmplayer_dump_pipeline_state( player );
4607 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4610 if ( mainbin[MMPLAYER_M_SRC_FAKESINK].gst )
4611 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4613 /* free avsysaudiosink
4614 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4615 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4617 MMPLAYER_FREEIF( audiobin );
4618 MMPLAYER_FREEIF( videobin );
4619 MMPLAYER_FREEIF( textbin );
4620 MMPLAYER_FREEIF( subtitlebin);
4621 MMPLAYER_FREEIF( mainbin );
4625 gst_tag_list_free(tag_list);
4627 MMPLAYER_FREEIF( player->pipeline );
4630 player->pipeline_is_constructed = FALSE;
4637 static int __gst_realize(mm_player_t* player) // @
4640 int ret = MM_ERROR_NONE;
4644 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4646 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4648 __ta__("__mmplayer_gst_create_pipeline",
4649 ret = __mmplayer_gst_create_pipeline(player);
4652 debug_critical("failed to create pipeline\n");
4657 /* set pipeline state to READY */
4658 /* NOTE : state change to READY must be performed sync. */
4659 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4660 ret = __mmplayer_gst_set_state(player,
4661 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4663 if (MMPLAYER_PLAY_SUBTITLE(player))
4664 ret = __mmplayer_gst_set_state(player,
4665 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4667 if ( ret != MM_ERROR_NONE )
4669 /* return error if failed to set state */
4670 debug_error("failed to set state PAUSED (live : READY).\n");
4672 /* dump state of all element */
4673 __mmplayer_dump_pipeline_state( player );
4679 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
4682 /* create dot before error-return. for debugging */
4683 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-realize" );
4690 static int __gst_unrealize(mm_player_t* player) // @
4692 int ret = MM_ERROR_NONE;
4696 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4698 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4699 MMPLAYER_PRINT_STATE(player);
4701 player->use_video_stream = FALSE;
4702 player->video_stream_cb = NULL;
4703 player->video_stream_cb_user_param = NULL;
4705 player->audio_stream_cb = NULL;
4706 player->audio_stream_cb_user_param = NULL;
4708 player->audio_buffer_cb = NULL;
4709 player->audio_buffer_cb_user_param = NULL;
4711 player->sent_bos = FALSE;
4712 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4714 /* clean found parsers */
4715 if (player->parsers)
4717 g_list_free(player->parsers);
4718 player->parsers = NULL;
4721 MMPLAYER_FREEIF(player->album_art);
4723 /* destroy pipeline */
4724 ret = __mmplayer_gst_destroy_pipeline( player );
4725 if ( ret != MM_ERROR_NONE )
4727 debug_error("failed to destory pipeline\n");
4732 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
4740 static int __gst_pending_seek ( mm_player_t* player )
4742 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
4743 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
4744 int ret = MM_ERROR_NONE;
4748 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4750 if ( !player->pending_seek.is_pending )
4752 debug_log("pending seek is not reserved. nothing to do.\n" );
4756 /* check player state if player could pending seek or not. */
4757 current_state = MMPLAYER_CURRENT_STATE(player);
4758 pending_state = MMPLAYER_PENDING_STATE(player);
4760 if ( current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING )
4762 debug_warning("try to pending seek in %s state, try next time. \n",
4763 MMPLAYER_STATE_GET_NAME(current_state));
4767 debug_log("trying to play from (%lu) pending position\n", player->pending_seek.pos);
4769 ret = __gst_set_position ( player, player->pending_seek.format, player->pending_seek.pos );
4771 if ( MM_ERROR_NONE != ret )
4772 debug_error("failed to seek pending postion. just keep staying current position.\n");
4774 player->pending_seek.is_pending = FALSE;
4782 static int __gst_start(mm_player_t* player) // @
4784 gboolean sound_extraction = 0;
4785 gboolean async = FALSE;
4787 int ret = MM_ERROR_NONE;
4791 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
4793 /* get sound_extraction property */
4794 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
4795 /* NOTE : if SetPosition was called before Start. do it now */
4796 /* streaming doesn't support it. so it should be always sync */
4797 /* !! create one more api to check if there is pending seek rather than checking variables */
4799 if ( (player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player))
4801 ret = __gst_pause(player, FALSE);
4802 if ( ret != MM_ERROR_NONE )
4804 debug_error("failed to set state to PAUSED for pending seek\n");
4808 if ( sound_extraction )
4810 debug_log("setting pcm extraction\n");
4812 ret = __mmplayer_set_pcm_extraction(player);
4813 if ( MM_ERROR_NONE != ret )
4815 debug_warning("failed to set pcm extraction\n");
4821 if ( MM_ERROR_NONE != __gst_pending_seek(player) )
4823 debug_warning("failed to seek pending postion. starting from the begin of content.\n");
4828 debug_log("current state before doing transition");
4829 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
4830 MMPLAYER_PRINT_STATE(player);
4832 /* NOTE : note that current variant of rtspsrc has their own buffering mechanism.
4833 * their keeping rtp packets without gst timestamping. there's no easy way to export buffering mechanism to plugin-level. and
4834 * application also not ready. thus, just for now. state transition to PLAYING will done in asyn mode.
4835 * please do not confused with async property hack which done by __gst_set_async_state_change()
4837 /* NOTE : testing async start when local playback also */
4839 mm_attrs_get_int_by_name(player->attrs,"profile_async_start", &async);
4840 debug_log("start mode : %s", (async ? "async" : "sync"));
4842 /* set pipeline state to PLAYING */
4843 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4844 ret = __mmplayer_gst_set_state(player,
4845 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
4847 if (MMPLAYER_PLAY_SUBTITLE(player))
4848 ret = __mmplayer_gst_set_state(player,
4849 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, FALSE, timeout );
4851 if (ret == MM_ERROR_NONE)
4856 debug_log("sync state changing is completed");
4858 mm_attrs_get_int_by_name(player->attrs, "content_duration", &duration);
4861 debug_warning("try to update duration more");
4862 player->need_update_content_attrs = TRUE;
4863 player->need_update_content_dur = TRUE;
4864 _mmplayer_update_content_attrs(player);
4867 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
4872 debug_error("failed to set state to PLAYING");
4874 /* dump state of all element */
4875 __mmplayer_dump_pipeline_state( player );
4880 /* FIXIT : analyze so called "async problem" */
4882 __gst_set_async_state_change( player, FALSE );
4884 /* generating debug info before returning error */
4885 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-start" );
4892 static void __mmplayer_do_sound_fadedown(mm_player_t* player, unsigned int time)
4896 return_if_fail(player
4898 && player->pipeline->audiobin
4899 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4901 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 2, NULL);
4908 static void __mmplayer_undo_sound_fadedown(mm_player_t* player)
4912 return_if_fail(player
4914 && player->pipeline->audiobin
4915 && player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
4917 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
4922 static int __gst_stop(mm_player_t* player) // @
4924 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
4925 MMHandleType attrs = 0;
4926 gboolean fadewown = FALSE;
4927 gboolean rewind = FALSE;
4929 int ret = MM_ERROR_NONE;
4933 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4935 debug_log("current state before doing transition");
4936 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4937 MMPLAYER_PRINT_STATE(player);
4939 attrs = MMPLAYER_GET_ATTRS(player);
4942 debug_error("cannot get content attribute\n");
4943 return MM_ERROR_PLAYER_INTERNAL;
4946 mm_attrs_get_int_by_name(attrs,"sound_fadedown", &fadewown);
4948 /* enable fadedown */
4950 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
4952 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
4953 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT ( player );
4954 if ( player->profile.uri_type == MM_PLAYER_URI_TYPE_BUFF || player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
4956 ret = __mmplayer_gst_set_state(player,
4957 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout );
4961 ret = __mmplayer_gst_set_state( player,
4962 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
4964 if (MMPLAYER_PLAY_SUBTITLE(player))
4965 ret = __mmplayer_gst_set_state( player,
4966 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout );
4968 if ( !MMPLAYER_IS_STREAMING(player))
4972 /* disable fadeout */
4974 __mmplayer_undo_sound_fadedown(player);
4977 /* return if set_state has failed */
4978 if ( ret != MM_ERROR_NONE )
4980 debug_error("failed to set state.\n");
4982 /* dump state of all element. don't care it success or not */
4983 __mmplayer_dump_pipeline_state( player );
4991 if ( ! __gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
4992 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
4993 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE) )
4995 debug_warning("failed to rewind\n");
4996 ret = MM_ERROR_PLAYER_SEEK;
5001 player->sent_bos = FALSE;
5003 /* wait for seek to complete */
5004 change_ret = gst_element_get_state (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5005 if (MMPLAYER_PLAY_SUBTITLE(player))
5006 change_ret = gst_element_get_state (player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
5008 if ( change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL )
5010 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_READY );
5014 debug_error("fail to stop player.\n");
5015 ret = MM_ERROR_PLAYER_INTERNAL;
5018 /* generate dot file if enabled */
5019 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-stop" );
5027 int __gst_pause(mm_player_t* player, gboolean async) // @
5030 int ret = MM_ERROR_NONE;
5034 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5036 debug_log("current state before doing transition");
5037 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
5038 MMPLAYER_PRINT_STATE(player);
5041 debug_log("do async state transition to PAUSE.\n");
5043 /* set pipeline status to PAUSED */
5044 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5045 ret = __mmplayer_gst_set_state(player,
5046 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout );
5048 if (MMPLAYER_PLAY_SUBTITLE(player))
5049 ret = __mmplayer_gst_set_state(player,
5050 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PAUSED, async, timeout );
5052 if ( ret != MM_ERROR_NONE )
5054 debug_error("failed to set state to PAUSED\n");
5056 /* dump state of all element */
5057 __mmplayer_dump_pipeline_state( player );
5063 if ( async == FALSE )
5065 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PAUSED );
5069 /* FIXIT : analyze so called "async problem" */
5071 __gst_set_async_state_change( player, TRUE);
5074 /* generate dot file before returning error */
5075 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-pause" );
5082 int __gst_resume(mm_player_t* player, gboolean async) // @
5084 int ret = MM_ERROR_NONE;
5089 return_val_if_fail(player && player->pipeline,
5090 MM_ERROR_PLAYER_NOT_INITIALIZED);
5092 debug_log("current state before doing transition");
5093 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
5094 MMPLAYER_PRINT_STATE(player);
5096 /* generate dot file before returning error */
5097 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5099 __mmplayer_set_antishock( player , FALSE );
5102 debug_log("do async state transition to PLAYING.\n");
5104 /* set pipeline state to PLAYING */
5105 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5106 ret = __mmplayer_gst_set_state(player,
5107 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5109 if (MMPLAYER_PLAY_SUBTITLE(player))
5110 ret = __mmplayer_gst_set_state(player,
5111 player->pipeline->subtitlebin[MMPLAYER_SUB_PIPE].gst, GST_STATE_PLAYING, async, timeout );
5113 if (ret != MM_ERROR_NONE)
5115 debug_error("failed to set state to PLAYING\n");
5117 /* dump state of all element */
5118 __mmplayer_dump_pipeline_state( player );
5126 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_PLAYING );
5130 /* FIXIT : analyze so called "async problem" */
5132 __gst_set_async_state_change( player, FALSE );
5134 /* generate dot file before returning error */
5135 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-resume" );
5143 __gst_set_position(mm_player_t* player, int format, unsigned long position) // @
5145 GstFormat fmt = GST_FORMAT_TIME;
5146 unsigned long dur_msec = 0;
5147 gint64 dur_nsec = 0;
5148 gint64 pos_nsec = 0;
5149 gboolean ret = TRUE;
5152 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
5153 return_val_if_fail ( !MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP );
5155 if ( MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
5156 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED )
5159 /* check duration */
5160 /* NOTE : duration cannot be zero except live streaming.
5161 * Since some element could have some timing problemn with quering duration, try again.
5163 if ( !player->duration )
5165 if ( !gst_element_query_duration( player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec ))
5169 player->duration = dur_nsec;
5172 if ( player->duration )
5174 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
5178 debug_error("could not get the duration. fail to seek.\n");
5182 debug_log("playback rate: %f\n", player->playback_rate);
5187 case MM_PLAYER_POS_FORMAT_TIME:
5189 /* check position is valid or not */
5190 if ( position > dur_msec )
5193 debug_log("seeking to (%lu) msec, duration is %d msec\n", position, dur_msec);
5195 if (player->doing_seek)
5197 debug_log("not completed seek");
5198 return MM_ERROR_PLAYER_DOING_SEEK;
5200 player->doing_seek = TRUE;
5202 pos_nsec = position * G_GINT64_CONSTANT(1000000);
5203 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5204 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5205 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5208 debug_error("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
5214 case MM_PLAYER_POS_FORMAT_PERCENT:
5216 if ( position < 0 && position > 100 )
5219 debug_log("seeking to (%lu)%% \n", position);
5221 if (player->doing_seek)
5223 debug_log("not completed seek");
5224 return MM_ERROR_PLAYER_DOING_SEEK;
5226 player->doing_seek = TRUE;
5228 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
5229 pos_nsec = (gint64) ( ( position * player->duration ) / 100 );
5230 ret = __gst_seek ( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
5231 GST_FORMAT_TIME, ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
5232 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
5235 debug_error("failed to set position. dur[%lud] pos[%lud] pos_msec[%llud]\n", dur_msec, position, pos_nsec);
5246 /* NOTE : store last seeking point to overcome some bad operation
5247 * ( returning zero when getting current position ) of some elements
5249 player->last_position = pos_nsec;
5251 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
5252 if ( player->playback_rate > 1.0 )
5253 _mmplayer_set_playspeed ( (MMHandleType)player, player->playback_rate );
5256 return MM_ERROR_NONE;
5259 player->pending_seek.is_pending = TRUE;
5260 player->pending_seek.format = format;
5261 player->pending_seek.pos = position;
5263 debug_warning("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
5264 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
5266 return MM_ERROR_NONE;
5269 debug_error("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
5270 return MM_ERROR_INVALID_ARGUMENT;
5273 player->doing_seek = FALSE;
5274 return MM_ERROR_PLAYER_SEEK;
5277 #define TRICKPLAY_OFFSET GST_MSECOND
5280 __gst_get_position(mm_player_t* player, int format, unsigned long* position) // @
5282 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5283 GstFormat fmt = GST_FORMAT_TIME;
5284 signed long long pos_msec = 0;
5285 gboolean ret = TRUE;
5287 return_val_if_fail( player && position && player->pipeline && player->pipeline->mainbin,
5288 MM_ERROR_PLAYER_NOT_INITIALIZED );
5290 current_state = MMPLAYER_CURRENT_STATE(player);
5292 /* NOTE : query position except paused state to overcome some bad operation
5293 * please refer to below comments in details
5295 if ( current_state != MM_PLAYER_STATE_PAUSED )
5297 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
5300 /* NOTE : get last point to overcome some bad operation of some elements
5301 * ( returning zero when getting current position in paused state
5302 * and when failed to get postion during seeking
5304 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
5306 //|| ( player->last_position != 0 && pos_msec == 0 ) )
5308 debug_warning ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
5310 if(player->playback_rate < 0.0)
5311 pos_msec = player->last_position - TRICKPLAY_OFFSET;
5313 pos_msec = player->last_position;
5316 pos_msec = player->last_position;
5318 player->last_position = pos_msec;
5320 debug_warning("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
5325 player->last_position = pos_msec;
5329 case MM_PLAYER_POS_FORMAT_TIME:
5330 *position = GST_TIME_AS_MSECONDS(pos_msec);
5333 case MM_PLAYER_POS_FORMAT_PERCENT:
5338 dur = player->duration / GST_SECOND;
5341 debug_log ("duration is [%d], so returning position 0\n",dur);
5346 pos = pos_msec / GST_SECOND;
5347 *position = pos * 100 / dur;
5352 return MM_ERROR_PLAYER_INTERNAL;
5355 debug_log("current position : %lu\n", *position);
5358 return MM_ERROR_NONE;
5362 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
5364 GstElement *element = NULL;
5365 GstQuery *query = NULL;
5367 return_val_if_fail( player &&
5369 player->pipeline->mainbin,
5370 MM_ERROR_PLAYER_NOT_INITIALIZED );
5372 return_val_if_fail( start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT );
5374 if ( MMPLAYER_IS_HTTP_STREAMING ( player ) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
5376 /* Note : In case of http streaming or HLS, the buffering queue [ queue2 ] could handle buffering query. */
5377 element = GST_ELEMENT ( player->pipeline->mainbin[MMPLAYER_M_S_BUFFER].gst );
5379 else if ( MMPLAYER_IS_RTSP_STREAMING ( player ) )
5381 debug_warning ( "it's not supported yet.\n" );
5382 return MM_ERROR_NONE;
5386 debug_warning ( "it's only used for streaming case.\n" );
5387 return MM_ERROR_NONE;
5395 case MM_PLAYER_POS_FORMAT_PERCENT :
5397 query = gst_query_new_buffering ( GST_FORMAT_PERCENT );
5398 if ( gst_element_query ( element, query ) )
5405 gst_query_parse_buffering_percent ( query, &busy, &percent);
5406 gst_query_parse_buffering_range ( query, &format, &start, &stop, NULL );
5408 debug_log ( "buffering start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT "\n", start, stop);
5411 *start_pos = 100 * start / GST_FORMAT_PERCENT_MAX;
5416 *stop_pos = 100 * stop / GST_FORMAT_PERCENT_MAX;
5420 gst_query_unref (query);
5424 case MM_PLAYER_POS_FORMAT_TIME :
5425 debug_warning ( "Time format is not supported yet.\n" );
5432 debug_log("current buffer position : %lu~%lu \n", *start_pos, *stop_pos );
5434 return MM_ERROR_NONE;
5438 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param) // @
5444 debug_warning("set_message_callback is called with invalid player handle\n");
5445 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5448 player->msg_cb = callback;
5449 player->msg_cb_param = user_param;
5451 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
5455 return MM_ERROR_NONE;
5458 static gboolean __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data) // @
5460 gboolean ret = FALSE;
5465 return_val_if_fail ( uri , FALSE);
5466 return_val_if_fail ( data , FALSE);
5467 return_val_if_fail ( ( strlen(uri) <= MM_MAX_URL_LEN ), FALSE );
5469 memset(data, 0, sizeof(MMPlayerParseProfile));
5471 if ((path = strstr(uri, "file://")))
5473 if (util_exist_file_path(path + 7)) {
5474 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5476 if ( util_is_sdp_file ( path ) )
5478 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5479 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5483 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5489 debug_warning("could access %s.\n", path);
5492 else if ((path = strstr(uri, "buff://")))
5494 data->uri_type = MM_PLAYER_URI_TYPE_BUFF;
5497 else if ((path = strstr(uri, "rtsp://")))
5500 strcpy(data->uri, uri);
5501 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5505 else if ((path = strstr(uri, "http://")))
5508 strcpy(data->uri, uri);
5510 #ifdef NO_USE_GST_HLSDEMUX
5511 if ((path = strstr(uri, "m3u")))
5513 data->uri_type = MM_PLAYER_URI_TYPE_HLS;
5517 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5522 else if ((path = strstr(uri, "https://")))
5525 strcpy(data->uri, uri);
5527 #ifdef NO_USE_GST_HLSDEMUX
5528 if ((path = strstr(uri, "m3u")))
5530 data->uri_type = MM_PLAYER_URI_TYPE_HLS;
5534 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5539 else if ((path = strstr(uri, "rtspu://")))
5542 strcpy(data->uri, uri);
5543 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5547 else if ((path = strstr(uri, "rtspr://")))
5549 strcpy(data->uri, path);
5550 char *separater =strstr(path, "*");
5554 char *urgent = separater + strlen("*");
5556 if ((urgent_len = strlen(urgent))) {
5557 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5558 strcpy(data->urgent, urgent);
5559 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5564 else if ((path = strstr(uri, "mms://")))
5567 strcpy(data->uri, uri);
5568 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5572 else if ((path = strstr(uri, "mem://")))
5576 char *buffer = NULL;
5577 char *seperator = strchr(path, ',');
5578 char ext[100] = {0,}, size[100] = {0,};
5581 if ((buffer = strstr(path, "ext="))) {
5582 buffer += strlen("ext=");
5584 if (strlen(buffer)) {
5585 strcpy(ext, buffer);
5587 if ((seperator = strchr(ext, ','))
5588 || (seperator = strchr(ext, ' '))
5589 || (seperator = strchr(ext, '\0'))) {
5590 seperator[0] = '\0';
5595 if ((buffer = strstr(path, "size="))) {
5596 buffer += strlen("size=");
5598 if (strlen(buffer) > 0) {
5599 strcpy(size, buffer);
5601 if ((seperator = strchr(size, ','))
5602 || (seperator = strchr(size, ' '))
5603 || (seperator = strchr(size, '\0'))) {
5604 seperator[0] = '\0';
5607 mem_size = atoi(size);
5612 debug_log("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
5613 if ( mem_size && param) {
5615 data->mem_size = mem_size;
5616 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
5623 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
5624 if (util_exist_file_path(uri))
5626 debug_warning("uri has no protocol-prefix. giving 'file://' by default.\n");
5628 sprintf( data->uri, "file://%s", uri );
5630 if ( util_is_sdp_file( (char*)uri ) )
5632 debug_log("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5633 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5637 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5643 debug_error ("invalid uri, could not play..\n");
5644 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5648 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE) {
5653 /* dump parse result */
5654 debug_log("profile parsing result ---\n");
5655 debug_log("incomming uri : %s\n", uri);
5656 debug_log("uri : %s\n", data->uri);
5657 debug_log("uri_type : %d\n", data->uri_type);
5658 debug_log("play_mode : %d\n", data->play_mode);
5659 debug_log("mem : 0x%x\n", (guint)data->mem);
5660 debug_log("mem_size : %d\n", data->mem_size);
5661 debug_log("urgent : %s\n", data->urgent);
5662 debug_log("--------------------------\n");
5669 gboolean _asm_postmsg(gpointer *data)
5671 mm_player_t* player = (mm_player_t*)data;
5672 MMMessageParamType msg = {0, };
5676 return_val_if_fail ( player, FALSE );
5678 msg.union_type = MM_MSG_UNION_CODE;
5679 msg.code = player->sm.event_src;
5681 MMPLAYER_POST_MSG( player, MM_MESSAGE_READY_TO_RESUME, &msg);
5685 gboolean _asm_lazy_pause(gpointer *data)
5687 mm_player_t* player = (mm_player_t*)data;
5688 int ret = MM_ERROR_NONE;
5692 return_val_if_fail ( player, FALSE );
5694 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING)
5696 debug_log ("Ready to proceed lazy pause\n");
5697 ret = _mmplayer_pause((MMHandleType)player);
5698 if(MM_ERROR_NONE != ret)
5700 debug_error("MMPlayer pause failed in ASM callback lazy pause\n");
5705 debug_log ("Invalid state to proceed lazy pause\n");
5709 if (player->pipeline && player->pipeline->audiobin)
5710 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "mute", 0, NULL);
5712 player->sm.by_asm_cb = 0; //should be reset here
5719 __mmplayer_asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
5721 mm_player_t* player = (mm_player_t*) cb_data;
5722 ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
5723 int result = MM_ERROR_NONE;
5724 gboolean lazy_pause = FALSE;
5728 return_val_if_fail ( player && player->pipeline, ASM_CB_RES_IGNORE );
5729 return_val_if_fail ( player->attrs, MM_ERROR_PLAYER_INTERNAL );
5731 if (player->is_sound_extraction)
5733 debug_log("sound extraction is working...so, asm command is ignored.\n");
5737 player->sm.by_asm_cb = 1; // it should be enabled for player state transition with called application command
5738 player->sm.event_src = event_src;
5740 if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
5742 player->sm.event_src = ASM_EVENT_SOURCE_OTHER_APP;
5744 else if(event_src == ASM_EVENT_SOURCE_EARJACK_UNPLUG )
5746 int stop_by_asm = 0;
5748 mm_attrs_get_int_by_name(player->attrs, "sound_stop_when_unplugged", &stop_by_asm);
5752 else if (event_src == ASM_EVENT_SOURCE_RESOURCE_CONFLICT)
5754 /* can use video overlay simultaneously */
5755 /* video resource conflict */
5756 if(player->pipeline->videobin)
5758 if (PLAYER_INI()->multiple_codec_supported)
5760 debug_log("video conflict but, can support to use video overlay simultaneously");
5761 result = _mmplayer_pause((MMHandleType)player);
5762 cb_res = ASM_CB_RES_PAUSE;
5766 debug_log("video conflict, can't support for multiple codec instance");
5767 result = _mmplayer_unrealize((MMHandleType)player);
5768 cb_res = ASM_CB_RES_STOP;
5776 case ASM_COMMAND_PLAY:
5777 case ASM_COMMAND_STOP:
5778 debug_warning ("Got unexpected asm command (%d)", command);
5781 case ASM_COMMAND_PAUSE:
5783 debug_log("Got msg from asm to Pause");
5785 if(event_src == ASM_EVENT_SOURCE_CALL_START
5786 || event_src == ASM_EVENT_SOURCE_ALARM_START
5787 || event_src == ASM_EVENT_SOURCE_OTHER_APP)
5789 //hold 0.7 second to excute "fadedown mute" effect
5790 debug_log ("do fade down->pause->undo fade down");
5792 __mmplayer_do_sound_fadedown(player, MM_PLAYER_FADEOUT_TIME_DEFAULT);
5794 result = _mmplayer_pause((MMHandleType)player);
5795 if (result != MM_ERROR_NONE)
5797 debug_warning("fail to set Pause state by asm");
5798 cb_res = ASM_CB_RES_IGNORE;
5801 __mmplayer_undo_sound_fadedown(player);
5803 else if(event_src == ASM_EVENT_SOURCE_OTHER_PLAYER_APP)
5805 lazy_pause = TRUE; // return as soon as possible, for fast start of other app
5807 if ( player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_SINK].gst )
5808 g_object_set( player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "mute", 2, NULL);
5810 player->lazy_pause_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc)_asm_lazy_pause, (gpointer)player);
5811 debug_log ("set lazy pause timer (id=[%d], timeout=[%d ms])", player->lazy_pause_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
5816 debug_log ("immediate pause");
5817 result = _mmplayer_pause((MMHandleType)player);
5819 cb_res = ASM_CB_RES_PAUSE;
5823 case ASM_COMMAND_RESUME:
5825 debug_log("Got msg from asm to Resume. So, application can resume. code (%d) \n", event_src);
5826 player->sm.by_asm_cb = 0;
5827 //ASM server is single thread daemon. So use g_idle_add() to post resume msg
5828 g_idle_add((GSourceFunc)_asm_postmsg, (gpointer)player);
5829 cb_res = ASM_CB_RES_IGNORE;
5838 player->sm.by_asm_cb = 0;
5846 _mmplayer_create_player(MMHandleType handle) // @
5848 mm_player_t* player = MM_PLAYER_CAST(handle);
5853 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
5855 MMTA_ACUM_ITEM_BEGIN("[KPI] media player service create->playing", FALSE);
5857 /* initialize player state */
5858 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
5859 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
5860 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
5861 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
5863 /* check current state */
5864 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_CREATE );
5866 /* construct attributes */
5867 player->attrs = _mmplayer_construct_attribute(handle);
5869 if ( !player->attrs )
5871 debug_critical("Failed to construct attributes\n");
5875 /* initialize gstreamer with configured parameter */
5876 if ( ! __mmplayer_gstreamer_init() )
5878 debug_critical("Initializing gstreamer failed\n");
5882 /* initialize factories if not using decodebin */
5883 if ( FALSE == PLAYER_INI()->use_decodebin )
5885 if( player->factories == NULL )
5886 __mmplayer_init_factories(player);
5889 /* create lock. note that g_tread_init() has already called in gst_init() */
5890 player->fsink_lock = g_mutex_new();
5891 if ( ! player->fsink_lock )
5893 debug_critical("Cannot create mutex for command lock\n");
5897 /* create repeat mutex */
5898 player->repeat_thread_mutex = g_mutex_new();
5899 if ( ! player->repeat_thread_mutex )
5901 debug_critical("Cannot create repeat mutex\n");
5905 /* create repeat cond */
5906 player->repeat_thread_cond = g_cond_new();
5907 if ( ! player->repeat_thread_cond )
5909 debug_critical("Cannot create repeat cond\n");
5913 /* create repeat thread */
5914 player->repeat_thread =
5915 g_thread_create (__mmplayer_repeat_thread, (gpointer)player, TRUE, NULL);
5916 if ( ! player->repeat_thread )
5921 if ( MM_ERROR_NONE != _mmplayer_initialize_video_capture(player))
5923 debug_error("failed to initialize video capture\n");
5927 /* register to asm */
5928 if ( MM_ERROR_NONE != _mmplayer_asm_register(&player->sm, (ASM_sound_cb_t)__mmplayer_asm_callback, (void*)player) )
5930 /* NOTE : we are dealing it as an error since we cannot expect it's behavior */
5931 debug_error("failed to register asm server\n");
5932 return MM_ERROR_POLICY_INTERNAL;
5935 if (MMPLAYER_IS_HTTP_PD(player))
5937 player->pd_downloader = NULL;
5938 player->pd_file_location = NULL;
5941 /* give default value of sound effect setting */
5942 player->bypass_sound_effect = TRUE;
5943 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
5944 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5945 player->no_more_pad = TRUE;
5947 /* set player state to null */
5948 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
5949 MMPLAYER_SET_STATE ( player, MM_PLAYER_STATE_NULL );
5952 return MM_ERROR_NONE;
5956 if ( player->fsink_lock )
5957 g_mutex_free( player->fsink_lock );
5958 player->fsink_lock = NULL;
5961 if ( player->repeat_thread_cond &&
5962 player->repeat_thread_mutex &&
5963 player->repeat_thread )
5965 player->repeat_thread_exit = TRUE;
5966 g_cond_signal( player->repeat_thread_cond );
5968 g_thread_join( player->repeat_thread );
5969 player->repeat_thread = NULL;
5971 g_mutex_free ( player->repeat_thread_mutex );
5972 player->repeat_thread_mutex = NULL;
5974 g_cond_free ( player->repeat_thread_cond );
5975 player->repeat_thread_cond = NULL;
5977 /* clear repeat thread mutex/cond if still alive
5978 * this can happen if only thread creating has failed
5980 if ( player->repeat_thread_mutex )
5981 g_mutex_free ( player->repeat_thread_mutex );
5983 if ( player->repeat_thread_cond )
5984 g_cond_free ( player->repeat_thread_cond );
5986 /* release attributes */
5987 _mmplayer_deconstruct_attribute(handle);
5989 return MM_ERROR_PLAYER_INTERNAL;
5993 __mmplayer_gstreamer_init(void) // @
5995 static gboolean initialized = FALSE;
5996 static const int max_argc = 50;
5998 gchar** argv = NULL;
6006 debug_log("gstreamer already initialized.\n");
6011 argc = malloc( sizeof(int) );
6012 argv = malloc( sizeof(gchar*) * max_argc );
6014 if ( !argc || !argv )
6017 memset( argv, 0, sizeof(gchar*) * max_argc );
6021 argv[0] = g_strdup( "mmplayer" );
6024 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
6026 if ( strlen( PLAYER_INI()->gst_param[i] ) > 0 )
6028 argv[*argc] = g_strdup( PLAYER_INI()->gst_param[i] );
6033 /* we would not do fork for scanning plugins */
6034 argv[*argc] = g_strdup("--gst-disable-registry-fork");
6037 /* check disable registry scan */
6038 if ( PLAYER_INI()->skip_rescan )
6040 argv[*argc] = g_strdup("--gst-disable-registry-update");
6044 /* check disable segtrap */
6045 if ( PLAYER_INI()->disable_segtrap )
6047 argv[*argc] = g_strdup("--gst-disable-segtrap");
6051 debug_log("initializing gstreamer with following parameter\n");
6052 debug_log("argc : %d\n", *argc);
6054 for ( i = 0; i < *argc; i++ )
6056 debug_log("argv[%d] : %s\n", i, argv[i]);
6060 /* initializing gstreamer */
6061 __ta__("gst_init time",
6063 if ( ! gst_init_check (argc, &argv, &err))
6065 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6076 for ( i = 0; i < *argc; i++ )
6078 MMPLAYER_FREEIF( argv[i] );
6081 MMPLAYER_FREEIF( argv );
6082 MMPLAYER_FREEIF( argc );
6093 MMPLAYER_FREEIF( argv );
6094 MMPLAYER_FREEIF( argc );
6100 __mmplayer_release_extended_streaming(mm_player_t* player)
6102 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6104 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6106 _mmplayer_pd_stop ((MMHandleType)player);
6107 _mmplayer_pd_deinitialize ((MMHandleType)player);
6108 _mmplayer_pd_destroy((MMHandleType)player);
6111 #ifdef NO_USE_GST_HLSDEMUX
6112 /* destroy can called at anytime */
6113 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6115 if (player->ahs_player)
6117 __mm_player_ahs_stop (player->ahs_player);
6118 __mm_player_ahs_deinitialize (player->ahs_player);
6119 __mm_player_ahs_destroy(player->ahs_player);
6120 player->ahs_player = NULL;
6125 if (MMPLAYER_IS_STREAMING(player))
6127 if (player->streamer)
6129 __mm_player_streaming_deinitialize (player->streamer);
6130 __mm_player_streaming_destroy(player->streamer);
6131 player->streamer = NULL;
6137 _mmplayer_destroy(MMHandleType handle) // @
6139 mm_player_t* player = MM_PLAYER_CAST(handle);
6143 /* check player handle */
6144 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6146 /* destroy can called at anytime */
6147 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL ( player, MMPLAYER_COMMAND_DESTROY );
6149 __mmplayer_release_extended_streaming(player);
6151 /* release repeat thread */
6152 if ( player->repeat_thread_cond &&
6153 player->repeat_thread_mutex &&
6154 player->repeat_thread )
6156 player->repeat_thread_exit = TRUE;
6157 g_cond_signal( player->repeat_thread_cond );
6159 debug_log("waitting for repeat thread exit\n");
6160 g_thread_join ( player->repeat_thread );
6161 g_mutex_free ( player->repeat_thread_mutex );
6162 g_cond_free ( player->repeat_thread_cond );
6163 debug_log("repeat thread released\n");
6166 if (MM_ERROR_NONE != _mmplayer_release_video_capture(player))
6168 debug_error("failed to release video capture\n");
6169 return MM_ERROR_PLAYER_INTERNAL;
6173 if ( MM_ERROR_NONE != _mmplayer_asm_deregister(&player->sm) )
6175 debug_error("failed to deregister asm server\n");
6176 return MM_ERROR_PLAYER_INTERNAL;
6179 /* release pipeline */
6180 if ( MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline( player ) )
6182 debug_error("failed to destory pipeline\n");
6183 return MM_ERROR_PLAYER_INTERNAL;
6186 /* release attributes */
6187 _mmplayer_deconstruct_attribute( handle );
6189 /* release factories */
6190 __mmplayer_release_factories( player );
6192 /* release miscellaneous information */
6193 __mmplayer_release_misc( player );
6196 if ( player->fsink_lock )
6197 g_mutex_free( player->fsink_lock );
6199 if ( player->msg_cb_lock )
6200 g_mutex_free( player->msg_cb_lock );
6202 if (player->lazy_pause_event_id)
6204 g_source_remove (player->lazy_pause_event_id);
6205 player->lazy_pause_event_id = 0;
6210 return MM_ERROR_NONE;
6215 __mmplayer_init_extended_streaming(mm_player_t* player)
6217 int ret = MM_ERROR_NONE;
6219 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6221 #ifdef NO_USE_GST_HLSDEMUX
6222 /* prepare adaptive http streaming */
6223 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS)
6225 player->ahs_player = __mm_player_ahs_create ();
6227 if (NULL == player->ahs_player)
6229 debug_error ("Unable to create AHS player\n");
6230 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6234 if ( !__mm_player_ahs_initialize (player->ahs_player, player->profile.uri_type,
6235 player->profile.uri, player->pipeline->mainbin[MMPLAYER_M_SRC].gst) )
6237 debug_error ("failed to initialize ahs player\n");
6238 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6244 if (MMPLAYER_IS_HTTP_PD(player))
6246 gboolean bret = FALSE;
6247 gchar *src_uri = NULL;
6249 player->pd_downloader = _mmplayer_pd_create ();
6251 if ( !player->pd_downloader )
6253 debug_error ("Unable to create PD Downloader...");
6254 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6257 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6258 src_uri = player->profile.uri;
6260 bret = _mmplayer_pd_initialize ((MMHandleType)player, src_uri, player->pd_file_location, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6264 debug_error ("Unable to create PD Downloader...");
6265 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6273 _mmplayer_realize(MMHandleType hplayer) // @
6275 mm_player_t* player = (mm_player_t*)hplayer;
6278 int application_pid = -1;
6279 gboolean update_registry = FALSE;
6280 MMHandleType attrs = 0;
6281 int ret = MM_ERROR_NONE;
6285 /* check player handle */
6286 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6288 /* check current state */
6289 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_REALIZE );
6291 attrs = MMPLAYER_GET_ATTRS(player);
6294 debug_error("fail to get attributes.\n");
6295 return MM_ERROR_PLAYER_INTERNAL;
6298 mm_attrs_get_int_by_name(attrs, "sound_application_pid", &application_pid );
6299 player->sm.pid = application_pid;
6301 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6302 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6304 if (! __mmfplayer_parse_profile((const char*)uri, param, &player->profile) )
6306 debug_error("failed to parse profile\n");
6307 return MM_ERROR_PLAYER_INVALID_URI;
6310 /* FIXIT : we can use thouse in player->profile directly */
6311 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM)
6313 player->mem_buf.buf = (char *)player->profile.mem;
6314 player->mem_buf.len = player->profile.mem_size;
6315 player->mem_buf.offset = 0;
6318 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS)
6320 debug_warning("mms protocol is not supported format.\n");
6321 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6324 if (MMPLAYER_IS_STREAMING(player))
6325 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->live_state_change_timeout;
6327 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_INI()->localplayback_state_change_timeout;
6329 player->videodec_linked = 0;
6330 player->videosink_linked = 0;
6331 player->audiodec_linked = 0;
6332 player->audiosink_linked = 0;
6333 player->textsink_linked = 0;
6335 /* set the subtitle ON default */
6336 player->is_subtitle_off = FALSE;
6338 /* we need to update content attrs only the content has changed */
6339 player->need_update_content_attrs = TRUE;
6340 player->need_update_content_dur = FALSE;
6342 /* registry should be updated for downloadable codec */
6343 mm_attrs_get_int_by_name(attrs, "profile_update_registry", &update_registry);
6345 if ( update_registry )
6347 debug_log("updating registry...\n");
6348 gst_update_registry();
6350 /* then we have to rebuild factories */
6351 __mmplayer_release_factories( player );
6352 __mmplayer_init_factories(player);
6355 /* realize pipeline */
6356 ret = __gst_realize( player );
6357 if ( ret != MM_ERROR_NONE )
6359 debug_error("fail to realize the player.\n");
6363 __mmplayer_init_extended_streaming(player);
6372 __mmplayer_deinit_extended_streaming(mm_player_t *player)
6374 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6376 /* destroy can called at anytime */
6377 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6379 //__mmplayer_pd_deinitalize (player->ahs_player);
6380 _mmplayer_pd_stop ((MMHandleType)player);
6383 #ifdef NO_USE_GST_HLSDEMUX
6384 /* destroy can called at anytime */
6385 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6387 __mm_player_ahs_stop (player->ahs_player);
6388 //__mm_player_ahs_deinitalize (player->ahs_player);
6391 return MM_ERROR_NONE;
6396 _mmplayer_unrealize(MMHandleType hplayer) // @
6398 mm_player_t* player = (mm_player_t*)hplayer;
6399 int ret = MM_ERROR_NONE;
6403 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED )
6405 /* check current state */
6406 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_UNREALIZE );
6408 __mmplayer_deinit_extended_streaming(player);
6410 /* unrealize pipeline */
6411 ret = __gst_unrealize( player );
6413 /* set player state if success */
6414 if ( MM_ERROR_NONE == ret )
6416 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_STOP);
6419 debug_error("failed to set asm state to STOP\n");
6430 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param) // @
6432 mm_player_t* player = (mm_player_t*)hplayer;
6434 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6436 return __gst_set_message_callback(player, callback, user_param);
6440 _mmplayer_get_state(MMHandleType hplayer, int* state) // @
6442 mm_player_t *player = (mm_player_t*)hplayer;
6444 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
6446 *state = MMPLAYER_CURRENT_STATE(player);
6448 return MM_ERROR_NONE;
6453 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume) // @
6455 mm_player_t* player = (mm_player_t*) hplayer;
6456 GstElement* vol_element = NULL;
6461 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6463 debug_log("volume [L]=%f:[R]=%f\n",
6464 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
6466 /* invalid factor range or not */
6467 for ( i = 0; i < MM_VOLUME_CHANNEL_NUM; i++ )
6469 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
6470 debug_error("Invalid factor! (valid factor:0~1.0)\n");
6471 return MM_ERROR_INVALID_ARGUMENT;
6475 /* Save volume to handle. Currently the first array element will be saved. */
6476 player->sound.volume = volume.level[0];
6478 /* check pipeline handle */
6479 if ( ! player->pipeline || ! player->pipeline->audiobin )
6481 debug_log("audiobin is not created yet\n");
6482 debug_log("but, current stored volume will be set when it's created.\n");
6484 /* NOTE : stored volume will be used in create_audiobin
6485 * returning MM_ERROR_NONE here makes application to able to
6486 * set volume at anytime.
6488 return MM_ERROR_NONE;
6491 /* setting volume to volume element */
6492 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6496 debug_log("volume is set [%f]\n", player->sound.volume);
6497 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6502 return MM_ERROR_NONE;
6507 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6509 mm_player_t* player = (mm_player_t*) hplayer;
6514 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6515 return_val_if_fail( volume, MM_ERROR_INVALID_ARGUMENT );
6517 /* returning stored volume */
6518 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
6519 volume->level[i] = player->sound.volume;
6523 return MM_ERROR_NONE;
6529 _mmplayer_set_mute(MMHandleType hplayer, int mute) // @
6531 mm_player_t* player = (mm_player_t*) hplayer;
6532 GstElement* vol_element = NULL;
6536 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6538 debug_log("mute : %d\n", mute);
6540 /* mute value shoud 0 or 1 */
6541 if ( mute != 0 && mute != 1 )
6543 debug_error("bad mute value\n");
6545 /* FIXIT : definitly, we need _BAD_PARAM error code */
6546 return MM_ERROR_INVALID_ARGUMENT;
6550 /* just hold mute value if pipeline is not ready */
6551 if ( !player->pipeline || !player->pipeline->audiobin )
6553 debug_log("pipeline is not ready. holding mute value\n");
6554 player->sound.mute = mute;
6555 return MM_ERROR_NONE;
6559 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6561 /* NOTE : volume will only created when the bt is enabled */
6564 g_object_set(vol_element, "mute", mute, NULL);
6568 debug_log("volume elemnet is not created. using volume in audiosink\n");
6571 player->sound.mute = mute;
6575 return MM_ERROR_NONE;
6579 _mmplayer_get_mute(MMHandleType hplayer, int* pmute) // @
6581 mm_player_t* player = (mm_player_t*) hplayer;
6582 GstElement* vol_element = NULL;
6586 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6587 return_val_if_fail ( pmute, MM_ERROR_INVALID_ARGUMENT );
6589 /* just hold mute value if pipeline is not ready */
6590 if ( !player->pipeline || !player->pipeline->audiobin )
6592 debug_log("pipeline is not ready. returning stored value\n");
6593 *pmute = player->sound.mute;
6594 return MM_ERROR_NONE;
6598 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6602 g_object_get(vol_element, "mute", pmute, NULL);
6603 debug_log("mute=%d\n\n", *pmute);
6607 *pmute = player->sound.mute;
6612 return MM_ERROR_NONE;
6616 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param) // @
6618 mm_player_t* player = (mm_player_t*) hplayer;
6622 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6623 return_val_if_fail ( callback, MM_ERROR_INVALID_ARGUMENT );
6625 player->video_stream_cb = callback;
6626 player->video_stream_cb_user_param = user_param;
6627 player->use_video_stream = TRUE;
6628 debug_log("Stream cb Handle value is %p : %p\n", player, player->video_stream_cb);
6632 return MM_ERROR_NONE;
6636 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6638 mm_player_t* player = (mm_player_t*) hplayer;
6642 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6643 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6645 player->audio_stream_cb = callback;
6646 player->audio_stream_cb_user_param = user_param;
6647 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
6651 return MM_ERROR_NONE;
6655 _mmplayer_set_audiobuffer_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param) // @
6657 mm_player_t* player = (mm_player_t*) hplayer;
6661 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6662 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6664 player->audio_buffer_cb = callback;
6665 player->audio_buffer_cb_user_param = user_param;
6666 debug_log("Audio Stream cb Handle value is %p : %p\n", player, player->audio_buffer_cb);
6670 return MM_ERROR_NONE;
6674 _mmplayer_set_buffer_need_data_cb(MMHandleType hplayer, mm_player_buffer_need_data_callback callback, void *user_param) // @
6676 mm_player_t* player = (mm_player_t*) hplayer;
6680 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6681 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6683 player->need_data_cb = callback;
6684 player->buffer_cb_user_param = user_param;
6686 debug_log("buffer need dataHandle value is %p : %p\n", player, player->need_data_cb);
6690 return MM_ERROR_NONE;
6694 _mmplayer_set_buffer_enough_data_cb(MMHandleType hplayer, mm_player_buffer_enough_data_callback callback, void *user_param) // @
6696 mm_player_t* player = (mm_player_t*) hplayer;
6700 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6701 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6703 player->enough_data_cb = callback;
6704 player->buffer_cb_user_param = user_param;
6706 debug_log("buffer enough data cb Handle value is %p : %p\n", player, player->enough_data_cb);
6710 return MM_ERROR_NONE;
6714 _mmplayer_set_buffer_seek_data_cb(MMHandleType hplayer, mm_player_buffer_seek_data_callback callback, void *user_param) // @
6716 mm_player_t* player = (mm_player_t*) hplayer;
6720 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
6721 return_val_if_fail(callback, MM_ERROR_INVALID_ARGUMENT);
6723 player->seek_data_cb = callback;
6724 player->buffer_cb_user_param = user_param;
6726 debug_log("buffer seek data cb Handle value is %p : %p\n", player, player->seek_data_cb);
6730 return MM_ERROR_NONE;
6733 int __mmplayer_start_extended_streaming(mm_player_t *player)
6735 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6737 if (MMPLAYER_IS_HTTP_PD(player) && player->pd_downloader)
6739 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6741 gboolean bret = FALSE;
6743 bret = _mmplayer_pd_start ((MMHandleType)player);
6746 debug_error ("ERROR while starting PD...\n");
6747 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6752 #ifdef NO_USE_GST_HLSDEMUX
6753 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6755 if ( !__mm_player_ahs_start (player->ahs_player))
6757 debug_error("failed to start ahs\n");
6758 return MM_ERROR_PLAYER_INTERNAL;
6762 return MM_ERROR_NONE;
6766 _mmplayer_start(MMHandleType hplayer) // @
6768 mm_player_t* player = (mm_player_t*) hplayer;
6769 gint ret = MM_ERROR_NONE;
6773 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6775 /* check current state */
6776 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_START );
6778 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
6779 if ( ret != MM_ERROR_NONE )
6781 debug_error("failed to set asm state to PLAYING\n");
6785 /* NOTE : we should check and create pipeline again if not created as we destroy
6786 * whole pipeline when stopping in streamming playback
6788 if ( ! player->pipeline )
6790 ret = __gst_realize( player );
6791 if ( MM_ERROR_NONE != ret )
6793 debug_error("failed to realize before starting. only in streamming\n");
6798 if (__mmplayer_start_extended_streaming(player) != MM_ERROR_NONE)
6799 return MM_ERROR_PLAYER_INTERNAL;
6801 /* start pipeline */
6802 ret = __gst_start( player );
6803 if ( ret != MM_ERROR_NONE )
6805 debug_error("failed to start player.\n");
6815 /* NOTE: post "not supported codec message" to application
6816 * when one codec is not found during AUTOPLUGGING in MSL.
6817 * So, it's separated with error of __mmplayer_gst_callback().
6818 * And, if any codec is not found, don't send message here.
6819 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
6822 __mmplayer_post_missed_plugin(mm_player_t* player)
6824 MMMessageParamType msg_param;
6825 memset (&msg_param, 0, sizeof(MMMessageParamType));
6826 gboolean post_msg_direct = FALSE;
6830 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6832 debug_log("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
6833 player->not_supported_codec, player->can_support_codec);
6835 if( player->not_found_demuxer )
6837 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6838 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
6840 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6841 MMPLAYER_FREEIF(msg_param.data);
6843 return MM_ERROR_NONE;
6846 if (player->not_supported_codec)
6848 if ( player->can_support_codec ) // There is one codec to play
6850 post_msg_direct = TRUE;
6854 if ( player->pipeline->audiobin ) // Some content has only PCM data in container.
6855 post_msg_direct = TRUE;
6858 if ( post_msg_direct )
6860 MMMessageParamType msg_param;
6861 memset (&msg_param, 0, sizeof(MMMessageParamType));
6863 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6865 debug_warning("not found AUDIO codec, posting error code to application.\n");
6867 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6868 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6870 else if ( player->not_supported_codec == MISSING_PLUGIN_VIDEO )
6872 debug_warning("not found VIDEO codec, posting error code to application.\n");
6874 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
6875 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
6878 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6880 MMPLAYER_FREEIF(msg_param.data);
6882 return MM_ERROR_NONE;
6884 else // no any supported codec case
6886 debug_warning("not found any codec, posting error code to application.\n");
6888 if ( player->not_supported_codec == MISSING_PLUGIN_AUDIO )
6890 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6891 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6895 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6896 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
6899 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
6901 MMPLAYER_FREEIF(msg_param.data);
6907 return MM_ERROR_NONE;
6910 /* NOTE : it should be able to call 'stop' anytime*/
6912 _mmplayer_stop(MMHandleType hplayer) // @
6914 mm_player_t* player = (mm_player_t*)hplayer;
6915 int ret = MM_ERROR_NONE;
6919 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6921 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
6923 __mm_player_ahs_stop (player->ahs_player);
6926 /* check current state */
6927 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_STOP );
6929 /* NOTE : application should not wait for EOS after calling STOP */
6930 __mmplayer_cancel_delayed_eos( player );
6933 ret = __gst_stop( player );
6935 if ( ret != MM_ERROR_NONE )
6937 debug_error("failed to stop player.\n");
6947 _mmplayer_pause(MMHandleType hplayer) // @
6949 mm_player_t* player = (mm_player_t*)hplayer;
6950 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6951 GstFormat fmt = GST_FORMAT_TIME;
6952 signed long long pos_msec = 0;
6953 int ret = MM_ERROR_NONE;
6957 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
6959 /* check current state */
6960 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_PAUSE );
6962 /* NOTE : store current point to overcome some bad operation
6963 * ( returning zero when getting current position in paused state) of some
6966 current_state = MMPLAYER_CURRENT_STATE(player);
6967 if ( current_state == MM_PLAYER_STATE_PLAYING )
6969 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &pos_msec);
6971 debug_warning("getting current position failed in paused\n");
6973 player->last_position = pos_msec;
6976 /* pause pipeline */
6977 ret = __gst_pause( player, FALSE );
6979 if ( MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
6981 //__mm_player_ahs_pause (player->ahs_player); // Not yet implemented
6984 if ( ret != MM_ERROR_NONE )
6986 debug_error("failed to pause player.\n");
6995 _mmplayer_resume(MMHandleType hplayer)
6997 mm_player_t* player = (mm_player_t*)hplayer;
6998 int ret = MM_ERROR_NONE;
7002 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7004 ret = _mmplayer_asm_set_state(hplayer, ASM_STATE_PLAYING);
7007 debug_error("failed to set asm state to PLAYING\n");
7011 /* check current state */
7012 MMPLAYER_CHECK_STATE_RETURN_IF_FAIL( player, MMPLAYER_COMMAND_RESUME );
7014 /* resume pipeline */
7015 ret = __gst_resume( player, FALSE );
7017 if ( ret != MM_ERROR_NONE )
7019 debug_error("failed to resume player.\n");
7029 __mmplayer_set_play_count(mm_player_t* player, gint count)
7031 MMHandleType attrs = 0;
7035 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7037 attrs = MMPLAYER_GET_ATTRS(player);
7040 debug_error("fail to get attributes.\n");
7041 return MM_ERROR_PLAYER_INTERNAL;
7044 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7045 if ( mmf_attrs_commit ( attrs ) ) /* return -1 if error */
7046 debug_error("failed to commit\n");
7050 return MM_ERROR_NONE;
7054 _mmplayer_activate_section_repeat(MMHandleType hplayer, unsigned long start, unsigned long end)
7056 mm_player_t* player = (mm_player_t*)hplayer;
7057 gint64 start_pos = 0;
7063 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7064 return_val_if_fail ( end <= GST_TIME_AS_MSECONDS(player->duration), MM_ERROR_INVALID_ARGUMENT );
7066 player->section_repeat = TRUE;
7067 player->section_repeat_start = start;
7068 player->section_repeat_end = end;
7070 start_pos = player->section_repeat_start * G_GINT64_CONSTANT(1000000);
7071 end_pos = player->section_repeat_end * G_GINT64_CONSTANT(1000000);
7073 __mmplayer_set_play_count( player, infinity );
7075 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7078 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7079 GST_SEEK_TYPE_SET, start_pos,
7080 GST_SEEK_TYPE_SET, end_pos)))
7082 debug_error("failed to activate section repeat\n");
7084 return MM_ERROR_PLAYER_SEEK;
7087 debug_log("succeeded to set section repeat from %d to %d\n",
7088 player->section_repeat_start, player->section_repeat_end);
7092 return MM_ERROR_NONE;
7096 __mmplayer_set_pcm_extraction(mm_player_t* player)
7098 guint64 start_nsec = 0;
7099 guint64 end_nsec = 0;
7100 guint64 dur_nsec = 0;
7101 guint64 dur_msec = 0;
7102 GstFormat fmt = GST_FORMAT_TIME;
7103 int required_start = 0;
7104 int required_end = 0;
7109 return_val_if_fail( player, FALSE );
7111 mm_attrs_multiple_get(player->attrs,
7113 "pcm_extraction_start_msec", &required_start,
7114 "pcm_extraction_end_msec", &required_end,
7117 debug_log("pcm extraction required position is from [%d] to [%d] (msec)\n", required_start, required_end);
7119 if (required_start == 0 && required_end == 0)
7121 debug_log("extracting entire stream");
7122 return MM_ERROR_NONE;
7124 else if (required_start < 0 || required_start > required_end || required_end < 0 )
7126 debug_log("invalid range for pcm extraction");
7127 return MM_ERROR_INVALID_ARGUMENT;
7131 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &dur_nsec);
7134 debug_error("failed to get duration");
7135 return MM_ERROR_PLAYER_INTERNAL;
7137 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
7139 if (dur_msec < required_end) // FIXME
7141 debug_log("invalid end pos for pcm extraction");
7142 return MM_ERROR_INVALID_ARGUMENT;
7145 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
7146 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
7148 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7151 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7152 GST_SEEK_TYPE_SET, start_nsec,
7153 GST_SEEK_TYPE_SET, end_nsec)))
7155 debug_error("failed to seek for pcm extraction\n");
7157 return MM_ERROR_PLAYER_SEEK;
7160 debug_log("succeeded to set up segment extraction from [%llu] to [%llu] (nsec)\n", start_nsec, end_nsec);
7164 return MM_ERROR_NONE;
7168 _mmplayer_deactivate_section_repeat(MMHandleType hplayer)
7170 mm_player_t* player = (mm_player_t*)hplayer;
7172 GstFormat fmt = GST_FORMAT_TIME;
7177 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7179 player->section_repeat = FALSE;
7181 __mmplayer_set_play_count( player, onetime );
7183 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &fmt, &cur_pos);
7185 if ( (!__gst_seek( player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7188 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7189 GST_SEEK_TYPE_SET, cur_pos,
7190 GST_SEEK_TYPE_SET, player->duration )))
7192 debug_error("failed to deactivate section repeat\n");
7194 return MM_ERROR_PLAYER_SEEK;
7199 return MM_ERROR_NONE;
7203 _mmplayer_set_playspeed(MMHandleType hplayer, gdouble rate)
7205 mm_player_t* player = (mm_player_t*)hplayer;
7206 signed long long pos_msec = 0;
7207 int ret = MM_ERROR_NONE;
7209 GstFormat format =GST_FORMAT_TIME;
7210 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7213 return_val_if_fail ( player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED );
7214 return_val_if_fail ( !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API );
7216 /* The sound of video is not supported under 0.0 and over 2.0. */
7217 if(rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN)
7219 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7222 _mmplayer_set_mute(hplayer, mute);
7224 if (player->playback_rate == rate)
7225 return MM_ERROR_NONE;
7227 /* If the position is reached at start potion during fast backward, EOS is posted.
7228 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7230 player->playback_rate = rate;
7232 current_state = MMPLAYER_CURRENT_STATE(player);
7234 if ( current_state != MM_PLAYER_STATE_PAUSED )
7235 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &format, &pos_msec);
7237 debug_log ("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS (pos_msec), ret, current_state);
7239 if ( ( current_state == MM_PLAYER_STATE_PAUSED )
7241 //|| ( player->last_position != 0 && pos_msec == 0 ) )
7243 debug_warning("returning last point : %lld\n", player->last_position );
7244 pos_msec = player->last_position;
7247 if ((!gst_element_seek (player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7250 ( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ),
7251 //( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT),
7252 GST_SEEK_TYPE_SET, pos_msec,
7253 //GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
7254 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)))
7256 debug_error("failed to set speed playback\n");
7257 return MM_ERROR_PLAYER_SEEK;
7260 debug_log("succeeded to set speed playback as %fl\n", rate);
7264 return MM_ERROR_NONE;;
7268 _mmplayer_set_position(MMHandleType hplayer, int format, int position) // @
7270 mm_player_t* player = (mm_player_t*)hplayer;
7271 int ret = MM_ERROR_NONE;
7275 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7277 ret = __gst_set_position ( player, format, (unsigned long)position );
7285 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position) // @
7287 mm_player_t* player = (mm_player_t*)hplayer;
7288 int ret = MM_ERROR_NONE;
7290 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7292 ret = __gst_get_position ( player, format, position );
7298 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos) // @
7300 mm_player_t* player = (mm_player_t*)hplayer;
7301 int ret = MM_ERROR_NONE;
7303 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7305 ret = __gst_get_buffer_position ( player, format, start_pos, stop_pos );
7311 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position) // @
7313 mm_player_t* player = (mm_player_t*)hplayer;
7314 int ret = MM_ERROR_NONE;
7318 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7320 ret = __gst_adjust_subtitle_position(player, format, position);
7328 __mmplayer_is_midi_type( gchar* str_caps)
7330 if ( ( g_strrstr(str_caps, "audio/midi") ) ||
7331 ( g_strrstr(str_caps, "application/x-gst_ff-mmf") ) ||
7332 ( g_strrstr(str_caps, "application/x-smaf") ) ||
7333 ( g_strrstr(str_caps, "audio/x-imelody") ) ||
7334 ( g_strrstr(str_caps, "audio/mobile-xmf") ) ||
7335 ( g_strrstr(str_caps, "audio/xmf") ) ||
7336 ( g_strrstr(str_caps, "audio/mxmf") ) )
7338 debug_log("midi\n");
7343 debug_log("not midi.\n");
7349 __mmplayer_is_amr_type (gchar *str_caps)
7351 if ((g_strrstr(str_caps, "AMR")) ||
7352 (g_strrstr(str_caps, "amr")))
7360 __mmplayer_is_only_mp3_type (gchar *str_caps)
7362 if (g_strrstr(str_caps, "application/x-id3") ||
7363 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
7371 __mmplayer_typefind_have_type( GstElement *tf, guint probability, // @
7372 GstCaps *caps, gpointer data)
7374 mm_player_t* player = (mm_player_t*)data;
7379 return_if_fail( player && tf && caps );
7381 /* store type string */
7382 MMPLAYER_FREEIF(player->type);
7383 player->type = gst_caps_to_string(caps);
7385 debug_log("meida type %s found, probability %d%% / %d\n", player->type, probability, gst_caps_get_size(caps));
7387 /* midi type should be stored because it will be used to set audio gain in avsysauiosink */
7388 if ( __mmplayer_is_midi_type(player->type))
7390 player->profile.play_mode = MM_PLAYER_MODE_MIDI;
7392 else if (__mmplayer_is_amr_type(player->type))
7394 player->bypass_sound_effect = FALSE;
7395 if ( (PLAYER_INI()->use_audio_filter_preset || PLAYER_INI()->use_audio_filter_custom) )
7397 if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_PRESET )
7399 if (!_mmplayer_sound_filter_preset_apply(player, player->audio_filter_info.preset))
7401 debug_msg("apply sound effect(preset:%d) setting success\n",player->audio_filter_info.preset);
7404 else if ( player->audio_filter_info.filter_type == MM_AUDIO_FILTER_TYPE_CUSTOM )
7406 if (!_mmplayer_sound_filter_custom_apply(player))
7408 debug_msg("apply sound effect(custom) setting success\n");
7413 else if ( g_strrstr(player->type, "application/x-hls"))
7415 /* If it can't know exact type when it parses uri because of redirection case,
7416 * it will be fixed by typefinder here.
7418 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7421 pad = gst_element_get_static_pad(tf, "src");
7424 debug_error("fail to get typefind src pad.\n");
7430 if ( ! __mmplayer_try_to_plug( player, pad, caps ) )
7432 debug_error("failed to autoplug for type : %s\n", player->type);
7434 if ( ( PLAYER_INI()->async_start ) &&
7435 ( player->posted_msg == FALSE ) )
7437 __mmplayer_post_missed_plugin( player );
7443 /* finish autopluging if no dynamic pad waiting */
7444 if( ( ! player->have_dynamic_pad) && ( ! player->has_many_types) )
7446 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
7448 __mmplayer_pipeline_complete( NULL, (gpointer)player );
7453 gst_object_unref( GST_OBJECT(pad) );
7461 __mmplayer_warm_up_video_codec( mm_player_t* player, GstElementFactory *factory)
7463 GstElement *element;
7464 GstStateChangeReturn ret;
7465 gboolean usable = TRUE;
7467 return_val_if_fail ( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
7468 return_val_if_fail ( factory, MM_ERROR_COMMON_INVALID_ARGUMENT );
7470 element = gst_element_factory_create (factory, NULL);
7472 ret = gst_element_set_state (element, GST_STATE_READY);
7474 if (ret != GST_STATE_CHANGE_SUCCESS)
7476 debug_error ("resource conflict so, %s unusable\n", GST_PLUGIN_FEATURE_NAME (factory));
7480 gst_element_set_state (element, GST_STATE_NULL);
7481 gst_object_unref (element);
7486 /* it will return first created element */
7488 __mmplayer_try_to_plug(mm_player_t* player, GstPad *pad, const GstCaps *caps) // @
7490 MMPlayerGstElement* mainbin = NULL;
7491 const char* mime = NULL;
7492 const GList* item = NULL;
7493 const gchar* klass = NULL;
7494 GstCaps* res = NULL;
7495 gboolean skip = FALSE;
7496 GstPad* queue_pad = NULL;
7497 GstElement* queue = NULL;
7498 GstElement *element = NULL;
7502 return_val_if_fail( player &&
7504 player->pipeline->mainbin,
7508 mainbin = player->pipeline->mainbin;
7510 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7512 /* return if we got raw output */
7513 if(g_str_has_prefix(mime, "video/x-raw") || g_str_has_prefix(mime, "audio/x-raw") ||g_str_has_prefix(mime, "text/plain") )
7516 element = (GstElement*)gst_pad_get_parent(pad);
7519 /* NOTE : When no decoder has added during autoplugging. like a simple wave playback.
7520 * No queue will be added. I think it can caused breaking sound when playing raw audio
7521 * frames but there's no different. Decodebin also doesn't add with those wav fils.
7522 * Anyway, currentely raw-queue seems not necessary.
7526 /* NOTE : check if previously linked element is demuxer/depayloader/parse means no decoder
7527 * has linked. if so, we need to add queue for quality of output. note that
7528 * decodebin also has same problem.
7531 klass = gst_element_factory_get_klass( gst_element_get_factory(element) );
7533 /* add queue if needed */
7534 if( g_strrstr(klass, "Demux") ||
7535 g_strrstr(klass, "Depayloader") ||
7536 g_strrstr(klass, "Parse") )
7538 debug_log("adding raw queue\n");
7540 queue = gst_element_factory_make("queue", NULL);
7543 debug_warning("failed to create queue\n");
7548 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
7550 debug_warning("failed to set state READY to queue\n");
7554 /* add to pipeline */
7555 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
7557 debug_warning("failed to add queue\n");
7562 queue_pad = gst_element_get_static_pad(queue, "sink");
7564 if ( GST_PAD_LINK_OK != gst_pad_link(pad, queue_pad) )
7566 debug_warning("failed to link queue\n");
7569 gst_object_unref ( GST_OBJECT(queue_pad) );
7573 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_PAUSED) )
7575 debug_warning("failed to set state READY to queue\n");
7579 /* replace given pad to queue:src */
7580 pad = gst_element_get_static_pad(queue, "src");
7583 debug_warning("failed to get pad from queue\n");
7588 /* check if player can do start continually */
7589 MMPLAYER_CHECK_CMD_IF_EXIT(player);
7591 if(__mmplayer_link_sink(player,pad))
7592 __mmplayer_gst_decode_callback(element, pad, FALSE, player);
7594 gst_object_unref( GST_OBJECT(element));
7601 item = player->factories;
7602 for(; item != NULL ; item = item->next)
7605 GstElementFactory *factory = GST_ELEMENT_FACTORY(item->data);
7611 /* filtering exclude keyword */
7612 for ( idx = 0; PLAYER_INI()->exclude_element_keyword[idx][0] != '\0'; idx++ )
7614 if ( g_strrstr(GST_PLUGIN_FEATURE_NAME (factory),
7615 PLAYER_INI()->exclude_element_keyword[idx] ) )
7617 debug_warning("skipping [%s] by exculde keyword [%s]\n",
7618 GST_PLUGIN_FEATURE_NAME (factory),
7619 PLAYER_INI()->exclude_element_keyword[idx] );
7626 if ( skip ) continue;
7629 /* check factory class for filtering */
7630 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
7632 /* NOTE : msl don't need to use image plugins.
7633 * So, those plugins should be skipped for error handling.
7635 if ( g_strrstr(klass, "Codec/Decoder/Image") )
7637 debug_log("player doesn't need [%s] so, skipping it\n",
7638 GST_PLUGIN_FEATURE_NAME (factory) );
7644 /* check pad compatability */
7645 for(pads = gst_element_factory_get_static_pad_templates(factory);
7646 pads != NULL; pads=pads->next)
7648 GstStaticPadTemplate *temp1 = pads->data;
7649 GstCaps* static_caps = NULL;
7651 if( temp1->direction != GST_PAD_SINK ||
7652 temp1->presence != GST_PAD_ALWAYS)
7656 if ( GST_IS_CAPS( &temp1->static_caps.caps) )
7658 /* using existing caps */
7659 static_caps = gst_caps_ref( &temp1->static_caps.caps );
7664 static_caps = gst_caps_from_string ( temp1->static_caps.string );
7667 res = gst_caps_intersect(caps, static_caps);
7669 gst_caps_unref( static_caps );
7672 if( res && !gst_caps_is_empty(res) )
7674 GstElement *new_element;
7675 GList *elements = player->parsers;
7676 char *name_template = g_strdup(temp1->name_template);
7677 gchar *name_to_plug = GST_PLUGIN_FEATURE_NAME(factory);
7679 gst_caps_unref(res);
7681 debug_log("found %s to plug\n", name_to_plug);
7683 new_element = gst_element_factory_create(GST_ELEMENT_FACTORY(factory), NULL);
7684 if ( ! new_element )
7686 debug_error("failed to create element [%s]. continue with next.\n",
7687 GST_PLUGIN_FEATURE_NAME (factory));
7689 MMPLAYER_FREEIF(name_template);
7694 /* check and skip it if it was already used. Otherwise, it can be an infinite loop
7695 * because parser can accept its own output as input.
7697 if (g_strrstr(klass, "Parser"))
7699 gchar *selected = NULL;
7701 for ( ; elements; elements = g_list_next(elements))
7703 gchar *element_name = elements->data;
7705 if (g_strrstr(element_name, name_to_plug))
7707 debug_log("but, %s already linked, so skipping it\n", name_to_plug);
7714 selected = g_strdup(name_to_plug);
7716 player->parsers = g_list_append(player->parsers, selected);
7719 /* store specific handles for futher control */
7720 if(g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse"))
7722 /* FIXIT : first value will be overwritten if there's more
7723 * than 1 demuxer/parser
7725 debug_log("plugged element is demuxer. take it\n");
7726 mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7727 mainbin[MMPLAYER_M_DEMUX].gst = new_element;
7729 else if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,pad))
7731 if(mainbin[MMPLAYER_M_DEC1].gst == NULL)
7733 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC1]\n");
7734 mainbin[MMPLAYER_M_DEC1].id = MMPLAYER_M_DEC1;
7735 mainbin[MMPLAYER_M_DEC1].gst = new_element;
7737 else if(mainbin[MMPLAYER_M_DEC2].gst == NULL)
7739 debug_log("plugged element is decoder. take it[MMPLAYER_M_DEC2]\n");
7740 mainbin[MMPLAYER_M_DEC2].id = MMPLAYER_M_DEC2;
7741 mainbin[MMPLAYER_M_DEC2].gst = new_element;
7744 /* NOTE : IF one codec is found, add it to supported_codec and remove from
7745 * missing plugin. Both of them are used to check what's supported codec
7746 * before returning result of play start. And, missing plugin should be
7747 * updated here for multi track files.
7749 if(g_str_has_prefix(mime, "video"))
7751 GstPad *src_pad = NULL;
7752 GstPadTemplate *pad_templ = NULL;
7753 GstCaps *caps = NULL;
7754 gchar *caps_type = NULL;
7756 debug_log("found VIDEO decoder\n");
7757 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7758 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7760 src_pad = gst_element_get_static_pad (new_element, "src");
7761 pad_templ = gst_pad_get_pad_template (src_pad);
7762 caps = GST_PAD_TEMPLATE_CAPS(pad_templ);
7764 caps_type = gst_caps_to_string(caps);
7766 if ( g_strrstr( caps_type, "ST12") )
7767 player->is_nv12_tiled = TRUE;
7770 MMPLAYER_FREEIF( caps_type );
7771 gst_object_unref (src_pad);
7773 else if (g_str_has_prefix(mime, "audio"))
7775 debug_log("found AUDIO decoder\n");
7776 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7777 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7780 if ( ! __mmplayer_close_link(player, pad, new_element,
7781 name_template,gst_element_factory_get_static_pad_templates(factory)) )
7783 if (player->keep_detecting_vcodec)
7786 /* Link is failed even though a supportable codec is found. */
7787 __mmplayer_check_not_supported_codec(player, (gchar *)mime);
7789 MMPLAYER_FREEIF(name_template);
7790 debug_error("failed to call _close_link\n");
7794 MMPLAYER_FREEIF(name_template);
7798 gst_caps_unref(res);
7804 /* There is no any found codec. */
7805 __mmplayer_check_not_supported_codec(player,(gchar *)mime);
7807 debug_error("failed to autoplug\n");
7818 gst_object_unref( queue );
7822 gst_object_unref( queue_pad );
7825 gst_object_unref ( element );
7832 int __mmplayer_check_not_supported_codec(mm_player_t* player, gchar* mime)
7836 return_val_if_fail(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7837 return_val_if_fail ( mime, MM_ERROR_INVALID_ARGUMENT );
7839 debug_log("mimetype to check: %s\n", mime );
7841 /* add missing plugin */
7842 /* NOTE : msl should check missing plugin for image mime type.
7843 * Some motion jpeg clips can have playable audio track.
7844 * So, msl have to play audio after displaying popup written video format not supported.
7846 if ( !( player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst ) )
7848 if ( !( player->can_support_codec | player->videodec_linked | player->audiodec_linked ) )
7850 debug_log("not found demuxer\n");
7851 player->not_found_demuxer = TRUE;
7852 player->unlinked_demuxer_mime = g_strdup_printf ( "%s", mime );
7858 if( ( g_str_has_prefix(mime, "video") ) ||( g_str_has_prefix(mime, "image") ) )
7860 debug_log("can support codec=%d, vdec_linked=%d, adec_linked=%d\n",
7861 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
7863 /* check that clip have multi tracks or not */
7864 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) && ( player->videodec_linked ) )
7866 debug_log("video plugin is already linked\n");
7870 debug_warning("add VIDEO to missing plugin\n");
7871 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
7874 else if ( g_str_has_prefix(mime, "audio") )
7876 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) && ( player->audiodec_linked ) )
7878 debug_log("audio plugin is already linked\n");
7882 debug_warning("add AUDIO to missing plugin\n");
7883 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
7890 return MM_ERROR_NONE;
7894 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data) // @
7896 mm_player_t* player = (mm_player_t*)data;
7900 return_if_fail( player );
7902 /* remove fakesink */
7903 if ( ! __mmplayer_gst_remove_fakesink( player,
7904 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]) )
7906 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
7907 * signaling mechanism ( pad-added, no-more-pad, new-decoded-pad ) from various
7908 * source element are not same. To overcome this situation, this function will called
7909 * several places and several times. Therefore, this is not an error case.
7913 debug_log("pipeline has completely constructed\n");
7915 player->pipeline_is_constructed = TRUE;
7917 if ( ( PLAYER_INI()->async_start ) &&
7918 ( player->posted_msg == FALSE ) )
7920 __mmplayer_post_missed_plugin( player );
7923 MMPLAYER_GENERATE_DOT_IF_ENABLED ( player, "pipeline-status-complate" );
7926 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
7930 return_val_if_fail ( player, FALSE );
7933 if ( MMPLAYER_IS_STREAMING(player) )
7936 /* This callback can be set to music player only. */
7937 if((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO)
7939 debug_warning("audio callback is not supported for video");
7943 if (player->audio_stream_cb)
7948 pad = gst_element_get_static_pad (player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
7952 debug_error("failed to get sink pad from audiosink to probe data\n");
7956 player->audio_cb_probe_id = gst_pad_add_buffer_probe (pad,
7957 G_CALLBACK (__mmplayer_audio_stream_probe), player);
7959 gst_object_unref (pad);
7966 debug_error("There is no audio callback to configure.\n");
7976 __mmplayer_init_factories(mm_player_t* player) // @
7980 return_if_fail ( player );
7982 player->factories = gst_registry_feature_filter(gst_registry_get_default(),
7983 (GstPluginFeatureFilter)__mmplayer_feature_filter, FALSE, NULL);
7985 player->factories = g_list_sort(player->factories, (GCompareFunc)util_factory_rank_compare);
7991 __mmplayer_release_factories(mm_player_t* player) // @
7995 return_if_fail ( player );
7997 if (player->factories)
7999 gst_plugin_feature_list_free (player->factories);
8000 player->factories = NULL;
8007 __mmplayer_release_misc(mm_player_t* player)
8011 return_if_fail ( player );
8013 /* free memory related to sound effect */
8014 if(player->audio_filter_info.custom_ext_level_for_plugin)
8016 free(player->audio_filter_info.custom_ext_level_for_plugin);
8022 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8024 GstElement *element = NULL;
8027 debug_log("creating %s to plug\n", name);
8029 element = gst_element_factory_make(name, NULL);
8032 debug_error("failed to create queue\n");
8036 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY) )
8038 debug_error("failed to set state READY to %s\n", name);
8042 if ( ! gst_bin_add(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, element) )
8044 debug_error("failed to add %s\n", name);
8048 sinkpad = gst_element_get_static_pad(element, "sink");
8050 if ( GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad) )
8052 debug_error("failed to link %s\n", name);
8053 gst_object_unref (sinkpad);
8058 debug_log("linked %s to pipeline successfully\n", name);
8060 gst_object_unref (sinkpad);
8066 __mmplayer_close_link(mm_player_t* player, GstPad *srcpad, GstElement *sinkelement,
8067 const char *padname, const GList *templlist)
8070 gboolean has_dynamic_pads = FALSE;
8071 gboolean has_many_types = FALSE;
8072 const char *klass = NULL;
8073 GstStaticPadTemplate *padtemplate = NULL;
8074 GstElementFactory *factory = NULL;
8075 GstElement* queue = NULL;
8076 GstElement* parser = NULL;
8077 GstPad *pssrcpad = NULL;
8078 GstPad *qsrcpad = NULL, *qsinkpad = NULL;
8079 MMPlayerGstElement *mainbin = NULL;
8080 GstStructure* str = NULL;
8081 GstCaps* srccaps = NULL;
8082 GstState warmup = GST_STATE_READY;
8083 gboolean isvideo_decoder = FALSE;
8084 guint q_max_size_time = 0;
8088 return_val_if_fail ( player &&
8090 player->pipeline->mainbin,
8093 mainbin = player->pipeline->mainbin;
8095 debug_log("plugging pad %s:%s to newly create %s:%s\n",
8096 GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad ) ),
8097 GST_PAD_NAME( srcpad ),
8098 GST_ELEMENT_NAME( sinkelement ),
8102 factory = gst_element_get_factory(sinkelement);
8103 klass = gst_element_factory_get_klass(factory);
8105 /* check if player can do start continually */
8106 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8108 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, warmup) )
8110 if (isvideo_decoder)
8111 player->keep_detecting_vcodec = TRUE;
8113 debug_error("failed to set %d state to %s\n", warmup, GST_ELEMENT_NAME( sinkelement ));
8117 /* add to pipeline */
8118 if ( ! gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), sinkelement) )
8120 debug_error("failed to add %s to mainbin\n", GST_ELEMENT_NAME( sinkelement ));
8124 debug_log("element klass : %s\n", klass);
8126 /* added to support multi track files */
8127 /* only decoder case and any of the video/audio still need to link*/
8128 if(g_strrstr(klass, "Decoder") && __mmplayer_link_decoder(player,srcpad))
8132 name = g_strdup(GST_ELEMENT_NAME( GST_PAD_PARENT ( srcpad )));
8134 if (g_strrstr(name, "mpegtsdemux"))
8136 gchar *demux_caps = NULL;
8137 gchar *parser_name = NULL;
8138 GstCaps *dcaps = NULL;
8140 dcaps = gst_pad_get_caps(srcpad);
8141 demux_caps = gst_caps_to_string(dcaps);
8143 if (g_strrstr(demux_caps, "video/x-h264"))
8145 parser_name = g_strdup("h264parse");
8147 else if (g_strrstr(demux_caps, "video/mpeg"))
8149 parser_name = g_strdup("mpeg4videoparse");
8152 gst_caps_unref(dcaps);
8153 MMPLAYER_FREEIF( demux_caps );
8157 parser = __mmplayer_element_create_and_link(player, srcpad, parser_name);
8159 MMPLAYER_FREEIF(parser_name);
8163 debug_error("failed to create parser\n");
8167 /* update srcpad if parser is created */
8168 pssrcpad = gst_element_get_static_pad(parser, "src");
8173 MMPLAYER_FREEIF(name);
8175 queue = __mmplayer_element_create_and_link(player, srcpad, "queue"); // parser - queue or demuxer - queue
8178 debug_error("failed to create queue\n");
8182 /* update srcpad to link with decoder */
8183 qsrcpad = gst_element_get_static_pad(queue, "src");
8186 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8187 q_max_size_time = GST_QUEUE_HLS_TIME;
8189 q_max_size_time = GST_QUEUE_DEFAULT_TIME;
8191 /* assigning queue handle for futher manipulation purpose */
8192 /* FIXIT : make it some kind of list so that msl can support more then two stream (text, data, etc...) */
8193 if(mainbin[MMPLAYER_M_Q1].gst == NULL)
8195 mainbin[MMPLAYER_M_Q1].id = MMPLAYER_M_Q1;
8196 mainbin[MMPLAYER_M_Q1].gst = queue;
8198 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q1].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8200 else if(mainbin[MMPLAYER_M_Q2].gst == NULL)
8202 mainbin[MMPLAYER_M_Q2].id = MMPLAYER_M_Q2;
8203 mainbin[MMPLAYER_M_Q2].gst = queue;
8205 g_object_set (G_OBJECT (mainbin[MMPLAYER_M_Q2].gst), "max-size-time", q_max_size_time * GST_SECOND, NULL);
8209 debug_critical("Not supporting more then two elementary stream\n");
8213 pad = gst_element_get_static_pad(sinkelement, padname);
8217 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8218 padname, GST_ELEMENT_NAME(sinkelement) );
8220 pad = gst_element_get_static_pad(sinkelement, "sink");
8223 debug_error("failed to get pad(sink) from %s. \n",
8224 GST_ELEMENT_NAME(sinkelement) );
8229 /* to check the video/audio type set the proper flag*/
8231 srccaps = gst_pad_get_caps( srcpad );
8235 str = gst_caps_get_structure( srccaps, 0 );
8239 name = gst_structure_get_name(str);
8244 /* link queue and decoder. so, it will be queue - decoder. */
8245 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8247 gst_object_unref(GST_OBJECT(pad));
8248 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8250 /* reconstitute supportable codec */
8252 if (strstr(name, "video"))
8254 player->can_support_codec ^= FOUND_PLUGIN_VIDEO;
8257 if (strstr(name, "audio"))
8259 player->can_support_codec ^= FOUND_PLUGIN_AUDIO;
8265 gst_object_unref(GST_OBJECT(pad));
8268 if (strstr(name, "video"))
8270 player->videodec_linked = 1;
8271 debug_msg("player->videodec_linked set to 1\n");
8274 if (strstr(name, "audio"))
8276 player->audiodec_linked = 1;
8277 debug_msg("player->auddiodec_linked set to 1\n");
8280 gst_caps_unref(GST_CAPS(srccaps));
8285 if ( !MMPLAYER_IS_HTTP_PD(player) )
8287 if( (g_strrstr(klass, "Demux") && !g_strrstr(klass, "Metadata")) || (g_strrstr(klass, "Parser") ) )
8289 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8291 GstFormat fmt = GST_FORMAT_BYTES;
8292 gint64 dur_bytes = 0L;
8293 gchar *file_buffering_path = NULL;
8294 gboolean use_file_buffer = FALSE;
8296 if ( !mainbin[MMPLAYER_M_S_BUFFER].gst)
8298 debug_log("creating http streaming buffering queue\n");
8300 queue = gst_element_factory_make("queue2", "http_streaming_buffer");
8303 debug_critical ( "failed to create buffering queue element\n" );
8307 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(queue, GST_STATE_READY) )
8309 debug_error("failed to set state READY to buffering queue\n");
8313 if ( !gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue) )
8315 debug_error("failed to add buffering queue\n");
8319 qsinkpad = gst_element_get_static_pad(queue, "sink");
8320 qsrcpad = gst_element_get_static_pad(queue, "src");
8322 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, qsinkpad) )
8324 debug_error("failed to link buffering queue\n");
8330 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_S_BUFFER;
8331 mainbin[MMPLAYER_M_S_BUFFER].gst = queue;
8333 if ( !MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
8335 if ( !gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, &fmt, &dur_bytes))
8336 debug_error("fail to get duration.\n");
8340 use_file_buffer = MMPLAYER_USE_FILE_FOR_BUFFERING(player);
8341 file_buffering_path = g_strdup(PLAYER_INI()->http_file_buffer_path);
8345 __mm_player_streaming_set_buffer(player->streamer,
8348 PLAYER_INI()->http_max_size_bytes,
8350 PLAYER_INI()->http_buffering_limit,
8351 PLAYER_INI()->http_buffering_time,
8353 file_buffering_path,
8356 MMPLAYER_FREEIF(file_buffering_path);
8361 /* if it is not decoder or */
8362 /* in decoder case any of the video/audio still need to link*/
8363 if(!g_strrstr(klass, "Decoder"))
8366 pad = gst_element_get_static_pad(sinkelement, padname);
8369 debug_warning("failed to get pad(%s) from %s. retrying with [sink]\n",
8370 padname, GST_ELEMENT_NAME(sinkelement) );
8372 pad = gst_element_get_static_pad(sinkelement, "sink");
8376 debug_error("failed to get pad(sink) from %s. \n",
8377 GST_ELEMENT_NAME(sinkelement) );
8382 if ( GST_PAD_LINK_OK != gst_pad_link(srcpad, pad) )
8384 gst_object_unref(GST_OBJECT(pad));
8385 debug_error("failed to link (%s) to pad(%s)\n", GST_ELEMENT_NAME( sinkelement ), padname );
8389 gst_object_unref(GST_OBJECT(pad));
8392 for(;templlist != NULL; templlist = templlist->next)
8394 padtemplate = templlist->data;
8396 debug_log ("director = [%d], presence = [%d]\n", padtemplate->direction, padtemplate->presence);
8398 if( padtemplate->direction != GST_PAD_SRC ||
8399 padtemplate->presence == GST_PAD_REQUEST )
8402 switch(padtemplate->presence)
8404 case GST_PAD_ALWAYS:
8406 GstPad *srcpad = gst_element_get_static_pad(sinkelement, "src");
8407 GstCaps *caps = gst_pad_get_caps(srcpad);
8409 /* Check whether caps has many types */
8410 if ( gst_caps_get_size (caps) > 1 && g_strrstr(klass, "Parser")) {
8411 debug_log ("has_many_types for this caps [%s]\n", gst_caps_to_string(caps));
8412 has_many_types = TRUE;
8416 if ( ! __mmplayer_try_to_plug(player, srcpad, caps) )
8418 gst_object_unref(GST_OBJECT(srcpad));
8419 gst_caps_unref(GST_CAPS(caps));
8421 debug_error("failed to plug something after %s\n", GST_ELEMENT_NAME( sinkelement ));
8425 gst_caps_unref(GST_CAPS(caps));
8426 gst_object_unref(GST_OBJECT(srcpad));
8432 case GST_PAD_SOMETIMES:
8433 has_dynamic_pads = TRUE;
8441 /* check if player can do start continually */
8442 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8444 if( has_dynamic_pads )
8446 player->have_dynamic_pad = TRUE;
8447 MMPLAYER_SIGNAL_CONNECT ( player, sinkelement, "pad-added",
8448 G_CALLBACK(__mmplayer_add_new_pad), player);
8450 /* for streaming, more then one typefind will used for each elementary stream
8451 * so this doesn't mean the whole pipeline completion
8453 if ( ! MMPLAYER_IS_RTSP_STREAMING( player ) )
8455 MMPLAYER_SIGNAL_CONNECT( player, sinkelement, "no-more-pads",
8456 G_CALLBACK(__mmplayer_pipeline_complete), player);
8464 player->has_many_types = has_many_types;
8466 pad = gst_element_get_static_pad(sinkelement, "src");
8467 MMPLAYER_SIGNAL_CONNECT (player, pad, "notify::caps", G_CALLBACK(__mmplayer_add_new_caps), player);
8468 gst_object_unref (GST_OBJECT(pad));
8472 /* check if player can do start continually */
8473 MMPLAYER_CHECK_CMD_IF_EXIT(player);
8475 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkelement, GST_STATE_PAUSED) )
8477 debug_error("failed to set state PAUSED to %s\n", GST_ELEMENT_NAME( sinkelement ));
8483 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (queue, GST_STATE_PAUSED) )
8485 debug_error("failed to set state PAUSED to queue\n");
8491 gst_object_unref (GST_OBJECT(qsrcpad));
8497 if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state (parser, GST_STATE_PAUSED) )
8499 debug_error("failed to set state PAUSED to queue\n");
8505 gst_object_unref (GST_OBJECT(pssrcpad));
8517 gst_object_unref(GST_OBJECT(qsrcpad));
8519 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8520 * You need to explicitly set elements to the NULL state before
8521 * dropping the final reference, to allow them to clean up.
8523 gst_element_set_state(queue, GST_STATE_NULL);
8524 /* And, it still has a parent "player".
8525 * You need to let the parent manage the object instead of unreffing the object directly.
8528 gst_bin_remove (GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue);
8529 //gst_object_unref( queue );
8533 gst_caps_unref(GST_CAPS(srccaps));
8538 static gboolean __mmplayer_feature_filter(GstPluginFeature *feature, gpointer data) // @
8541 //const gchar *name;
8543 /* we only care about element factories */
8544 if (!GST_IS_ELEMENT_FACTORY(feature))
8547 /* only parsers, demuxers and decoders */
8548 klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
8549 //name = gst_element_factory_get_longname(GST_ELEMENT_FACTORY(feature));
8551 if( g_strrstr(klass, "Demux") == NULL &&
8552 g_strrstr(klass, "Codec/Decoder") == NULL &&
8553 g_strrstr(klass, "Depayloader") == NULL &&
8554 g_strrstr(klass, "Parse") == NULL)
8562 static void __mmplayer_add_new_caps(GstPad* pad, GParamSpec* unused, gpointer data)
8564 mm_player_t* player = (mm_player_t*) data;
8565 GstCaps *caps = NULL;
8566 GstStructure *str = NULL;
8571 return_if_fail ( pad )
8572 return_if_fail ( unused )
8573 return_if_fail ( data )
8575 caps = gst_pad_get_caps(pad);
8579 str = gst_caps_get_structure(caps, 0);
8583 name = gst_structure_get_name(str);
8586 debug_log("name=%s\n", name);
8588 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8590 debug_error("failed to autoplug for type (%s)\n", name);
8591 gst_caps_unref(caps);
8595 gst_caps_unref(caps);
8597 __mmplayer_pipeline_complete( NULL, (gpointer)player );
8604 static void __mmplayer_set_unlinked_mime_type(mm_player_t* player, GstCaps *caps)
8608 const char *stream_type;
8609 gchar *version_field = NULL;
8613 return_if_fail ( player );
8614 return_if_fail ( caps );
8616 str = gst_caps_get_structure(caps, 0);
8620 stream_type = gst_structure_get_name(str);
8625 /* set unlinked mime type for downloadable codec */
8626 if (g_str_has_prefix(stream_type, "video/"))
8628 if (g_str_has_prefix(stream_type, "video/mpeg"))
8630 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8631 version_field = MM_PLAYER_MPEG_VNAME;
8633 else if (g_str_has_prefix(stream_type, "video/x-wmv"))
8635 gst_structure_get_int (str, MM_PLAYER_WMV_VNAME, &version);
8636 version_field = MM_PLAYER_WMV_VNAME;
8639 else if (g_str_has_prefix(stream_type, "video/x-divx"))
8641 gst_structure_get_int (str, MM_PLAYER_DIVX_VNAME, &version);
8642 version_field = MM_PLAYER_DIVX_VNAME;
8647 player->unlinked_video_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8651 player->unlinked_video_mime = g_strdup_printf("%s", stream_type);
8654 else if (g_str_has_prefix(stream_type, "audio/"))
8656 if (g_str_has_prefix(stream_type, "audio/mpeg")) // mp3 or aac
8658 gst_structure_get_int (str, MM_PLAYER_MPEG_VNAME, &version);
8659 version_field = MM_PLAYER_MPEG_VNAME;
8661 else if (g_str_has_prefix(stream_type, "audio/x-wma"))
8663 gst_structure_get_int (str, MM_PLAYER_WMA_VNAME, &version);
8664 version_field = MM_PLAYER_WMA_VNAME;
8669 player->unlinked_audio_mime = g_strdup_printf("%s, %s=%d", stream_type, version_field, version);
8673 player->unlinked_audio_mime = g_strdup_printf("%s", stream_type);
8680 static void __mmplayer_add_new_pad(GstElement *element, GstPad *pad, gpointer data)
8682 mm_player_t* player = (mm_player_t*) data;
8683 GstCaps *caps = NULL;
8684 GstStructure *str = NULL;
8688 return_if_fail ( player );
8689 return_if_fail ( pad );
8691 GST_OBJECT_LOCK (pad);
8692 if ((caps = GST_PAD_CAPS(pad)))
8694 GST_OBJECT_UNLOCK (pad);
8698 caps = gst_pad_get_caps(pad);
8699 if ( !caps ) return;
8702 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8704 str = gst_caps_get_structure(caps, 0);
8708 name = gst_structure_get_name(str);
8712 player->num_dynamic_pad++;
8713 debug_log("stream count inc : %d\n", player->num_dynamic_pad);
8715 /* Note : If the stream is the subtitle, we try not to play it. Just close the demuxer subtitle pad.
8716 * If want to play it, remove this code.
8718 if (g_strrstr(name, "application"))
8720 if (g_strrstr(name, "x-id3") || g_strrstr(name, "x-apetag"))
8722 /* If id3/ape tag comes, keep going */
8723 debug_log("application mime exception : id3/ape tag");
8727 /* Otherwise, we assume that this stream is subtile. */
8728 debug_log(" application mime type pad is closed.");
8732 else if (g_strrstr(name, "audio"))
8734 gint samplerate = 0, channels = 0;
8736 /* set stream information */
8737 /* if possible, set it here because the caps is not distrubed by resampler. */
8738 gst_structure_get_int (str, "rate", &samplerate);
8739 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
8741 gst_structure_get_int (str, "channels", &channels);
8742 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
8744 debug_log("audio samplerate : %d channels : %d", samplerate, channels);
8747 if ( mmf_attrs_commit ( player->attrs ) )
8749 debug_error("failed to update attributes");
8753 else if (g_strrstr(name, "video"))
8756 mm_attrs_get_int_by_name (player->attrs, "display_surface_type", &stype);
8758 /* don't make video because of not required */
8759 if (stype == MM_DISPLAY_SURFACE_NULL)
8761 debug_log("no video because it's not required");
8765 player->v_stream_caps = gst_caps_copy(caps); //if needed, video caps is required when videobin is created
8768 if ( ! __mmplayer_try_to_plug(player, pad, caps) )
8770 debug_error("failed to autoplug for type (%s)", name);
8772 __mmplayer_set_unlinked_mime_type(player, caps);
8775 gst_caps_unref(caps);
8781 /* test API for tuning audio gain. this API should be
8782 * deprecated before the day of final release
8785 _mmplayer_set_volume_tune(MMHandleType hplayer, MMPlayerVolumeType volume)
8787 mm_player_t* player = (mm_player_t*) hplayer;
8788 gint error = MM_ERROR_NONE;
8790 gboolean isMidi = FALSE;
8795 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
8796 return_val_if_fail( player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED )
8798 debug_log("clip type=%d(1-midi, 0-others), volume [L]=%d:[R]=%d\n",
8799 player->profile.play_mode, volume.level[0], volume.level[1]);
8801 isMidi = ( player->profile.play_mode == MM_PLAYER_MODE_MIDI ) ? TRUE : FALSE;
8808 /* is it proper volume level? */
8809 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; ++i)
8811 if (volume.level[i] < 0 || volume.level[i] > vol_max) {
8812 debug_log("Invalid Volume level!!!! \n");
8813 return MM_ERROR_INVALID_ARGUMENT;
8819 if ( player->pipeline->mainbin )
8821 GstElement *midi_element = player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst;
8823 if ( midi_element && ( strstr(GST_ELEMENT_NAME(midi_element), "midiparse")) )
8825 debug_log("setting volume (%d) level to midi plugin\n", volume.level[0]);
8827 g_object_set(midi_element, "volume", volume.level[0], NULL);
8833 if ( player->pipeline->audiobin )
8835 GstElement *sink_element = player->pipeline->audiobin[MMPLAYER_A_SINK].gst;
8837 /* Set to Avsysaudiosink element */
8841 gboolean mute = FALSE;
8842 vol_value = volume.level[0];
8844 g_object_set(G_OBJECT(sink_element), "tuningvolume", vol_value, NULL);
8846 mute = (vol_value == 0)? TRUE:FALSE;
8848 g_object_set(G_OBJECT(sink_element), "mute", mute, NULL);
8860 __mmplayer_dump_pipeline_state( mm_player_t* player )
8862 GstIterator*iter = NULL;
8863 gboolean done = FALSE;
8865 GstElement *item = NULL;
8866 GstElementFactory *factory = NULL;
8868 GstState state = GST_STATE_VOID_PENDING;
8869 GstState pending = GST_STATE_VOID_PENDING;
8870 GstClockTime time = 200*GST_MSECOND;
8874 return_val_if_fail ( player &&
8876 player->pipeline->mainbin,
8880 iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) );
8885 switch ( gst_iterator_next (iter, (gpointer)&item) )
8887 case GST_ITERATOR_OK:
8888 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8890 factory = gst_element_get_factory (item) ;
8891 debug_log("%s:%s : From:%s To:%s refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(item) ,
8892 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(item));
8895 gst_object_unref (item);
8897 case GST_ITERATOR_RESYNC:
8898 gst_iterator_resync (iter);
8900 case GST_ITERATOR_ERROR:
8903 case GST_ITERATOR_DONE:
8910 item = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8912 gst_element_get_state(GST_ELEMENT (item),&state, &pending,time);
8914 factory = gst_element_get_factory (item) ;
8916 debug_log("%s:%s : From:%s To:%s refcount : %d\n",
8917 GST_OBJECT_NAME(factory),
8918 GST_ELEMENT_NAME(item),
8919 gst_element_state_get_name(state),
8920 gst_element_state_get_name(pending),
8921 GST_OBJECT_REFCOUNT_VALUE(item) );
8924 gst_iterator_free (iter);
8933 __mmplayer_check_subtitle( mm_player_t* player )
8935 MMHandleType attrs = 0;
8936 char *subtitle_uri = NULL;
8940 return_val_if_fail( player, FALSE );
8942 /* get subtitle attribute */
8943 attrs = MMPLAYER_GET_ATTRS(player);
8947 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8948 if ( !subtitle_uri || !strlen(subtitle_uri))
8951 debug_log ("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
8959 __mmplayer_can_extract_pcm( mm_player_t* player )
8961 MMHandleType attrs = 0;
8962 gboolean is_drm = FALSE;
8963 gboolean sound_extraction = FALSE;
8967 return_val_if_fail ( player, FALSE );
8969 attrs = MMPLAYER_GET_ATTRS(player);
8972 debug_error("fail to get attributes.");
8976 /* check file is drm or not */
8977 g_object_get(G_OBJECT(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), "is-drm", &is_drm, NULL);
8979 /* get sound_extraction property */
8980 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
8982 if ( ! sound_extraction || is_drm )
8984 debug_log("pcm extraction param.. is drm = %d, extraction mode = %d", is_drm, sound_extraction);
8994 __mmplayer_handle_gst_error ( mm_player_t* player, GstMessage * message, GError* error )
8996 MMMessageParamType msg_param;
8997 gchar *msg_src_element;
9001 return_val_if_fail( player, FALSE );
9002 return_val_if_fail( error, FALSE );
9004 /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
9006 memset (&msg_param, 0, sizeof(MMMessageParamType));
9008 if ( error->domain == GST_CORE_ERROR )
9010 msg_param.code = __gst_handle_core_error( player, error->code );
9012 else if ( error->domain == GST_LIBRARY_ERROR )
9014 msg_param.code = __gst_handle_library_error( player, error->code );
9016 else if ( error->domain == GST_RESOURCE_ERROR )
9018 msg_param.code = __gst_handle_resource_error( player, error->code );
9020 else if ( error->domain == GST_STREAM_ERROR )
9022 msg_param.code = __gst_handle_stream_error( player, error, message );
9026 debug_warning("This error domain is not defined.\n");
9028 /* we treat system error as an internal error */
9029 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
9034 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9036 msg_param.data = (void *) error->message;
9038 debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n",
9039 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg_param.code);
9042 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player))
9044 __mm_player_ahs_stop (player->ahs_player);
9047 /* post error to application */
9048 if ( ! player->posted_msg )
9050 if (msg_param.code == MM_MESSAGE_DRM_NOT_AUTHORIZED)
9052 MMPLAYER_POST_MSG( player, MM_MESSAGE_DRM_NOT_AUTHORIZED, NULL );
9056 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9059 /* don't post more if one was sent already */
9060 player->posted_msg = TRUE;
9064 debug_log("skip error post because it's sent already.\n");
9073 __mmplayer_handle_streaming_error ( mm_player_t* player, GstMessage * message )
9076 MMMessageParamType msg_param;
9077 gchar *msg_src_element = NULL;
9078 GstStructure *s = NULL;
9080 gchar *error_string = NULL;
9084 return_val_if_fail ( player, FALSE );
9085 return_val_if_fail ( message, FALSE );
9087 s = malloc( sizeof(GstStructure) );
9088 memcpy ( s, gst_message_get_structure ( message ), sizeof(GstStructure));
9090 if ( !gst_structure_get_uint (s, "error_id", &error_id) )
9091 error_id = MMPLAYER_STREAMING_ERROR_NONE;
9095 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
9096 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
9098 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
9099 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
9101 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
9102 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9104 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
9105 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
9107 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
9108 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
9110 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
9111 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
9113 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
9114 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
9116 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
9117 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
9119 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
9120 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
9122 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
9123 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
9125 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
9126 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
9128 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
9129 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
9131 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
9132 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
9134 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
9135 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
9137 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
9138 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
9140 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
9141 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
9143 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
9144 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
9146 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
9147 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
9149 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
9150 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
9152 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
9153 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
9155 case MMPLAYER_STREAMING_ERROR_GONE:
9156 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
9158 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
9159 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
9161 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
9162 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
9164 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
9165 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
9167 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
9168 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
9170 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
9171 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
9173 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
9174 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
9176 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
9177 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
9179 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
9180 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
9182 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
9183 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
9185 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
9186 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
9188 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
9189 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
9191 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
9192 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
9194 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
9195 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
9197 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
9198 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
9200 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
9201 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
9203 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
9204 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
9206 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
9207 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
9209 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
9210 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
9212 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
9213 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
9215 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
9216 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
9218 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
9219 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
9221 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
9222 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
9224 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
9225 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
9227 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
9228 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
9231 return MM_ERROR_PLAYER_STREAMING_FAIL;
9234 error_string = g_strdup(gst_structure_get_string (s, "error_string"));
9236 msg_param.data = (void *) error_string;
9240 msg_src_element = GST_ELEMENT_NAME( GST_ELEMENT_CAST( message->src ) );
9242 debug_error("-Msg src : [%s] Code : [%x] Error : [%s] \n",
9243 msg_src_element, msg_param.code, (char*)msg_param.data );
9246 /* post error to application */
9247 if ( ! player->posted_msg )
9249 MMPLAYER_POST_MSG( player, MM_MESSAGE_ERROR, &msg_param );
9251 /* don't post more if one was sent already */
9252 player->posted_msg = TRUE;
9256 debug_log("skip error post because it's sent already.\n");
9266 __gst_handle_core_error( mm_player_t* player, int code )
9268 gint trans_err = MM_ERROR_NONE;
9272 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9276 case GST_CORE_ERROR_STATE_CHANGE:
9277 case GST_CORE_ERROR_MISSING_PLUGIN:
9278 case GST_CORE_ERROR_SEEK:
9279 case GST_CORE_ERROR_NOT_IMPLEMENTED:
9280 case GST_CORE_ERROR_FAILED:
9281 case GST_CORE_ERROR_TOO_LAZY:
9282 case GST_CORE_ERROR_PAD:
9283 case GST_CORE_ERROR_THREAD:
9284 case GST_CORE_ERROR_NEGOTIATION:
9285 case GST_CORE_ERROR_EVENT:
9286 case GST_CORE_ERROR_CAPS:
9287 case GST_CORE_ERROR_TAG:
9288 case GST_CORE_ERROR_CLOCK:
9289 case GST_CORE_ERROR_DISABLED:
9291 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9301 __gst_handle_library_error( mm_player_t* player, int code )
9303 gint trans_err = MM_ERROR_NONE;
9307 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9311 case GST_LIBRARY_ERROR_FAILED:
9312 case GST_LIBRARY_ERROR_TOO_LAZY:
9313 case GST_LIBRARY_ERROR_INIT:
9314 case GST_LIBRARY_ERROR_SHUTDOWN:
9315 case GST_LIBRARY_ERROR_SETTINGS:
9316 case GST_LIBRARY_ERROR_ENCODE:
9318 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9329 __gst_handle_resource_error( mm_player_t* player, int code )
9331 gint trans_err = MM_ERROR_NONE;
9335 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9339 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
9340 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
9342 case GST_RESOURCE_ERROR_NOT_FOUND:
9343 case GST_RESOURCE_ERROR_OPEN_READ:
9344 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ) )
9346 trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
9349 case GST_RESOURCE_ERROR_READ:
9350 if ( MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING ( player ))
9352 trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
9355 case GST_RESOURCE_ERROR_SEEK:
9356 case GST_RESOURCE_ERROR_FAILED:
9357 case GST_RESOURCE_ERROR_TOO_LAZY:
9358 case GST_RESOURCE_ERROR_BUSY:
9359 case GST_RESOURCE_ERROR_OPEN_WRITE:
9360 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
9361 case GST_RESOURCE_ERROR_CLOSE:
9362 case GST_RESOURCE_ERROR_WRITE:
9363 case GST_RESOURCE_ERROR_SYNC:
9364 case GST_RESOURCE_ERROR_SETTINGS:
9366 trans_err = MM_ERROR_PLAYER_FILE_NOT_FOUND;
9377 __gst_handle_stream_error( mm_player_t* player, GError* error, GstMessage * message )
9379 gint trans_err = MM_ERROR_NONE;
9383 return_val_if_fail( player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9384 return_val_if_fail( error, MM_ERROR_INVALID_ARGUMENT );
9385 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9387 switch ( error->code )
9389 case GST_STREAM_ERROR_FAILED:
9390 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9391 case GST_STREAM_ERROR_DECODE:
9392 case GST_STREAM_ERROR_WRONG_TYPE:
9393 case GST_STREAM_ERROR_DECRYPT:
9394 trans_err = __gst_transform_gsterror( player, message, error );
9397 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
9398 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
9399 case GST_STREAM_ERROR_TOO_LAZY:
9400 case GST_STREAM_ERROR_ENCODE:
9401 case GST_STREAM_ERROR_DEMUX:
9402 case GST_STREAM_ERROR_MUX:
9403 case GST_STREAM_ERROR_FORMAT:
9404 case GST_STREAM_ERROR_DECRYPT_NOKEY:
9406 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
9416 /* NOTE : decide gstreamer state whether there is some playable track or not. */
9418 __gst_transform_gsterror( mm_player_t* player, GstMessage * message, GError* error )
9420 gchar *src_element_name = NULL;
9421 GstElement *src_element = NULL;
9422 GstElementFactory *factory = NULL;
9423 const gchar* klass = NULL;
9428 return_val_if_fail ( message, MM_ERROR_INVALID_ARGUMENT );
9429 return_val_if_fail ( message->src, MM_ERROR_INVALID_ARGUMENT );
9430 return_val_if_fail ( error, MM_ERROR_INVALID_ARGUMENT );
9432 src_element = GST_ELEMENT_CAST(message->src);
9434 goto INTERNAL_ERROR;
9436 src_element_name = GST_ELEMENT_NAME(src_element);
9437 if ( !src_element_name )
9438 goto INTERNAL_ERROR;
9440 factory = gst_element_get_factory(src_element);
9442 goto INTERNAL_ERROR;
9444 klass = gst_element_factory_get_klass(factory);
9446 goto INTERNAL_ERROR;
9448 debug_log("error code=%d, msg=%s, src element=%s, class=%s\n",
9449 error->code, error->message, src_element_name, klass);
9452 switch ( error->code )
9454 case GST_STREAM_ERROR_DECODE:
9456 /* NOTE : Delay is needed because gst callback is sometime sent
9457 * before completing autoplugging.
9458 * Timer is more better than usleep.
9459 * But, transformed msg value should be stored in player handle
9460 * for function to call by timer.
9462 if ( PLAYER_INI()->async_start )
9465 /* Demuxer can't parse one track because it's corrupted.
9466 * So, the decoder for it is not linked.
9467 * But, it has one playable track.
9469 if ( g_strrstr(klass, "Demux") )
9471 if ( player->can_support_codec == FOUND_PLUGIN_VIDEO )
9473 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9475 else if ( player->can_support_codec == FOUND_PLUGIN_AUDIO )
9477 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9481 if ( player->pipeline->audiobin ) // PCM
9483 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9487 goto CODEC_NOT_FOUND;
9491 return MM_ERROR_PLAYER_INVALID_STREAM;
9495 case GST_STREAM_ERROR_WRONG_TYPE:
9497 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9501 case GST_STREAM_ERROR_FAILED:
9503 /* Decoder Custom Message */
9504 if ( strstr(error->message, "ongoing") )
9506 if ( strcasestr(klass, "audio") )
9508 if ( ( player->can_support_codec & FOUND_PLUGIN_VIDEO ) )
9510 debug_log("Video can keep playing.\n");
9511 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9515 goto CODEC_NOT_FOUND;
9519 else if ( strcasestr(klass, "video") )
9521 if ( ( player->can_support_codec & FOUND_PLUGIN_AUDIO ) )
9523 debug_log("Audio can keep playing.\n");
9524 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9528 goto CODEC_NOT_FOUND;
9532 return MM_ERROR_PLAYER_INVALID_STREAM;
9536 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
9538 goto CODEC_NOT_FOUND;
9542 case GST_STREAM_ERROR_DECRYPT:
9544 debug_log("%s failed reason : %s\n", src_element_name, error->message);
9545 return MM_MESSAGE_DRM_NOT_AUTHORIZED;
9555 return MM_ERROR_PLAYER_INVALID_STREAM;
9558 return MM_ERROR_PLAYER_INTERNAL;
9561 debug_log("not found any available codec. Player should be destroyed.\n");
9562 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9566 __mmplayer_post_delayed_eos( mm_player_t* player, int delay_in_ms )
9570 return_if_fail( player );
9572 /* cancel if existing */
9573 __mmplayer_cancel_delayed_eos( player );
9576 /* post now if delay is zero */
9577 if ( delay_in_ms == 0 || player->is_sound_extraction)
9579 debug_log("eos delay is zero. posting EOS now\n");
9580 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9582 if ( player->is_sound_extraction )
9583 __mmplayer_cancel_delayed_eos(player);
9588 /* init new timeout */
9589 /* NOTE : consider give high priority to this timer */
9591 debug_log("posting EOS message after [%d] msec\n", delay_in_ms);
9592 player->eos_timer = g_timeout_add( delay_in_ms,
9593 __mmplayer_eos_timer_cb, player );
9596 /* check timer is valid. if not, send EOS now */
9597 if ( player->eos_timer == 0 )
9599 debug_warning("creating timer for delayed EOS has failed. sending EOS now\n");
9600 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9607 __mmplayer_cancel_delayed_eos( mm_player_t* player )
9611 return_if_fail( player );
9613 if ( player->eos_timer )
9615 g_source_remove( player->eos_timer );
9618 player->eos_timer = 0;
9626 __mmplayer_eos_timer_cb(gpointer u_data)
9628 mm_player_t* player = NULL;
9629 player = (mm_player_t*) u_data;
9633 return_val_if_fail( player, FALSE );
9636 MMPLAYER_POST_MSG( player, MM_MESSAGE_END_OF_STREAM, NULL );
9638 /* cleare timer id */
9639 player->eos_timer = 0;
9643 /* we are returning FALSE as we need only one posting */
9647 static void __mmplayer_set_antishock( mm_player_t* player, gboolean disable_by_force)
9649 gint antishock = FALSE;
9650 MMHandleType attrs = 0;
9654 return_if_fail ( player && player->pipeline );
9656 /* It should be passed for video only clip */
9657 if ( ! player->pipeline->audiobin )
9660 if ( ( g_strrstr(PLAYER_INI()->name_of_audiosink, "avsysaudiosink")) )
9662 attrs = MMPLAYER_GET_ATTRS(player);
9665 debug_error("fail to get attributes.\n");
9669 mm_attrs_get_int_by_name(attrs, "sound_fadeup", &antishock);
9671 debug_log("setting antishock as (%d)\n", antishock);
9673 if ( disable_by_force )
9675 debug_log("but, antishock is disabled by force when is seeked\n");
9680 g_object_set(G_OBJECT(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), "fadeup", antishock, NULL);
9690 __mmplayer_link_decoder( mm_player_t* player, GstPad *srcpad)
9692 const gchar* name = NULL;
9693 GstStructure* str = NULL;
9694 GstCaps* srccaps = NULL;
9698 return_val_if_fail( player, FALSE );
9699 return_val_if_fail ( srcpad, FALSE );
9701 /* to check any of the decoder (video/audio) need to be linked to parser*/
9702 srccaps = gst_pad_get_caps( srcpad );
9706 str = gst_caps_get_structure( srccaps, 0 );
9710 name = gst_structure_get_name(str);
9714 if (strstr(name, "video"))
9716 if(player->videodec_linked)
9718 debug_msg("Video decoder already linked\n");
9722 if (strstr(name, "audio"))
9724 if(player->audiodec_linked)
9726 debug_msg("Audio decoder already linked\n");
9731 gst_caps_unref( srccaps );
9739 gst_caps_unref( srccaps );
9745 __mmplayer_link_sink( mm_player_t* player , GstPad *srcpad)
9747 const gchar* name = NULL;
9748 GstStructure* str = NULL;
9749 GstCaps* srccaps = NULL;
9753 return_val_if_fail ( player, FALSE );
9754 return_val_if_fail ( srcpad, FALSE );
9756 /* to check any of the decoder (video/audio) need to be linked to parser*/
9757 srccaps = gst_pad_get_caps( srcpad );
9761 str = gst_caps_get_structure( srccaps, 0 );
9765 name = gst_structure_get_name(str);
9769 if (strstr(name, "video"))
9771 if(player->videosink_linked)
9773 debug_msg("Video Sink already linked\n");
9777 if (strstr(name, "audio"))
9779 if(player->audiosink_linked)
9781 debug_msg("Audio Sink already linked\n");
9785 if (strstr(name, "text"))
9787 if(player->textsink_linked)
9789 debug_msg("Text Sink already linked\n");
9794 gst_caps_unref( srccaps );
9799 //return (!player->videosink_linked || !player->audiosink_linked);
9803 gst_caps_unref( srccaps );
9809 /* sending event to one of sinkelements */
9811 __gst_send_event_to_sink( mm_player_t* player, GstEvent* event )
9813 GList *sinks = NULL;
9814 gboolean res = FALSE;
9818 return_val_if_fail( player, FALSE );
9819 return_val_if_fail ( event, FALSE );
9821 sinks = player->sink_elements;
9824 GstElement *sink = GST_ELEMENT_CAST (sinks->data);
9826 if (GST_IS_ELEMENT(sink))
9828 /* keep ref to the event */
9829 gst_event_ref (event);
9831 if ( (res = gst_element_send_event (sink, event)) )
9833 debug_log("sending event[%s] to sink element [%s] success!\n",
9834 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9838 debug_log("sending event[%s] to sink element [%s] failed. try with next one.\n",
9839 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink) );
9842 sinks = g_list_next (sinks);
9845 /* Note : Textbin is not linked to the video or audio bin.
9846 * It needs to send the event to the text sink seperatelly.
9848 if ( MMPLAYER_PLAY_SUBTITLE(player) )
9850 GstElement *subtitle_sink = GST_ELEMENT_CAST (player->pipeline->subtitlebin[MMPLAYER_SUB_SINK].gst);
9852 if ( (res != gst_element_send_event (subtitle_sink, event)) )
9854 debug_error("sending event[%s] to subtitle sink element [%s] failed!\n",
9855 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
9859 debug_log("sending event[%s] to subtitle sink element [%s] success!\n",
9860 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(subtitle_sink) );
9864 gst_event_unref (event);
9872 __mmplayer_add_sink( mm_player_t* player, GstElement* sink )
9876 return_if_fail ( player );
9877 return_if_fail ( sink );
9879 player->sink_elements =
9880 g_list_append(player->sink_elements, sink);
9886 __mmplayer_del_sink( mm_player_t* player, GstElement* sink )
9890 return_if_fail ( player );
9891 return_if_fail ( sink );
9893 player->sink_elements =
9894 g_list_remove(player->sink_elements, sink);
9900 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
9901 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
9902 gint64 cur, GstSeekType stop_type, gint64 stop )
9904 GstEvent* event = NULL;
9905 gboolean result = FALSE;
9909 return_val_if_fail( player, FALSE );
9911 event = gst_event_new_seek (rate, format, flags, cur_type,
9912 cur, stop_type, stop);
9914 result = __gst_send_event_to_sink( player, event );
9921 /* NOTE : be careful with calling this api. please refer to below glib comment
9922 * glib comment : Note that there is a bug in GObject that makes this function much
9923 * less useful than it might seem otherwise. Once gobject is disposed, the callback
9924 * will no longer be called, but, the signal handler is not currently disconnected.
9925 * If the instance is itself being freed at the same time than this doesn't matter,
9926 * since the signal will automatically be removed, but if instance persists,
9927 * then the signal handler will leak. You should not remove the signal yourself
9928 * because in a future versions of GObject, the handler will automatically be
9931 * It's possible to work around this problem in a way that will continue to work
9932 * with future versions of GObject by checking that the signal handler is still
9933 * connected before disconnected it:
9935 * if (g_signal_handler_is_connected (instance, id))
9936 * g_signal_handler_disconnect (instance, id);
9939 __mmplayer_release_signal_connection(mm_player_t* player)
9941 GList* sig_list = player->signals;
9942 MMPlayerSignalItem* item = NULL;
9946 return_if_fail( player );
9948 for ( ; sig_list; sig_list = sig_list->next )
9950 item = sig_list->data;
9952 if ( item && item->obj && GST_IS_ELEMENT(item->obj) )
9954 debug_log("checking signal connection : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
9956 if ( g_signal_handler_is_connected ( item->obj, item->sig ) )
9958 debug_log("signal disconnecting : [%lud] from [%s]\n", item->sig, GST_OBJECT_NAME( item->obj ));
9959 g_signal_handler_disconnect ( item->obj, item->sig );
9963 MMPLAYER_FREEIF( item );
9966 g_list_free ( player->signals );
9967 player->signals = NULL;
9975 /* Note : if silent is true, then subtitle would not be displayed. :*/
9976 int _mmplayer_set_subtitle_silent (MMHandleType hplayer, int silent)
9978 mm_player_t* player = (mm_player_t*) hplayer;
9982 /* check player handle */
9983 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
9984 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
9986 player->is_subtitle_off = silent;
9988 debug_log("subtitle is %s.\n", player->is_subtitle_off ? "ON" : "OFF");
9992 return MM_ERROR_NONE;
9996 int _mmplayer_get_subtitle_silent (MMHandleType hplayer, int* silent)
9998 mm_player_t* player = (mm_player_t*) hplayer;
10002 /* check player handle */
10003 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED );
10004 return_val_if_fail ( MMPLAYER_PLAY_SUBTITLE(player), MM_ERROR_PLAYER_NOT_INITIALIZED );
10006 *silent = player->is_subtitle_off;
10008 debug_log("subtitle is %s.\n", silent ? "ON" : "OFF");
10012 return MM_ERROR_NONE;
10015 int _mmplayer_get_track_count(MMHandleType hplayer, MMPlayerTrackType track_type, int *count)
10017 mm_player_t* player = (mm_player_t*) hplayer;
10018 MMHandleType attrs = 0;
10019 int ret = MM_ERROR_NONE;
10023 /* check player handle */
10024 return_val_if_fail(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10025 return_val_if_fail(count, MM_ERROR_COMMON_INVALID_ARGUMENT);
10026 return_val_if_fail((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
10027 ||(MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING),
10028 MM_ERROR_PLAYER_INVALID_STATE);
10030 attrs = MMPLAYER_GET_ATTRS(player);
10033 debug_error("cannot get content attribute");
10034 return MM_ERROR_PLAYER_INTERNAL;
10037 switch (track_type)
10039 case MM_PLAYER_TRACK_TYPE_AUDIO:
10040 ret = mm_attrs_get_int_by_name(attrs, "content_audio_track_num", count);
10042 case MM_PLAYER_TRACK_TYPE_VIDEO:
10043 ret = mm_attrs_get_int_by_name(attrs, "content_video_track_num", count);
10045 case MM_PLAYER_TRACK_TYPE_TEXT:
10046 ret = mm_attrs_get_int_by_name(attrs, "content_text_track_num", count);
10049 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
10053 debug_log ("%d track num is %d\n", track_type, *count);
10063 __get_state_name ( int state )
10067 case MM_PLAYER_STATE_NULL:
10069 case MM_PLAYER_STATE_READY:
10071 case MM_PLAYER_STATE_PAUSED:
10073 case MM_PLAYER_STATE_PLAYING:
10075 case MM_PLAYER_STATE_NONE:
10082 __is_rtsp_streaming ( mm_player_t* player )
10084 return_val_if_fail ( player, FALSE );
10086 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP ) ? TRUE : FALSE;
10090 __is_http_streaming ( mm_player_t* player )
10092 return_val_if_fail ( player, FALSE );
10094 return ( player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP ) ? TRUE : FALSE;
10098 __is_streaming ( mm_player_t* player )
10100 return_val_if_fail ( player, FALSE );
10102 return ( __is_rtsp_streaming ( player ) || __is_http_streaming ( player ) || __is_http_live_streaming ( player )) ? TRUE : FALSE;
10106 __is_live_streaming ( mm_player_t* player )
10108 return_val_if_fail ( player, FALSE );
10110 return ( __is_rtsp_streaming ( player ) && player->streaming_type == STREAMING_SERVICE_LIVE ) ? TRUE : FALSE;
10114 __is_http_live_streaming( mm_player_t* player )
10116 return_val_if_fail( player, FALSE );
10118 return ( (player->ahs_player) && (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ) ? TRUE : FALSE;
10122 __is_http_progressive_down(mm_player_t* player)
10124 return_val_if_fail( player, FALSE );
10126 return ((player->pd_mode) ? TRUE:FALSE);