From c4e27f450eb6baa7f0f4d06ff851c1be0ed9fbc7 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Mon, 8 Aug 2016 11:13:38 +0900 Subject: [PATCH 01/16] Change variable type and property name video_cea_supprt/video_vesa_support/video_hh_support to guint64 video_param -> wfd-video-formats audio_param -> wfd-audio-codecs hdcp_param -> wfd-content-protection pause -> request-pause resume -> request-resume close -> request-close debug -> dump-rtsp-message Signed-off-by: SeokHoon Lee Change-Id: I5138a8f0ed732b7f7c299682ff33c7c343769ba7 --- packaging/gst-plugins-tizen.spec | 2 +- waylandsrc/src/gstwaylandsrc.c | 7 +- waylandsrc/src/gstwaylandsrc.h | 7 - wfdmanager/wfdbase/gstwfdbasesrc.c | 452 ++-- wfdmanager/wfdbase/gstwfdbasesrc.c.orig | 4016 ------------------------------- wfdmanager/wfdbase/gstwfdbasesrc.h | 10 +- wfdmanager/wfdbase/gstwfdsinkmessage.c | 26 +- wfdmanager/wfdbase/gstwfdsinkmessage.h | 184 +- 8 files changed, 382 insertions(+), 4322 deletions(-) mode change 100755 => 100644 wfdmanager/wfdbase/gstwfdbasesrc.c delete mode 100755 wfdmanager/wfdbase/gstwfdbasesrc.c.orig mode change 100755 => 100644 wfdmanager/wfdbase/gstwfdbasesrc.h mode change 100755 => 100644 wfdmanager/wfdbase/gstwfdsinkmessage.c mode change 100755 => 100644 wfdmanager/wfdbase/gstwfdsinkmessage.h diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index f0e4223..c73b558 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 25 +Release: 26 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/waylandsrc/src/gstwaylandsrc.c b/waylandsrc/src/gstwaylandsrc.c index abaadf1..53904af 100644 --- a/waylandsrc/src/gstwaylandsrc.c +++ b/waylandsrc/src/gstwaylandsrc.c @@ -618,6 +618,7 @@ tbm_buffer_create (GstWaylandSrc * src) struct output_buffer *out_buffer = NULL; tbm_bufmgr bufmgr; tbm_surface_info_s info; + int bo_num; if (src->tbm_client == NULL) { GST_ERROR_OBJECT (src, "wayland tbm client is NULL"); @@ -692,6 +693,8 @@ tbm_buffer_create (GstWaylandSrc * src) tbm_bo_alloc (bufmgr, info.size, TBM_BO_DEFAULT); if (out_buffer->bo[0] == NULL) goto failed; + + bo_num = 1; #else out_buffer->bo[0] = tbm_bo_alloc (bufmgr, info.planes[0].size, TBM_BO_DEFAULT); @@ -702,10 +705,12 @@ tbm_buffer_create (GstWaylandSrc * src) tbm_bo_alloc (bufmgr, info.planes[1].size, TBM_BO_DEFAULT); if (out_buffer->bo[1] == NULL) goto failed; + + bo_num = 2; #endif out_buffer->surface = - tbm_surface_internal_create_with_bos(&info, out_buffer->bo, NUMBER_OF_BOS); + tbm_surface_internal_create_with_bos(&info, out_buffer->bo, bo_num); if (out_buffer->surface == NULL) goto failed; diff --git a/waylandsrc/src/gstwaylandsrc.h b/waylandsrc/src/gstwaylandsrc.h index 60f309c..ababdea 100644 --- a/waylandsrc/src/gstwaylandsrc.h +++ b/waylandsrc/src/gstwaylandsrc.h @@ -139,13 +139,6 @@ GType gst_wayland_src_get_type (void) G_GNUC_CONST; -/* Number of BO */ -#ifdef TIZEN_PROFILE_LITE -#define NUMBER_OF_BOS 1 -#else -#define NUMBER_OF_BOS 2 -#endif - /*MFC Buffer alignment macros*/ #define S5P_FIMV_DEC_BUF_ALIGN (8 * 1024) #define S5P_FIMV_ENC_BUF_ALIGN (8 * 1024) diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c old mode 100755 new mode 100644 index 749a9a1..bdc4d30 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -117,16 +117,16 @@ enum { SIGNAL_UPDATE_MEDIA_INFO, SIGNAL_AV_FORMAT_CHANGE, - SIGNAL_PAUSE, - SIGNAL_RESUME, - SIGNAL_CLOSE, + SIGNAL_REQUEST_PAUSE, + SIGNAL_REQUEST_RESUME, + SIGNAL_REQUEST_CLOSE, SIGNAL_SET_STANDBY, LAST_SIGNAL }; /* properties default values */ #define DEFAULT_LOCATION NULL -#define DEFAULT_DEBUG FALSE +#define DEFAULT_DUMP_RTSP_MESSAGE FALSE #define DEFAULT_RETRY 50 #define DEFAULT_TCP_TIMEOUT 20000000 #define DEFAULT_PROXY NULL @@ -144,14 +144,14 @@ enum { PROP_0, PROP_LOCATION, - PROP_DEBUG, + PROP_DUMP_RTSP_MESSAGE, PROP_RETRY, PROP_TCP_TIMEOUT, PROP_RTP_BLOCKSIZE, PROP_USER_AGENT, - PROP_AUDIO_PARAM, - PROP_VIDEO_PARAM, - PROP_HDCP_PARAM, + PROP_WFD_AUDIO_CODECS, + PROP_WFD_VIDEO_FORMATS, + PROP_WFD_CONTENT_PROTECTION, PROP_ENABLE_PAD_PROBE, PROP_LAST }; @@ -162,8 +162,8 @@ enum #define WFD_CMD_PAUSE (1 << 2) #define WFD_CMD_CLOSE (1 << 3) #define WFD_CMD_WAIT (1 << 4) -#define WFD_CMD_REQUEST (1 << 6) -#define WFD_CMD_LOOP (1 << 7) +#define WFD_CMD_REQUEST (1 << 5) +#define WFD_CMD_LOOP (1 << 6) #define WFD_CMD_ALL ((WFD_CMD_LOOP << 1) - 1) #define GST_ELEMENT_PROGRESS(el, type, code, text) \ @@ -203,14 +203,14 @@ struct _GstWFDBaseSrcPrivate gboolean do_stop; /* properties */ - gboolean debug; + gboolean dump_rtsp_message; guint retry; GTimeVal tcp_timeout; GTimeVal *ptcp_timeout; guint rtp_blocksize; - GstStructure *audio_param; - GstStructure *video_param; - GstStructure *hdcp_param; + GstStructure *wfd_audio_codecs; + GstStructure *wfd_video_formats; + GstStructure *wfd_content_protection; gchar *user_agent; /* Set RTP port */ @@ -227,7 +227,7 @@ struct _GstWFDBaseSrcPrivate guint video_height; guint video_width; guint video_framerate; - gchar * audio_format; + gchar *audio_format; guint audio_channels; guint audio_bitwidth; guint audio_frequency; @@ -248,8 +248,10 @@ static gboolean gst_wfd_base_src_send_event (GstElement * element, GstEvent * ev static void gst_wfd_base_src_handle_message (GstBin * bin, GstMessage * message); /* pad */ -static gboolean gst_wfd_base_src_handle_src_event (GstPad * pad, GstObject *parent, GstEvent * event); -static gboolean gst_wfd_base_src_handle_src_query(GstPad * pad, GstObject *parent, GstQuery * query); +static gboolean gst_wfd_base_src_handle_src_event (GstPad * pad, + GstObject *parent, GstEvent * event); +static gboolean gst_wfd_base_src_handle_src_query(GstPad * pad, + GstObject *parent, GstQuery * query); /* fundemental functions */ static GstRTSPResult gst_wfd_base_src_open (GstWFDBaseSrc * src); @@ -257,9 +259,11 @@ static gboolean gst_wfd_base_src_setup (GstWFDBaseSrc * src); static GstRTSPResult gst_wfd_base_src_play (GstWFDBaseSrc * src); static GstRTSPResult gst_wfd_base_src_pause (GstWFDBaseSrc * src); static GstRTSPResult gst_wfd_base_src_close (GstWFDBaseSrc * src, gboolean only_close); -static void gst_wfd_base_src_send_pause_cmd (GstWFDBaseSrc * src); -static void gst_wfd_base_src_send_play_cmd (GstWFDBaseSrc * src); -static void gst_wfd_base_src_send_close_cmd (GstWFDBaseSrc * src); + +/* actions */ +static void gst_wfd_base_src_request_pause (GstWFDBaseSrc * src); +static void gst_wfd_base_src_request_resume (GstWFDBaseSrc * src); +static void gst_wfd_base_src_request_close (GstWFDBaseSrc * src); static void gst_wfd_base_src_set_standby (GstWFDBaseSrc * src); /* URI interface */ @@ -281,11 +285,13 @@ static GstRTSPResult gst_wfd_base_src_send (GstWFDBaseSrc * src, GstRTSPMessage * request, GstRTSPMessage * response, GstRTSPStatusCode * code); -static GstRTSPResult gst_wfd_base_src_get_video_parameter(GstWFDBaseSrc * src, GstWFDMessage *msg); -static GstRTSPResult gst_wfd_base_src_get_audio_parameter(GstWFDBaseSrc * src, GstWFDMessage *msg); +static GstRTSPResult gst_wfd_base_src_get_wfd_video_formatseter(GstWFDBaseSrc * src, + GstWFDMessage *msg); +static GstRTSPResult gst_wfd_base_src_get_wfd_audio_codecseter(GstWFDBaseSrc * src, + GstWFDMessage *msg); /* util */ -static GstRTSPResult _rtsp_message_dump (GstRTSPMessage * msg); +static void _dump_rtsp_message (GstRTSPMessage * msg); static const char *_cmd_to_string (guint cmd); static guint gst_wfd_base_src_signals[LAST_SIGNAL] = { 0 }; @@ -359,10 +365,10 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) "Location of the RTSP url to read", DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DEBUG, - g_param_spec_boolean ("debug", "Debug", - "Dump request and response messages to stdout", - DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DUMP_RTSP_MESSAGE, + g_param_spec_boolean ("dump-rtsp-message", "Dump RTSP Message", + "Dump request and response RTSP messages to stdout", + DEFAULT_DUMP_RTSP_MESSAGE, G_PARAM_READWRITE |G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RETRY, g_param_spec_uint ("retry", "Retry", @@ -387,9 +393,9 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) "User agent specified string", DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_AUDIO_PARAM, - g_param_spec_boxed ("audio-param", "audio parameters", - "A GstStructure mapped for wfd audio parameters, " + g_object_class_install_property (gobject_class, PROP_WFD_AUDIO_CODECS, + g_param_spec_boxed ("wfd-audio-codecs", "Wi-Fi Display Audio codecs", + "A GstStructure mapped for Wi-Fi Display audio codecs parameters, " "See all attributes in WFD specification(wfd-audio-codecs)." "\n audio_codec: LPCM:0x01, AAC:0x02, AC3:0x04" "\n audio_latency: an integer" @@ -397,15 +403,15 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) "\n audio_sampling_frequency: 44.1khz:1, 48khz:2\n", GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_VIDEO_PARAM, - g_param_spec_boxed ("video-param", "video parameters", - "A GstStructure mapped for wfd video parameters, " + g_object_class_install_property (gobject_class, PROP_WFD_VIDEO_FORMATS, + g_param_spec_boxed ("wfd-video-formats", "Wi-Fi Display Video Formats", + "A GstStructure mapped for Wi-Fi Dispaly video formats parameters, " "See all attributes in WFD specification(wfd-video-formats).\n", GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_HDCP_PARAM, - g_param_spec_boxed ("hdcp-param", "HDCP parameters", - "A GstStructure mapped for WFD HDCP parameters." + g_object_class_install_property (gobject_class, PROP_WFD_CONTENT_PROTECTION, + g_param_spec_boxed ("wfd-content-protection", "Wi-Fi Display Content Protection", + "A GstStructure mapped for Wi-Fi Display Content Protection HDCP parameters." "\n hdcp_version: none:0, 2.0:1, 2.1:2" "\n hdcp_port_no: an integer\n", GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); @@ -425,22 +431,22 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWFDBaseSrcClass, change_av_format), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - gst_wfd_base_src_signals[SIGNAL_PAUSE] = - g_signal_new ("pause", G_TYPE_FROM_CLASS (klass), + gst_wfd_base_src_signals[SIGNAL_REQUEST_PAUSE] = + g_signal_new ("request-pause", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, pause), NULL, NULL, + G_STRUCT_OFFSET (GstWFDBaseSrcClass, request_pause), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - gst_wfd_base_src_signals[SIGNAL_RESUME] = - g_signal_new ("resume", G_TYPE_FROM_CLASS (klass), + gst_wfd_base_src_signals[SIGNAL_REQUEST_RESUME] = + g_signal_new ("request-resume", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, resume), NULL, NULL, + G_STRUCT_OFFSET (GstWFDBaseSrcClass, request_resume), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - gst_wfd_base_src_signals[SIGNAL_CLOSE] = - g_signal_new ("close", G_TYPE_FROM_CLASS (klass), + gst_wfd_base_src_signals[SIGNAL_REQUEST_CLOSE] = + g_signal_new ("request-close", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, close), NULL, NULL, + G_STRUCT_OFFSET (GstWFDBaseSrcClass, request_close), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); gst_wfd_base_src_signals[SIGNAL_SET_STANDBY] = @@ -460,19 +466,20 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_wfd_base_src_src_template)); - klass->pause = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_pause_cmd); - klass->resume = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_play_cmd); - klass->close = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_close_cmd); - klass->set_standby = GST_DEBUG_FUNCPTR (gst_wfd_base_src_set_standby); - klass->push_event = GST_DEBUG_FUNCPTR (gst_wfd_base_src_push_event); + + /* actions */ + klass->request_pause = GST_DEBUG_FUNCPTR (gst_wfd_base_src_request_pause); + klass->request_resume = GST_DEBUG_FUNCPTR (gst_wfd_base_src_request_resume); + klass->request_close = GST_DEBUG_FUNCPTR (gst_wfd_base_src_request_close); + klass->set_standby = GST_DEBUG_FUNCPTR (gst_wfd_base_src_set_standby); } static GstStructure * -gst_wfd_rtsp_set_default_audio_param () +gst_wfd_rtsp_set_default_wfd_audio_codecs () { GstStructure *param = NULL; - param = gst_structure_new ("audio_param", + param = gst_structure_new ("wfd_audio_codecs", "audio_codec", G_TYPE_UINT, 0x3, "audio_latency", G_TYPE_UINT, 0x0, "audio_channels", G_TYPE_UINT, 0x3, @@ -483,15 +490,15 @@ gst_wfd_rtsp_set_default_audio_param () } static GstStructure * -gst_wfd_rtsp_set_default_video_param () +gst_wfd_rtsp_set_default_wfd_video_formats () { GstStructure *param = NULL; - param = gst_structure_new ("video_param", + param = gst_structure_new ("wfd_video_formats", "video_codec", G_TYPE_UINT, 0x1, "video_native_resolution", G_TYPE_UINT, 0x20, - "video_cea_support", G_TYPE_UINT, 0x194ab, - "video_vesa_support", G_TYPE_UINT, 0x15555555, - "video_hh_support", G_TYPE_UINT, 0x555, + "video_cea_support", G_TYPE_UINT64, 0x194abULL, + "video_vesa_support", G_TYPE_UINT64, 0x15555555ULL, + "video_hh_support", G_TYPE_UINT64, 0x555ULL, "video_profile", G_TYPE_UINT, 0x1, "video_level", G_TYPE_UINT, 0x2, "video_latency", G_TYPE_UINT, 0x0, @@ -526,14 +533,14 @@ gst_wfd_base_src_init (GstWFDBaseSrc * src, gpointer g_class) src->priv->conninfo.location = g_strdup (DEFAULT_LOCATION); src->priv->conninfo.url_str = NULL; - src->priv->debug = DEFAULT_DEBUG; + src->priv->dump_rtsp_message = DEFAULT_DUMP_RTSP_MESSAGE; src->priv->retry = DEFAULT_RETRY; gst_wfd_base_src_set_tcp_timeout (src, DEFAULT_TCP_TIMEOUT); src->priv->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE; src->priv->user_agent = g_strdup (DEFAULT_USER_AGENT); - src->priv->hdcp_param = NULL; - src->priv->audio_param = gst_wfd_rtsp_set_default_audio_param (); - src->priv->video_param = gst_wfd_rtsp_set_default_video_param (); + src->priv->wfd_audio_codecs = gst_wfd_rtsp_set_default_wfd_audio_codecs (); + src->priv->wfd_video_formats = gst_wfd_rtsp_set_default_wfd_video_formats (); + src->priv->wfd_content_protection = NULL; src->priv->timebase = -1; src->priv->seqbase = -1; gst_rtsp_transport_init(&src->priv->transport); @@ -587,15 +594,15 @@ gst_wfd_base_src_finalize (GObject * object) if (src->priv->user_agent) g_free (src->priv->user_agent); src->priv->user_agent = NULL; - if(src->priv->audio_param) - gst_structure_free(src->priv->audio_param); - src->priv->audio_param = NULL; - if(src->priv->video_param) - gst_structure_free(src->priv->video_param); - src->priv->video_param = NULL; - if(src->priv->hdcp_param) - gst_structure_free(src->priv->hdcp_param); - src->priv->hdcp_param = NULL; + if(src->priv->wfd_audio_codecs) + gst_structure_free(src->priv->wfd_audio_codecs); + src->priv->wfd_audio_codecs = NULL; + if(src->priv->wfd_video_formats) + gst_structure_free(src->priv->wfd_video_formats); + src->priv->wfd_video_formats = NULL; + if(src->priv->wfd_content_protection) + gst_structure_free(src->priv->wfd_content_protection); + src->priv->wfd_content_protection = NULL; /* free locks */ g_rec_mutex_clear (&(src->state_rec_lock)); @@ -634,8 +641,8 @@ gst_wfd_base_src_set_property (GObject * object, guint prop_id, const GValue * v gst_wfd_base_src_uri_set_uri (GST_URI_HANDLER (src), g_value_get_string (value), &err); break; - case PROP_DEBUG: - src->priv->debug = g_value_get_boolean (value); + case PROP_DUMP_RTSP_MESSAGE: + src->priv->dump_rtsp_message = g_value_get_boolean (value); break; case PROP_RETRY: src->priv->retry = g_value_get_uint (value); @@ -651,37 +658,37 @@ gst_wfd_base_src_set_property (GObject * object, guint prop_id, const GValue * v g_free(src->priv->user_agent); src->priv->user_agent = g_value_dup_string (value); break; - case PROP_AUDIO_PARAM: + case PROP_WFD_AUDIO_CODECS: { const GstStructure *s = gst_value_get_structure (value); - if (src->priv->audio_param) - gst_structure_free (src->priv->audio_param); + if (src->priv->wfd_audio_codecs) + gst_structure_free (src->priv->wfd_audio_codecs); if (s) - src->priv->audio_param = gst_structure_copy (s); + src->priv->wfd_audio_codecs = gst_structure_copy (s); else - src->priv->audio_param = NULL; + src->priv->wfd_audio_codecs = NULL; break; } - case PROP_VIDEO_PARAM: + case PROP_WFD_VIDEO_FORMATS: { const GstStructure *s = gst_value_get_structure (value); - if (src->priv->video_param) - gst_structure_free (src->priv->video_param); + if (src->priv->wfd_video_formats) + gst_structure_free (src->priv->wfd_video_formats); if (s) - src->priv->video_param = gst_structure_copy (s); + src->priv->wfd_video_formats = gst_structure_copy (s); else - src->priv->video_param = NULL; + src->priv->wfd_video_formats = NULL; break; } - case PROP_HDCP_PARAM: + case PROP_WFD_CONTENT_PROTECTION: { const GstStructure *s = gst_value_get_structure (value); - if (src->priv->hdcp_param) - gst_structure_free (src->priv->hdcp_param); + if (src->priv->wfd_content_protection) + gst_structure_free (src->priv->wfd_content_protection); if (s) - src->priv->hdcp_param = gst_structure_copy (s); + src->priv->wfd_content_protection = gst_structure_copy (s); else - src->priv->hdcp_param = NULL; + src->priv->wfd_content_protection = NULL; break; } case PROP_ENABLE_PAD_PROBE: @@ -703,8 +710,8 @@ gst_wfd_base_src_get_property (GObject * object, guint prop_id, GValue * value, case PROP_LOCATION: g_value_set_string (value, src->priv->conninfo.location); break; - case PROP_DEBUG: - g_value_set_boolean (value, src->priv->debug); + case PROP_DUMP_RTSP_MESSAGE: + g_value_set_boolean (value, src->priv->dump_rtsp_message); break; case PROP_RETRY: g_value_set_uint (value, src->priv->retry); @@ -724,14 +731,14 @@ gst_wfd_base_src_get_property (GObject * object, guint prop_id, GValue * value, case PROP_USER_AGENT: g_value_set_string (value, src->priv->user_agent); break; - case PROP_AUDIO_PARAM: - gst_value_set_structure (value, src->priv->audio_param); + case PROP_WFD_AUDIO_CODECS: + gst_value_set_structure (value, src->priv->wfd_audio_codecs); break; - case PROP_VIDEO_PARAM: - gst_value_set_structure (value, src->priv->video_param); + case PROP_WFD_VIDEO_FORMATS: + gst_value_set_structure (value, src->priv->wfd_video_formats); break; - case PROP_HDCP_PARAM: - gst_value_set_structure (value, src->priv->hdcp_param); + case PROP_WFD_CONTENT_PROTECTION: + gst_value_set_structure (value, src->priv->wfd_content_protection); break; case PROP_ENABLE_PAD_PROBE: g_value_set_boolean (value, src->enable_pad_probe); @@ -789,8 +796,8 @@ gst_wfd_base_src_connection_send (GstWFDBaseSrc * src, { GstRTSPResult ret = GST_RTSP_OK; - if (src->priv->debug) - _rtsp_message_dump (message); + if (src->priv->dump_rtsp_message) + _dump_rtsp_message (message); if (src->priv->conninfo.connection) ret = gst_rtsp_connection_send (src->priv->conninfo.connection, message, timeout); @@ -811,8 +818,8 @@ gst_wfd_base_src_connection_receive (GstWFDBaseSrc * src, else ret = GST_RTSP_ERROR; - if (src->priv->debug) - _rtsp_message_dump (message); + if (src->priv->dump_rtsp_message) + _dump_rtsp_message (message); return ret; } @@ -1396,16 +1403,16 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) guint audio_channels = 0; guint audio_latency = 0; - if(priv->audio_param != NULL) { - GstStructure *audio_param = priv->audio_param; - if (gst_structure_has_field (audio_param, "audio_codec")) - gst_structure_get_uint (audio_param, "audio_codec", &audio_codec); - if (gst_structure_has_field (audio_param, "audio_latency")) - gst_structure_get_uint (audio_param, "audio_latency", &audio_latency); - if (gst_structure_has_field (audio_param, "audio_channels")) - gst_structure_get_uint (audio_param, "audio_channels", &audio_channels); - if (gst_structure_has_field (audio_param, "audio_sampling_frequency")) - gst_structure_get_uint (audio_param, "audio_sampling_frequency", &audio_sampling_frequency); + if(priv->wfd_audio_codecs != NULL) { + GstStructure *wfd_audio_codecs = priv->wfd_audio_codecs; + if (gst_structure_has_field (wfd_audio_codecs, "audio_codec")) + gst_structure_get_uint (wfd_audio_codecs, "audio_codec", &audio_codec); + if (gst_structure_has_field (wfd_audio_codecs, "audio_latency")) + gst_structure_get_uint (wfd_audio_codecs, "audio_latency", &audio_latency); + if (gst_structure_has_field (wfd_audio_codecs, "audio_channels")) + gst_structure_get_uint (wfd_audio_codecs, "audio_channels", &audio_channels); + if (gst_structure_has_field (wfd_audio_codecs, "audio_sampling_frequency")) + gst_structure_get_uint (wfd_audio_codecs, "audio_sampling_frequency", &audio_sampling_frequency); } wfd_res = gst_wfd_message_set_supported_audio_format (wfd_msg, @@ -1428,9 +1435,9 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) if(wfd_msg->video_formats) { guint video_codec = 0; guint video_native_resolution = 0; - guint video_cea_support = 0; - guint video_vesa_support = 0; - guint video_hh_support = 0; + guint64 video_cea_support = 0; + guint64 video_vesa_support = 0; + guint64 video_hh_support = 0; guint video_profile = 0; guint video_level = 0; guint video_latency = 0; @@ -1440,35 +1447,35 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) gint video_slice_enc_param = 0; gint video_framerate_control_support = 0; - if (priv->video_param != NULL) { - GstStructure *video_param = priv->video_param; - - if (gst_structure_has_field (video_param, "video_codec")) - gst_structure_get_uint (video_param, "video_codec", &video_codec); - if (gst_structure_has_field (video_param, "video_native_resolution")) - gst_structure_get_uint (video_param, "video_native_resolution", &video_native_resolution); - if (gst_structure_has_field (video_param, "video_cea_support")) - gst_structure_get_uint (video_param, "video_cea_support", &video_cea_support); - if (gst_structure_has_field (video_param, "video_vesa_support")) - gst_structure_get_uint (video_param, "video_vesa_support", &video_vesa_support); - if (gst_structure_has_field (video_param, "video_hh_support")) - gst_structure_get_uint (video_param, "video_hh_support", &video_hh_support); - if (gst_structure_has_field (video_param, "video_profile")) - gst_structure_get_uint (video_param, "video_profile", &video_profile); - if (gst_structure_has_field (video_param, "video_level")) - gst_structure_get_uint (video_param, "video_level", &video_level); - if (gst_structure_has_field (video_param, "video_latency")) - gst_structure_get_uint (video_param, "video_latency", &video_latency); - if (gst_structure_has_field (video_param, "video_vertical_resolution")) - gst_structure_get_int (video_param, "video_vertical_resolution", &video_vertical_resolution); - if (gst_structure_has_field (video_param, "video_horizontal_resolution")) - gst_structure_get_int (video_param, "video_horizontal_resolution", &video_horizontal_resolution); - if (gst_structure_has_field (video_param, "video_minimum_slicing")) - gst_structure_get_int (video_param, "video_minimum_slicing", &video_minimum_slicing); - if (gst_structure_has_field (video_param, "video_slice_enc_param")) - gst_structure_get_int (video_param, "video_slice_enc_param", &video_slice_enc_param); - if (gst_structure_has_field (video_param, "video_framerate_control_support")) - gst_structure_get_int (video_param, "video_framerate_control_support", &video_framerate_control_support); + if (priv->wfd_video_formats != NULL) { + GstStructure *wfd_video_formats = priv->wfd_video_formats; + + if (gst_structure_has_field (wfd_video_formats, "video_codec")) + gst_structure_get_uint (wfd_video_formats, "video_codec", &video_codec); + if (gst_structure_has_field (wfd_video_formats, "video_native_resolution")) + gst_structure_get_uint (wfd_video_formats, "video_native_resolution", &video_native_resolution); + if (gst_structure_has_field (wfd_video_formats, "video_cea_support")) + gst_structure_get_uint64 (wfd_video_formats, "video_cea_support", &video_cea_support); + if (gst_structure_has_field (wfd_video_formats, "video_vesa_support")) + gst_structure_get_uint64 (wfd_video_formats, "video_vesa_support", &video_vesa_support); + if (gst_structure_has_field (wfd_video_formats, "video_hh_support")) + gst_structure_get_uint64 (wfd_video_formats, "video_hh_support", &video_hh_support); + if (gst_structure_has_field (wfd_video_formats, "video_profile")) + gst_structure_get_uint (wfd_video_formats, "video_profile", &video_profile); + if (gst_structure_has_field (wfd_video_formats, "video_level")) + gst_structure_get_uint (wfd_video_formats, "video_level", &video_level); + if (gst_structure_has_field (wfd_video_formats, "video_latency")) + gst_structure_get_uint (wfd_video_formats, "video_latency", &video_latency); + if (gst_structure_has_field (wfd_video_formats, "video_vertical_resolution")) + gst_structure_get_int (wfd_video_formats, "video_vertical_resolution", &video_vertical_resolution); + if (gst_structure_has_field (wfd_video_formats, "video_horizontal_resolution")) + gst_structure_get_int (wfd_video_formats, "video_horizontal_resolution", &video_horizontal_resolution); + if (gst_structure_has_field (wfd_video_formats, "video_minimum_slicing")) + gst_structure_get_int (wfd_video_formats, "video_minimum_slicing", &video_minimum_slicing); + if (gst_structure_has_field (wfd_video_formats, "video_slice_enc_param")) + gst_structure_get_int (wfd_video_formats, "video_slice_enc_param", &video_slice_enc_param); + if (gst_structure_has_field (wfd_video_formats, "video_framerate_control_support")) + gst_structure_get_int (wfd_video_formats, "video_framerate_control_support", &video_framerate_control_support); } wfd_res = gst_wfd_message_set_supported_video_format (wfd_msg, @@ -1508,13 +1515,13 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) gint hdcp_version = 0; gint hdcp_port_no = 0; - if (priv->hdcp_param != NULL) { - GstStructure *hdcp_param = priv->hdcp_param; + if (priv->wfd_content_protection != NULL) { + GstStructure *wfd_content_protection = priv->wfd_content_protection; - if (gst_structure_has_field (hdcp_param, "hdcp_version")) - gst_structure_get_int (hdcp_param, "hdcp_version", &hdcp_version); - if (gst_structure_has_field (hdcp_param, "hdcp_port_no")) - gst_structure_get_int (hdcp_param, "hdcp_port_no", &hdcp_port_no); + if (gst_structure_has_field (wfd_content_protection, "hdcp_version")) + gst_structure_get_int (wfd_content_protection, "hdcp_version", &hdcp_version); + if (gst_structure_has_field (wfd_content_protection, "hdcp_port_no")) + gst_structure_get_int (wfd_content_protection, "hdcp_port_no", &hdcp_port_no); } wfd_res = gst_wfd_message_set_contentprotection_type (wfd_msg, @@ -1647,13 +1654,16 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) wfd_res = gst_wfd_message_new (&wfd_msg); if (wfd_res != GST_WFD_OK) - goto message_config_error; + goto message_config_error; + wfd_res = gst_wfd_message_init (wfd_msg); if (wfd_res != GST_WFD_OK) goto message_config_error; + wfd_res = gst_wfd_message_parse_buffer (data, size, wfd_msg); if (wfd_res != GST_WFD_OK) goto message_config_error; + //gst_wfd_message_dump (wfd_msg); if (!wfd_msg) @@ -1700,7 +1710,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); if(wfd_msg->audio_codecs) { - res = gst_wfd_base_src_get_audio_parameter(src, wfd_msg); + res = gst_wfd_base_src_get_wfd_audio_codecseter(src, wfd_msg); if(res != GST_RTSP_OK) { goto message_config_error; } @@ -1714,7 +1724,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) } if(wfd_msg->video_formats) { - res = gst_wfd_base_src_get_video_parameter(src, wfd_msg); + res = gst_wfd_base_src_get_wfd_video_formatseter(src, wfd_msg); if(res != GST_RTSP_OK) { goto message_config_error; } @@ -1765,6 +1775,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) if(wfd_res != GST_WFD_OK) { goto message_config_error; } + priv->transport.trans = trans; priv->transport.profile = profile; priv->transport.lower_transport = lowertrans; @@ -2871,7 +2882,7 @@ cleanup_error: } static void -gst_wfd_base_src_send_close_cmd (GstWFDBaseSrc * src) +gst_wfd_base_src_request_close (GstWFDBaseSrc * src) { gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_CLOSE, WFD_CMD_ALL); } @@ -3028,7 +3039,7 @@ gst_wfd_base_src_parse_rtpinfo (GstWFDBaseSrc * src, gchar * rtpinfo) } static void -gst_wfd_base_src_send_play_cmd (GstWFDBaseSrc * src) +gst_wfd_base_src_request_resume (GstWFDBaseSrc * src) { gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PLAY, WFD_CMD_LOOP); } @@ -3121,7 +3132,7 @@ send_error: } static void -gst_wfd_base_src_send_pause_cmd (GstWFDBaseSrc * src) +gst_wfd_base_src_request_pause (GstWFDBaseSrc * src) { gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PAUSE, WFD_CMD_LOOP); } @@ -3583,13 +3594,12 @@ gst_wfd_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data) iface->set_uri = gst_wfd_base_src_uri_set_uri; } -static GstRTSPResult _get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, GstWFDVideoCEAResolution Resolution) +GstRTSPResult gst_wfd_base_src_get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution) { GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDVideoCEAResolution CEARes = Resolution; + guint64 CEARes = Resolution; - switch(CEARes) - { + switch(CEARes) { case GST_WFD_CEA_UNKNOWN: break; case GST_WFD_CEA_640x480P60: @@ -3677,16 +3687,66 @@ static GstRTSPResult _get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, GstW priv->video_height=1080; priv->video_framerate=24; break; + case GST_WFD_CEA_3840x2160P24: + priv->video_width=3840; + priv->video_height=2160; + priv->video_framerate=24; + break; + case GST_WFD_CEA_3840x2160P25: + priv->video_width=3840; + priv->video_height=2160; + priv->video_framerate=25; + break; + case GST_WFD_CEA_3840x2160P30: + priv->video_width=3840; + priv->video_height=2160; + priv->video_framerate=30; + break; + case GST_WFD_CEA_3840x2160P50: + priv->video_width=3840; + priv->video_height=2160; + priv->video_framerate=50; + break; + case GST_WFD_CEA_3840x2160P60: + priv->video_width=3840; + priv->video_height=2160; + priv->video_framerate=60; + break; + case GST_WFD_CEA_4096x2160P24: + priv->video_width=4096; + priv->video_height=2160; + priv->video_framerate=24; + break; + case GST_WFD_CEA_4096x2160P25: + priv->video_width=4096; + priv->video_height=2160; + priv->video_framerate=25; + break; + case GST_WFD_CEA_4096x2160P30: + priv->video_width=4096; + priv->video_height=2160; + priv->video_framerate=30; + break; + case GST_WFD_CEA_4096x2160P50: + priv->video_width=4096; + priv->video_height=2160; + priv->video_framerate=50; + break; + case GST_WFD_CEA_4096x2160P60: + priv->video_width=4096; + priv->video_height=2160; + priv->video_framerate=60; + break; default: break; } return GST_RTSP_OK; } -static GstRTSPResult _get_vesa_resolution_and_set_to_src(GstWFDBaseSrc *src, GstWFDVideoVESAResolution Resolution) +GstRTSPResult gst_wfd_base_src_get_vesa_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution) { GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDVideoVESAResolution VESARes = Resolution; + guint64 VESARes = Resolution; switch(VESARes) { @@ -3842,16 +3902,36 @@ static GstRTSPResult _get_vesa_resolution_and_set_to_src(GstWFDBaseSrc *src, Gst priv->video_height=1200; priv->video_framerate=60; break; + case GST_WFD_VESA_2560x1440P30: + priv->video_width=2560; + priv->video_height=1440; + priv->video_framerate=30; + break; + case GST_WFD_VESA_2560x1440P60: + priv->video_width=2560; + priv->video_height=1440; + priv->video_framerate=60; + break; + case GST_WFD_VESA_2560x1600P30: + priv->video_width=2560; + priv->video_height=1600; + priv->video_framerate=30; + break; + case GST_WFD_VESA_2560x1600P60: + priv->video_width=2560; + priv->video_height=1600; + priv->video_framerate=60; + break; default: break; } return GST_RTSP_OK; } -static GstRTSPResult _get_hh_resolution_and_set_to_src(GstWFDBaseSrc *src, GstWFDVideoHHResolution Resolution) +GstRTSPResult gst_wfd_base_src_get_hh_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution) { GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDVideoHHResolution HHRes = Resolution; + guint64 HHRes = Resolution; switch(HHRes) { @@ -3924,7 +4004,7 @@ static GstRTSPResult _get_hh_resolution_and_set_to_src(GstWFDBaseSrc *src, GstWF } static GstRTSPResult -gst_wfd_base_src_get_audio_parameter(GstWFDBaseSrc * src, GstWFDMessage * msg) +gst_wfd_base_src_get_wfd_audio_codecseter(GstWFDBaseSrc * src, GstWFDMessage * msg) { GstWFDBaseSrcPrivate *priv = src->priv; GstWFDAudioFormats audio_format = GST_WFD_AUDIO_UNKNOWN; @@ -3963,14 +4043,14 @@ gst_wfd_base_src_get_audio_parameter(GstWFDBaseSrc * src, GstWFDMessage * msg) } static GstRTSPResult -gst_wfd_base_src_get_video_parameter(GstWFDBaseSrc * src, GstWFDMessage * msg) +gst_wfd_base_src_get_wfd_video_formatseter(GstWFDBaseSrc * src, GstWFDMessage * msg) { GstWFDVideoCodecs cvCodec = GST_WFD_VIDEO_UNKNOWN; GstWFDVideoNativeResolution cNative = GST_WFD_VIDEO_CEA_RESOLUTION; guint64 cNativeResolution = 0; - GstWFDVideoCEAResolution cCEAResolution = GST_WFD_CEA_UNKNOWN; - GstWFDVideoVESAResolution cVESAResolution = GST_WFD_VESA_UNKNOWN; - GstWFDVideoHHResolution cHHResolution = GST_WFD_HH_UNKNOWN; + guint64 cCEAResolution = GST_WFD_CEA_UNKNOWN; + guint64 cVESAResolution = GST_WFD_VESA_UNKNOWN; + guint64 cHHResolution = GST_WFD_HH_UNKNOWN; GstWFDVideoH264Profile cProfile = GST_WFD_H264_UNKNOWN_PROFILE; GstWFDVideoH264Level cLevel = GST_WFD_H264_LEVEL_UNKNOWN; guint32 cMaxHeight = 0; @@ -3989,32 +4069,13 @@ gst_wfd_base_src_get_video_parameter(GstWFDBaseSrc * src, GstWFDMessage * msg) GST_ERROR("Failed to get prefered video format."); return GST_RTSP_ERROR; } -#if 0 - switch(cNative) - { - case GST_WFD_VIDEO_CEA_RESOLUTION: - _get_cea_resolution_and_set_to_src(src, cCEAResolution); - break; - case GST_WFD_VIDEO_VESA_RESOLUTION: - _get_vesa_resolution_and_set_to_src(src, cVESAResolution); - break; - case GST_WFD_VIDEO_HH_RESOLUTION: - _get_hh_resolution_and_set_to_src(src, cHHResolution); - break; - default: - break; - } -#endif - if(cCEAResolution != GST_WFD_CEA_UNKNOWN) { - _get_cea_resolution_and_set_to_src(src, cCEAResolution); - } - else if(cVESAResolution != GST_WFD_VESA_UNKNOWN) { - _get_vesa_resolution_and_set_to_src(src, cVESAResolution); - } - else if(cHHResolution != GST_WFD_HH_UNKNOWN) { - _get_hh_resolution_and_set_to_src(src, cHHResolution); - } + if(cCEAResolution != GST_WFD_CEA_UNKNOWN) + gst_wfd_base_src_get_cea_resolution_and_set_to_src(src, cCEAResolution); + else if(cVESAResolution != GST_WFD_VESA_UNKNOWN) + gst_wfd_base_src_get_vesa_resolution_and_set_to_src(src, cVESAResolution); + else if(cHHResolution != GST_WFD_HH_UNKNOWN) + gst_wfd_base_src_get_hh_resolution_and_set_to_src(src, cHHResolution); return GST_RTSP_OK; } @@ -4076,13 +4137,13 @@ _cmd_to_string (guint cmd) return "unknown"; } -static GstRTSPResult -_rtsp_message_dump (GstRTSPMessage * msg) +static void +_dump_rtsp_message (GstRTSPMessage * msg) { guint8 *data; guint size; - g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL); + g_return_if_fail (msg != NULL); GST_ERROR("------------------------------------------------------"); switch (msg->type) { @@ -4154,10 +4215,9 @@ _rtsp_message_dump (GstRTSPMessage * msg) break; default: GST_ERROR ("unsupported message type %d", msg->type); - return GST_RTSP_EINVAL; + break; } GST_ERROR("------------------------------------------------------"); - return GST_RTSP_OK; } /*rtsp dump code end*/ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c.orig b/wfdmanager/wfdbase/gstwfdbasesrc.c.orig deleted file mode 100755 index ea50ad5..0000000 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c.orig +++ /dev/null @@ -1,4016 +0,0 @@ -/* - * wfdbasesrc - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** -* SECTION:element-wfdbasesrc -* -* Makes a connection to an RTSP server and read the data. -* Device recognition is through wifi direct. -* wfdbasesrc strictly follows Wifi display specification. -* -* RTSP supports transport over TCP or UDP in unicast or multicast mode. By -* default wfdbasesrc will negotiate a connection in the following order: -* UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed -* protocols can be controlled with the #GstWFDBaseSrc:protocols property. -* -* wfdbasesrc currently understands WFD capability negotiation messages -* -* wfdbasesrc will internally instantiate an RTP session manager element -* that will handle the RTCP messages to and from the server, jitter removal, -* packet reordering along with providing a clock for the pipeline. -* This feature is implemented using the gstrtpbin element. -* -* wfdbasesrc acts like a live source and will therefore only generate data in the -* PLAYING state. -* -* -* Example launch line -* |[ -* gst-launch wfdbasesrc location=rtsp://some.server/url ! fakesink -* ]| Establish a connection to an RTSP server and send the raw RTP packets to a -* fakesink. -* -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif /* HAVE_UNISTD_H */ -#include -#include -#include -#include -#include -#include -#include - -#include "gstwfdbasesrc.h" -#include "wfdrtspmacro.h" - -#ifdef G_OS_WIN32 -#include -#endif - -GST_DEBUG_CATEGORY_STATIC (wfdbasesrc_debug); -#define GST_CAT_DEFAULT (wfdbasesrc_debug) - -#define GST_WFD_BASE_TASK_GET_LOCK(wfd) (GST_WFD_BASE_SRC_CAST(wfd)->priv->task_rec_lock) -#define GST_WFD_BASE_TASK_LOCK(wfd) (g_rec_mutex_lock (&(GST_WFD_BASE_TASK_GET_LOCK(wfd)))) -#define GST_WFD_BASE_TASK_UNLOCK(wfd) (g_rec_mutex_unlock(&(GST_WFD_BASE_TASK_GET_LOCK(wfd)))) - -static GstStaticPadTemplate gst_wfd_base_src_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-rtp, " - "media = (string) \"video\", " - "clock-rate = (int) 90000, " - "payload = (int) 33")); - -/* signals and args */ -enum -{ - SIGNAL_UPDATE_MEDIA_INFO, - SIGNAL_AV_FORMAT_CHANGE, - SIGNAL_PAUSE, - SIGNAL_RESUME, - SIGNAL_CLOSE, - SIGNAL_SET_STANDBY, - LAST_SIGNAL -}; - -/* properties default values */ -#define DEFAULT_LOCATION NULL -#define DEFAULT_DEBUG FALSE -#define DEFAULT_RETRY 50 -#define DEFAULT_TCP_TIMEOUT 20000000 -#define DEFAULT_PROXY NULL -#define DEFAULT_RTP_BLOCKSIZE 0 -#define DEFAULT_USER_ID NULL -#define DEFAULT_USER_PW NULL -#define DEFAULT_PORT_RANGE NULL -#define DEFAULT_USER_AGENT "TIZEN-WFD-SINK" - -enum -{ - PROP_0, - PROP_LOCATION, - PROP_DEBUG, - PROP_RETRY, - PROP_TCP_TIMEOUT, - PROP_RTP_BLOCKSIZE, - PROP_USER_AGENT, - PROP_AUDIO_PARAM, - PROP_VIDEO_PARAM, - PROP_HDCP_PARAM, - PROP_ENABLE_PAD_PROBE, - PROP_LAST -}; - -/* commands we send to out loop to notify it of events */ -#define WFD_CMD_OPEN (1 << 0) -#define WFD_CMD_PLAY (1 << 1) -#define WFD_CMD_PAUSE (1 << 2) -#define WFD_CMD_CLOSE (1 << 3) -#define WFD_CMD_WAIT (1 << 4) -#define WFD_CMD_REQUEST (1 << 6) -#define WFD_CMD_LOOP (1 << 7) -#define WFD_CMD_ALL ((WFD_CMD_LOOP << 1) - 1) - -#define GST_ELEMENT_PROGRESS(el, type, code, text) \ -G_STMT_START { \ - gchar *__txt = _gst_element_error_printf text; \ - gst_element_post_message (GST_ELEMENT_CAST (el), \ - gst_message_new_progress (GST_OBJECT_CAST (el), \ - GST_PROGRESS_TYPE_ ##type, code, __txt)); \ - g_free (__txt); \ -} G_STMT_END - - -typedef struct _GstWFDConnInfo { - gchar *location; - GstRTSPUrl *url; - gchar *url_str; - GstRTSPConnection *connection; - gboolean connected; -}GstWFDConnInfo; - -#define GST_WFD_BASE_SRC_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_WFD_BASE_SRC, GstWFDBaseSrcPrivate)) - -struct _GstWFDBaseSrcPrivate -{ - /* state */ - GstRTSPState state; - - /* supported RTSP methods */ - gint methods; - - /* task and mutex */ - GstTask *task; - GRecMutex task_rec_lock; - gint pending_cmd; - gint busy_cmd; - gboolean do_stop; - - /* properties */ - gboolean debug; - guint retry; - GTimeVal tcp_timeout; - GTimeVal *ptcp_timeout; - guint rtp_blocksize; - GstStructure *audio_param; - GstStructure *video_param; - GstStructure *hdcp_param; - gchar *user_agent; - - /* Set RTP port */ - gint primary_rtpport; - - GstWFDConnInfo conninfo; - GstRTSPLowerTrans protocol; - - /* stream info */ - guint video_height; - guint video_width; - guint video_framerate; - gchar * audio_format; - guint audio_channels; - guint audio_bitwidth; - guint audio_frequency; -}; - -/* object */ -static void gst_wfd_base_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_wfd_base_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -/* element */ -static GstStateChangeReturn gst_wfd_base_src_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_wfd_base_src_send_event (GstElement * element, GstEvent * event); - -/* bin */ -static void gst_wfd_base_src_handle_message (GstBin * bin, GstMessage * message); - -/* pad */ -static gboolean gst_wfd_base_src_handle_src_event (GstPad * pad, GstObject *parent, GstEvent * event); -static gboolean gst_wfd_base_src_handle_src_query(GstPad * pad, GstObject *parent, GstQuery * query); - -/* fundemental functions */ -static GstRTSPResult gst_wfd_base_src_open (GstWFDBaseSrc * src); -static gboolean gst_wfd_base_src_setup (GstWFDBaseSrc * src); -static GstRTSPResult gst_wfd_base_src_play (GstWFDBaseSrc * src); -static GstRTSPResult gst_wfd_base_src_pause (GstWFDBaseSrc * src); -static GstRTSPResult gst_wfd_base_src_close (GstWFDBaseSrc * src, gboolean only_close); -static void gst_wfd_base_src_send_pause_cmd (GstWFDBaseSrc * src); -static void gst_wfd_base_src_send_play_cmd (GstWFDBaseSrc * src); -static void gst_wfd_base_src_send_close_cmd (GstWFDBaseSrc * src); -static void gst_wfd_base_src_set_standby (GstWFDBaseSrc * src); - -/* URI interface */ -static void gst_wfd_base_src_uri_handler_init (gpointer g_iface, - gpointer iface_data); -static gboolean gst_wfd_base_src_uri_set_uri (GstURIHandler * handler, - const gchar * uri, GError **error); - -/* task */ -static GstRTSPResult gst_wfd_base_src_loop (GstWFDBaseSrc * src); -static gboolean gst_wfd_base_src_loop_send_cmd (GstWFDBaseSrc * src, gint cmd, - gint mask); - -static gboolean gst_wfd_base_src_push_event (GstWFDBaseSrc * src, GstEvent * event); -static void gst_wfd_base_src_set_tcp_timeout (GstWFDBaseSrc * src, guint64 timeout); - - -static GstRTSPResult -gst_wfd_base_src_send (GstWFDBaseSrc * src, GstRTSPMessage * request, GstRTSPMessage * response, - GstRTSPStatusCode * code); - -static GstRTSPResult gst_wfd_base_src_get_video_parameter(GstWFDBaseSrc * src, WFDMessage *msg); -static GstRTSPResult gst_wfd_base_src_get_audio_parameter(GstWFDBaseSrc * src, WFDMessage *msg); - -/* util */ -static GstRTSPResult _rtsp_message_dump (GstRTSPMessage * msg); -static const char *_cmd_to_string (guint cmd); - - -#ifdef ENABLE_WFD_MESSAGE -static gint -__wfd_config_message_init(GstWFDBaseSrc * src) -{ - src->message_handle = dlopen(WFD_MESSAGE_FEATURES_PATH, RTLD_LAZY); - if (src->message_handle == NULL) { - GST_ERROR_OBJECT(src, "failed to init __wfd_config_message_init"); - src->extended_wfd_message_support = FALSE; - return FALSE; - } else { - src->extended_wfd_message_support = TRUE; - } - return TRUE; -} - -static void * -__wfd_config_message_func(GstWFDBaseSrc *src, const char *func) -{ - return dlsym(src->message_handle, func); -} - -static void -__wfd_config_message_close(GstWFDBaseSrc *src) -{ - dlclose(src->message_handle); - src->message_handle = NULL; - src->extended_wfd_message_support = FALSE; -} -#endif - -static guint gst_wfd_base_src_signals[LAST_SIGNAL] = { 0 }; - -static GstBinClass *parent_class = NULL; - -static void gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass); -static void gst_wfd_base_src_init (GstWFDBaseSrc * src, gpointer g_class); -static void gst_wfd_base_src_finalize (GObject * object); - -GType -gst_wfd_base_src_get_type (void) -{ - static volatile gsize wfd_base_src_type = 0; - - static const GInterfaceInfo urihandler_info = { - gst_wfd_base_src_uri_handler_init, - NULL, - NULL - }; - - if (g_once_init_enter (&wfd_base_src_type)) { - GType object_type; - static const GTypeInfo wfd_base_src_info = { - sizeof (GstWFDBaseSrcClass), - NULL, - NULL, - (GClassInitFunc) gst_wfd_base_src_class_init, - NULL, - NULL, - sizeof (GstWFDBaseSrc), - 0, - (GInstanceInitFunc) gst_wfd_base_src_init, - }; - - object_type = g_type_register_static (GST_TYPE_BIN, - "GstWFDBaseSrc", &wfd_base_src_info, G_TYPE_FLAG_ABSTRACT); - - g_type_add_interface_static (object_type, GST_TYPE_URI_HANDLER, - &urihandler_info); - - g_once_init_leave (&wfd_base_src_type, object_type); - } - return wfd_base_src_type; -} - - -static void -gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBinClass *gstbin_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbin_class = (GstBinClass *) klass; - - GST_DEBUG_CATEGORY_INIT (wfdbasesrc_debug, "wfdbasesrc", 0, "Wi-Fi Display Sink Base Source"); - - g_type_class_add_private (klass, sizeof (GstWFDBaseSrcPrivate)); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_wfd_base_src_set_property; - gobject_class->get_property = gst_wfd_base_src_get_property; - gobject_class->finalize = gst_wfd_base_src_finalize; - - g_object_class_install_property (gobject_class, PROP_LOCATION, - g_param_spec_string ("location", "RTSP Location", - "Location of the RTSP url to read", - DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_DEBUG, - g_param_spec_boolean ("debug", "Debug", - "Dump request and response messages to stdout", - DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_RETRY, - g_param_spec_uint ("retry", "Retry", - "Max number of retries when connecting Wi-Fi Display source", - 0, G_MAXUINT16, DEFAULT_RETRY, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_TCP_TIMEOUT, - g_param_spec_uint64 ("tcp-timeout", "TCP Timeout", - "Fail after timeout microseconds on TCP connections (0 = disabled)", - 0, G_MAXUINT64, DEFAULT_TCP_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_RTP_BLOCKSIZE, - g_param_spec_uint ("rtp-blocksize", "RTP Blocksize", - "RTP package size to suggest to server (0 = disabled)", - 0, 65536, DEFAULT_RTP_BLOCKSIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_USER_AGENT, - g_param_spec_string ("user-agent", "User Agent", - "User agent specified string", DEFAULT_USER_AGENT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_AUDIO_PARAM, - g_param_spec_boxed ("audio-param", "audio parameters", - "A GstStructure specifies the mapping for audio parameters", - GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_VIDEO_PARAM, - g_param_spec_boxed ("video-param", "video parameters", - "A GstStructure specifies the mapping for video parameters", - GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_HDCP_PARAM, - g_param_spec_boxed ("hdcp-param", "HDCP parameters", - "A GstStructure specifies the mapping for HDCP parameters", - GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_ENABLE_PAD_PROBE, - g_param_spec_boolean ("enable-pad-probe", "Enable Pad Probe", - "Enable pad probe for debugging", - FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gst_wfd_base_src_signals[SIGNAL_UPDATE_MEDIA_INFO] = - g_signal_new ("update-media-info", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWFDBaseSrcClass, update_media_info), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); - - gst_wfd_base_src_signals[SIGNAL_AV_FORMAT_CHANGE] = - g_signal_new ("change-av-format", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWFDBaseSrcClass, change_av_format), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - - gst_wfd_base_src_signals[SIGNAL_PAUSE] = - g_signal_new ("pause", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, pause), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - - gst_wfd_base_src_signals[SIGNAL_RESUME] = - g_signal_new ("resume", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, resume), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - - gst_wfd_base_src_signals[SIGNAL_CLOSE] = - g_signal_new ("close", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, close), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - - gst_wfd_base_src_signals[SIGNAL_SET_STANDBY] = - g_signal_new ("set-standby", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstWFDBaseSrcClass, set_standby), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - - gstelement_class->send_event = - GST_DEBUG_FUNCPTR(gst_wfd_base_src_send_event); - gstelement_class->change_state = - GST_DEBUG_FUNCPTR(gst_wfd_base_src_change_state); - - gstbin_class->handle_message = - GST_DEBUG_FUNCPTR(gst_wfd_base_src_handle_message); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_wfd_base_src_src_template)); - - klass->pause = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_pause_cmd); - klass->resume = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_play_cmd); - klass->close = GST_DEBUG_FUNCPTR (gst_wfd_base_src_send_close_cmd); - klass->set_standby = GST_DEBUG_FUNCPTR (gst_wfd_base_src_set_standby); - - klass->push_event = GST_DEBUG_FUNCPTR (gst_wfd_base_src_push_event); -} - -static GstStructure * -gst_wfd_rtsp_set_default_audio_param () -{ - GstStructure *param = NULL; - param = gst_structure_new ("audio_param", - "audio_codec", G_TYPE_UINT, 0x3, - "audio_latency", G_TYPE_UINT, 0x0, - "audio_channels", G_TYPE_UINT, 0x3, - "audio_sampling_frequency", G_TYPE_UINT, 0x1, - NULL); - - return param; -} - -static GstStructure * -gst_wfd_rtsp_set_default_video_param () -{ - GstStructure *param = NULL; - param = gst_structure_new ("video_param", - "video_codec", G_TYPE_UINT, 0x1, - "video_native_resolution", G_TYPE_UINT, 0x20, - "video_cea_support", G_TYPE_UINT, 0x194ab, - "video_vesa_support", G_TYPE_UINT, 0x15555555, - "video_hh_support", G_TYPE_UINT, 0x555, - "video_profile", G_TYPE_UINT, 0x1, - "video_level", G_TYPE_UINT, 0x2, - "video_latency", G_TYPE_UINT, 0x0, - "video_vertical_resolution", G_TYPE_INT, 1200, - "video_horizontal_resolution", G_TYPE_INT, 1920, - "video_minimum_slicing", G_TYPE_INT, 0, - "video_slice_enc_param", G_TYPE_INT, 200, - "video_framerate_control_support", G_TYPE_INT, 11, - NULL); - - return param; -} - -static void -gst_wfd_base_src_init (GstWFDBaseSrc * src, gpointer g_class) -{ - GstPadTemplate *template = NULL; - gint result = FALSE; - -#ifdef G_OS_WIN32 - WSADATA wsa_data; - - if (WSAStartup (MAKEWORD (2, 2), &wsa_data) != 0) { - GST_ERROR_OBJECT (src, "WSAStartup failed: 0x%08x", WSAGetLastError ()); - } -#endif - src->priv = GST_WFD_BASE_SRC_GET_PRIVATE (src); - - src->is_ipv6 = FALSE; - src->srcpad = NULL; - - src->priv->conninfo.location = g_strdup (DEFAULT_LOCATION); - src->priv->conninfo.url_str = NULL; - src->priv->protocol = GST_RTSP_LOWER_TRANS_UNKNOWN; - src->priv->debug = DEFAULT_DEBUG; - src->priv->retry = DEFAULT_RETRY; - gst_wfd_base_src_set_tcp_timeout (src, DEFAULT_TCP_TIMEOUT); - src->priv->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE; - src->priv->user_agent = g_strdup (DEFAULT_USER_AGENT); - src->priv->hdcp_param = NULL; - src->priv->audio_param = gst_wfd_rtsp_set_default_audio_param (); - src->priv->video_param = gst_wfd_rtsp_set_default_video_param (); - - src->enable_pad_probe = FALSE; - src->request_param.type = WFD_PARAM_NONE; - - g_rec_mutex_init (&(src->state_rec_lock)); - g_rec_mutex_init (&(src->priv->task_rec_lock)); - -#ifdef ENABLE_WFD_MESSAGE - result = __wfd_config_message_init(src); - if(result == FALSE) - return; -#endif - - /* create ghost pad for using src pad */ - template = gst_static_pad_template_get (&gst_wfd_base_src_src_template); - src->srcpad = gst_ghost_pad_new_no_target_from_template ("src", template); - gst_element_add_pad (GST_ELEMENT_CAST (src), src->srcpad); - gst_object_unref (template); - - gst_pad_set_event_function (src->srcpad, - GST_DEBUG_FUNCPTR (gst_wfd_base_src_handle_src_event)); - gst_pad_set_query_function (src->srcpad, - GST_DEBUG_FUNCPTR (gst_wfd_base_src_handle_src_query)); - - src->caps = gst_static_pad_template_get_caps (&gst_wfd_base_src_src_template); - gst_pad_set_caps (src->srcpad, src->caps); - - src->priv->do_stop = FALSE; - src->priv->state = GST_RTSP_STATE_INVALID; - - GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_SOURCE); -} - -static void -gst_wfd_base_src_finalize (GObject * object) -{ - GstWFDBaseSrc *src; - - src = GST_WFD_BASE_SRC (object); - - gst_rtsp_url_free (src->priv->conninfo.url); - if (src->priv->conninfo.location) - g_free (src->priv->conninfo.location); - src->priv->conninfo.location = NULL; - if (src->priv->conninfo.url_str) - g_free (src->priv->conninfo.url_str); - src->priv->conninfo.url_str = NULL; - if (src->priv->conninfo.location) - g_free (src->priv->conninfo.location); - src->priv->conninfo.location = NULL; - if (src->priv->conninfo.url_str) - g_free (src->priv->conninfo.url_str); - src->priv->conninfo.url_str = NULL; - if (src->priv->user_agent) - g_free (src->priv->user_agent); - src->priv->user_agent = NULL; - if(src->priv->audio_param) - gst_structure_free(src->priv->audio_param); - src->priv->audio_param = NULL; - if(src->priv->video_param) - gst_structure_free(src->priv->video_param); - src->priv->video_param = NULL; - if(src->priv->hdcp_param) - gst_structure_free(src->priv->hdcp_param); - src->priv->hdcp_param = NULL; - - /* free locks */ - g_rec_mutex_clear (&(src->state_rec_lock)); - g_rec_mutex_clear (&(src->priv->task_rec_lock)); - -#ifdef ENABLE_WFD_MESSAGE -__wfd_config_message_close(src); -#endif - -#ifdef G_OS_WIN32 - WSACleanup (); -#endif - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_wfd_base_src_set_tcp_timeout (GstWFDBaseSrc * src, guint64 timeout) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - - priv->tcp_timeout.tv_sec = timeout / G_USEC_PER_SEC; - priv->tcp_timeout.tv_usec = timeout % G_USEC_PER_SEC; - - if (timeout != 0) - priv->ptcp_timeout = &priv->tcp_timeout; - else - priv->ptcp_timeout = NULL; -} - -static void -gst_wfd_base_src_set_property (GObject * object, guint prop_id, const GValue * value, - GParamSpec * pspec) -{ - GstWFDBaseSrc *src = GST_WFD_BASE_SRC (object); - GError *err = NULL; - - switch (prop_id) { - case PROP_LOCATION: - gst_wfd_base_src_uri_set_uri (GST_URI_HANDLER (src), - g_value_get_string (value), &err); - break; - case PROP_DEBUG: - src->priv->debug = g_value_get_boolean (value); - break; - case PROP_RETRY: - src->priv->retry = g_value_get_uint (value); - break; - case PROP_TCP_TIMEOUT: - gst_wfd_base_src_set_tcp_timeout (src, g_value_get_uint64 (value)); - break; - case PROP_RTP_BLOCKSIZE: - src->priv->rtp_blocksize = g_value_get_uint (value); - break; - case PROP_USER_AGENT: - if (src->priv->user_agent) - g_free(src->priv->user_agent); - src->priv->user_agent = g_value_dup_string (value); - break; - case PROP_AUDIO_PARAM: - { - const GstStructure *s = gst_value_get_structure (value); - if (src->priv->audio_param) - gst_structure_free (src->priv->audio_param); - if (s) - src->priv->audio_param = gst_structure_copy (s); - else - src->priv->audio_param = NULL; - break; - } - case PROP_VIDEO_PARAM: - { - const GstStructure *s = gst_value_get_structure (value); - if (src->priv->video_param) - gst_structure_free (src->priv->video_param); - if (s) - src->priv->video_param = gst_structure_copy (s); - else - src->priv->video_param = NULL; - break; - } - case PROP_HDCP_PARAM: - { - const GstStructure *s = gst_value_get_structure (value); - if (src->priv->hdcp_param) - gst_structure_free (src->priv->hdcp_param); - if (s) - src->priv->hdcp_param = gst_structure_copy (s); - else - src->priv->hdcp_param = NULL; - break; - } - case PROP_ENABLE_PAD_PROBE: - src->enable_pad_probe = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_wfd_base_src_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstWFDBaseSrc *src = GST_WFD_BASE_SRC (object); - - switch (prop_id) { - case PROP_LOCATION: - g_value_set_string (value, src->priv->conninfo.location); - break; - case PROP_DEBUG: - g_value_set_boolean (value, src->priv->debug); - break; - case PROP_RETRY: - g_value_set_uint (value, src->priv->retry); - break; - case PROP_TCP_TIMEOUT: - { - guint64 timeout; - - timeout = src->priv->tcp_timeout.tv_sec * (guint64)G_USEC_PER_SEC + - src->priv->tcp_timeout.tv_usec; - g_value_set_uint64 (value, timeout); - break; - } - case PROP_RTP_BLOCKSIZE: - g_value_set_uint (value, src->priv->rtp_blocksize); - break; - case PROP_USER_AGENT: - g_value_set_string (value, src->priv->user_agent); - break; - case PROP_AUDIO_PARAM: - gst_value_set_structure (value, src->priv->audio_param); - break; - case PROP_VIDEO_PARAM: - gst_value_set_structure (value, src->priv->video_param); - break; - case PROP_HDCP_PARAM: - gst_value_set_structure (value, src->priv->hdcp_param); - break; - case PROP_ENABLE_PAD_PROBE: - g_value_set_boolean (value, src->enable_pad_probe); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_wfd_base_src_cleanup (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcClass *klass = NULL; - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (src->caps) - gst_caps_unref (src->caps); - src->caps = NULL; - - if (klass->cleanup) - klass->cleanup(src); -} - -static void -gst_wfd_base_src_flush (GstWFDBaseSrc * src, gboolean flush) -{ - GstWFDBaseSrcClass *klass; - GstEvent *event; - GstState state; - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (flush) { - event = gst_event_new_flush_start (); - GST_DEBUG_OBJECT (src, "start flush"); - state = GST_STATE_PAUSED; - } else { - event = gst_event_new_flush_stop (FALSE); - GST_DEBUG_OBJECT (src, "stop flush"); - state = GST_STATE_PLAYING; - } - - if (klass->push_event) - klass->push_event(src, event); - - if (klass->set_state) - klass->set_state (src, state); -} - -static GstRTSPResult -gst_wfd_base_src_connection_send (GstWFDBaseSrc * src, - GstRTSPMessage * message, GTimeVal * timeout) -{ - GstRTSPResult ret = GST_RTSP_OK; - - if (src->priv->debug) - _rtsp_message_dump (message); - - if (src->priv->conninfo.connection) - ret = gst_rtsp_connection_send (src->priv->conninfo.connection, message, timeout); - else - ret = GST_RTSP_ERROR; - - return ret; -} - -static GstRTSPResult -gst_wfd_base_src_connection_receive (GstWFDBaseSrc * src, - GstRTSPMessage * message, GTimeVal * timeout) -{ - GstRTSPResult ret; - - if (src->priv->conninfo.connection) - ret = gst_rtsp_connection_receive (src->priv->conninfo.connection, message, timeout); - else - ret = GST_RTSP_ERROR; - - if (src->priv->debug) - _rtsp_message_dump (message); - - return ret; -} - -static GstRTSPResult -gst_wfd_base_src_send_request (GstWFDBaseSrc * src) -{ - GstWFDRequestParam request_param = {0}; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstRTSPResult res = GST_RTSP_OK; - WFDResult wfd_res = WFD_OK; - WFDMessage *wfd_msg= NULL; - gchar *rtsp_body = NULL; - guint rtsp_body_length = 0; - GString *rtsp_body_length_str = NULL; - - GST_OBJECT_LOCK(src); - if (src->request_param.type==WFD_PARAM_NONE) { - GST_DEBUG_OBJECT(src, "nothing to request..."); - GST_OBJECT_UNLOCK(src); - return GST_RTSP_EINVAL; - } - request_param = src->request_param; - memset (&src->request_param, 0, sizeof(GstWFDRequestParam)); - GST_OBJECT_UNLOCK(src); - - GST_DEBUG_OBJECT (src, "need to send request message with %d parameter", request_param.type); - - res = gst_rtsp_message_init_request (&request, GST_RTSP_SET_PARAMETER, - src->priv->conninfo.url_str); - if (res < 0) - goto error; - - /* Create set_parameter body to be sent in the request */ - WFDCONFIG_MESSAGE_NEW (&wfd_msg, error); - WFDCONFIG_MESSAGE_INIT(wfd_msg, error); - - switch(request_param.type) { - case WFD_ROUTE: - /* Note : RTSP M10 : - * Send RTSP SET_PARAMETER with wfd-route to change the WFD sink at which audio is rendered. - * Applies only when both a primary and secondary sinks are in WFD session with a WFD source. - */ - WFDCONFIG_SET_AUDIO_SINK_TYPE(wfd_msg, request_param.route_setting.type, error); - break; - - case WFD_CONNECTOR_TYPE: - /* Note : RTSP M11 : - * Send RTSP SET_PARAMETER with wfd-connector-type to indicate change of active connector type, - * when the WFD source and WFD sink support content protection. - */ - WFDCONFIG_SET_CONNECTOR_TYPE(wfd_msg, request_param.connector_setting.type, error); - break; - - case WFD_STANDBY: - /* Note : RTSP M12 : - * Send RTSP SET_PARAMETER with wfd-standby to indicate that the sender is entering WFD standby mode. - */ - WFDCONFIG_SET_STANDBY(wfd_msg, TRUE, error); - break; - - case WFD_IDR_REQUEST: - /* Note : RTSP M13 : - * Send RTSP SET_PARAMETER with wfd-idr-request to request IDR refresh. - */ - WFDCONFIG_SET_IDR_REQUEST(wfd_msg, error); - break; - - default: - GST_ERROR_OBJECT (src, "Unhandled WFD message type..."); - goto error; - break; - } - - WFDCONFIG_MESSAGE_DUMP(wfd_msg); - WFDCONFIG_MESSAGE_AS_TEXT(wfd_msg, rtsp_body, error); - - if(rtsp_body == NULL) - goto error; - - rtsp_body_length = strlen(rtsp_body); - rtsp_body_length_str = g_string_new (""); - g_string_append_printf (rtsp_body_length_str,"%d",rtsp_body_length); - - GST_DEBUG ("WFD message body: %s", rtsp_body); - - /* add content-length type */ - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (rtsp_body_length_str, FALSE)); - - /* adding wfdconfig data to request */ - res = gst_rtsp_message_set_body (&request,(guint8 *)rtsp_body, rtsp_body_length); - if (res != GST_RTSP_OK) { - GST_ERROR_OBJECT (src, "Failed to set body to rtsp request..."); - goto error; - } - - WFDCONFIG_MESSAGE_FREE(wfd_msg); - - /* send request message */ - GST_DEBUG_OBJECT (src, "send reuest..."); - if ((res = gst_wfd_base_src_send (src, &request, &response, - NULL)) < 0) - goto error; - - return res; - -/* ERRORS */ -error: - { - if(wfd_msg) - WFDCONFIG_MESSAGE_FREE(wfd_msg); - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - if(wfd_res != WFD_OK) { - GST_ERROR_OBJECT(src, "Message config error : %d", wfd_res); - return GST_RTSP_ERROR; - } - return res; - } -} - -static gboolean -gst_wfd_base_src_handle_src_event (GstPad * pad, GstObject *parent, GstEvent * event) -{ - GstWFDBaseSrc *src; - gboolean res = TRUE; - gboolean forward = FALSE; - const GstStructure *s; - - src = GST_WFD_BASE_SRC_CAST (parent); - if(src == NULL) { - GST_ERROR_OBJECT (src, "src is NULL."); - return FALSE; - } - - //GST_DEBUG_OBJECT (src, "pad %s:%s received event %s", - // GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_QOS: - case GST_EVENT_NAVIGATION: - case GST_EVENT_LATENCY: - break; - case GST_EVENT_CUSTOM_UPSTREAM: - s = gst_event_get_structure (event); - if (gst_structure_has_name (s, "GstWFDIDRRequest")) { - /* Send IDR request */ - GST_OBJECT_LOCK(src); - src->request_param.type = WFD_IDR_REQUEST; - GST_OBJECT_UNLOCK(src); - gst_wfd_base_src_loop_send_cmd(src, WFD_CMD_REQUEST, WFD_CMD_LOOP); - } - break; - default: - forward = TRUE; - break; - } - - if (forward) { - GstPad *target; - - if ((target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad)))) { - res = gst_pad_send_event (target, event); - gst_object_unref (target); - } else { - gst_event_unref (event); - } - } else { - gst_event_unref (event); - } - - return res; -} - -/* this query is executed on the ghost source pad exposed on manager. */ -static gboolean -gst_wfd_base_src_handle_src_query (GstPad * pad, GstObject *parent, GstQuery * query) -{ - GstWFDBaseSrc *src = NULL; - gboolean res = FALSE; - - src = GST_WFD_BASE_SRC_CAST (parent); - if(src == NULL) - { - GST_ERROR_OBJECT (src, "src is NULL."); - return res; - } - - //GST_DEBUG_OBJECT (src, "pad %s:%s received query %s", - // GST_DEBUG_PAD_NAME (pad), GST_QUERY_TYPE_NAME (query)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_URI: - { - if (src->priv->conninfo.location == NULL) { - res = FALSE; - } else { - gst_query_set_uri( query, src->priv->conninfo.location); - res = TRUE; - } - break; - } - default: - { - GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad)); - - /* forward the query to the proxy target pad */ - if (target) { - res = gst_pad_query (target, query); - gst_object_unref (target); - } - break; - } - } - - return res; -} - -static void -gst_wfd_base_src_configure_caps (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstCaps *caps; - GstStructure *structure; - - GST_DEBUG_OBJECT (src, "configuring caps"); - - if ((caps = src->caps)) { - caps = gst_caps_make_writable (caps); - structure = gst_caps_get_structure (caps, 0); - /* update caps */ - gst_structure_set (structure, "height", G_TYPE_INT, priv->video_height, NULL); - gst_structure_set (structure, "width", G_TYPE_INT, priv->video_width, NULL); - gst_structure_set (structure, "video-framerate", G_TYPE_INT, priv->video_framerate, NULL); - - src->caps = caps; - } - - if (src->srcpad) { - GST_DEBUG_OBJECT (src, "set caps for srcpad"); - gst_pad_set_caps(src->srcpad, src->caps); - } -} - -static gboolean -gst_wfd_base_src_push_event (GstWFDBaseSrc * src, GstEvent * event) -{ - gboolean res = TRUE; - - g_return_val_if_fail(GST_IS_EVENT(event), FALSE); - - if (src ->srcpad) { - gst_event_ref (event); - res = gst_pad_push_event (src ->srcpad, event); - } - - gst_event_unref (event); - - return res; -} - -static GstRTSPResult -gst_wfd_base_src_conninfo_connect (GstWFDBaseSrc * src, GstWFDConnInfo * info) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res; - - if (info->connection == NULL) { - if (info->url == NULL) { - GST_DEBUG_OBJECT (src, "parsing uri (%s)...", info->location); - if ((res = gst_rtsp_url_parse (info->location, &info->url)) < 0) - goto parse_error; - } - - /* create connection */ - GST_DEBUG_OBJECT (src, "creating connection (%s)...", info->location); - if ((res = gst_rtsp_connection_create (info->url, &info->connection)) < 0) - goto could_not_create; - - if (info->url_str) - g_free (info->url_str); - info->url_str = gst_rtsp_url_get_request_uri (info->url); - - GST_DEBUG_OBJECT (src, "sanitized uri %s", info->url_str); - } - - if (!info->connected) { - /* connect */ - GST_DEBUG_OBJECT (src, "connecting (%s)...", info->location); - int retry = 0; -connect_retry: - if (priv->do_stop) { - GST_ERROR_OBJECT (src, "stop connecting...."); - return GST_RTSP_EINTR; - } - - if ((res = - gst_rtsp_connection_connect (info->connection, - priv->ptcp_timeout)) < 0) { - if (retry < priv->retry) { - GST_ERROR_OBJECT(src, "Connection failed... Try again..."); - usleep(100000); - retry++; - goto connect_retry; - } else { - goto could_not_connect; - } - } else { - GST_INFO_OBJECT(src, "Connection success"); - } - - info->connected = TRUE; - } - return GST_RTSP_OK; - - /* ERRORS */ -parse_error: - { - GST_ERROR_OBJECT (src, "No valid RTSP URL was provided"); - return res; - } -could_not_create: - { - gchar *str = gst_rtsp_strresult (res); - GST_ERROR_OBJECT (src, "Could not create connection. (%s)", str); - g_free (str); - return res; - } -could_not_connect: - { - gchar *str = gst_rtsp_strresult (res); - GST_ERROR_OBJECT (src, "Could not connect to server. (%s)", str); - g_free (str); - return res; - } -} - -static GstRTSPResult -gst_wfd_base_src_conninfo_close (GstWFDBaseSrc * src, GstWFDConnInfo * info, - gboolean free) -{ - g_return_val_if_fail (info, GST_RTSP_EINVAL); - - GST_WFD_BASE_STATE_LOCK (src); - if (info->connected) { - GST_DEBUG_OBJECT (src, "closing connection..."); - gst_rtsp_connection_close (info->connection); - info->connected = FALSE; - } - if (free && info->connection) { - /* free connection */ - GST_DEBUG_OBJECT (src, "freeing connection..."); - gst_rtsp_connection_free (info->connection); - info->connection = NULL; - } - GST_WFD_BASE_STATE_UNLOCK (src); - return GST_RTSP_OK; -} - -static void -gst_wfd_base_src_connection_flush (GstWFDBaseSrc * src, gboolean flush) -{ - GST_DEBUG_OBJECT (src, "set flushing %d", flush); - GST_WFD_BASE_STATE_LOCK (src); - if (src->priv->conninfo.connection) { - GST_DEBUG_OBJECT (src, "connection flush %d", flush); - gst_rtsp_connection_flush (src->priv->conninfo.connection, flush); - } - GST_WFD_BASE_STATE_UNLOCK (src); -} - -static GstRTSPResult -gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDBaseSrcClass *klass = NULL; - GstRTSPMethod method = GST_RTSP_INVALID; - GstRTSPVersion version = GST_RTSP_VERSION_INVALID; - GstRTSPMessage response = { 0 }; - GstRTSPResult res = GST_RTSP_OK; - WFDResult wfd_res = WFD_OK; - const gchar *uristr; - guint8 *data = NULL; - guint size = 0; - WFDMessage *wfd_msg = NULL; - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - res = gst_rtsp_message_parse_request (request, &method, &uristr, &version); - if (res < 0) - goto send_error; - - if (version != GST_RTSP_VERSION_1_0) { - /* we can only handle 1.0 requests */ - res = GST_RTSP_ENOTIMPL; - goto send_error; - } - - GST_DEBUG_OBJECT (src, "got %s request", gst_rtsp_method_as_text(method)); - - switch(method) { - case GST_RTSP_OPTIONS: - { - /* Note : RTSP M1 : - * A WFD source shall send an RTSP M1 request to a WFD sink to begin the RTSP procedures and a WFD Capability Negotiation. - * A WFD sink shall respond with an RTSP M1 response message which contains an RTSP OPTIONS. - */ - gchar *options_str = NULL; - GstRTSPMethod options = 0; - gchar *str = NULL; - - options = GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN | GST_RTSP_OPTIONS - | GST_RTSP_PLAY | GST_RTSP_PAUSE | GST_RTSP_SETUP; - - str = gst_rtsp_options_as_text (options); - if (!str) { - GST_ERROR ("Failed to make options string, str is NULL."); - res = GST_RTSP_ENOMEM; - goto send_error; - } - - options_str = g_strconcat ((const gchar*)str, ", org.wfa.wfd1.0", NULL); - if (!options_str) { - GST_ERROR ("Failed to make options string."); - res = GST_RTSP_ENOMEM; - g_free(str); - goto send_error; - } - g_free(str); - - res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, - gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - if(res < 0) { - g_free (options_str); - goto send_error; - } - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, options_str); - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_USER_AGENT, (const gchar*)priv->user_agent); - g_free (options_str); - - break; - } - - case GST_RTSP_GET_PARAMETER: - { - gchar *rtsp_body = NULL; - guint rtsp_body_length = 0; - GString *rtsp_body_length_str = NULL; - - res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - if (res < 0) - goto send_error; - - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters"); - - res = gst_rtsp_message_get_body (request, &data, &size); - if (res < 0) - goto send_error; - - if (size==0) { - /* Note : RTSP M16 : WFD keep-alive : - * The WFD keep-alive function is used to periodically ensure the status of WFD sesion. - * A WFD source indicates the timeout value via the "Session:" line in the RTSP M6 response. - * A WFD sink shall respond with an RTSP M16 request message upon successful receiving the RTSP M16 request message. - */ - res = gst_rtsp_connection_reset_timeout (priv->conninfo.connection); - if (res < 0) - goto send_error; - break; - } - - WFDCONFIG_MESSAGE_NEW(&wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_INIT(wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_PARSE_BUFFER(data, size, wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_DUMP(wfd_msg); - - /* Note : RTSP M3 : - * The WFD source shall send RTSP M3 request to the WFD sink to query the WFD sink's attributes and capabilities. - * A WFD sink shall respond with an RTSP M3 response message which contains the values of the requested parameters. - * The WFD source may query all parameters at once with a single RTSP M3 request message or may send separate RTSP M3 request message. - * The WFD sink shall only response with formats and settings that it can accept in the following RTSP M4 message exchnage. - */ - /* Note : wfd-audio-codecs : - * The wfd-audio-codecs parameter specifies the audio formats supported in the WFD session. - * Valid audio codecs are LPCM, AAC, AC3. - * Primary sink should support one of audio codecs. - */ - if(wfd_msg->audio_codecs) { - guint audio_codec = 0; - guint audio_sampling_frequency = 0; - guint audio_channels = 0; - guint audio_latency = 0; - - if(priv->audio_param != NULL) { - GstStructure *audio_param = priv->audio_param; - if (gst_structure_has_field (audio_param, "audio_codec")) - gst_structure_get_uint (audio_param, "audio_codec", &audio_codec); - if (gst_structure_has_field (audio_param, "audio_latency")) - gst_structure_get_uint (audio_param, "audio_latency", &audio_latency); - if (gst_structure_has_field (audio_param, "audio_channels")) - gst_structure_get_uint (audio_param, "audio_channels", &audio_channels); - if (gst_structure_has_field (audio_param, "audio_sampling_frequency")) - gst_structure_get_uint (audio_param, "audio_sampling_frequency", &audio_sampling_frequency); - } - - WFDCONFIG_SET_SUPPORTED_AUDIO_FORMAT(wfd_msg, - audio_codec, - audio_sampling_frequency, - audio_channels, - 16, - audio_latency, - message_config_error); - } - - /* Note : wfd-video-formats : - * The wfd-video-formats parameter specifies the supported video resolutions, - * H.644 codec profile, level, decoder latency, minimum slice size, slice encoding parameters - * and support for video frame rate control (including explicit frame rate change and implicit video frame skipping. - */ - if(wfd_msg->video_formats) { - guint video_codec = 0; - guint video_native_resolution = 0; - guint video_cea_support = 0; - guint video_vesa_support = 0; - guint video_hh_support = 0; - guint video_profile = 0; - guint video_level = 0; - guint video_latency = 0; - gint video_vertical_resolution = 0; - gint video_horizontal_resolution = 0; - gint video_minimum_slicing = 0; - gint video_slice_enc_param = 0; - gint video_framerate_control_support = 0; - - if (priv->video_param != NULL) { - GstStructure *video_param = priv->video_param; - - if (gst_structure_has_field (video_param, "video_codec")) - gst_structure_get_uint (video_param, "video_codec", &video_codec); - if (gst_structure_has_field (video_param, "video_native_resolution")) - gst_structure_get_uint (video_param, "video_native_resolution", &video_native_resolution); - if (gst_structure_has_field (video_param, "video_cea_support")) - gst_structure_get_uint (video_param, "video_cea_support", &video_cea_support); - if (gst_structure_has_field (video_param, "video_vesa_support")) - gst_structure_get_uint (video_param, "video_vesa_support", &video_vesa_support); - if (gst_structure_has_field (video_param, "video_hh_support")) - gst_structure_get_uint (video_param, "video_hh_support", &video_hh_support); - if (gst_structure_has_field (video_param, "video_profile")) - gst_structure_get_uint (video_param, "video_profile", &video_profile); - if (gst_structure_has_field (video_param, "video_level")) - gst_structure_get_uint (video_param, "video_level", &video_level); - if (gst_structure_has_field (video_param, "video_latency")) - gst_structure_get_uint (video_param, "video_latency", &video_latency); - if (gst_structure_has_field (video_param, "video_vertical_resolution")) - gst_structure_get_int (video_param, "video_vertical_resolution", &video_vertical_resolution); - if (gst_structure_has_field (video_param, "video_horizontal_resolution")) - gst_structure_get_int (video_param, "video_horizontal_resolution", &video_horizontal_resolution); - if (gst_structure_has_field (video_param, "video_minimum_slicing")) - gst_structure_get_int (video_param, "video_minimum_slicing", &video_minimum_slicing); - if (gst_structure_has_field (video_param, "video_slice_enc_param")) - gst_structure_get_int (video_param, "video_slice_enc_param", &video_slice_enc_param); - if (gst_structure_has_field (video_param, "video_framerate_control_support")) - gst_structure_get_int (video_param, "video_framerate_control_support", &video_framerate_control_support); - } - - WFDCONFIG_SET_SUPPORTED_VIDEO_FORMAT(wfd_msg, - video_codec, - WFD_VIDEO_CEA_RESOLUTION, - video_native_resolution, - video_cea_support, - video_vesa_support, - video_hh_support, - video_profile, - video_level, - video_latency, - video_vertical_resolution, - video_horizontal_resolution, - video_minimum_slicing, - video_slice_enc_param, - video_framerate_control_support, - WFD_PREFERRED_DISPLAY_MODE_NOT_SUPPORTED, - message_config_error); - } - - /* Note : wfd-3d-formats : - * The wfd-3d-formats parameter specifies the support for stereoscopic video capabilities. - */ - if(wfd_msg->video_3d_formats) { - /* TODO : Set preferred video_3d_formats */ - wfd_res = WFD_OK; - } - - /* Note : wfd-content-protection : - * The wfd-content-protection parameter specifies whether the WFD sink supports the HDCP system 2.0/2.1 for content protection. - */ - if(wfd_msg->content_protection) { - gint hdcp_version = 0; - gint hdcp_port_no = 0; - - if (priv->hdcp_param != NULL) { - GstStructure *hdcp_param = priv->hdcp_param; - - if (gst_structure_has_field (hdcp_param, "hdcp_version")) - gst_structure_get_int (hdcp_param, "hdcp_version", &hdcp_version); - if (gst_structure_has_field (hdcp_param, "hdcp_port_no")) - gst_structure_get_int (hdcp_param, "hdcp_port_no", &hdcp_port_no); - } - - WFDCONFIG_SET_CONTENT_PROTECTION_TYPE(wfd_msg, - hdcp_version, - (guint32)hdcp_port_no, - message_config_error); - } - - /* Note : wfd-display-edid : - * The wfd-display-edid parameter specifies the EDID of the display on which the content will be rendered. - * EDID data comes in multiples of 128-byte blocks of EDID data depending on the EDID structure that it supports. - * If a WFD sink reports wfd-connector-type as HDMI or DP or UDI, the WFD sink should return the EDID of the display that renders the streamed video. - * The WFD sink dongle without an integrated display or with an integrated display that is not being used to render streamed video - * shall not set the edid filed of the wfd-display-edid paramter to "none" regardless of whether an external display devices is attached or not. - */ - if(wfd_msg->display_edid) { - /* TODO: Set preferred display_edid */ - WFDCONFIG_SET_DISPLAY_EDID(wfd_msg, - FALSE, - 0, - NULL, - message_config_error); - } - - /* Note : wfd-coupled-sink : - * The wfd-coupled-sink parameter is used by a WFD sink to convey its coupled status - * and if coupled to another WFD sink, the coupled WFD sink's MAC address - */ - if(wfd_msg->coupled_sink) { - /* To test with dummy coupled sink address */ - WFDCONFIG_SET_COUPLED_SINK(wfd_msg, - WFD_SINK_COUPLED, - (gchar *)"1.0.0.1:435", - message_config_error); - } - - /* Note : wfd-client-rtp-ports : - * The wfd-coupled-sink parameter is used by a WFD sink to convey the RTP port(s) that the WFD sink is listening on - * and by the a WFD source to indicate how audio, video or both audio and video payload will be encapsulated in the MPEG2-TS stream - * transmitted from the WFD source to the WFD sink. - */ - if(wfd_msg->client_rtp_ports) { - /* Hardcoded as of now. This is to comply with dongle port settings. - This should be derived from gst_wfd_base_src_alloc_udp_ports */ - priv->primary_rtpport = 19000; - WFDCONFIG_SET_PREFERD_RTP_PORT(wfd_msg, - WFD_RTSP_TRANS_RTP, - WFD_RTSP_PROFILE_AVP, - WFD_RTSP_LOWER_TRANS_UDP, - priv->primary_rtpport, - 0, - message_config_error); - } - - /* Note : wfd-I2C : - * The wfd-I2C parameter is used by a WFD source to inquire whether a WFD sink supports remote I2C read/write function or not. - * If the WFD sink supports remote I2C read/write function, it shall set the value of this parameter to the TCP port number - * to be used by the WFD source to exchange remote I2C read/write messaging transactions with the WFD sink. - */ - if(wfd_msg->I2C) { - /* TODO */ - wfd_res = WFD_OK; - } - - /* Note : wfd-connector-type : - * The WFD source may send wfd-connector-type parameter to inquire about the connector type that is currently active in the WFD sink. - * The WFD sink shall not send wfd-connector-type parameter unless the WFD source support this parameter. - * The WFD sink dongle that is not connected to an external display and it is not acting as a WFD sink with embedded display - * (to render streamed content) shall return a value of "none". Otherwise, the WFD sink shall choose a non-reserved value. - */ - if(wfd_msg->connector_type) { - /* TODO */ - wfd_res = WFD_OK; - } - - /* Note : wfd-standby-resume-capability : - * The wfd-standby-resume-capability parameter describes support of both standby control using - * a wfd-standby parameter and resume control using PLAY and using triggered-method setting PLAY. - */ - if(wfd_msg->standby_resume_capability) { - /* TODO */ - wfd_res = WFD_OK; - } - - WFDCONFIG_MESSAGE_AS_TEXT(wfd_msg, rtsp_body, message_config_error); - - rtsp_body_length = strlen(rtsp_body); - rtsp_body_length_str = g_string_new (""); - g_string_append_printf (rtsp_body_length_str,"%d", rtsp_body_length); - - gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (rtsp_body_length_str, FALSE)); - - res = gst_rtsp_message_set_body (&response, (guint8*)rtsp_body, rtsp_body_length); - if (res < 0) - goto send_error; - - if (klass->handle_get_parameter) { - GST_DEBUG_OBJECT(src, "try to handle more GET_PARAMETER parameter"); - res = klass->handle_get_parameter(src, request, &response); - if (res < 0) - goto send_error; - } - break; - } - - case GST_RTSP_SET_PARAMETER: - { - res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - if (res < 0) - goto send_error; - - res = gst_rtsp_message_get_body (request, &data, &size); - if (res < 0) - goto send_error; - - WFDCONFIG_MESSAGE_NEW(&wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_INIT(wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_PARSE_BUFFER(data, size, wfd_msg, message_config_error); - WFDCONFIG_MESSAGE_DUMP(wfd_msg); - - if (!wfd_msg) - goto message_config_error; - - /* Note : RTSP M4 : - */ - /* Note : wfd-trigger-method : - * The wfd-trigger-method parameter is used by a WFD source to trigger the WFD sink to initiate an operation with the WFD source. - */ - if (wfd_msg->trigger_method) { - WFDTrigger trigger = WFD_TRIGGER_UNKNOWN; - - WFDCONFIG_GET_TRIGGER_TYPE(wfd_msg, &trigger, message_config_error); - - res = gst_wfd_base_src_connection_send (src, &response, NULL); - if (res < 0) - goto send_error; - - GST_DEBUG_OBJECT (src, "got trigger method for %s", GST_STR_NULL(wfd_msg->trigger_method->wfd_trigger_method)); - switch(trigger) { - case WFD_TRIGGER_PAUSE: - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PAUSE, WFD_CMD_LOOP); - break; - case WFD_TRIGGER_PLAY: - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PLAY, WFD_CMD_LOOP); - break; - case WFD_TRIGGER_TEARDOWN: - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_CLOSE, WFD_CMD_ALL); - break; - case WFD_TRIGGER_SETUP: - if (!gst_wfd_base_src_setup (src)) - goto setup_failed; - break; - default: - break; - } - goto done; - } - - if (wfd_msg->audio_codecs || wfd_msg->video_formats || wfd_msg->video_3d_formats) { - GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); - - if(wfd_msg->audio_codecs) { - res = gst_wfd_base_src_get_audio_parameter(src, wfd_msg); - if(res != GST_RTSP_OK) { - goto message_config_error; - } - - gst_structure_set (stream_info, - "audio_format", G_TYPE_STRING, priv->audio_format, - "audio_channels", G_TYPE_INT, priv->audio_channels, - "audio_rate", G_TYPE_INT, priv->audio_frequency, - "audio_bitwidth", G_TYPE_INT, priv->audio_bitwidth/16, - NULL); - } - - if(wfd_msg->video_formats) { - res = gst_wfd_base_src_get_video_parameter(src, wfd_msg); - if(res != GST_RTSP_OK) { - goto message_config_error; - } - - gst_structure_set (stream_info, - "video_format", G_TYPE_STRING, "H264", - "video_width", G_TYPE_INT, priv->video_width, - "video_height", G_TYPE_INT, priv->video_height, - "video_framerate", G_TYPE_INT, priv->video_framerate, - NULL); - } - - if(wfd_msg->video_3d_formats) { - /* TO DO */ - } - g_signal_emit (src, gst_wfd_base_src_signals[SIGNAL_UPDATE_MEDIA_INFO], 0, stream_info); - } - - /* Note : wfd-presentation-url : - * The wfd-presentation-url parameter describes the Universial Resource Identified (URI) - * to be used in the RTSP Setup (RTSP M6) request message in order to setup the WFD session from the WFD sink to the WFD source. - */ - if(wfd_msg->presentation_url) { - gchar *url0 = NULL, *url1 = NULL; - - WFDCONFIG_GET_PRESENTATION_URL(wfd_msg, &url0, &url1, message_config_error); - - g_free (priv->conninfo.location); - priv->conninfo.location = g_strdup (url0); - /* url1 is ignored as of now */ - } - - /* Note : wfd-client-rtp-ports : - * The wfd-coupled-sink parameter is used by a WFD sink to convey the RTP port(s) that the WFD sink is listening on - * and by the a WFD source to indicate how audio, video or both audio and video payload will be encapsulated in the MPEG2-TS stream - * transmitted from the WFD source to the WFD sink. - */ - if(wfd_msg->client_rtp_ports) { - WFDRTSPTransMode trans = WFD_RTSP_TRANS_UNKNOWN; - WFDRTSPProfile profile = WFD_RTSP_PROFILE_UNKNOWN; - WFDRTSPLowerTrans lowertrans = WFD_RTSP_LOWER_TRANS_UNKNOWN; - guint32 rtp_port0 =0, rtp_port1 =0; - - WFDCONFIG_GET_PREFERD_RTP_PORT(wfd_msg, &trans, &profile, &lowertrans, &rtp_port0, &rtp_port1, message_config_error); - } - - /* Note : wfd-preferred-display-mode : - * The wfd-preferred-display-mode-supported field in a wfd-video-formats and/or in a wfd-3d-formats parameter in an RTSP M3 response message - * indicates whether a WFD sink supports the prefered display mod operation or not. - */ - if(wfd_msg->preferred_display_mode) { - } - - /* Note : wfd-av-format-change-timing : - * The wfd-av-format-change-timing parameter is used to signal the actual AV format change timing of the streaming data to the WFD sink. - * It shall be included in an RTSP M4 request message for WFD capability re-nogotiation after a WFD session has been established. - */ - if (wfd_msg->av_format_change_timing) { - guint64 pts=0LL, dts=0LL; - gboolean need_to_flush = FALSE; - - WFDCONFIG_GET_AV_FORMAT_CHANGE_TIMING(wfd_msg, &pts, &dts, message_config_error); - - if (priv->state == GST_RTSP_STATE_PLAYING) { - GST_DEBUG_OBJECT(src, "change format with PTS[%lld] and DTS[%lld]", pts, dts); - - g_signal_emit (src, gst_wfd_base_src_signals[SIGNAL_AV_FORMAT_CHANGE], 0, (gpointer)&need_to_flush); - - if (need_to_flush) { - gst_wfd_base_src_flush(src,TRUE); - gst_wfd_base_src_flush(src, FALSE); - } - } - } - - /* Note : RTSP M10 : - */ - /* Note : wfd-route : - * The wfd-route parameter provides a mechanism to specify the destination to which the audio stream is to be routed. - */ - if(wfd_msg->route) { - /* TO DO*/ - } - - /* Note : RTSP M12 : - */ - /* Note : wfd-standby : - * The wfd-standby parameter is used to indicate that the sender is entering WFD standby mode. - */ - if(wfd_msg->standby) { - gboolean standby_enable = FALSE; - - WFDCONFIG_GET_STANDBY(wfd_msg, &standby_enable, message_config_error); - - GST_DEBUG_OBJECT (src, "wfd source is entering standby mode"); - } - - if (klass->handle_set_parameter) { - GST_DEBUG_OBJECT(src, "try to handle more SET_PARAMETER parameter"); - res = klass->handle_set_parameter(src, request, &response); - if (res < 0) - goto send_error; - } - break; - } - - default: - { - res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); - if (res < 0) - goto send_error; - - break; - } - } - - res = gst_wfd_base_src_connection_send (src, &response, priv->ptcp_timeout); - if (res < 0) - goto send_error; - -done: - gst_rtsp_message_unset (request); - gst_rtsp_message_unset (&response); - WFDCONFIG_MESSAGE_FREE(wfd_msg); - - return GST_RTSP_OK; - - /* ERRORS */ -setup_failed: - { - GST_ERROR_OBJECT(src, "Could not setup(error)"); - gst_rtsp_message_unset (request); - gst_rtsp_message_unset (&response); - WFDCONFIG_MESSAGE_FREE(wfd_msg); - return GST_RTSP_ERROR; - } -message_config_error: - { - GST_ERROR_OBJECT(src, "Message config error (%d)", wfd_res); - gst_rtsp_message_unset (request); - gst_rtsp_message_unset (&response); - WFDCONFIG_MESSAGE_FREE(wfd_msg); - return GST_RTSP_ERROR; - } -send_error: - { - GST_ERROR_OBJECT(src, "Could not send message"); - gst_rtsp_message_unset (request); - gst_rtsp_message_unset (&response); - WFDCONFIG_MESSAGE_FREE(wfd_msg); - return res; - } -} - -static void -gst_wfd_base_src_loop_start_cmd (GstWFDBaseSrc * src, gint cmd) -{ - GST_DEBUG_OBJECT (src, "start cmd %s", _cmd_to_string(cmd)); - - switch (cmd) { - case WFD_CMD_OPEN: - GST_ELEMENT_PROGRESS (src, START, "open", ("Opening Stream")); - break; - case WFD_CMD_PLAY: - GST_ELEMENT_PROGRESS (src, START, "play", ("Sending PLAY request")); - break; - case WFD_CMD_PAUSE: - GST_ELEMENT_PROGRESS (src, START, "pause", ("Sending PAUSE request")); - break; - case WFD_CMD_CLOSE: - GST_ELEMENT_PROGRESS (src, START, "close", ("Closing Stream")); - break; - default: - break; - } -} - -static void -gst_wfd_base_src_loop_complete_cmd (GstWFDBaseSrc * src, gint cmd) -{ - GST_DEBUG_OBJECT (src, "complete cmd %s", _cmd_to_string(cmd)); - - switch (cmd) { - case WFD_CMD_OPEN: - GST_ELEMENT_PROGRESS (src, COMPLETE, "open", ("Opened Stream")); - break; - case WFD_CMD_PLAY: - GST_ELEMENT_PROGRESS (src, COMPLETE, "play", ("Sent PLAY request")); - break; - case WFD_CMD_PAUSE: - GST_ELEMENT_PROGRESS (src, COMPLETE, "pause", ("Sent PAUSE request")); - break; - case WFD_CMD_CLOSE: - GST_ELEMENT_PROGRESS (src, COMPLETE, "close", ("Closed Stream")); - break; - default: - break; - } -} - -static void -gst_wfd_base_src_loop_cancel_cmd (GstWFDBaseSrc * src, gint cmd) -{ - GST_DEBUG_OBJECT (src, "cancel cmd %s", _cmd_to_string(cmd)); - - switch (cmd) { - case WFD_CMD_OPEN: - GST_ELEMENT_PROGRESS (src, CANCELED, "open", ("Open canceled")); - break; - case WFD_CMD_PLAY: - GST_ELEMENT_PROGRESS (src, CANCELED, "play", ("PLAY canceled")); - break; - case WFD_CMD_PAUSE: - GST_ELEMENT_PROGRESS (src, CANCELED, "pause", ("PAUSE canceled")); - break; - case WFD_CMD_CLOSE: - GST_ELEMENT_PROGRESS (src, CANCELED, "close", ("Close canceled")); - break; - default: - break; - } -} - -static void -gst_wfd_base_src_loop_error_cmd (GstWFDBaseSrc * src, gint cmd) -{ - GST_DEBUG_OBJECT (src, "error cmd %s", _cmd_to_string(cmd)); - - switch (cmd) { - case WFD_CMD_OPEN: - GST_ELEMENT_PROGRESS (src, ERROR, "open", ("Open failed")); - break; - case WFD_CMD_PLAY: - GST_ELEMENT_PROGRESS (src, ERROR, "play", ("PLAY failed")); - break; - case WFD_CMD_PAUSE: - GST_ELEMENT_PROGRESS (src, ERROR, "pause", ("PAUSE failed")); - break; - case WFD_CMD_CLOSE: - GST_ELEMENT_PROGRESS (src, ERROR, "close", ("Close failed")); - break; - default: - break; - } -} - -static void -gst_wfd_base_src_loop_end_cmd (GstWFDBaseSrc * src, gint cmd, GstRTSPResult ret) -{ - GST_DEBUG_OBJECT (src, "end cmd %s", _cmd_to_string(cmd)); - - if (ret == GST_RTSP_OK) - gst_wfd_base_src_loop_complete_cmd (src, cmd); - else if (ret == GST_RTSP_EINTR) - gst_wfd_base_src_loop_cancel_cmd (src, cmd); - else - gst_wfd_base_src_loop_error_cmd (src, cmd); -} - -static gboolean -gst_wfd_base_src_loop_send_cmd (GstWFDBaseSrc * src, gint cmd, gint mask) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - gboolean flushed = FALSE; - gint old; - - /* start new request */ - gst_wfd_base_src_loop_start_cmd (src, cmd); - - GST_DEBUG_OBJECT (src, "sending cmd %s", _cmd_to_string(cmd)); - - GST_OBJECT_LOCK (src); - old = priv->pending_cmd; - if (old != WFD_CMD_WAIT) { - priv->pending_cmd = WFD_CMD_WAIT; - GST_OBJECT_UNLOCK (src); - /* cancel previous request */ - GST_DEBUG_OBJECT (src, "cancel previous request %s", _cmd_to_string (old)); - gst_wfd_base_src_loop_cancel_cmd (src, old); - GST_OBJECT_LOCK (src); - } - priv->pending_cmd = cmd; - /* interrupt if allowed */ - if (priv->busy_cmd & mask) { - GST_DEBUG_OBJECT (src, "connection flush busy %s", - _cmd_to_string (priv->busy_cmd)); - gst_wfd_base_src_connection_flush (src, TRUE); - flushed = TRUE; - } else { - GST_DEBUG_OBJECT (src, "not interrupting busy cmd %s", - _cmd_to_string (priv->busy_cmd)); - } - - if (priv->task) - gst_task_start (priv->task); - GST_OBJECT_UNLOCK (src); - - return flushed; -} - -static GstRTSPResult -gst_wfd_base_src_loop (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res = GST_RTSP_OK; - GstRTSPMessage message = { 0 }; - - if (!priv->conninfo.connection || !priv->conninfo.connected) - goto no_connection; - - while (TRUE) { - GTimeVal tv_timeout; - - /* get the next timeout interval */ - gst_rtsp_connection_next_timeout (priv->conninfo.connection, &tv_timeout); - - GST_DEBUG_OBJECT (src, "doing receive with timeout %d seconds", - (gint) tv_timeout.tv_sec); - - gst_rtsp_message_unset (&message); - - /* we should continue reading the TCP socket because the server might - * send us requests. */ - res = gst_wfd_base_src_connection_receive (src, &message, &tv_timeout); - - switch (res) { - case GST_RTSP_OK: - GST_DEBUG_OBJECT (src, "we received a server message"); - break; - case GST_RTSP_EINTR: - /* we got interrupted, see what we have to do */ - goto interrupt; - case GST_RTSP_ETIMEOUT: - /* timeout */ - break; - case GST_RTSP_EEOF: - /* server closed the connection.*/ - GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), - ("The server closed the connection.")); - goto connect_error; - default: - goto receive_error; - } - - switch (message.type) { - case GST_RTSP_MESSAGE_REQUEST: - /* server sends us a request message, handle it */ - res = gst_wfd_base_src_handle_request(src, &message); - if (res == GST_RTSP_EEOF) - goto server_eof; - else if (res < 0) - goto handle_request_failed; - break; - case GST_RTSP_MESSAGE_RESPONSE: - /* we ignore response and data messages */ - GST_DEBUG_OBJECT (src, "ignoring response message"); - break; - case GST_RTSP_MESSAGE_DATA: - /* we ignore response and data messages */ - GST_DEBUG_OBJECT (src, "ignoring data message"); - break; - default: - GST_WARNING_OBJECT (src, "ignoring unknown message type %d", - message.type); - break; - } - } - g_assert_not_reached (); - - return res; - -no_connection: - { - res = GST_RTSP_ERROR; - GST_ERROR_OBJECT (src, "we are not connected"); - goto pause; - } -interrupt: - { - /* we get here when the connection got interrupted */ - gst_rtsp_message_unset (&message); - GST_DEBUG_OBJECT (src, "got interrupted"); - goto pause; - } -connect_error: - { - gchar *str = gst_rtsp_strresult (res); - - priv->conninfo.connected = FALSE; - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Could not connect to server. (%s)", str)); - g_free (str); - - goto pause; - } -receive_error: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Could not receive message. (%s)", str)); - g_free (str); - - goto pause; - } -handle_request_failed: - { - gchar *str = gst_rtsp_strresult (res); - - gst_rtsp_message_unset (&message); - if (res != GST_RTSP_EINTR) - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not handle server message. (%s)", str)); - g_free (str); - - goto pause; - } -server_eof: - { - GST_DEBUG_OBJECT (src, "we got an eof from the server"); - GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), - ("The server closed the connection.")); - priv->conninfo.connected = FALSE; - gst_rtsp_message_unset (&message); - - goto pause; - } -pause: - { - gchar *str = gst_rtsp_strresult (res); - GstWFDBaseSrcClass *klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (res == GST_RTSP_EEOF) { - /* perform EOS logic */ - if (klass->push_event) - klass->push_event(src, gst_event_new_eos ()); - } else if (res == GST_RTSP_EINTR) { - GST_DEBUG_OBJECT (src, "interupted"); - } else if (res < GST_RTSP_OK) { - /* for fatal errors we post an error message, post the error before the - * EOS so the app knows about the error first. */ - GST_ELEMENT_ERROR (src, STREAM, FAILED, - ("Internal data flow error."), - ("streaming task paused, reason %s (%d)", str, res)); - if (klass->push_event) - klass->push_event(src, gst_event_new_eos ()); - } - - if (res != GST_RTSP_EINTR) { - GST_DEBUG_OBJECT (src, "pausing task, reason %s", str); - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_WAIT, WFD_CMD_LOOP); - } - - g_free (str); - - return res; - } -} - -static GstRTSPResult -gst_wfd_base_src_try_send (GstWFDBaseSrc * src, GstRTSPMessage * request, - GstRTSPMessage * response, GstRTSPStatusCode * code) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res = GST_RTSP_OK; - GstRTSPStatusCode thecode = GST_RTSP_STS_OK; - - res = gst_wfd_base_src_connection_send (src, request, priv->ptcp_timeout); - if (res < 0) - goto send_error; - - gst_rtsp_connection_reset_timeout (priv->conninfo.connection); - -next: - res = gst_wfd_base_src_connection_receive (src, response, priv->ptcp_timeout); - if (res < 0) - goto receive_error; - - switch (response->type) { - case GST_RTSP_MESSAGE_REQUEST: - res = gst_wfd_base_src_handle_request(src, response); - if (res == GST_RTSP_EEOF) - goto server_eof; - else if (res < 0) - goto handle_request_failed; - goto next; - case GST_RTSP_MESSAGE_RESPONSE: - /* ok, a response is good */ - GST_DEBUG_OBJECT (src, "received response message"); - break; - default: - case GST_RTSP_MESSAGE_DATA: - /* get next response */ - GST_DEBUG_OBJECT (src, "ignoring data response message"); - goto next; - } - - thecode = response->type_data.response.code; - - GST_DEBUG_OBJECT (src, "got response message %d", thecode); - - /* if the caller wanted the result code, we store it. */ - if (code) - *code = thecode; - - /* If the request didn't succeed, bail out before doing any more */ - if (thecode != GST_RTSP_STS_OK) - return GST_RTSP_OK; - - return GST_RTSP_OK; - - /* ERRORS */ -send_error: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message. (%s)", str)); - g_free (str); - return res; - } -receive_error: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Could not receive message. (%s)", str)); - g_free (str); - return res; - } -handle_request_failed: - { - /* ERROR was posted */ - gst_rtsp_message_unset (response); - return res; - } -server_eof: - { - GST_DEBUG_OBJECT (src, "we got an eof from the server"); - GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), - ("The server closed the connection.")); - gst_rtsp_message_unset (response); - return res; - } -} - -/** - * gst_wfd_base_src_send: - * @src: the rtsp source - * @conn: the connection to send on - * @request: must point to a valid request - * @response: must point to an empty #GstRTSPMessage - * @code: an optional code result - * - * send @request and retrieve the response in @response. optionally @code can be - * non-NULL in which case it will contain the status code of the response. - * - * If This function returns #GST_RTSP_OK, @response will contain a valid response - * message that should be cleaned with gst_rtsp_message_unset() after usage. - * - * If @code is NULL, this function will return #GST_RTSP_ERROR (with an invalid - * @response message) if the response code was not 200 (OK). - * - * Returns: #GST_RTSP_OK if the processing was successful. - */ - -static GstRTSPResult -gst_wfd_base_src_send (GstWFDBaseSrc * src, GstRTSPMessage * request, - GstRTSPMessage * response, GstRTSPStatusCode * code) -{ - GstRTSPStatusCode int_code = GST_RTSP_STS_OK; - GstRTSPResult res = GST_RTSP_ERROR; - GstRTSPMethod method = GST_RTSP_INVALID; - - /* save method so we can disable it when the server complains */ - method = request->type_data.request.method; - - if ((res = - gst_wfd_base_src_try_send (src, request, response, &int_code)) < 0) - goto error; - - /* If the user requested the code, let them handle errors, otherwise - * post an error below */ - if (code != NULL) - *code = int_code; - else if (int_code != GST_RTSP_STS_OK) - goto error_response; - - return res; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (src, "got error %d", res); - return res; - } -error_response: - { - res = GST_RTSP_ERROR; - - switch (response->type_data.response.code) { - case GST_RTSP_STS_NOT_FOUND: - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s", - response->type_data.response.reason)); - break; - case GST_RTSP_STS_NOT_ACCEPTABLE: - case GST_RTSP_STS_NOT_IMPLEMENTED: - case GST_RTSP_STS_METHOD_NOT_ALLOWED: - GST_ERROR_OBJECT (src, "got NOT IMPLEMENTED, disable method %s", - gst_rtsp_method_as_text (method)); - src->priv->methods &= ~method; - res = GST_RTSP_OK; - break; - default: - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Got error response: %d (%s).", response->type_data.response.code, - response->type_data.response.reason)); - break; - } - /* if we return ERROR we should unset the response ourselves */ - if (res == GST_RTSP_ERROR) - gst_rtsp_message_unset (response); - - return res; - } -} - - -/* parse the response and collect all the supported methods. We need this - * information so that we don't try to send an unsupported request to the - * server. - */ -static gboolean -gst_wfd_base_src_parse_methods (GstWFDBaseSrc * src, GstRTSPMessage * response) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPHeaderField field; - gchar *respoptions; - gchar **options; - gint indx = 0; - gint i; - - /* reset supported methods */ - priv->methods = 0; - - /* Try Allow Header first */ - field = GST_RTSP_HDR_ALLOW; - while (TRUE) { - respoptions = NULL; - gst_rtsp_message_get_header (response, field, &respoptions, indx); - if (indx == 0 && !respoptions) { - /* if no Allow header was found then try the Public header... */ - field = GST_RTSP_HDR_PUBLIC; - gst_rtsp_message_get_header (response, field, &respoptions, indx); - } - if (!respoptions) - break; - - /* If we get here, the server gave a list of supported methods, parse - * them here. The string is like: - * - * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ... - */ - options = g_strsplit (respoptions, ",", 0); - - for (i = 0; options[i]; i++) { - gchar *stripped; - gint method; - - stripped = g_strstrip (options[i]); - method = gst_rtsp_find_method (stripped); - - /* keep bitfield of supported methods */ - if (method != GST_RTSP_INVALID) - priv->methods |= method; - } - g_strfreev (options); - - indx++; - } - - if (priv->methods == 0) { - /* neither Allow nor Public are required, assume the server supports - * at least DESCRIBE, SETUP, we always assume it supports PLAY as - * well. */ - GST_DEBUG_OBJECT (src, "could not get OPTIONS"); - priv->methods = GST_RTSP_SETUP; - } - /* always assume PLAY, FIXME, extensions should be able to override - * this */ - priv->methods |= GST_RTSP_PLAY; - - if (!(priv->methods & GST_RTSP_SETUP)) - goto no_setup; - - return TRUE; - -no_setup: - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("Server does not support SETUP.")); - return FALSE; - } -} - -static GstRTSPResult -gst_wfd_base_src_create_transports_string (GstWFDBaseSrc * src, gchar ** transports) -{ - GString *result; - - *transports = NULL; - - GST_DEBUG_OBJECT (src, "got transports %s", GST_STR_NULL (*transports)); - - /* extension listed transports, use those */ - if (*transports != NULL) - return GST_RTSP_OK; - - /* the default RTSP transports */ - result = g_string_new (""); - GST_DEBUG_OBJECT (src, "adding UDP unicast"); - - g_string_append (result, "RTP/AVP"); - g_string_append (result, "/UDP"); - g_string_append (result, ";unicast;client_port="); - g_string_append_printf (result, "%d", src->priv->primary_rtpport); - g_string_append (result, "-"); - g_string_append_printf (result, "%d", src->priv->primary_rtpport+1); - - *transports = g_string_free (result, FALSE); - - GST_DEBUG_OBJECT (src, "prepared transports %s", GST_STR_NULL (*transports)); - - return GST_RTSP_OK; -} - -gboolean -gst_wfd_base_src_activate (GstWFDBaseSrc *src) -{ - GST_DEBUG_OBJECT (src, "activating streams"); - - if (src->srcpad) { - GST_DEBUG_OBJECT (src, "setting caps"); - gst_pad_set_caps (src->srcpad, src->caps); - - GST_DEBUG_OBJECT (src, "activating srcpad"); - gst_pad_set_active (src->srcpad, TRUE); - } - - return TRUE; -} - -void -gst_wfd_base_src_get_transport_info (GstWFDBaseSrc *src, - GstRTSPTransport * transport, const gchar ** destination, gint * min, gint * max) -{ - g_return_if_fail (transport); - g_return_if_fail (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); - - if (destination) { - /* first take the source, then the endpoint to figure out where to send - * the RTCP. */ - if (!(*destination = transport->source)) { - if (src->priv->conninfo.connection) - *destination = - gst_rtsp_connection_get_ip (src->priv->conninfo.connection); - } - } - if (min && max) { - /* for unicast we only expect the ports here */ - *min = transport->server_port.min; - *max = transport->server_port.max; - } -} - -/* Perform the SETUP request for all the streams. - * - * We ask the server for a specific transport, which initially includes all the - * ones we can support (UDP/TCP/MULTICAST). For the UDP transport we allocate - * two local UDP ports that we send to the server. - * - * Once the server replied with a transport, we configure the other streams - * with the same transport. - * - * This function will also configure the manager for the selected transport, - * which basically means creating the pipeline. - */ -static gboolean -gst_wfd_base_src_setup (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDBaseSrcClass * klass; - GstRTSPResult res = GST_RTSP_OK; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstRTSPLowerTrans protocols = GST_RTSP_LOWER_TRANS_UNKNOWN; - GstRTSPStatusCode code = GST_RTSP_STS_OK; - gchar *resptrans = NULL; - GstRTSPTransport transport = { 0 }; - gchar *transports = NULL; - GstRTSPUrl *url; - gchar *hval; - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (G_UNLIKELY (!klass->prepare_transport)) - goto no_function; - if (G_UNLIKELY (!klass->configure_transport)) - goto no_function; - - if (!priv->conninfo.connection || !priv->conninfo.connected) - goto no_connection; - - url = gst_rtsp_connection_get_url (priv->conninfo.connection); - protocols = url->transports & GST_RTSP_LOWER_TRANS_UDP; - if (protocols == 0) - goto no_protocols; - - GST_DEBUG_OBJECT (src, "doing setup of with %s", GST_STR_NULL(priv->conninfo.location)); - - GST_DEBUG_OBJECT (src, "protocols = 0x%x", protocols); - /* create a string with first transport in line */ - res = gst_wfd_base_src_create_transports_string (src, &transports); - if (res < 0 || transports == NULL) - goto setup_transport_failed; - - if (strlen (transports) == 0) { - g_free (transports); - GST_DEBUG_OBJECT (src, "no transports found"); - goto setup_transport_failed; - } - - /* now prepare with the selected transport */ - res = klass->prepare_transport(src, priv->primary_rtpport, priv->primary_rtpport+1); - if (res < 0) - goto setup_failed; - - /* create SETUP request */ -<<<<<<< HEAD:wfdmanager/src/gstwfdrtspsrc.c - res = gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, src->conninfo.location); -======= - res = - gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, priv->conninfo.location); ->>>>>>> ef7394e... [wfdmanager] Change the structure of Wi-Fi display sink's source element for making possible to be inherited:wfdmanager/wfdbase/gstwfdbasesrc.c.orig - if (res < 0) { - g_free (transports); - goto create_request_failed; - } - - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transports); - g_free (transports); - - /* if the user wants a non default RTP packet size we add the blocksize - * parameter */ - if (priv->rtp_blocksize > 0) { - hval = g_strdup_printf ("%d", priv->rtp_blocksize); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_BLOCKSIZE, hval); - g_free (hval); - } - - /* handle the code ourselves */ - if ((res = gst_wfd_base_src_send (src, &request, &response, &code) < 0)) - goto send_error; - - switch (code) { - case GST_RTSP_STS_OK: - break; - case GST_RTSP_STS_UNSUPPORTED_TRANSPORT: - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - goto no_protocols; - break; - default: - goto response_error; - } - - /* parse response transport */ - gst_rtsp_message_get_header (&response, GST_RTSP_HDR_TRANSPORT, - &resptrans, 0); - if (!resptrans) - goto no_transport; - - /* parse transport, go to next manager on parse error */ - if (gst_rtsp_transport_parse (resptrans, &transport) != GST_RTSP_OK) { - GST_ERROR_OBJECT (src, "failed to parse transport %s", resptrans); - goto setup_failed; - } - - /* now configure the manager with the selected transport */ - res = klass->configure_transport(src, &transport); - if (res < 0) - goto setup_failed; - - priv->protocol = transport.lower_transport; - - /* clean up our transport struct */ - gst_rtsp_transport_init (&transport); - /* clean up used RTSP messages */ - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - - priv->state = GST_RTSP_STATE_READY; - - return TRUE; - - /* ERRORS */ -no_function: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("No prepare or configure function.")); - return FALSE; - } -no_connection: - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Could not connct to server, no connection.")); - return FALSE; - } -no_protocols: - { - /* no transport possible, post an error and stop */ - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), - ("Could not connect to server, no protocols left")); - return FALSE; - } -create_request_failed: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Could not create request. (%s)", str)); - g_free (str); - goto cleanup_error; - } -setup_transport_failed: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Could not setup transport.")); - goto cleanup_error; - } -response_error: - { - const gchar *str = gst_rtsp_status_as_text (code); - - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Error (%d): %s", code, GST_STR_NULL (str))); - goto cleanup_error; - } -send_error: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message. (%s)", str)); - g_free (str); - goto cleanup_error; - } -no_transport: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Server did not select transport.")); - goto cleanup_error; - } -setup_failed: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), - ("Could not setup.")); - goto cleanup_error; - } -cleanup_error: - { - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - return FALSE; - } -} - -/* Note : RTSP M1~M6 : - * WFD session capability negotiation - */ -static GstRTSPResult -gst_wfd_base_src_open (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res = GST_RTSP_OK; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstRTSPMessage message = { 0 }; - GstRTSPMethod method = { 0 }; - gchar *str = NULL; - - /* can't continue without a valid url */ - if (G_UNLIKELY (priv->conninfo.url == NULL)) - goto no_url; - - if ((res = gst_wfd_base_src_conninfo_connect (src, &priv->conninfo)) < 0) - goto connect_failed; - - res = gst_wfd_base_src_connection_receive (src, &message, priv->ptcp_timeout); - if(res != GST_RTSP_OK) - goto connect_failed; - - if(message.type == GST_RTSP_MESSAGE_REQUEST) { - method = message.type_data.request.method; - if(method == GST_RTSP_OPTIONS) { - res = gst_wfd_base_src_handle_request(src, &message); - if (res < GST_RTSP_OK) - goto connect_failed; - } else - goto methods_error; - } else { - GST_ERROR_OBJECT (src, "failed to receive options..."); - goto methods_error; - } - - /* create OPTIONS */ - GST_DEBUG_OBJECT (src, "create options..."); - res = gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,"*"); - if (res < 0) - goto create_request_failed; - - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, "org.wfa.wfd1.0"); - - /* send OPTIONS */ - GST_DEBUG_OBJECT (src, "send options..."); - if ((res = gst_wfd_base_src_send (src, &request, &response, - NULL)) < 0) - goto send_error; - - /* parse OPTIONS */ - if (!gst_wfd_base_src_parse_methods (src, &response)) - goto methods_error; - - /* Receive request message from source */ -receive_request_message: - res = gst_wfd_base_src_connection_receive (src, &message, - priv->ptcp_timeout); - if(res != GST_RTSP_OK) - goto connect_failed; - - if(message.type == GST_RTSP_MESSAGE_REQUEST) { - method = message.type_data.request.method; - if(method == GST_RTSP_GET_PARAMETER ||method == GST_RTSP_SET_PARAMETER) { - res = gst_wfd_base_src_handle_request(src, &message); - if (res < GST_RTSP_OK) - goto handle_request_failed; - } else - goto methods_error; - - if (priv->state != GST_RTSP_STATE_READY) - goto receive_request_message; - } - - /* clean up any messages */ - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - - return res; - - /* ERRORS */ -no_url: - { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), - ("No valid RTSP URL was provided")); - goto cleanup_error; - } -connect_failed: - { - str = NULL; - str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Failed to connect. (%s)", str)); - g_free (str); - goto cleanup_error; - } -create_request_failed: - { - str = NULL; - str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Could not create request. (%s)", str)); - g_free (str); - goto cleanup_error; - } -send_error: - { - GST_ERROR_OBJECT (src, "send errors"); - /* Don't post a message - the rtsp_send method will have - * taken care of it because we passed NULL for the response code */ - goto cleanup_error; - } -methods_error: - { - GST_ERROR_OBJECT (src, "method errors"); - /* error was posted */ - goto cleanup_error; - } -handle_request_failed: - { - GST_ERROR_OBJECT (src, "failed to handle request"); - /* error was posted */ - goto cleanup_error; - } -cleanup_error: - { - GST_ERROR_OBJECT (src, "failed to open"); - - if (priv->conninfo.connection) { - GST_ERROR_OBJECT (src, "free connection"); - gst_wfd_base_src_conninfo_close (src, &priv->conninfo, TRUE); - } - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - return res; - } -} - -static void -gst_wfd_base_src_send_close_cmd (GstWFDBaseSrc * src) -{ - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_CLOSE, WFD_CMD_ALL); -} - -/* Note : RTSP M8 : - * Send TEARDOWN request to WFD source. - */ -static GstRTSPResult -gst_wfd_base_src_close (GstWFDBaseSrc * src, gboolean only_close) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDBaseSrcClass *klass; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstRTSPResult res = GST_RTSP_OK; - - GST_DEBUG_OBJECT (src, "TEARDOWN..."); - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (klass->set_state) - klass->set_state (src, GST_STATE_READY); - - if (priv->state < GST_RTSP_STATE_READY) { - GST_DEBUG_OBJECT (src, "not ready, doing cleanup"); - goto close; - } - - if (only_close) - goto close; - - if (!priv->conninfo.connection || !priv->conninfo.connected) - goto close; - - if (!(priv->methods & (GST_RTSP_PLAY | GST_RTSP_TEARDOWN))) - goto not_supported; - - /* do TEARDOWN */ - res = - gst_rtsp_message_init_request (&request, GST_RTSP_TEARDOWN, priv->conninfo.url_str); - if (res < 0) - goto create_request_failed; - - if ((res = - gst_wfd_base_src_send (src, &request, &response, - NULL)) < 0) - goto send_error; - - /* FIXME, parse result? */ - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - -close: - /* close connections */ - GST_DEBUG_OBJECT (src, "closing connection..."); - gst_wfd_base_src_conninfo_close (src, &priv->conninfo, TRUE); - - priv->state = GST_RTSP_STATE_INVALID; - - return res; - - /* ERRORS */ -create_request_failed: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Could not create request. (%s)", str)); - g_free (str); - goto close; - } -send_error: - { - gchar *str = gst_rtsp_strresult (res); - - gst_rtsp_message_unset (&request); - if (res != GST_RTSP_EINTR) { - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message. (%s)", str)); - } else { - GST_ERROR_OBJECT (src, "TEARDOWN interrupted"); - } - g_free (str); - goto close; - } -not_supported: - { - GST_ERROR_OBJECT (src, - "TEARDOWN and PLAY not supported, can't do TEARDOWN"); - goto close; - } -} - -/* RTP-Info is of the format: - * - * url=;[seq=;rtptime=] [, url=...] - * - * rtptime corresponds to the timestamp for the NPT time given in the header - * seqbase corresponds to the next sequence number we received. This number - * indicates the first seqnum after the seek and should be used to discard - * packets that are from before the seek. - */ -static gboolean -gst_wfd_base_src_parse_rtpinfo (GstWFDBaseSrc * src, gchar * rtpinfo) -{ - gchar **infos; - gint i, j; - - GST_DEBUG_OBJECT (src, "parsing RTP-Info %s", rtpinfo); - - infos = g_strsplit (rtpinfo, ",", 0); - for (i = 0; infos[i]; i++) { - gchar **fields; - gint64 seqbase; - gint64 timebase; - - GST_DEBUG_OBJECT (src, "parsing info %s", infos[i]); - - /* init values, types of seqbase and timebase are bigger than needed so we - * can store -1 as uninitialized values */ - seqbase = GST_CLOCK_TIME_NONE; - timebase = GST_CLOCK_TIME_NONE; - - /* parse url, find manager for url. - * parse seq and rtptime. The seq number should be configured in the rtp - * depayloader or session manager to detect gaps. Same for the rtptime, it - * should be used to create an initial time newsegment. */ - fields = g_strsplit (infos[i], ";", 0); - for (j = 0; fields[j]; j++) { - GST_DEBUG_OBJECT (src, "parsing field %s", fields[j]); - /* remove leading whitespace */ - fields[j] = g_strchug (fields[j]); - if (g_str_has_prefix (fields[j], "url=")) { - /* get the url and the manager */ - } else if (g_str_has_prefix (fields[j], "seq=")) { - seqbase = atoi (fields[j] + 4); - } else if (g_str_has_prefix (fields[j], "rtptime=")) { - timebase = g_ascii_strtoll (fields[j] + 8, NULL, 10); - } - } - g_strfreev (fields); - /* now we need to store the values for the caps of the manager */ - GST_DEBUG_OBJECT (src, - "setting: seqbase %"G_GINT64_FORMAT", timebase %" G_GINT64_FORMAT, - seqbase, timebase); - } - g_strfreev (infos); - - return TRUE; -} - -static void -gst_wfd_base_src_send_play_cmd (GstWFDBaseSrc * src) -{ - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PLAY, WFD_CMD_LOOP); -} - -/* Note : RTSP M7 : - * Send PLAY request to WFD source. WFD source begins audio and/or video streaming. - */ -static GstRTSPResult -gst_wfd_base_src_play (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstWFDBaseSrcClass *klass; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstRTSPResult res = GST_RTSP_OK; - gchar *hval; - gint hval_idx; - - GST_DEBUG_OBJECT (src, "PLAY..."); - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (!priv->conninfo.connection || !priv->conninfo.connected) - goto done; - - if (!(priv->methods & GST_RTSP_PLAY)) - goto not_supported; - - if (priv->state == GST_RTSP_STATE_PLAYING) - goto was_playing; - - /* do play */ - res = gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, priv->conninfo.url_str); - if (res < 0) - goto create_request_failed; - - if ((res = gst_wfd_base_src_send (src, &request, &response, NULL)) < 0) - goto send_error; - - gst_rtsp_message_unset (&request); - - /* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp - * for the RTP packets. If this is not present, we assume all starts from 0... - * This is info for the RTP session manager that we pass to it in caps. */ - hval_idx = 0; - while (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_RTP_INFO, - &hval, hval_idx++) == GST_RTSP_OK) - gst_wfd_base_src_parse_rtpinfo (src, hval); - - gst_rtsp_message_unset (&response); - - /* configure the caps of the streams after we parsed all headers. */ - gst_wfd_base_src_configure_caps (src); - - /* set to PLAYING after we have configured the caps, otherwise we - * might end up calling request_key (with SRTP) while caps are still - * being configured. */ - if (klass->set_state) - klass->set_state (src, GST_STATE_PLAYING); - - priv->state = GST_RTSP_STATE_PLAYING; - -done: - return res; - - /* ERRORS */ -not_supported: - { - GST_ERROR_OBJECT (src, "PLAY is not supported"); - goto done; - } -was_playing: - { - GST_DEBUG_OBJECT (src, "we were already PLAYING"); - goto done; - } -create_request_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Could not create request.")); - return FALSE; - } -send_error: - { - gst_rtsp_message_unset (&request); - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message.")); - return FALSE; - } -} - -static void -gst_wfd_base_src_send_pause_cmd (GstWFDBaseSrc * src) -{ - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PAUSE, WFD_CMD_LOOP); -} - -/* Note : RTSP M9 : - * Send PAUSE request to WFD source. WFD source pauses the audio video stream(s). - */ -static GstRTSPResult -gst_wfd_base_src_pause (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res = GST_RTSP_OK; - GstRTSPMessage request = { 0 }; - GstRTSPMessage response = { 0 }; - GstWFDBaseSrcClass * klass; - - GST_DEBUG_OBJECT (src, "PAUSE..."); - - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (!priv->conninfo.connection || !priv->conninfo.connected) - goto no_connection; - - if (!(priv->methods & GST_RTSP_PAUSE)) - goto not_supported; - - if (priv->state == GST_RTSP_STATE_READY) - goto was_paused; - - if (gst_rtsp_message_init_request (&request, GST_RTSP_PAUSE, priv->conninfo.url_str) < 0) - goto create_request_failed; - - if ((res = gst_wfd_base_src_send (src, &request, &response, NULL)) < 0) - goto send_error; - - gst_rtsp_message_unset (&request); - gst_rtsp_message_unset (&response); - - if (klass->set_state) - klass->set_state (src, GST_STATE_PAUSED); - -no_connection: - priv->state = GST_RTSP_STATE_READY; - -done: - return res; - - /* ERRORS */ -not_supported: - { - GST_ERROR_OBJECT (src, "PAUSE is not supported"); - goto done; - } -was_paused: - { - GST_DEBUG_OBJECT (src, "we were already PAUSED"); - goto done; - } -create_request_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Could not create request.")); - goto done; - } -send_error: - { - gst_rtsp_message_unset (&request); - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message.")); - goto done; - } -} - -static void -gst_wfd_base_src_handle_message (GstBin * bin, GstMessage * message) -{ - GstWFDBaseSrc *src = GST_WFD_BASE_SRC (bin); - - GST_DEBUG_OBJECT (src, "got %s message from %s", - GST_MESSAGE_TYPE_NAME (message), GST_MESSAGE_SRC_NAME (message)); - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_EOS: - gst_message_unref (message); - break; - case GST_MESSAGE_ELEMENT: - { - const GstStructure *s = gst_message_get_structure (message); - if (gst_structure_has_name (s, "GstUDPSrcTimeout")) - GST_DEBUG_OBJECT (bin, "timeout on UDP port"); - - GST_BIN_CLASS (parent_class)->handle_message (bin, message); - break; - } - case GST_MESSAGE_ERROR: - { - gchar* debug = NULL; - GError* error = NULL; - - gst_message_parse_error (message, &error, &debug); - GST_ERROR_OBJECT (src, "error : %s", error->message); - GST_ERROR_OBJECT (src, "debug : %s", debug); - g_free (debug); - g_error_free (error); - - /* fatal but not our message, forward */ - GST_BIN_CLASS (parent_class)->handle_message (bin, message); - break; - } - default: - { - GST_BIN_CLASS (parent_class)->handle_message (bin, message); - break; - } - } -} - -/* the thread where everything happens */ -static void -gst_wfd_base_src_thread (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstRTSPResult res = GST_RTSP_OK; - gint cmd; - - GST_OBJECT_LOCK (src); - cmd = priv->pending_cmd; - if (cmd == WFD_CMD_PLAY || cmd == WFD_CMD_PAUSE || cmd == WFD_CMD_REQUEST - || cmd == WFD_CMD_LOOP || cmd == WFD_CMD_OPEN) - priv->pending_cmd = WFD_CMD_LOOP; - else - priv->pending_cmd = WFD_CMD_WAIT; - - GST_DEBUG_OBJECT (src, "got command %s", _cmd_to_string (cmd)); - - /* we got the message command, so ensure communication is possible again */ - gst_wfd_base_src_connection_flush (src, FALSE); - - priv->busy_cmd = cmd; - GST_OBJECT_UNLOCK (src); - - switch (cmd) { - case WFD_CMD_OPEN: - res = gst_wfd_base_src_open (src); - break; - case WFD_CMD_PLAY: - res = gst_wfd_base_src_play (src); - break; - case WFD_CMD_PAUSE: - res = gst_wfd_base_src_pause (src); - break; - case WFD_CMD_CLOSE: - res = gst_wfd_base_src_close (src, FALSE); - break; - case WFD_CMD_LOOP: - res = gst_wfd_base_src_loop (src); - break; - case WFD_CMD_REQUEST: - res = gst_wfd_base_src_send_request (src); - break; - default: - break; - } - - GST_OBJECT_LOCK (src); - /* and go back to sleep */ - if (priv->pending_cmd == WFD_CMD_WAIT) { - if (priv->task) - gst_task_pause (priv->task); - } - /* reset waiting */ - priv->busy_cmd = WFD_CMD_WAIT; - GST_OBJECT_UNLOCK (src); - - if (cmd == WFD_CMD_PLAY || cmd == WFD_CMD_PAUSE - || cmd == WFD_CMD_CLOSE || cmd == WFD_CMD_OPEN) - gst_wfd_base_src_loop_end_cmd (src, cmd, res); -} - -static gboolean -gst_wfd_base_src_start (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - - GST_DEBUG_OBJECT (src, "starting"); - - GST_OBJECT_LOCK (src); - - priv->state = GST_RTSP_STATE_INIT; - - priv->pending_cmd = WFD_CMD_WAIT; - - if (priv->task == NULL) { - priv->task = gst_task_new ((GstTaskFunction) gst_wfd_base_src_thread, src, NULL); - if (priv->task == NULL) - goto task_error; - - gst_task_set_lock (priv->task, &(GST_WFD_BASE_TASK_GET_LOCK (src))); - } - GST_OBJECT_UNLOCK (src); - - return TRUE; - - /* ERRORS */ -task_error: - { - GST_OBJECT_UNLOCK (src); - GST_ERROR_OBJECT (src, "failed to create task"); - return FALSE; - } -} - -static gboolean -gst_wfd_base_src_stop (GstWFDBaseSrc * src) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - GstTask *task; - - GST_DEBUG_OBJECT (src, "stopping"); - - GST_OBJECT_LOCK (src); - priv->do_stop = TRUE; - GST_OBJECT_UNLOCK (src); - - /* also cancels pending task */ - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_WAIT, WFD_CMD_ALL); - - GST_OBJECT_LOCK (src); - if ((task = priv->task)) { - priv->task = NULL; - GST_OBJECT_UNLOCK (src); - - gst_task_stop (task); - - /* make sure it is not running */ - GST_WFD_BASE_TASK_LOCK (src); - GST_WFD_BASE_TASK_UNLOCK (src); - - /* now wait for the task to finish */ - gst_task_join (task); - - /* and free the task */ - gst_object_unref (GST_OBJECT (task)); - GST_OBJECT_LOCK (src); - } - GST_OBJECT_UNLOCK (src); - - /* ensure synchronously all is closed */ - gst_wfd_base_src_close (src, TRUE); - - /* cleanup */ - gst_wfd_base_src_cleanup (src); - - return TRUE; -} - - -static GstStateChangeReturn -gst_wfd_base_src_change_state (GstElement * element, GstStateChange transition) -{ - GstWFDBaseSrc *src; - GstStateChangeReturn ret; - - src = GST_WFD_BASE_SRC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - GST_DEBUG_OBJECT (src, "NULL->READY"); - if (!gst_wfd_base_src_start (src)) - goto start_failed; - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (src, "READY->PAUSED"); - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_OPEN, 0); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - GST_DEBUG_OBJECT(src, "PAUSED->PLAYING"); - break; - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - GST_DEBUG_OBJECT(src, "PLAYING->PAUSED"); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_DEBUG_OBJECT(src, "PAUSED->READY"); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - GST_DEBUG_OBJECT (src, "READY->NULL"); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - goto done; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - gst_wfd_base_src_loop_send_cmd (src, WFD_CMD_PLAY, WFD_CMD_LOOP); - break; - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_READY_TO_PAUSED: - ret = GST_STATE_CHANGE_NO_PREROLL; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_wfd_base_src_stop (src); - break; - default: - break; - } - -done: - return ret; - -start_failed: - { - GST_ERROR_OBJECT (src, "start failed"); - return GST_STATE_CHANGE_FAILURE; - } -} - -static gboolean -gst_wfd_base_src_send_event (GstElement * element, GstEvent * event) -{ - gboolean res = FALSE; - GstWFDBaseSrc *src; - GstWFDBaseSrcClass *klass; - - src = GST_WFD_BASE_SRC (element); - klass = GST_WFD_BASE_SRC_GET_CLASS (src); - - if (GST_EVENT_IS_DOWNSTREAM (event)) { - if (klass->push_event) - res = klass->push_event(src, event); - } else { - res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); - } - - return res; -} - -static void -gst_wfd_base_src_set_standby (GstWFDBaseSrc * src) -{ - GST_OBJECT_LOCK(src); - memset (&src->request_param, 0, sizeof(GstWFDRequestParam)); - src->request_param.type = WFD_STANDBY; - GST_OBJECT_UNLOCK(src); - - gst_wfd_base_src_loop_send_cmd(src, WFD_CMD_REQUEST, WFD_CMD_LOOP); -} - -gboolean -gst_wfd_base_src_set_target (GstWFDBaseSrc * src, GstPad *target) -{ - gboolean ret; - - ret = gst_ghost_pad_set_target (GST_GHOST_PAD (src->srcpad), target); - - return ret; -} - -/*** GSTURIHANDLER INTERFACE *************************************************/ -static GstURIType -gst_wfd_base_src_uri_get_type (GType type) -{ - return GST_URI_SRC; -} - -static const gchar * const * -gst_wfd_base_src_uri_get_protocols (GType type) -{ - static const gchar *protocols[] = - { "rtsp", NULL }; - - return protocols; -} - -static gchar * -gst_wfd_base_src_uri_get_uri (GstURIHandler * handler) -{ - GstWFDBaseSrc *src = GST_WFD_BASE_SRC (handler); - - /* should not dup */ - return src->priv->conninfo.location; -} - -static gboolean -gst_wfd_base_src_uri_set_uri (GstURIHandler * handler, const gchar * uri, GError **error) -{ - GstWFDBaseSrc *src; - GstRTSPResult res; - GstRTSPUrl *newurl = NULL; - - src = GST_WFD_BASE_SRC (handler); - - /* same URI, we're fine */ - if (src->priv->conninfo.location && uri && !strcmp (uri, src->priv->conninfo.location)) - goto was_ok; - - /* try to parse */ - GST_DEBUG_OBJECT (src, "parsing URI"); - if ((res = gst_rtsp_url_parse (uri, &newurl)) < 0) - goto parse_error; - - - /* if worked, free previous and store new url object along with the original - * location. */ - GST_DEBUG_OBJECT (src, "configuring URI"); - g_free (src->priv->conninfo.location); - src->priv->conninfo.location = g_strdup (uri); - gst_rtsp_url_free (src->priv->conninfo.url); - src->priv->conninfo.url = newurl; - g_free (src->priv->conninfo.url_str); - if (newurl) - src->priv->conninfo.url_str = gst_rtsp_url_get_request_uri (src->priv->conninfo.url); - else - src->priv->conninfo.url_str = NULL; - - GST_DEBUG_OBJECT (src, "set uri: %s", GST_STR_NULL (uri)); - GST_DEBUG_OBJECT (src, "request uri is: %s", - GST_STR_NULL (src->priv->conninfo.url_str)); - - return TRUE; - - /* Special cases */ -was_ok: - { - GST_DEBUG_OBJECT (src, "URI was ok: '%s'", GST_STR_NULL (uri)); - return TRUE; - } -parse_error: - { - GST_ERROR_OBJECT (src, "Not a valid RTSP url '%s' (%d)", - GST_STR_NULL (uri), res); - return FALSE; - } -} - -static void -gst_wfd_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - - iface->get_type = gst_wfd_base_src_uri_get_type; - iface->get_protocols = gst_wfd_base_src_uri_get_protocols; - iface->get_uri = gst_wfd_base_src_uri_get_uri; - iface->set_uri = gst_wfd_base_src_uri_set_uri; -} - -static GstRTSPResult _get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, WFDVideoCEAResolution Resolution) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - WFDVideoCEAResolution CEARes = Resolution; - - switch(CEARes) - { - case WFD_CEA_UNKNOWN: - break; - case WFD_CEA_640x480P60: - priv->video_width=640; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_CEA_720x480P60: - priv->video_width=720; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_CEA_720x480I60: - priv->video_width=720; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_CEA_720x576P50: - priv->video_width=720; - priv->video_height=576; - priv->video_framerate=50; - break; - case WFD_CEA_720x576I50: - priv->video_width=720; - priv->video_height=576; - priv->video_framerate=50; - break; - case WFD_CEA_1280x720P30: - priv->video_width=1280; - priv->video_height=720; - priv->video_framerate=30; - break; - case WFD_CEA_1280x720P60: - priv->video_width=1280; - priv->video_height=720; - priv->video_framerate=60; - break; - case WFD_CEA_1920x1080P30: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=30; - break; - case WFD_CEA_1920x1080P60: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=60; - break; - case WFD_CEA_1920x1080I60: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=60; - break; - case WFD_CEA_1280x720P25: - priv->video_width=1280; - priv->video_height=720; - priv->video_framerate=25; - break; - case WFD_CEA_1280x720P50: - priv->video_width=1280; - priv->video_height=720; - priv->video_framerate=50; - break; - case WFD_CEA_1920x1080P25: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=25; - break; - case WFD_CEA_1920x1080P50: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=50; - break; - case WFD_CEA_1920x1080I50: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=50; - break; - case WFD_CEA_1280x720P24: - priv->video_width=1280; - priv->video_height=720; - priv->video_framerate=24; - break; - case WFD_CEA_1920x1080P24: - priv->video_width=1920; - priv->video_height=1080; - priv->video_framerate=24; - break; - default: - break; - } - return GST_RTSP_OK; -} - -static GstRTSPResult _get_vesa_resolution_and_set_to_src(GstWFDBaseSrc *src, WFDVideoVESAResolution Resolution) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - WFDVideoVESAResolution VESARes = Resolution; - - switch(VESARes) - { - case WFD_VESA_UNKNOWN: - break; - case WFD_VESA_800x600P30: - priv->video_width=800; - priv->video_height=600; - priv->video_framerate=30; - break; - case WFD_VESA_800x600P60: - priv->video_width=800; - priv->video_height=600; - priv->video_framerate=60; - break; - case WFD_VESA_1024x768P30: - priv->video_width=1024; - priv->video_height=768; - priv->video_framerate=30; - break; - case WFD_VESA_1024x768P60: - priv->video_width=1024; - priv->video_height=768; - priv->video_framerate=60; - break; - case WFD_VESA_1152x864P30: - priv->video_width=1152; - priv->video_height=864; - priv->video_framerate=30; - break; - case WFD_VESA_1152x864P60: - priv->video_width=1152; - priv->video_height=864; - priv->video_framerate=60; - break; - case WFD_VESA_1280x768P30: - priv->video_width=1280; - priv->video_height=768; - priv->video_framerate=30; - break; - case WFD_VESA_1280x768P60: - priv->video_width=1280; - priv->video_height=768; - priv->video_framerate=60; - break; - case WFD_VESA_1280x800P30: - priv->video_width=1280; - priv->video_height=800; - priv->video_framerate=30; - break; - case WFD_VESA_1280x800P60: - priv->video_width=1280; - priv->video_height=800; - priv->video_framerate=60; - break; - case WFD_VESA_1360x768P30: - priv->video_width=1360; - priv->video_height=768; - priv->video_framerate=30; - break; - case WFD_VESA_1360x768P60: - priv->video_width=1360; - priv->video_height=768; - priv->video_framerate=60; - break; - case WFD_VESA_1366x768P30: - priv->video_width=1366; - priv->video_height=768; - priv->video_framerate=30; - break; - case WFD_VESA_1366x768P60: - priv->video_width=1366; - priv->video_height=768; - priv->video_framerate=60; - break; - case WFD_VESA_1280x1024P30: - priv->video_width=1280; - priv->video_height=1024; - priv->video_framerate=30; - break; - case WFD_VESA_1280x1024P60: - priv->video_width=1280; - priv->video_height=1024; - priv->video_framerate=60; - break; - case WFD_VESA_1400x1050P30: - priv->video_width=1400; - priv->video_height=1050; - priv->video_framerate=30; - break; - case WFD_VESA_1400x1050P60: - priv->video_width=1400; - priv->video_height=1050; - priv->video_framerate=60; - break; - case WFD_VESA_1440x900P30: - priv->video_width=1440; - priv->video_height=900; - priv->video_framerate=30; - break; - case WFD_VESA_1440x900P60: - priv->video_width=1440; - priv->video_height=900; - priv->video_framerate=60; - break; - case WFD_VESA_1600x900P30: - priv->video_width=1600; - priv->video_height=900; - priv->video_framerate=30; - break; - case WFD_VESA_1600x900P60: - priv->video_width=1600; - priv->video_height=900; - priv->video_framerate=60; - break; - case WFD_VESA_1600x1200P30: - priv->video_width=1600; - priv->video_height=1200; - priv->video_framerate=30; - break; - case WFD_VESA_1600x1200P60: - priv->video_width=1600; - priv->video_height=1200; - priv->video_framerate=60; - break; - case WFD_VESA_1680x1024P30: - priv->video_width=1680; - priv->video_height=1024; - priv->video_framerate=30; - break; - case WFD_VESA_1680x1024P60: - priv->video_width=1680; - priv->video_height=1024; - priv->video_framerate=60; - break; - case WFD_VESA_1680x1050P30: - priv->video_width=1680; - priv->video_height=1050; - priv->video_framerate=30; - break; - case WFD_VESA_1680x1050P60: - priv->video_width=1680; - priv->video_height=1050; - priv->video_framerate=60; - break; - case WFD_VESA_1920x1200P30: - priv->video_width=1920; - priv->video_height=1200; - priv->video_framerate=30; - break; - case WFD_VESA_1920x1200P60: - priv->video_width=1920; - priv->video_height=1200; - priv->video_framerate=60; - break; - default: - break; - } - return GST_RTSP_OK; -} - -static GstRTSPResult _get_hh_resolution_and_set_to_src(GstWFDBaseSrc *src, WFDVideoHHResolution Resolution) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - WFDVideoHHResolution HHRes = Resolution; - - switch(HHRes) - { - case WFD_HH_UNKNOWN: - break; - case WFD_HH_800x480P30: - priv->video_width=800; - priv->video_height=480; - priv->video_framerate=30; - break; - case WFD_HH_800x480P60: - priv->video_width=800; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_HH_854x480P30: - priv->video_width=854; - priv->video_height=480; - priv->video_framerate=30; - break; - case WFD_HH_854x480P60: - priv->video_width=854; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_HH_864x480P30: - priv->video_width=864; - priv->video_height=480; - priv->video_framerate=30; - break; - case WFD_HH_864x480P60: - priv->video_width=864; - priv->video_height=480; - priv->video_framerate=60; - break; - case WFD_HH_640x360P30: - priv->video_width=640; - priv->video_height=360; - priv->video_framerate=30; - break; - case WFD_HH_640x360P60: - priv->video_width=640; - priv->video_height=360; - priv->video_framerate=60; - break; - case WFD_HH_960x540P30: - priv->video_width=960; - priv->video_height=540; - priv->video_framerate=30; - break; - case WFD_HH_960x540P60: - priv->video_width=960; - priv->video_height=540; - priv->video_framerate=60; - break; - case WFD_HH_848x480P30: - priv->video_width=848; - priv->video_height=480; - priv->video_framerate=30; - break; - case WFD_HH_848x480P60: - priv->video_width=848; - priv->video_height=480; - priv->video_framerate=60; - break; - default: - break; - } - return GST_RTSP_OK; -} - -static GstRTSPResult -gst_wfd_base_src_get_audio_parameter(GstWFDBaseSrc * src, WFDMessage * msg) -{ - GstWFDBaseSrcPrivate *priv = src->priv; - WFDAudioFormats audio_format = WFD_AUDIO_UNKNOWN; - WFDAudioChannels audio_channels = WFD_CHANNEL_UNKNOWN; - WFDAudioFreq audio_frequency = WFD_FREQ_UNKNOWN; - guint audio_bitwidth = 0; - guint32 audio_latency = 0; - WFDResult wfd_res = WFD_OK; - - WFDCONFIG_GET_PREFERED_AUDIO_FORMAT(msg, &audio_format, &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); - if(wfd_res != WFD_OK) { - GST_ERROR("Failed to get prefered audio format."); - return GST_RTSP_ERROR; - } - - priv->audio_format = g_strdup(msg->audio_codecs->list->audio_format); - if(audio_frequency == WFD_FREQ_48000) - audio_frequency = 48000; - else if(audio_frequency == WFD_FREQ_44100) - audio_frequency = 44100; - - if(audio_channels == WFD_CHANNEL_2) - audio_channels = 2; - else if(audio_channels == WFD_CHANNEL_4) - audio_channels = 4; - else if(audio_channels == WFD_CHANNEL_6) - audio_channels = 6; - else if(audio_channels == WFD_CHANNEL_8) - audio_channels = 8; - - priv->audio_channels = audio_channels; - priv->audio_frequency = audio_frequency; - priv->audio_bitwidth = audio_bitwidth; - - return GST_RTSP_OK; -} - -static GstRTSPResult -gst_wfd_base_src_get_video_parameter(GstWFDBaseSrc * src, WFDMessage * msg) -{ - WFDVideoCodecs cvCodec = WFD_VIDEO_UNKNOWN; - WFDVideoNativeResolution cNative = WFD_VIDEO_CEA_RESOLUTION; - guint64 cNativeResolution = 0; - WFDVideoCEAResolution cCEAResolution = WFD_CEA_UNKNOWN; - WFDVideoVESAResolution cVESAResolution = WFD_VESA_UNKNOWN; - WFDVideoHHResolution cHHResolution = WFD_HH_UNKNOWN; - WFDVideoH264Profile cProfile = WFD_H264_UNKNOWN_PROFILE; - WFDVideoH264Level cLevel = WFD_H264_LEVEL_UNKNOWN; - guint32 cMaxHeight = 0; - guint32 cMaxWidth = 0; - guint32 cmin_slice_size = 0; - guint32 cslice_enc_params = 0; - guint cframe_rate_control = 0; - guint cvLatency = 0; - WFDResult wfd_res = WFD_OK; - - WFDCONFIG_GET_PREFERED_VIDEO_FORMAT(msg, &cvCodec, &cNative, &cNativeResolution, - &cCEAResolution, &cVESAResolution, &cHHResolution, - &cProfile, &cLevel, &cvLatency, &cMaxHeight, - &cMaxWidth, &cmin_slice_size, &cslice_enc_params, &cframe_rate_control); - if(wfd_res != WFD_OK) { - GST_ERROR("Failed to get prefered video format."); - return GST_RTSP_ERROR; - } -#if 0 - switch(cNative) - { - case WFD_VIDEO_CEA_RESOLUTION: - _get_cea_resolution_and_set_to_src(src, cCEAResolution); - break; - case WFD_VIDEO_VESA_RESOLUTION: - _get_vesa_resolution_and_set_to_src(src, cVESAResolution); - break; - case WFD_VIDEO_HH_RESOLUTION: - _get_hh_resolution_and_set_to_src(src, cHHResolution); - break; - default: - break; - } -#endif - - if(cCEAResolution != WFD_CEA_UNKNOWN) { - _get_cea_resolution_and_set_to_src(src, cCEAResolution); - } - else if(cVESAResolution != WFD_VESA_UNKNOWN) { - _get_vesa_resolution_and_set_to_src(src, cVESAResolution); - } - else if(cHHResolution != WFD_HH_UNKNOWN) { - _get_hh_resolution_and_set_to_src(src, cHHResolution); - } - - return GST_RTSP_OK; -} - -/*rtsp dump code start*/ -typedef struct _RTSPKeyValue -{ - GstRTSPHeaderField field; - gchar *value; - gchar *custom_key; /* custom header string (field is INVALID then) */ -} RTSPKeyValue; - -static void -_key_value_foreach (GArray * array, GFunc func, gpointer user_data) -{ - guint i; - - g_return_if_fail (array != NULL); - - for (i = 0; i < array->len; i++) { - (*func) (&g_array_index (array, RTSPKeyValue, i), user_data); - } -} - -static void -_dump_key_value (gpointer data, gpointer user_data G_GNUC_UNUSED) -{ - RTSPKeyValue *key_value = (RTSPKeyValue *) data; - const gchar *key_string; - - if (key_value->custom_key != NULL) - key_string = key_value->custom_key; - else - key_string = gst_rtsp_header_as_text (key_value->field); - - GST_ERROR (" key: '%s', value: '%s'", key_string, key_value->value); -} - -static const char * -_cmd_to_string (guint cmd) -{ - switch (cmd) { - case WFD_CMD_OPEN: - return "OPEN"; - case WFD_CMD_PLAY: - return "PLAY"; - case WFD_CMD_PAUSE: - return "PAUSE"; - case WFD_CMD_CLOSE: - return "CLOSE"; - case WFD_CMD_WAIT: - return "WAIT"; - case WFD_CMD_LOOP: - return "LOOP"; - case WFD_CMD_REQUEST: - return "REQUEST"; - } - - return "unknown"; -} - -static GstRTSPResult -_rtsp_message_dump (GstRTSPMessage * msg) -{ - guint8 *data; - guint size; - - g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL); - - GST_ERROR("------------------------------------------------------"); - switch (msg->type) { - case GST_RTSP_MESSAGE_REQUEST: - GST_ERROR ("RTSP request message %p", msg); - GST_ERROR (" request line:"); - GST_ERROR (" method: '%s'", - gst_rtsp_method_as_text (msg->type_data.request.method)); - GST_ERROR (" uri: '%s'", msg->type_data.request.uri); - GST_ERROR (" version: '%s'", - gst_rtsp_version_as_text (msg->type_data.request.version)); - GST_ERROR (" headers:"); - _key_value_foreach (msg->hdr_fields, _dump_key_value, NULL); - GST_ERROR (" body:"); - gst_rtsp_message_get_body (msg, &data, &size); - //gst_util_dump_mem (data, size); - if (size > 0) GST_ERROR ("%s(%d)", data, size); - break; - case GST_RTSP_MESSAGE_RESPONSE: - GST_ERROR ("RTSP response message %p", msg); - GST_ERROR (" status line:"); - GST_ERROR (" code: '%d'", msg->type_data.response.code); - GST_ERROR (" reason: '%s'", msg->type_data.response.reason); - GST_ERROR (" version: '%s'", - gst_rtsp_version_as_text (msg->type_data.response.version)); - GST_ERROR (" headers:"); - _key_value_foreach (msg->hdr_fields, _dump_key_value, NULL); - gst_rtsp_message_get_body (msg, &data, &size); - GST_ERROR (" body: length %d", size); - //gst_util_dump_mem (data, size); - if (size > 0) GST_ERROR ("%s(%d)", data, size); - break; - case GST_RTSP_MESSAGE_HTTP_REQUEST: - GST_ERROR ("HTTP request message %p", msg); - GST_ERROR (" request line:"); - GST_ERROR (" method: '%s'", - gst_rtsp_method_as_text (msg->type_data.request.method)); - GST_ERROR (" uri: '%s'", msg->type_data.request.uri); - GST_ERROR (" version: '%s'", - gst_rtsp_version_as_text (msg->type_data.request.version)); - GST_ERROR (" headers:"); - _key_value_foreach (msg->hdr_fields, _dump_key_value, NULL); - GST_ERROR (" body:"); - gst_rtsp_message_get_body (msg, &data, &size); - //gst_util_dump_mem (data, size); - if (size > 0) GST_ERROR ("%s(%d)", data, size); - break; - case GST_RTSP_MESSAGE_HTTP_RESPONSE: - GST_ERROR ("HTTP response message %p", msg); - GST_ERROR (" status line:"); - GST_ERROR (" code: '%d'", msg->type_data.response.code); - GST_ERROR (" reason: '%s'", msg->type_data.response.reason); - GST_ERROR (" version: '%s'", - gst_rtsp_version_as_text (msg->type_data.response.version)); - GST_ERROR (" headers:"); - _key_value_foreach (msg->hdr_fields, _dump_key_value, NULL); - gst_rtsp_message_get_body (msg, &data, &size); - GST_ERROR (" body: length %d", size); - //gst_util_dump_mem (data, size); - if (size > 0) GST_ERROR ("%s(%d)", data, size); - break; - case GST_RTSP_MESSAGE_DATA: - GST_ERROR ("RTSP data message %p", msg); - GST_ERROR (" channel: '%d'", msg->type_data.data.channel); - GST_ERROR (" size: '%d'", msg->body_size); - gst_rtsp_message_get_body (msg, &data, &size); - //gst_util_dump_mem (data, size); - if (size > 0) GST_ERROR ("%s(%d)", data, size); - break; - default: - GST_ERROR ("unsupported message type %d", msg->type); - return GST_RTSP_EINVAL; - } - - GST_ERROR("------------------------------------------------------"); - return GST_RTSP_OK; -} -/*rtsp dump code end*/ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.h b/wfdmanager/wfdbase/gstwfdbasesrc.h old mode 100755 new mode 100644 index 6e377ca..b8a4309 --- a/wfdmanager/wfdbase/gstwfdbasesrc.h +++ b/wfdmanager/wfdbase/gstwfdbasesrc.h @@ -138,9 +138,9 @@ struct _GstWFDBaseSrcClass { void (*change_av_format) (GstWFDBaseSrc *src, gpointer *need_to_flush); /* actions */ - void (*pause) (GstWFDBaseSrc *src); - void (*resume) (GstWFDBaseSrc *src); - void (*close) (GstWFDBaseSrc *src); + void (*request_pause) (GstWFDBaseSrc *src); + void (*request_resume) (GstWFDBaseSrc *src); + void (*request_close) (GstWFDBaseSrc *src); void (*set_standby) (GstWFDBaseSrc *src); }; @@ -148,6 +148,10 @@ GType gst_wfd_base_src_get_type(void); gboolean gst_wfd_base_src_set_target (GstWFDBaseSrc * src, GstPad *target); gboolean gst_wfd_base_src_activate (GstWFDBaseSrc *src); +GstRTSPResult gst_wfd_base_src_get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution); +GstRTSPResult gst_wfd_base_src_get_vesa_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution); +GstRTSPResult gst_wfd_base_src_get_hh_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution); + void gst_wfd_base_src_get_transport_info (GstWFDBaseSrc *src, GstRTSPTransport * transport, const gchar ** destination, gint * min, gint * max); GstRTSPTransport gst_wfd_base_src_get_transport (GstWFDBaseSrc *src); diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.c b/wfdmanager/wfdbase/gstwfdsinkmessage.c old mode 100755 new mode 100644 index 83bf1be..ee910fb --- a/wfdmanager/wfdbase/gstwfdsinkmessage.c +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.c @@ -229,6 +229,7 @@ gst_wfd_message_free(GstWFDMessage *msg) gst_wfd_message_uninit(msg); g_free(msg); + msg = NULL; return GST_WFD_OK; } @@ -276,9 +277,9 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) g_string_append_printf(lines, " %02x", msg->video_formats->list->preferred_display_mode_supported); g_string_append_printf(lines, " %02x", msg->video_formats->list->H264_codec.profile); g_string_append_printf(lines, " %02x", msg->video_formats->list->H264_codec.level); - g_string_append_printf(lines, " %08x", msg->video_formats->list->H264_codec.misc_params.CEA_Support); - g_string_append_printf(lines, " %08x", msg->video_formats->list->H264_codec.misc_params.VESA_Support); - g_string_append_printf(lines, " %08x", msg->video_formats->list->H264_codec.misc_params.HH_Support); + g_string_append_printf(lines, " %08llx", msg->video_formats->list->H264_codec.misc_params.CEA_Support); + g_string_append_printf(lines, " %08llx", msg->video_formats->list->H264_codec.misc_params.VESA_Support); + g_string_append_printf(lines, " %08llx", msg->video_formats->list->H264_codec.misc_params.HH_Support); g_string_append_printf(lines, " %02x", msg->video_formats->list->H264_codec.misc_params.latency); g_string_append_printf(lines, " %04x", msg->video_formats->list->H264_codec.misc_params.min_slice_size); g_string_append_printf(lines, " %04x", msg->video_formats->list->H264_codec.misc_params.slice_enc_params); @@ -1141,7 +1142,6 @@ gst_wfd_message_dump(const GstWFDMessage *msg) GstWFDResult gst_wfd_message_set_supported_audio_format(GstWFDMessage *msg, GstWFDAudioFormats aCodec, guint aFreq, guint aChanels, guint aBitwidth, guint32 aLatency) { - guint temp = aCodec; guint i = 0; guint pcm = 0, aac = 0, ac3 = 0; @@ -1151,10 +1151,14 @@ GstWFDResult gst_wfd_message_set_supported_audio_format(GstWFDMessage *msg, GstW msg->audio_codecs = g_new0(GstWFDAudioCodeclist, 1); if (aCodec != GST_WFD_AUDIO_UNKNOWN) { - while (temp) { + + if (aCodec & GST_WFD_AUDIO_LPCM) msg->audio_codecs->count++; - temp >>= 1; - } + if (aCodec & GST_WFD_AUDIO_AAC) + msg->audio_codecs->count++; + if (aCodec & GST_WFD_AUDIO_AC3) + msg->audio_codecs->count++; + msg->audio_codecs->list = g_new0(GstWFDAudioCodec, msg->audio_codecs->count); for (; i < msg->audio_codecs->count; i++) { if ((aCodec & GST_WFD_AUDIO_LPCM) && (!pcm)) { @@ -1311,8 +1315,8 @@ GstWFDResult gst_wfd_message_set_supported_video_format(GstWFDMessage *msg, GstW GstWFDResult gst_wfd_message_set_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, GstWFDVideoNativeResolution vNative, guint64 vNativeResolution, - GstWFDVideoCEAResolution vCEAResolution, GstWFDVideoVESAResolution vVESAResolution, - GstWFDVideoHHResolution vHHResolution, GstWFDVideoH264Profile vProfile, + guint64 vCEAResolution, guint64 vVESAResolution, + guint64 vHHResolution, GstWFDVideoH264Profile vProfile, GstWFDVideoH264Level vLevel, guint32 vLatency, guint32 vMaxHeight, guint32 vMaxWidth, guint32 min_slice_size, guint32 slice_enc_params, guint frame_rate_control) { @@ -1385,8 +1389,8 @@ GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg, GstW GstWFDResult gst_wfd_message_get_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, GstWFDVideoNativeResolution *vNative, guint64 *vNativeResolution, - GstWFDVideoCEAResolution *vCEAResolution, GstWFDVideoVESAResolution *vVESAResolution, - GstWFDVideoHHResolution *vHHResolution, GstWFDVideoH264Profile *vProfile, + guint64 *vCEAResolution, guint64 *vVESAResolution, + guint64 *vHHResolution, GstWFDVideoH264Profile *vProfile, GstWFDVideoH264Level *vLevel, guint32 *vLatency, guint32 *vMaxHeight, guint32 *vMaxWidth, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control) { diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.h b/wfdmanager/wfdbase/gstwfdsinkmessage.h old mode 100755 new mode 100644 index 221ed03..0761d2a --- a/wfdmanager/wfdbase/gstwfdsinkmessage.h +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.h @@ -24,6 +24,7 @@ #define __GST_WFD_SINK_MESSAGE_H__ #include +#include G_BEGIN_DECLS @@ -143,76 +144,85 @@ typedef enum { GST_WFD_VIDEO_HH_RESOLUTION } GstWFDVideoNativeResolution; -typedef enum { - GST_WFD_CEA_UNKNOWN = 0, - GST_WFD_CEA_640x480P60 = (1 << 0), - GST_WFD_CEA_720x480P60 = (1 << 1), - GST_WFD_CEA_720x480I60 = (1 << 2), - GST_WFD_CEA_720x576P50 = (1 << 3), - GST_WFD_CEA_720x576I50 = (1 << 4), - GST_WFD_CEA_1280x720P30 = (1 << 5), - GST_WFD_CEA_1280x720P60 = (1 << 6), - GST_WFD_CEA_1920x1080P30 = (1 << 7), - GST_WFD_CEA_1920x1080P60 = (1 << 8), - GST_WFD_CEA_1920x1080I60 = (1 << 9), - GST_WFD_CEA_1280x720P25 = (1 << 10), - GST_WFD_CEA_1280x720P50 = (1 << 11), - GST_WFD_CEA_1920x1080P25 = (1 << 12), - GST_WFD_CEA_1920x1080P50 = (1 << 13), - GST_WFD_CEA_1920x1080I50 = (1 << 14), - GST_WFD_CEA_1280x720P24 = (1 << 15), - GST_WFD_CEA_1920x1080P24 = (1 << 16) -} GstWFDVideoCEAResolution; - -typedef enum { - GST_WFD_VESA_UNKNOWN = 0, - GST_WFD_VESA_800x600P30 = (1 << 0), - GST_WFD_VESA_800x600P60 = (1 << 1), - GST_WFD_VESA_1024x768P30 = (1 << 2), - GST_WFD_VESA_1024x768P60 = (1 << 3), - GST_WFD_VESA_1152x864P30 = (1 << 4), - GST_WFD_VESA_1152x864P60 = (1 << 5), - GST_WFD_VESA_1280x768P30 = (1 << 6), - GST_WFD_VESA_1280x768P60 = (1 << 7), - GST_WFD_VESA_1280x800P30 = (1 << 8), - GST_WFD_VESA_1280x800P60 = (1 << 9), - GST_WFD_VESA_1360x768P30 = (1 << 10), - GST_WFD_VESA_1360x768P60 = (1 << 11), - GST_WFD_VESA_1366x768P30 = (1 << 12), - GST_WFD_VESA_1366x768P60 = (1 << 13), - GST_WFD_VESA_1280x1024P30 = (1 << 14), - GST_WFD_VESA_1280x1024P60 = (1 << 15), - GST_WFD_VESA_1400x1050P30 = (1 << 16), - GST_WFD_VESA_1400x1050P60 = (1 << 17), - GST_WFD_VESA_1440x900P30 = (1 << 18), - GST_WFD_VESA_1440x900P60 = (1 << 19), - GST_WFD_VESA_1600x900P30 = (1 << 20), - GST_WFD_VESA_1600x900P60 = (1 << 21), - GST_WFD_VESA_1600x1200P30 = (1 << 22), - GST_WFD_VESA_1600x1200P60 = (1 << 23), - GST_WFD_VESA_1680x1024P30 = (1 << 24), - GST_WFD_VESA_1680x1024P60 = (1 << 25), - GST_WFD_VESA_1680x1050P30 = (1 << 26), - GST_WFD_VESA_1680x1050P60 = (1 << 27), - GST_WFD_VESA_1920x1200P30 = (1 << 28), - GST_WFD_VESA_1920x1200P60 = (1 << 29) -} GstWFDVideoVESAResolution; -typedef enum { - GST_WFD_HH_UNKNOWN = 0, - GST_WFD_HH_800x480P30 = (1 << 0), - GST_WFD_HH_800x480P60 = (1 << 1), - GST_WFD_HH_854x480P30 = (1 << 2), - GST_WFD_HH_854x480P60 = (1 << 3), - GST_WFD_HH_864x480P30 = (1 << 4), - GST_WFD_HH_864x480P60 = (1 << 5), - GST_WFD_HH_640x360P30 = (1 << 6), - GST_WFD_HH_640x360P60 = (1 << 7), - GST_WFD_HH_960x540P30 = (1 << 8), - GST_WFD_HH_960x540P60 = (1 << 9), - GST_WFD_HH_848x480P30 = (1 << 10), - GST_WFD_HH_848x480P60 = (1 << 11) -} GstWFDVideoHHResolution; +#define GST_WFD_CEA_UNKNOWN 0 +#define GST_WFD_CEA_640x480P60 (1 << 0) +#define GST_WFD_CEA_720x480P60 (1 << 1) +#define GST_WFD_CEA_720x480I60 (1 << 2) +#define GST_WFD_CEA_720x576P50 (1 << 3) +#define GST_WFD_CEA_720x576I50 (1 << 4) +#define GST_WFD_CEA_1280x720P30 (1 << 5) +#define GST_WFD_CEA_1280x720P60 (1 << 6) +#define GST_WFD_CEA_1920x1080P30 (1 << 7) +#define GST_WFD_CEA_1920x1080P60 (1 << 8) +#define GST_WFD_CEA_1920x1080I60 (1 << 9) +#define GST_WFD_CEA_1280x720P25 (1 << 10) +#define GST_WFD_CEA_1280x720P50 (1 << 11) +#define GST_WFD_CEA_1920x1080P25 (1 << 12) +#define GST_WFD_CEA_1920x1080P50 (1 << 13) +#define GST_WFD_CEA_1920x1080I50 (1 << 14) +#define GST_WFD_CEA_1280x720P24 (1 << 15) +#define GST_WFD_CEA_1920x1080P24 (1 << 16) +#define GST_WFD_CEA_3840x2160P24 (1 << 17) +#define GST_WFD_CEA_3840x2160P25 (1 << 18) +#define GST_WFD_CEA_3840x2160P30 (1 << 19) +#define GST_WFD_CEA_3840x2160P50 (1 << 20) +#define GST_WFD_CEA_3840x2160P60 (1 << 21) +#define GST_WFD_CEA_4096x2160P24 (1 << 22) +#define GST_WFD_CEA_4096x2160P25 (1 << 23) +#define GST_WFD_CEA_4096x2160P30 (1 << 24) +#define GST_WFD_CEA_4096x2160P50 (1 << 25) +#define GST_WFD_CEA_4096x2160P60 (1 << 26) + +#define GST_WFD_VESA_UNKNOWN 0 +#define GST_WFD_VESA_800x600P30 (1 << 0) +#define GST_WFD_VESA_800x600P60 (1 << 1) +#define GST_WFD_VESA_1024x768P30 (1 << 2) +#define GST_WFD_VESA_1024x768P60 (1 << 3) +#define GST_WFD_VESA_1152x864P30 (1 << 4) +#define GST_WFD_VESA_1152x864P60 (1 << 5) +#define GST_WFD_VESA_1280x768P30 (1 << 6) +#define GST_WFD_VESA_1280x768P60 (1 << 7) +#define GST_WFD_VESA_1280x800P30 (1 << 8) +#define GST_WFD_VESA_1280x800P60 (1 << 9) +#define GST_WFD_VESA_1360x768P30 (1 << 10) +#define GST_WFD_VESA_1360x768P60 (1 << 11) +#define GST_WFD_VESA_1366x768P30 (1 << 12) +#define GST_WFD_VESA_1366x768P60 (1 << 13) +#define GST_WFD_VESA_1280x1024P30 (1 << 14) +#define GST_WFD_VESA_1280x1024P60 (1 << 15) +#define GST_WFD_VESA_1400x1050P30 (1 << 16) +#define GST_WFD_VESA_1400x1050P60 (1 << 17) +#define GST_WFD_VESA_1440x900P30 (1 << 18) +#define GST_WFD_VESA_1440x900P60 (1 << 19) +#define GST_WFD_VESA_1600x900P30 (1 << 20) +#define GST_WFD_VESA_1600x900P60 (1 << 21) +#define GST_WFD_VESA_1600x1200P30 (1 << 22) +#define GST_WFD_VESA_1600x1200P60 (1 << 23) +#define GST_WFD_VESA_1680x1024P30 (1 << 24) +#define GST_WFD_VESA_1680x1024P60 (1 << 25) +#define GST_WFD_VESA_1680x1050P30 (1 << 26) +#define GST_WFD_VESA_1680x1050P60 (1 << 27) +#define GST_WFD_VESA_1920x1200P30 (1 << 28) +#define GST_WFD_VESA_1920x1200P60 (1 << 29) +#define GST_WFD_VESA_2560x1440P30 (1 << 30) +#define GST_WFD_VESA_2560x1440P60 (1 << 31) +#define GST_WFD_VESA_2560x1600P30 (1ULL << 32) +#define GST_WFD_VESA_2560x1600P60 (1ULL << 33) + +#define GST_WFD_HH_UNKNOWN 0 +#define GST_WFD_HH_800x480P30 (1 << 0) +#define GST_WFD_HH_800x480P60 (1 << 1) +#define GST_WFD_HH_854x480P30 (1 << 2) +#define GST_WFD_HH_854x480P60 (1 << 3) +#define GST_WFD_HH_864x480P30 (1 << 4) +#define GST_WFD_HH_864x480P60 (1 << 5) +#define GST_WFD_HH_640x360P30 (1 << 6) +#define GST_WFD_HH_640x360P60 (1 << 7) +#define GST_WFD_HH_960x540P30 (1 << 8) +#define GST_WFD_HH_960x540P60 (1 << 9) +#define GST_WFD_HH_848x480P30 (1 << 10) +#define GST_WFD_HH_848x480P60 (1 << 11) typedef enum { GST_WFD_H264_UNKNOWN_PROFILE = 0, @@ -252,23 +262,23 @@ typedef enum { } GstWFDTrigger; typedef enum { - GST_WFD_RTSP_TRANS_UNKNOWN = 0, - GST_WFD_RTSP_TRANS_RTP = (1 << 0), - GST_WFD_RTSP_TRANS_RDT = (1 << 1) + GST_WFD_RTSP_TRANS_UNKNOWN = GST_RTSP_TRANS_UNKNOWN, + GST_WFD_RTSP_TRANS_RTP = GST_RTSP_TRANS_RTP, + GST_WFD_RTSP_TRANS_RDT = GST_RTSP_TRANS_RDT } GstWFDRTSPTransMode; typedef enum { - GST_WFD_RTSP_PROFILE_UNKNOWN = 0, - GST_WFD_RTSP_PROFILE_AVP = (1 << 0), - GST_WFD_RTSP_PROFILE_SAVP = (1 << 1) + GST_WFD_RTSP_PROFILE_UNKNOWN = GST_RTSP_PROFILE_UNKNOWN, + GST_WFD_RTSP_PROFILE_AVP = GST_RTSP_PROFILE_AVP, + GST_WFD_RTSP_PROFILE_SAVP = GST_RTSP_PROFILE_SAVP } GstWFDRTSPProfile; typedef enum { - GST_WFD_RTSP_LOWER_TRANS_UNKNOWN = 0, - GST_WFD_RTSP_LOWER_TRANS_UDP = (1 << 0), - GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST = (1 << 1), - GST_WFD_RTSP_LOWER_TRANS_TCP = (1 << 2), - GST_WFD_RTSP_LOWER_TRANS_HTTP = (1 << 3) + GST_WFD_RTSP_LOWER_TRANS_UNKNOWN = GST_RTSP_LOWER_TRANS_UNKNOWN, + GST_WFD_RTSP_LOWER_TRANS_UDP = GST_RTSP_LOWER_TRANS_UDP, + GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST = GST_RTSP_LOWER_TRANS_UDP_MCAST, + GST_WFD_RTSP_LOWER_TRANS_TCP = GST_RTSP_LOWER_TRANS_TCP, + GST_WFD_RTSP_LOWER_TRANS_HTTP = GST_RTSP_LOWER_TRANS_HTTP } GstWFDRTSPLowerTrans; typedef enum { @@ -312,9 +322,9 @@ typedef struct { typedef struct { - guint CEA_Support; - guint VESA_Support; - guint HH_Support; + guint64 CEA_Support; + guint64 VESA_Support; + guint64 HH_Support; guint latency; guint min_slice_size; guint slice_enc_params; @@ -511,8 +521,8 @@ GstWFDResult gst_wfd_message_set_supported_video_format(GstWFDMessage *msg, GstW guint preferred_display_mode); GstWFDResult gst_wfd_message_set_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, GstWFDVideoNativeResolution vNative, guint64 vNativeResolution, - GstWFDVideoCEAResolution vCEAResolution, GstWFDVideoVESAResolution vVESAResolution, - GstWFDVideoHHResolution vHHResolution, GstWFDVideoH264Profile vProfile, + guint64 vCEAResolution, guint64 vVESAResolution, + guint64 vHHResolution, GstWFDVideoH264Profile vProfile, GstWFDVideoH264Level vLevel, guint32 vLatency, guint32 vMaxHeight, guint32 vMaxWidth, guint32 min_slice_size, guint32 slice_enc_params, guint frame_rate_control); GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, @@ -522,8 +532,8 @@ GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg, GstW guint32 *vMaxWidth, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); GstWFDResult gst_wfd_message_get_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, GstWFDVideoNativeResolution *vNative, guint64 *vNativeResolution, - GstWFDVideoCEAResolution *vCEAResolution, GstWFDVideoVESAResolution *vVESAResolution, - GstWFDVideoHHResolution *vHHResolution, GstWFDVideoH264Profile *vProfile, + guint64 *vCEAResolution, guint64 *vVESAResolution, + guint64 *vHHResolution, GstWFDVideoH264Profile *vProfile, GstWFDVideoH264Level *vLevel, guint32 *vLatency, guint32 *vMaxHeight, guint32 *vMaxWidth, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); -- 2.7.4 From c1bea70d949042f1c1a69830e68e86e9451b875b Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Wed, 10 Aug 2016 15:08:12 +0900 Subject: [PATCH 02/16] [drmsrc] remove unused plugin Change-Id: I991317173cb6a111dd0bb136e0bf435df6433a95 --- Makefile.am | 8 - PLUGINS | 24 +- configure.ac | 14 -- drmsrc/Makefile.am | 1 - drmsrc/src/Makefile.am | 27 --- drmsrc/src/gstdrmsrc.c | 606 ------------------------------------------------- drmsrc/src/gstdrmsrc.h | 82 ------- 7 files changed, 15 insertions(+), 747 deletions(-) delete mode 100755 drmsrc/Makefile.am delete mode 100755 drmsrc/src/Makefile.am delete mode 100755 drmsrc/src/gstdrmsrc.c delete mode 100755 drmsrc/src/gstdrmsrc.h diff --git a/Makefile.am b/Makefile.am index 4cde130..a0b7a94 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,10 +13,6 @@ if GST_TIZEN_USE_EVASIMAGESINK SUBDIRS += evasimagesink endif -if GST_TIZEN_USE_DRMSRC -SUBDIRS += drmsrc -endif - if GST_TIZEN_USE_TOGGLE SUBDIRS += toggle endif @@ -67,10 +63,6 @@ if GST_TIZEN_USE_EVASIMAGESINK DIST_SUBDIRS += evasimagesink endif -if GST_TIZEN_USE_DRMSRC -DIST_SUBDIRS += drmsrc -endif - if GST_TIZEN_USE_TOGGLE DIST_SUBDIRS += toggle endif diff --git a/PLUGINS b/PLUGINS index a737f3a..438a7d3 100644 --- a/PLUGINS +++ b/PLUGINS @@ -1,15 +1,21 @@ -# This file is descriptions of the plugins which are included in gstreamer0.10-plugins-ext. -# If any plugin is added to the gstreamer0.10-plugins-ext, that shoud be described in this file. +# This file is descriptions of the plugins which are included in gstreamer1.0-plugins-tizen. +# If any plugin is added to the gstreamer1.0-plugins-tizen, that shoud be described in this file. # # ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -PLUGIN Registered Elements Description +PLUGIN Registered Elements Description ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -avsysaudiosrc avsysaudiosrc AV system audio source plugin -avsyssink avsysaudiosink, avsysmemsink AV system audio sink plugin -drmsrc drmsrc Plugin to read data from standad/DRM file -encodebin encodebin Extension encoder bin plugin -evasimagesink evasimagesink Evas video sink plugin -toggle toggle Base transform plugin +audioeq audioeq +audiotp audiotp +drmdecryptor drm_decryptor +encodebin encodebin Extension encoder bin plugin +evasimagesink evasimagesink Evas video sink plugin +fimcconvert fimcconvert +pdpushsrc pdpushsrc Progressive download src plugin +tizenipc tizenipcsrc,tizenipcsink +toggle toggle Base transform plugin +waylandsrc waylandsrc +wfdmanager wfdsrc,wfdrtpbuffer +wfdtsdemux wfdtsparse,wfdtsdemux ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 25823af..1111f3f 100644 --- a/configure.ac +++ b/configure.ac @@ -224,18 +224,6 @@ AC_ARG_ENABLE(evasimagesink, AC_HELP_STRING([--enable-evasimagesink], [using eva [GST_TIZEN_USE_EVASIMAGESINK=yes]) AM_CONDITIONAL(GST_TIZEN_USE_EVASIMAGESINK, test "x$GST_TIZEN_USE_EVASIMAGESINK" = "xyes") -dnl use drmsrc -------------------------------------------------------------------------- -AC_ARG_ENABLE(drmsrc, AC_HELP_STRING([--enable-drmsrc], [using drmsrc]), - [ - case "${enableval}" in - yes) GST_TIZEN_USE_DRMSRC=yes ;; - no) GST_TIZEN_USE_DRMSRC=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-drmsrc) ;; - esac - ], - [GST_TIZEN_USE_DRMSRC=yes]) -AM_CONDITIONAL(GST_TIZEN_USE_DRMSRC, test "x$GST_TIZEN_USE_DRMSRC" = "xyes") - dnl use toggle -------------------------------------------------------------------------- AC_ARG_ENABLE(toggle, AC_HELP_STRING([--enable-toggle], [using toggle]), [ @@ -387,8 +375,6 @@ evasimagesink/Makefile evasimagesink/src/Makefile toggle/Makefile toggle/src/Makefile -drmsrc/Makefile -drmsrc/src/Makefile audiotp/Makefile audiotp/src/Makefile audioeq/Makefile diff --git a/drmsrc/Makefile.am b/drmsrc/Makefile.am deleted file mode 100755 index 308a09c..0000000 --- a/drmsrc/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = src diff --git a/drmsrc/src/Makefile.am b/drmsrc/src/Makefile.am deleted file mode 100755 index 842ed43..0000000 --- a/drmsrc/src/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# plugindir is set in configure - -############################################################################## -# change libgstplugin.la to something more suitable, e.g. libmysomething.la # -############################################################################## -plugin_LTLIBRARIES = libgstdrmsrc.la - -############################################################################## -# for the next set of variables, rename the prefix if you renamed the .la, # -# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # -# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # -# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # -# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # -############################################################################## - -# sources used to compile this plug-in -libgstdrmsrc_la_SOURCES = gstdrmsrc.c - -# flags used to compile this plugin -# add other _CFLAGS and _LIBS as needed -libgstdrmsrc_la_CFLAGS = $(GST_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -libgstdrmsrc_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) -libgstdrmsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -# headers we need but don't want installed -noinst_HEADERS = gstdrmsrc.h - diff --git a/drmsrc/src/gstdrmsrc.c b/drmsrc/src/gstdrmsrc.c deleted file mode 100755 index 51a785b..0000000 --- a/drmsrc/src/gstdrmsrc.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * drmsrc - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "gstdrmsrc.h" - -#define LOG_TRACE(message) //g_print("DRM_SRC: %s: %d: %s - %s \n", __FILE__, __LINE__, __FUNCTION__, message); - -#define GST_TAG_PLAYREADY "playready_file_path" - -static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,GST_STATIC_CAPS_ANY); - - -GST_DEBUG_CATEGORY_STATIC (gst_drm_src_debug); -#define GST_CAT_DEFAULT gst_drm_src_debug - -enum -{ - ARG_0, - ARG_LOCATION, - ARG_FD -}; -static void gst_drm_src_finalize (GObject * object); -static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_drm_src_start (GstBaseSrc * basesrc); -static gboolean gst_drm_src_stop (GstBaseSrc * basesrc); -static gboolean gst_drm_src_is_seekable (GstBaseSrc * src); -static gboolean gst_drm_src_get_size (GstBaseSrc * src, guint64 * size); -static GstFlowReturn gst_drm_src_create (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buffer); -static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (GstDrmSrc, gst_drm_src, GST_TYPE_BASE_SRC, - G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, gst_drm_src_uri_handler_init)); -#if 0 -/** - * This function does the following: - * 1. Sets the class details - * 2. Adds the source pad template - * - * @param g_class [out] gpointer - * - * @return void - */ -static void gst_drm_src_base_init (gpointer g_class) -{ -} -#endif - -/** - * This function does the following: - * 1. Installs the properties - * 2. Assigns the function pointers GObject class attributes - * - * @param klass [out] GstDrmSrcClass Structure - * - * @return void - */ -static void gst_drm_src_class_init (GstDrmSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSrcClass *gstbasesrc_class; - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class= GST_ELEMENT_CLASS (klass); - gstbasesrc_class = GST_BASE_SRC_CLASS (klass); - // Assigns the function pointers GObject class attributes - gobject_class->set_property = gst_drm_src_set_property; - gobject_class->get_property = gst_drm_src_get_property; - // 1. Installs the properties - g_object_class_install_property (gobject_class, ARG_FD, - g_param_spec_int ("fd", "File-descriptor", - "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0, - G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, ARG_LOCATION, - g_param_spec_string ("location", "File Location", - "Location of the file to read", NULL, G_PARAM_READWRITE)); - - // 2. Sets the class details - gst_element_class_set_details_simple (gstelement_class, - "DRM Source", - "Source/File", - "Read from arbitrary point in a standard/DRM file", - "Kishore Arepalli and Sadanand Dodawadakar "); - // 3. Adds the source pad template - gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate)); - // 4. Assigns the function pointers GObject class attributes - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_drm_src_finalize); - gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_drm_src_start); - gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_drm_src_stop); - gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_drm_src_is_seekable); - gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_drm_src_get_size); - gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_drm_src_create); - - - gst_tag_register (GST_TAG_PLAYREADY, GST_TAG_FLAG_META, - G_TYPE_STRING, - "PlayReady File Path", - "a tag that is specific to PlayReady File", - NULL); -} -/** - * This function does the following: - * 1. Initilizes the parameters of GstDrmSrc - * - * @param src [out] GstDrmSrc structure - * @param g_class [in] GstDrmSrcClass structure - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static void gst_drm_src_init (GstDrmSrc * src) -{ - // 1. Initilizes the parameters of GstDrmSrc - src->filename = NULL; - src->fd = 0; - src->uri = NULL; - src->is_regular = FALSE; - src->seekable = FALSE; -} -/** - * This function does the following: - * 1. deallocates the filename and uri - * 2. calls the parent class->finalize - * - * @param object [in] GObject Structure - * - * @return void - */ -static void gst_drm_src_finalize (GObject * object) -{ - GstDrmSrc *src; - - src = GST_DRM_SRC (object); - // 1. deallocates the filename and uri - g_free (src->filename); - g_free (src->uri); - // 2. calls the parent class->finalize - G_OBJECT_CLASS (gst_drm_src_parent_class)->finalize (object); -} -/** - * This function does the following: - * 1. Checks the state - * 2. Checks the filename - * 3. Sets the filename - * - * @param src [in] GstDrmSrc Structure - * @param location [in] location of the file - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static gboolean gst_drm_src_set_location (GstDrmSrc * src, const gchar * location) -{ - GstState state; - - GST_OBJECT_LOCK (src); - // 1. Checks the state - state = GST_STATE (src); - if (state != GST_STATE_READY && state != GST_STATE_NULL) - { - GST_DEBUG_OBJECT (src, "setting location in wrong state"); - GST_OBJECT_UNLOCK (src); - return FALSE; - } - GST_OBJECT_UNLOCK (src); - g_free (src->filename); - g_free (src->uri); - // 2. Checks the filename - if (location == NULL) - { - src->filename = NULL; - src->uri = NULL; - } - else - { - // 3. Sets the filename - src->filename = g_strdup (location); - src->uri = gst_uri_construct ("file", src->filename); - } - g_object_notify (G_OBJECT (src), "location"); - return TRUE; -} -/** - * This function does the following: - * 1. Sets the location of the file. - * - * @param object [in] GObject Structure - * @param prop_id [in] id of the property - * @param value [in] property value - * @param pspec [in] GParamSpec Structure - * - * @return void - */ -static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstDrmSrc *src; - - g_return_if_fail (GST_IS_DRM_SRC (object)); - src = GST_DRM_SRC (object); - switch (prop_id) - { - // 1. Sets the location of the file. - case ARG_LOCATION: - gst_drm_src_set_location (src, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} -/** - * This function does the following: - * 1. Provides the location of the file. - * 2. Provides the file descriptor. - * - * @param object [in] GObject Structure - * @param prop_id [in] id of the property - * @param value [out] property value - * @param pspec [in] GParamSpec Structure - * - * @return void - */ -static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value,GParamSpec * pspec) -{ - GstDrmSrc *src; - - g_return_if_fail (GST_IS_DRM_SRC (object)); - src = GST_DRM_SRC (object); - switch (prop_id) - { - // 1. Provides the location of the file. - case ARG_LOCATION: - g_value_set_string (value, src->filename); - break; - // 2. Provides the file descriptor. - case ARG_FD: - g_value_set_int (value, src->fd); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/** - * This function does the following: - * 1. Seeks to the specified position. - * 2. Allocates a buffer to push the data - * 3. Reads from the file and sets the related params - * - * @param src [in] GstDrmSrc Structure - * @param offset [in] offset of the file to seek - * @param length [in] size of the data in bytes - * @param buffer [out] GstBuffer to hold the contents - * - * @return GstFlowReturn Returns GST_FLOW_OK on success and ERROR on failure - */ -static GstFlowReturn gst_drm_src_create_read (GstDrmSrc * src, guint64 offset, guint length, GstBuffer ** buffer) -{ - int ret; - GstBuffer *buf; - GstMapInfo buf_info = GST_MAP_INFO_INIT; - // 1. Seeks to the specified position. - if (G_UNLIKELY (src->read_position != offset)) - { - off_t res; - res = lseek (src->fd, offset, SEEK_SET); - if (G_UNLIKELY (res < 0 || res != offset)) - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); - return GST_FLOW_ERROR; - } - src->read_position = offset; - } - // 2. Allocates a buffer to push the data - buf = gst_buffer_new_and_alloc (length); - GST_LOG_OBJECT (src, "Reading %d bytes", length); - // 3. Reads from the file and sets the related params - gst_buffer_map(buf, &buf_info, GST_MAP_WRITE); - ret = read (src->fd, buf_info.data, length); - gst_buffer_unmap(buf, &buf_info); - if (G_UNLIKELY (ret < 0)) - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } - if (G_UNLIKELY ((guint) ret < length && src->seekable)) - { - GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),("unexpected end of file.")); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } - if (G_UNLIKELY (ret == 0 && length > 0)) - { - GST_DEBUG ("non-regular file hits EOS"); - gst_buffer_unref (buf); - return GST_FLOW_EOS; - } - length = ret; - GST_BUFFER_OFFSET (buf) = offset; - GST_BUFFER_OFFSET_END (buf) = offset + length; - *buffer = buf; - src->read_position += length; - return GST_FLOW_OK; -} -/** - * This function does the following: - * 1. Calls DRM file read chain method for drm files. - * 2. Calls normal file read chain method for standard files. - * - * @param basesrc [in] BaseSrc Structure - * @param size [out] Size of the file - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static GstFlowReturn gst_drm_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) -{ - GstDrmSrc *src = GST_DRM_SRC (basesrc); - - // 1. Calls DRM file read chain method for drm files. - - // 2. Calls normal file read chain method for standard files. - return gst_drm_src_create_read (src, offset, length, buffer); -} -/** - * - * @param basesrc [in] BaseSrc Structure - * - * @return gboolean Returns TRUE if the file is seekable and FALSE if the file is not seekable - */ -static gboolean gst_drm_src_is_seekable (GstBaseSrc * basesrc) -{ - GstDrmSrc *src = GST_DRM_SRC (basesrc); - return src->seekable; -} -/** - * This function does the following: - * 1. Gets the filesize for drm file by using seek oprations - * 2. Gets the file size for standard file by using statistics - * - * @param basesrc [in] BaseSrc Structure - * @param size [in] Size of the file - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static gboolean gst_drm_src_get_size (GstBaseSrc * basesrc, guint64 * size) -{ - struct stat stat_results; - GstDrmSrc *src = GST_DRM_SRC (basesrc); - - // 1. Gets the filesize for drm file by using seek oprations - - // 2. Gets the file size for standard file by using statistics - if (fstat (src->fd, &stat_results) < 0) - return FALSE; - *size = stat_results.st_size; - return TRUE; -} -/** - * This function does the following: - * 1. Checks the filename - * 2. Opens the file and check statistics of the file - * 7. Checks the seeking for standard files - * - * @param basesrc [in] BaseSrc Structure - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static gboolean gst_drm_src_start (GstBaseSrc * basesrc) -{ - GstDrmSrc *src = GST_DRM_SRC (basesrc); - struct stat stat_results; - off_t ret; - // 1. Checks the filename - if (src->filename == NULL || src->filename[0] == '\0') - { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,("No file name specified for reading."), (NULL)); - return FALSE; - } - // 2. Opens the file and check statistics of the file - GST_INFO_OBJECT (src, "opening file %s", src->filename); - src->fd = open (src->filename, O_RDONLY | O_BINARY); - if (src->fd < 0) - { - if(errno == ENOENT) - { - GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),("No such file \"%s\"", src->filename)); - return FALSE; - } - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not open file \"%s\" for reading.", src->filename), GST_ERROR_SYSTEM); - return FALSE; - } - if (fstat (src->fd, &stat_results) < 0) - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not get info on \"%s\".", src->filename), (NULL)); - close (src->fd); - return FALSE; - } - if (S_ISDIR (stat_results.st_mode)) - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("\"%s\" is a directory.", src->filename), (NULL)); - close (src->fd); - return FALSE; - } - if (S_ISSOCK (stat_results.st_mode)) - { - GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("File \"%s\" is a socket.", src->filename), (NULL)); - close (src->fd); - return FALSE; - } - src->read_position = 0; - - // 7. Checks the seeking for standard files - if (S_ISREG (stat_results.st_mode)) - src->is_regular = TRUE; - ret = lseek (src->fd, 0, SEEK_END); - if (ret < 0) - { - GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek " - "failed: %s", g_strerror (errno)); - src->seekable = FALSE; - } - else - { - src->seekable = TRUE; - } - lseek (src->fd, 0, SEEK_SET); - src->seekable = src->seekable && src->is_regular; - return TRUE; -} -/** - * This function does the following: - * 1. Closes the file desciptor and resets the flags - * - * @param basesrc [in] BaseSrc Structure - * - * @return gboolean Returns TRUE on success and FALSE on ERROR - */ -static gboolean gst_drm_src_stop (GstBaseSrc * basesrc) -{ - GstDrmSrc *src = GST_DRM_SRC (basesrc); - - // 1. Closes the file desciptor and resets the flags - if(src->fd > 0) - close (src->fd); - src->fd = 0; - src->is_regular = FALSE; - return TRUE; -} -/** - * - * @param void - * - * @return GstURIType Returns GST_URI_SRC - */ - -static GstURIType gst_drm_src_uri_get_type (GType type) -{ - return GST_URI_SRC; -} - -/** - * This function does the following: - * 1. Defines the list of protocols - * - * @param void - * - * @return gchar ** Returns the protocol list - */ - -static const gchar * const* gst_drm_src_uri_get_protocols (GType type) -{ - static const gchar *protocols[] = { "file", NULL }; - return protocols; -} -/** - * - * @param handler [in] GstURIHandler structure - * - * @return gchar* Returns the uri - */ -static gchar * gst_drm_src_uri_get_uri (GstURIHandler *handler) -{ - GstDrmSrc *src = GST_DRM_SRC (handler); - return g_strdup(src->uri); -} -/** - * This function does the following: - * 1. Checks the protocol - * 2. Checks the whether it is absolute or not - * 3 sets the location - * - * @param handler [in] GstURIHandler structure - * @param uri [in] uri string - * - * @return gboolean Returns TRUE on success and FALSE on Error - */ -static gboolean gst_drm_src_uri_set_uri (GstURIHandler *handler, const gchar * uri,GError ** error) -{ - gchar *protocol, *location; - gboolean ret; - GstDrmSrc *src = GST_DRM_SRC (handler); - // 1. Checks the protocol - protocol = gst_uri_get_protocol (uri); - if (strcmp (protocol, "file") != 0) - { - g_free (protocol); - return FALSE; - } - g_free (protocol); - if (g_str_has_prefix (uri, "file://localhost/")) - { - char *tmp; - tmp = g_strconcat ("file://", uri + 16, NULL); - location = gst_uri_get_location (tmp); - g_free (tmp); - } - else if (strcmp (uri, "file://") == 0) - { - gst_drm_src_set_location (src, NULL); - return TRUE; - } - else - { - location = gst_uri_get_location (uri); - } - if (!location) - return FALSE; - // 2. Checks the whether it is absolute or not - if (!g_path_is_absolute (location)) - { - g_free (location); - return FALSE; - } - // 3 sets the location - ret = gst_drm_src_set_location (src, location); - g_free (location); - return ret; -} -/** - * This function does the following: - * 1. Assignes the function pointer for URI related stuff - * - * @param g_iface [in] an interface to URI handler - * @param iface_data [in] a gpointer - * - * @return void - */ -static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data) -{ - GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; - // 1. Assigning the function pointer for URI related stuff - iface->get_type = gst_drm_src_uri_get_type; - iface->get_protocols = gst_drm_src_uri_get_protocols; - iface->get_uri = gst_drm_src_uri_get_uri; - iface->set_uri = gst_drm_src_uri_set_uri; -} -/** - * This function does the following: - * 1. Registers an element as drmsrc - * - * @param i_pPlugin [in] a plug-in structure - * - * @return gboolean TRUE on SUCCESS and FALSE on Error - */ -static gboolean plugin_init(GstPlugin* i_pPlugin) -{ - return gst_element_register(i_pPlugin, "drmsrc", GST_RANK_NONE, GST_TYPE_DRM_SRC);; -} -/** - * This function does the following: - * 1. plugin defination - * - */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - drmsrc, - "Plugin to read data from standad/DRM File", - plugin_init, - VERSION, - "LGPL", - "Samsung Electronics Co", - "http://www.samsung.com/") - diff --git a/drmsrc/src/gstdrmsrc.h b/drmsrc/src/gstdrmsrc.h deleted file mode 100755 index 44a7395..0000000 --- a/drmsrc/src/gstdrmsrc.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * drmsrc - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - - -#ifndef __GST_DRM_SRC_H__ -#define __GST_DRM_SRC_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef S_ISREG -#define S_ISREG(mode) ((mode)&_S_IFREG) -#endif -#ifndef S_ISDIR -#define S_ISDIR(mode) ((mode)&_S_IFDIR) -#endif -#ifndef S_ISSOCK -#define S_ISSOCK(x) (0) -#endif -#ifndef O_BINARY -#define O_BINARY (0) -#endif - -G_BEGIN_DECLS - -#define GST_TYPE_DRM_SRC (gst_drm_src_get_type()) -#define GST_DRM_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DRM_SRC,GstDrmSrc)) -#define GST_DRM_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DRM_SRC,GstDrmSrcClass)) -#define GST_IS_DRM_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DRM_SRC)) -#define GST_IS_DRM_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DRM_SRC)) - -typedef struct _GstDrmSrc GstDrmSrc; -typedef struct _GstDrmSrcClass GstDrmSrcClass; - -struct _GstDrmSrc -{ - GstBaseSrc element; - gchar *filename; - gchar *uri; - gint fd; - guint64 read_position; - gboolean seekable; - gboolean is_regular; -}; - -struct _GstDrmSrcClass -{ - GstBaseSrcClass parent_class; -}; - -GType gst_drm_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_DRM_SRC_H__ */ -- 2.7.4 From 338f077293cc2f6e1b6f6e20caa29d1fb6777f36 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Tue, 6 Sep 2016 20:50:02 +0900 Subject: [PATCH 03/16] apply tizen build option rule Change-Id: Ifd258a222fe2f3e99fea1221b7a0163c2427adbb --- encodebin/src/gstencodebin.c | 644 +++++++++++++++++------------------ encodebin/src/gstencodebin.h | 8 +- evasimagesink/src/gstevasimagesink.c | 100 +++--- evasimagesink/src/gstevasimagesink.h | 10 +- fimcconvert/src/gstfimcconvert.c | 16 +- fimcconvert/src/gstfimcconvert.h | 4 +- packaging/gst-plugins-tizen.spec | 4 +- 7 files changed, 393 insertions(+), 393 deletions(-) diff --git a/encodebin/src/gstencodebin.c b/encodebin/src/gstencodebin.c index ff7aa18..77050f3 100644 --- a/encodebin/src/gstencodebin.c +++ b/encodebin/src/gstencodebin.c @@ -60,7 +60,7 @@ g_object_set(G_OBJECT(x_queue), \ GST_INFO("Set to [%s], max [%d] byte, max [%d] buffer, max [%d] time(sec) ", GST_OBJECT_NAME(x_queue), x_byte, x_buffer, x_time);\ } #else -#define ENCODER_QUEUE_SET(x_queue, x_byte, x_buffer, x_time) +#define ENCODER_QUEUE_SET(x_queue, x_byte, x_buffer, x_time) #endif #define _GST_PAD_LINK_UNREF( srcpad, sinkpad, if_fail_goto )\ @@ -122,14 +122,14 @@ enum PROP_USE_VIDEO_TOGGLE, }; -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE /* signals */ enum { SIGNAL_STREAM_BLOCK, - SIGNAL_STREAM_UNBLOCK, + SIGNAL_STREAM_UNBLOCK, SIGNAL_STREAM_PAUSE, - SIGNAL_STREAM_RESUME, + SIGNAL_STREAM_RESUME, LAST_SIGNAL }; #endif @@ -282,7 +282,7 @@ static GstPadProbeReturn gst_encode_bin_video_probe_hs(GstPad *pad, GstPadProbeI static GstElementClass *parent_class; -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 }; #endif @@ -347,16 +347,16 @@ queue_overun_cb (GstElement * queue, GstEncodeBin *encodebin) GstClockTime now = gst_util_get_timestamp (); - g_object_get(G_OBJECT(queue), "current-level-bytes", &queue_size, + g_object_get(G_OBJECT(queue), "current-level-bytes", &queue_size, "current-level-buffers", &queue_bufnum, // "current-level-time", &queue_time, NULL); GST_ELEMENT_WARNING (encodebin, STREAM, TOO_LAZY, - ("[%" GST_TIME_FORMAT "][%s], [%u b], [%u]", - GST_TIME_ARGS(now), GST_OBJECT_NAME(queue), queue_size, queue_bufnum), (NULL)); + ("[%" GST_TIME_FORMAT "][%s], [%u b], [%u]", + GST_TIME_ARGS(now), GST_OBJECT_NAME(queue), queue_size, queue_bufnum), (NULL)); #else GST_ELEMENT_WARNING (encodebin, STREAM, TOO_LAZY, - ("%s overrun", GST_OBJECT_NAME(queue)), (NULL)); + ("%s overrun", GST_OBJECT_NAME(queue)), (NULL)); #endif } @@ -384,7 +384,7 @@ gst_encode_bin_get_property (GObject * object, break; case PROP_IENC_NAME: g_value_set_string (value, encodebin->ienc_name); - break; + break; case PROP_MUX_NAME: g_value_set_string (value, encodebin->mux_name); break; @@ -421,11 +421,11 @@ gst_encode_bin_get_property (GObject * object, // g_value_set_boolean (value, encodebin->use_venc_queue); if((encodebin->video_encode_queue == NULL) && (encodebin->profile == GST_ENCODE_BIN_PROFILE_AV)) { encodebin->video_encode_queue = gst_element_factory_make ("queue", "video_encode_queue"); - if(encodebin->video_encode_queue != NULL) + if(encodebin->video_encode_queue != NULL) gst_bin_add(GST_BIN(encodebin), encodebin->video_encode_queue); } - g_value_set_object (value, encodebin->video_encode_queue); - break; + g_value_set_object (value, encodebin->video_encode_queue); + break; case PROP_AENC_QUEUE: // g_value_set_boolean (value, encodebin->use_aenc_queue); if((encodebin->audio_encode_queue == NULL) && (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO)) { @@ -459,7 +459,7 @@ gst_encode_bin_get_property (GObject * object, gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); } g_value_set_object (value, encodebin->image_encode); - break; + break; case PROP_MUX: if(encodebin->mux == NULL && (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO)) { encodebin->mux = gst_element_factory_make (encodebin->mux_name, "mux"); @@ -501,7 +501,7 @@ gst_encode_bin_set_property (GObject * object, if(encodebin->profile != newprofile) { gst_encode_bin_change_profile(encodebin, newprofile); encodebin->profile = newprofile; - } + } */ break; case PROP_HIGH_SPEED: @@ -526,7 +526,7 @@ gst_encode_bin_set_property (GObject * object, } } break; - } + } case PROP_AENC_NAME: { const gchar *new_name; if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { @@ -536,12 +536,12 @@ gst_encode_bin_set_property (GObject * object, new_name = g_value_get_string (value); if(encodebin->audio_encode == NULL) { - if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) encodebin->aenc_name = g_strdup (new_name); } else { if(strcmp (encodebin->aenc_name, new_name)) { gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); - if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) encodebin->aenc_name = g_strdup (new_name); } } @@ -556,16 +556,16 @@ gst_encode_bin_set_property (GObject * object, new_name = g_value_get_string (value); if(encodebin->image_encode == NULL) { - if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) encodebin->ienc_name = g_strdup (new_name); } else { if(strcmp (encodebin->ienc_name, new_name)) { gst_encode_bin_remove_element(encodebin, encodebin->image_encode); - if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) encodebin->ienc_name = g_strdup (new_name); } } - break; + break; } case PROP_MUX_NAME: { const gchar *new_name; @@ -673,23 +673,23 @@ gst_encode_bin_set_property (GObject * object, gboolean newval = g_value_get_boolean (value); if(encodebin->block != newval) { if(!gst_encode_bin_block(encodebin, newval)) { -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE if(newval) { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_BLOCK], 0, FALSE); } else { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK], 0, FALSE); } -#endif +#endif break; - } + } } -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE if(newval) { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_BLOCK], 0, TRUE); } else { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK], 0, TRUE); } -#endif +#endif break; } case PROP_PAUSE: { @@ -698,13 +698,13 @@ gst_encode_bin_set_property (GObject * object, if(!gst_encode_bin_pause(encodebin, newval)) break; } -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE if(newval) { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, TRUE); } else { g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, TRUE); } -#endif +#endif break; } case PROP_VENC_QUEUE: @@ -723,7 +723,7 @@ gst_encode_bin_set_property (GObject * object, } break; } - break; + break; case PROP_AENC_QUEUE: // encodebin->use_aenc_queue = g_value_get_boolean (value); { @@ -740,8 +740,8 @@ gst_encode_bin_set_property (GObject * object, } break; } - break; - case PROP_VIDEO_ENC: + break; + case PROP_VIDEO_ENC: { GstElement *newelement = g_value_get_object (value); if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AV) { @@ -756,7 +756,7 @@ gst_encode_bin_set_property (GObject * object, } break; } - case PROP_AUDIO_ENC: + case PROP_AUDIO_ENC: { GstElement *newelement = g_value_get_object (value); if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { @@ -840,12 +840,12 @@ gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, g_return_val_if_fail (GST_IS_ENCODE_BIN (element), NULL); encodebin = GST_ENCODE_BIN (element); - + /* FIXME */ if (templ == gst_element_class_get_pad_template (klass, "audio")) { if (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO) { gst_encode_bin_init_audio_elements(element, NULL); //?? - + if(encodebin->audio_sinkpad == NULL) { pad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); @@ -855,10 +855,10 @@ gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, } else { - GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: audio pad is aleady existed, return existing audio pad\n"); + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: audio pad is aleady existed, return existing audio pad\n"); return encodebin->audio_sinkpad; } - + gst_element_add_pad (element, encodebin->audio_sinkpad); return encodebin->audio_sinkpad; } else @@ -870,16 +870,16 @@ gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, if(encodebin->video_sinkpad == NULL) { pad = gst_element_get_static_pad (encodebin->video_queue, "sink"); - encodebin->video_sinkpad = gst_ghost_pad_new ("video", pad); + encodebin->video_sinkpad = gst_ghost_pad_new ("video", pad); gst_object_unref(pad); pad = NULL; } else { - GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: video pad is aleady existed, return existing video pad\n"); + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: video pad is aleady existed, return existing video pad\n"); return encodebin->video_sinkpad; } - + gst_element_add_pad (element, encodebin->video_sinkpad); return encodebin->video_sinkpad; } else if (encodebin->profile == GST_ENCODE_BIN_PROFILE_IMAGE) { @@ -890,14 +890,14 @@ gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, pad = gst_element_get_static_pad (encodebin->image_queue, "sink"); encodebin->image_sinkpad = gst_ghost_pad_new ("image", pad); gst_object_unref(pad); - pad = NULL; + pad = NULL; } else { - GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); return encodebin->image_sinkpad; } - + gst_element_add_pad (element, encodebin->image_sinkpad); return encodebin->image_sinkpad; } else @@ -905,25 +905,25 @@ gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, } else { if (encodebin->profile == GST_ENCODE_BIN_PROFILE_IMAGE) { gst_encode_bin_init_image_elements(element, NULL); //?? - + if(encodebin->image_sinkpad == NULL) { pad = gst_element_get_static_pad (encodebin->image_queue, "sink"); encodebin->image_sinkpad = gst_ghost_pad_new ("image", pad); gst_object_unref(pad); - pad = NULL; + pad = NULL; } else { - GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); return encodebin->image_sinkpad; } - + gst_element_add_pad (element, encodebin->image_sinkpad); return encodebin->image_sinkpad; } else - return NULL; - } + return NULL; + } } static void @@ -934,12 +934,12 @@ gst_encode_bin_class_init (GstEncodeBinClass *klass) gobject_klass = (GObjectClass *) klass; gstelement_klass = (GstElementClass *) klass; - + parent_class = g_type_class_peek_parent (klass); gobject_klass->get_property = gst_encode_bin_get_property; gobject_klass->set_property = gst_encode_bin_set_property; - gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_encode_bin_dispose); + gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_encode_bin_dispose); gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_encode_bin_finalize); @@ -949,7 +949,7 @@ gst_encode_bin_class_init (GstEncodeBinClass *klass) G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, PROP_HIGH_SPEED, - g_param_spec_int ("high-speed-fps", "high speed rec. fps", "framerate for high speed recording", 0, G_MAXINT, + g_param_spec_int ("high-speed-fps", "high speed rec. fps", "framerate for high speed recording", 0, G_MAXINT, DEFAULT_PROP_HIGH_SPEED, G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, PROP_VENC_NAME, @@ -1007,11 +1007,11 @@ gst_encode_bin_class_init (GstEncodeBinClass *klass) #if 0 g_object_class_install_property (gobject_klass, PROP_VENC_QUEUE, g_param_spec_boolean ("use-venc-queue", "use queue between venc and mux", - "add queue between venc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); + "add queue between venc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, PROP_AENC_QUEUE, g_param_spec_boolean ("use-aenc-queue", "use queue between aenc and mux", - "add queue between aenc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); + "add queue between aenc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); #else g_object_class_install_property (gobject_klass, PROP_VENC_QUEUE, g_param_spec_object ("use-venc-queue", "Video Encoder queue", @@ -1053,25 +1053,25 @@ gst_encode_bin_class_init (GstEncodeBinClass *klass) g_param_spec_boolean ("use-video-toggle", "Use video toggle", "Use video toggle while AV recording", TRUE, G_PARAM_READWRITE)); -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE gst_encode_bin_signals[SIGNAL_STREAM_BLOCK] = g_signal_new ("stream-block", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_block), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_block), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK] = g_signal_new ("stream-unblock", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_unblock), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_unblock), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); gst_encode_bin_signals[SIGNAL_STREAM_PAUSE] = g_signal_new ("stream-pause", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_pause), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_pause), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); gst_encode_bin_signals[SIGNAL_STREAM_RESUME] = g_signal_new ("stream-resume", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_resume), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_resume), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); #endif @@ -1091,7 +1091,7 @@ gst_encode_bin_class_init (GstEncodeBinClass *klass) gstelement_klass->request_new_pad = GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad); - gstelement_klass->release_pad = + gstelement_klass->release_pad = GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad); gstelement_klass->change_state = GST_DEBUG_FUNCPTR (gst_encode_bin_change_state); @@ -1110,7 +1110,7 @@ gst_encode_bin_init (GstEncodeBin *encodebin) encodebin->image_sinkpad = NULL; encodebin->mux_audio_sinkpad = NULL; encodebin->mux_video_sinkpad = NULL; - + encodebin->profile = DEFAULT_PROP_PROFILE; encodebin->fps = 0; encodebin->high_speed_fps = DEFAULT_PROP_HIGH_SPEED; @@ -1175,7 +1175,7 @@ gst_encode_bin_dispose (GObject * object) encodebin->venc_name = NULL; g_free(encodebin->aenc_name); - encodebin->aenc_name = NULL; + encodebin->aenc_name = NULL; g_free(encodebin->ienc_name); encodebin->ienc_name = NULL; @@ -1221,7 +1221,7 @@ gst_encode_bin_dispose (GObject * object) encodebin->color_space = NULL; encodebin->audio_conv = NULL; encodebin->audio_sample = NULL; - + if (encodebin->mux && GST_IS_ELEMENT(encodebin->mux)) { int remain_count= 0; remain_count = GST_OBJECT_REFCOUNT_VALUE(encodebin->mux); @@ -1273,8 +1273,8 @@ gst_encode_bin_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: - gst_encode_bin_unlink_elements(encode_bin); - break; + gst_encode_bin_unlink_elements(encode_bin); + break; default: break; } @@ -1289,9 +1289,9 @@ static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad) { GstEncodeBin *encodebin = GST_ENCODE_BIN (element); - + if(!pad_compare_name(pad, "video")) { -#if 0 +#if 0 gst_encode_bin_remove_element(encodebin, encodebin->video_queue); encodebin->video_queue = NULL; gst_encode_bin_remove_element(encodebin, encodebin->video_toggle); @@ -1301,29 +1301,29 @@ gst_encode_bin_release_pad (GstElement * element, GstPad * pad) gst_encode_bin_remove_element(encodebin, encodebin->vcapsfilter); encodebin->vcapsfilter = NULL; gst_encode_bin_remove_element(encodebin, encodebin->video_encode_queue); - encodebin->video_encode_queue = NULL; + encodebin->video_encode_queue = NULL; gst_encode_bin_remove_element(encodebin, encodebin->video_encode); encodebin->video_encode = NULL; - gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); + gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); encodebin->mux_video_sinkpad = NULL; if(encodebin->mux_audio_sinkpad == NULL) { gst_encode_bin_remove_element(encodebin, encodebin->mux); encodebin->mux = NULL; } - else + else { encodebin->mux_audio_sinkpad = NULL; } -#endif +#endif if(encodebin->mux_video_sinkpad != NULL) - { + { gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); encodebin->mux_video_sinkpad = NULL; } - + gst_pad_set_active (pad, FALSE); //?? gst_element_remove_pad(element, pad); encodebin->video_sinkpad = NULL; @@ -1338,7 +1338,7 @@ gst_encode_bin_release_pad (GstElement * element, GstPad * pad) gst_encode_bin_remove_element(encodebin, encodebin->acapsfilter); encodebin->acapsfilter = NULL; gst_encode_bin_remove_element(encodebin, encodebin->audio_encode_queue); - encodebin->audio_encode_queue = NULL; + encodebin->audio_encode_queue = NULL; gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); encodebin->audio_encode = NULL; @@ -1349,11 +1349,11 @@ gst_encode_bin_release_pad (GstElement * element, GstPad * pad) gst_encode_bin_remove_element(encodebin, encodebin->mux); encodebin->mux = NULL; } - else + else { encodebin->mux_video_sinkpad = NULL; } -#endif +#endif if(encodebin->mux_audio_sinkpad != NULL) { gst_element_release_request_pad(encodebin->mux, encodebin->mux_audio_sinkpad); @@ -1361,7 +1361,7 @@ gst_encode_bin_release_pad (GstElement * element, GstPad * pad) encodebin->mux_audio_sinkpad = NULL; } - gst_pad_set_active (pad, FALSE); //?? + gst_pad_set_active (pad, FALSE); //?? gst_element_remove_pad(element, pad); encodebin->audio_sinkpad = NULL; } else { @@ -1376,8 +1376,8 @@ gst_encode_bin_release_pad (GstElement * element, GstPad * pad) encodebin->icapsfilter = NULL; gst_encode_bin_remove_element(encodebin, encodebin->image_encode); encodebin->image_encode = NULL; -#endif - gst_pad_set_active (pad, FALSE); //?? +#endif + gst_pad_set_active (pad, FALSE); //?? gst_element_remove_pad(element, pad); encodebin->image_sinkpad = NULL; } @@ -1395,7 +1395,7 @@ pad_compare_name (GstPad * pad1, const gchar * name) return result; } -static gboolean +static gboolean gst_encode_bin_add_element_by_name (GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name) { switch(type) { @@ -1455,14 +1455,14 @@ gst_encode_bin_add_element_by_name (GstEncodeBin *encodebin, GstEncodeBinElement } return TRUE; - + element_make_fail: GST_WARNING_OBJECT(encodebin, "no such element factory \"%s\"!", name); return FALSE; } #if 0 //disable unused function -static gboolean +static gboolean gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean newprofile) { @@ -1508,7 +1508,7 @@ gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean newprofile) } -static void +static void gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * newelement) { if(newelement == NULL) { @@ -1529,7 +1529,7 @@ gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * gst_object_ref (encodebin->audio_encode); gst_object_sink (GST_OBJECT_CAST (encodebin->audio_encode)); gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); - break; + break; case PROP_IMAGE_ENC: gst_encode_bin_remove_element(encodebin, encodebin->image_encode); encodebin->image_encode = newelement; @@ -1551,11 +1551,11 @@ gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * } } -static gboolean +static gboolean gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name) { GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; - + switch(type) { case ENCODEBIN_ELEMENT_VENC: if(encodebin->video_encode == NULL) { @@ -1581,7 +1581,7 @@ gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElem } } } - + if(gst_encode_bin_remove_element(encodebin, encodebin->video_encode)) { if(encodebin->video_encode = gst_element_factory_make (name, "video_encode") != NULL) { gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); @@ -1590,7 +1590,7 @@ gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElem goto link_fail; } } - + if(peersrc != NULL) { if(!gst_pad_link(gst_element_get_pad(encodebin->video_encode, "src"), peersrc)) { goto link_fail; @@ -1598,13 +1598,13 @@ gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElem } } else { GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] make fail\n", type); - return FALSE; + return FALSE; } } else { GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] remove fail\n", type); return FALSE; - } - } + } + } break; case ENCODEBIN_ELEMENT_AENC: break; @@ -1619,38 +1619,38 @@ gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElem gst_object_unref(sink1); gst_object_unref(sink2); gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); return TRUE; unlink_fail: gst_object_unref(sink1); gst_object_unref(sink2); gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] unlink fail\n", type); return FALSE; - + link_fail: gst_object_unref(sink1); gst_object_unref(sink2); gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] link fail\n", type); - return FALSE; + return FALSE; } -static gboolean +static gboolean gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinElement type, GstElement * element) { GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; - + switch(type) case ENCODEBIN_ELEMENT_VENC: if(encodebin->video_encode == NULL) { @@ -1669,7 +1669,7 @@ gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinEl } #endif //disable unused function -static gboolean +static gboolean gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element) { GstObject *parent; @@ -1701,7 +1701,7 @@ gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element) return TRUE; } -static gboolean +static gboolean gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? { GstPad *srcpad = NULL, *sinkpad = NULL; @@ -1730,7 +1730,7 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? { sinkpad = gst_element_get_static_pad(encodebin->video_toggle, "sink"); _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); - + srcpad = gst_element_get_static_pad(encodebin->video_toggle, "src"); } sinkpad = gst_element_get_static_pad(encodebin->color_space, "sink"); @@ -1749,89 +1749,89 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? if(encodebin->video_encode_queue == NULL) { encodebin->video_encode_queue = gst_element_factory_make ("queue","video_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->video_encode_queue); - - ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); - encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); - - } + + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + } srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } #else if(encodebin->video_encode_queue) { ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); - encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", G_CALLBACK(queue_overun_cb), encodebin); #if 0 - g_object_set(G_OBJECT(encodebin->video_queue), - "max-size-bytes", (guint)0, - "max-size-buffers", (guint)1, - "max-size-time", (guint64)0, - NULL); + g_object_set(G_OBJECT(encodebin->video_queue), + "max-size-bytes", (guint)0, + "max-size-buffers", (guint)1, + "max-size-time", (guint64)0, + NULL); #endif srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } #endif - + } else { srcpad = gst_element_get_static_pad(encodebin->video_queue, "src"); if( encodebin->video_toggle ) { sinkpad = gst_element_get_static_pad(encodebin->video_toggle, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); srcpad = gst_element_get_static_pad(encodebin->video_toggle, "src"); } sinkpad = gst_element_get_static_pad(encodebin->vcapsfilter, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); srcpad = gst_element_get_static_pad(encodebin->vcapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->video_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); #if 0 if(encodebin->use_venc_queue) { if(encodebin->video_encode_queue == NULL) { encodebin->video_encode_queue = gst_element_factory_make ("queue","video_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->video_encode_queue); - + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); - encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); } - + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); - - } + + } #else if(encodebin->video_encode_queue) { ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); - encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", G_CALLBACK(queue_overun_cb), encodebin); -#if 0 - g_object_set(G_OBJECT(encodebin->video_queue), - "max-size-bytes", (guint)0, - "max-size-buffers", (guint)1, - "max-size-time", (guint64)0, - NULL); +#if 0 + g_object_set(G_OBJECT(encodebin->video_queue), + "max-size-bytes", (guint)0, + "max-size-buffers", (guint)1, + "max-size-time", (guint64)0, + NULL); #endif srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } -#endif - +#endif + } // gst_element_get_request_pad (encodebin->mux, "video_%d"); @@ -1840,45 +1840,45 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? { srcpad = gst_element_get_static_pad(encodebin->video_encode_queue, "src"); sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } #else if(encodebin->video_encode_queue) { srcpad = gst_element_get_static_pad(encodebin->video_encode_queue, "src"); sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } #endif else { srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); } srcpad = gst_element_get_static_pad(encodebin->mux, "src"); if(gst_ghost_pad_get_target(GST_GHOST_PAD (encodebin->srcpad)) != srcpad) gst_ghost_pad_set_target(GST_GHOST_PAD (encodebin->srcpad), srcpad); gst_object_unref(srcpad); - srcpad = NULL; - + srcpad = NULL; + /* For pause/resume control */ // encodebin->vsink_probeid = gst_pad_add_data_probe (gst_element_get_static_pad (encodebin->video_queue, "sink"), sinkpad = gst_element_get_static_pad (encodebin->video_queue, "sink"); encodebin->vsink_probeid = gst_pad_add_probe(sinkpad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)gst_encode_bin_video_probe, encodebin, NULL); gst_object_unref(sinkpad); sinkpad = NULL; - + if(encodebin->high_speed_fps > DEFAULT_PROP_HIGH_SPEED) { // encodebin->vsink_hs_probeid = gst_pad_add_data_probe (gst_element_get_static_pad (encodebin->video_encode, "sink"), sinkpad = gst_element_get_static_pad (encodebin->video_encode, "sink"); encodebin->vsink_hs_probeid = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)gst_encode_bin_video_probe_hs, encodebin, NULL); gst_object_unref(sinkpad); - sinkpad = NULL; - } - + sinkpad = NULL; + } + if(encodebin->audio_queue == NULL) { GST_WARNING_OBJECT(encodebin, "Audio pad isn't requested, recording video only mode"); @@ -1886,7 +1886,7 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? } case GST_ENCODE_BIN_PROFILE_AUDIO : if(!gst_caps_is_any(encodebin->acaps)) - { + { g_object_set(encodebin->acapsfilter, "caps", encodebin->acaps, NULL); } if (encodebin->auto_audio_convert ||encodebin->auto_audio_resample) { @@ -1905,42 +1905,42 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); -#if 0 + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 if(encodebin->use_aenc_queue) { if(encodebin->audio_encode_queue == NULL) { encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); - - ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); - } + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); - } + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } #else if(encodebin->audio_encode_queue) { - + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } #endif - + } else if (!encodebin->auto_audio_resample) { if (encodebin->audio_conv == NULL) { encodebin->audio_conv = gst_element_factory_make ("audioconvert","audio_conv"); gst_bin_add (GST_BIN (encodebin), encodebin->audio_conv); - } + } srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_conv, "sink"); @@ -1952,38 +1952,38 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); -#if 0 + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 if(encodebin->use_aenc_queue) { if(encodebin->audio_encode_queue == NULL) { encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); - ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); - } + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); - - } + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } #else if(encodebin->audio_encode_queue) { - + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } -#endif - +#endif + } else { if(encodebin->audio_sample == NULL) { encodebin->audio_sample = gst_element_factory_make ("audioresample","audio_sample"); @@ -1996,7 +1996,7 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_conv, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); srcpad = gst_element_get_static_pad(encodebin->audio_conv, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_sample, "sink"); @@ -2004,89 +2004,89 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? srcpad = gst_element_get_static_pad(encodebin->audio_sample, "src"); sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); -#if 0 + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 if(encodebin->use_aenc_queue) { if(encodebin->audio_encode_queue == NULL) { encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); - - ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); - } + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); - - } + + } #else if(encodebin->audio_encode_queue) { - + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } -#endif - +#endif + } }else { srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); #if 0 if(encodebin->use_aenc_queue) { if(encodebin->audio_encode_queue == NULL) { encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); - + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); - } + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); - } + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } #else if(encodebin->audio_encode_queue) { - + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); - encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", - G_CALLBACK(queue_overun_cb), encodebin); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } -#endif - +#endif + } -#if 0 +#if 0 if(encodebin->use_aenc_queue) { srcpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "src"); sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } #else @@ -2095,16 +2095,16 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? { srcpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "src"); sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); } #endif else - { + { srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); - + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } srcpad = gst_element_get_static_pad(encodebin->mux, "src"); @@ -2122,10 +2122,10 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? break; case GST_ENCODE_BIN_PROFILE_IMAGE : if(!gst_caps_is_any(encodebin->icaps)) - { + { g_object_set(encodebin->icapsfilter, "caps", encodebin->icaps, NULL); } - + if (encodebin->auto_color_space) { if(encodebin->color_space == NULL) { encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); @@ -2138,30 +2138,30 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? srcpad = gst_element_get_static_pad(encodebin->image_toggle, "src"); sinkpad = gst_element_get_static_pad(encodebin->color_space, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); srcpad = gst_element_get_static_pad(encodebin->color_space, "src"); sinkpad = gst_element_get_static_pad(encodebin->icapsfilter, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); srcpad = gst_element_get_static_pad(encodebin->icapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->image_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); } else { - + srcpad = gst_element_get_static_pad(encodebin->image_queue, "src"); sinkpad = gst_element_get_static_pad(encodebin->image_toggle, "sink"); _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); srcpad = gst_element_get_static_pad(encodebin->image_toggle, "src"); sinkpad = gst_element_get_static_pad(encodebin->icapsfilter, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); srcpad = gst_element_get_static_pad(encodebin->icapsfilter, "src"); sinkpad = gst_element_get_static_pad(encodebin->image_encode, "sink"); - _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); } srcpad = gst_element_get_static_pad (encodebin->image_encode, "src"); @@ -2175,7 +2175,7 @@ gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? return FALSE; break; } -// gst_pad_set_active(encodebin->srcpad, TRUE); +// gst_pad_set_active(encodebin->srcpad, TRUE); return TRUE; video_link_fail: @@ -2183,28 +2183,28 @@ video_link_fail: gst_encode_bin_remove_element(encodebin, encodebin->color_space); GST_WARNING_OBJECT(encodebin, "encodebin link video elements fail"); return FALSE; - + audio_link_fail: - // remove element - gst_encode_bin_remove_element(encodebin, encodebin->audio_conv); - gst_encode_bin_remove_element(encodebin, encodebin->audio_sample); + // remove element + gst_encode_bin_remove_element(encodebin, encodebin->audio_conv); + gst_encode_bin_remove_element(encodebin, encodebin->audio_sample); GST_WARNING_OBJECT(encodebin, "encodebin link audio elements fail"); return FALSE; image_link_fail: - // remove element - gst_encode_bin_remove_element(encodebin, encodebin->color_space); + // remove element + gst_encode_bin_remove_element(encodebin, encodebin->color_space); GST_WARNING_OBJECT(encodebin, "encodebin link image elements fail"); return FALSE; - + } -static gboolean +static gboolean gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) { GstPad *pad = NULL; - + switch(encodebin->profile) { case GST_ENCODE_BIN_PROFILE_AV : if (encodebin->auto_color_space) { @@ -2280,9 +2280,9 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) gst_pad_remove_probe(pad, encodebin->vsink_probeid); encodebin->vsink_probeid = 0; gst_object_unref(pad); - pad = NULL; + pad = NULL; } - + if(encodebin->vsink_hs_probeid) { @@ -2305,22 +2305,22 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) encodebin->audio_sample, encodebin->acapsfilter, encodebin->audio_encode, - NULL); + NULL); } else if (!encodebin->auto_audio_resample) { gst_element_unlink_many ( encodebin->audio_queue, - encodebin->audio_conv, + encodebin->audio_conv, encodebin->acapsfilter, encodebin->audio_encode, - NULL); + NULL); } else { gst_element_unlink_many ( encodebin->audio_queue, encodebin->audio_conv, - encodebin->audio_sample, + encodebin->audio_sample, encodebin->acapsfilter, encodebin->audio_encode, - NULL); + NULL); } } else { @@ -2328,12 +2328,12 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) encodebin->audio_queue, encodebin->acapsfilter, encodebin->audio_encode, - NULL); + NULL); } if(encodebin->mux_audio_sinkpad != NULL) { -#if 0 +#if 0 if(encodebin->use_aenc_queue) { gst_element_unlink(encodebin->audio_encode, encodebin->audio_encode_queue); @@ -2341,12 +2341,12 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) pad = gst_element_get_static_pad (encodebin->audio_encode_queue, "src"); gst_pad_unlink(pad, muxpad); gst_object_unref(pad); - pad = NULL; + pad = NULL; if ( g_signal_handler_is_connected ( encodebin->audio_encode_queue, encodebin->veque_sig_id) ) { g_signal_handler_disconnect ( encodebin->audio_encode_queue, encodebin->veque_sig_id ); - } + } } #else if(encodebin->audio_encode_queue) @@ -2356,12 +2356,12 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) pad = gst_element_get_static_pad (encodebin->audio_encode_queue, "src"); gst_pad_unlink(pad, encodebin->mux_audio_sinkpad); gst_object_unref(pad); - pad = NULL; + pad = NULL; if ( g_signal_handler_is_connected ( encodebin->audio_encode_queue, encodebin->veque_sig_id) ) { g_signal_handler_disconnect ( encodebin->audio_encode_queue, encodebin->veque_sig_id ); - } + } } #endif else @@ -2370,7 +2370,7 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) gst_pad_unlink(pad, encodebin->mux_audio_sinkpad); gst_object_unref(pad); pad = NULL; - } + } gst_element_release_request_pad(encodebin->mux, encodebin->mux_audio_sinkpad); // gst_object_unref(encodebin->mux_audio_sinkpad); //*** @@ -2379,7 +2379,7 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) if(encodebin->asink_probeid) { - pad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); + pad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); gst_pad_remove_probe(pad, encodebin->asink_probeid); encodebin->asink_probeid =0; gst_object_unref(pad); @@ -2393,17 +2393,17 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) encodebin->image_queue, encodebin->image_toggle, encodebin->color_space, - encodebin->icapsfilter, + encodebin->icapsfilter, encodebin->image_encode, NULL); } else { gst_element_unlink_many ( encodebin->image_queue, - encodebin->image_toggle, - encodebin->icapsfilter, + encodebin->image_toggle, + encodebin->icapsfilter, encodebin->image_encode, - NULL); + NULL); } break; default: @@ -2411,12 +2411,12 @@ gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) return FALSE; break; } - // gst_pad_set_active(encodebin->srcpad, TRUE); + // gst_pad_set_active(encodebin->srcpad, TRUE); return TRUE; } -static gboolean +static gboolean gst_encode_bin_init_video_elements (GstElement *element, gpointer user_data) { GstEncodeBin *encodebin = GST_ENCODE_BIN (element); @@ -2446,14 +2446,14 @@ gst_encode_bin_init_video_elements (GstElement *element, gpointer user_data) if(encodebin->vcapsfilter == NULL) { encodebin->vcapsfilter = gst_element_factory_make ("capsfilter","vcapsfilter"); gst_bin_add (GST_BIN (element), encodebin->vcapsfilter); - } + } #if 0 encodebin->vcaps = gst_caps_new_simple("video/x-raw", "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), "width", G_TYPE_INT, 320, "height", G_TYPE_INT, 240, "framerate", GST_TYPE_FRACTION, 30, 1, - NULL); + NULL); #endif if(encodebin->video_encode == NULL) { @@ -2475,33 +2475,33 @@ gst_encode_bin_init_video_elements (GstElement *element, gpointer user_data) gst_bin_add (GST_BIN (element), encodebin->mux); } - if (!encodebin->video_encode -// || !encodebin->video_encode_queue - || !encodebin->mux - || !encodebin->video_queue + if (!encodebin->video_encode +// || !encodebin->video_encode_queue + || !encodebin->mux + || !encodebin->video_queue || !encodebin->vcapsfilter || !encodebin->srcpad ) { GST_ERROR_OBJECT(encodebin, "Faild create element \n"); return FALSE; } - + if( encodebin->use_video_toggle && !encodebin->video_toggle ) { GST_ERROR_OBJECT(encodebin, "Faild create video toggle element \n"); return FALSE; } -#if 0 +#if 0 if (encodebin->auto_color_space && (encodebin->color_space == NULL)) { encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); gst_bin_add (GST_BIN (element), encodebin->color_space); - } -#endif + } +#endif return TRUE; } -static gboolean +static gboolean gst_encode_bin_init_audio_elements (GstElement *element, gpointer user_data) { GstEncodeBin *encodebin = GST_ENCODE_BIN (element); @@ -2517,7 +2517,7 @@ gst_encode_bin_init_audio_elements (GstElement *element, gpointer user_data) if(encodebin->acapsfilter == NULL) { encodebin->acapsfilter = gst_element_factory_make ("capsfilter","acapsfilter"); gst_bin_add (GST_BIN (element), encodebin->acapsfilter); - } + } #if 0 encodebin->acaps = gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, 8000, @@ -2536,10 +2536,10 @@ encodebin->acaps = gst_caps_new_simple("audio/x-raw", gst_bin_add (GST_BIN (element), encodebin->mux); } - if (!encodebin->audio_encode + if (!encodebin->audio_encode || !encodebin->audio_queue || !encodebin->mux - || !encodebin->acapsfilter + || !encodebin->acapsfilter || !encodebin->srcpad ) { GST_ERROR_OBJECT(encodebin, "Faild create element \n"); @@ -2549,18 +2549,18 @@ encodebin->acaps = gst_caps_new_simple("audio/x-raw", if (encodebin->auto_audio_convert && (encodebin->audio_conv == NULL)) { encodebin->audio_conv = gst_element_factory_make ("audioconvert","audio_conv"); gst_bin_add (GST_BIN (element), encodebin->audio_conv); - } + } if (encodebin->auto_audio_resample && (encodebin->audio_sample == NULL)) { encodebin->audio_sample = gst_element_factory_make ("audioresample","audio_sample"); gst_bin_add (GST_BIN (element), encodebin->audio_sample); - } + } #endif return TRUE; } -static gboolean +static gboolean gst_encode_bin_init_image_elements (GstElement *element, gpointer user_data) { GstEncodeBin *encodebin = GST_ENCODE_BIN (element); @@ -2581,14 +2581,14 @@ gst_encode_bin_init_image_elements (GstElement *element, gpointer user_data) if(encodebin->icapsfilter == NULL) { encodebin->icapsfilter = gst_element_factory_make ("capsfilter","icapsfilter"); gst_bin_add (GST_BIN (element), encodebin->icapsfilter); - } + } if(encodebin->image_encode == NULL) { encodebin->image_encode = gst_element_factory_make (encodebin->ienc_name, "image_encode"); gst_bin_add (GST_BIN (element), encodebin->image_encode); - } + } - if (!encodebin->image_encode + if (!encodebin->image_encode || !encodebin->image_queue || !encodebin->image_toggle || !encodebin->icapsfilter @@ -2601,21 +2601,21 @@ gst_encode_bin_init_image_elements (GstElement *element, gpointer user_data) if (encodebin->auto_color_space && (encodebin->color_space == NULL)) { encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); gst_bin_add (GST_BIN (element), encodebin->color_space); - } + } #endif return TRUE; } static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) { - + if(value) { //block stream switch(encodebin->profile) { case GST_ENCODE_BIN_PROFILE_AV: if(encodebin->audio_queue == NULL && encodebin->video_queue == NULL) { goto block_fail; } else { - if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), "empty-buffers") == NULL) { GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); goto block_fail; @@ -2625,7 +2625,7 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) g_object_set(encodebin->video_toggle, "block-data", TRUE , NULL); GST_INFO_OBJECT( encodebin, "video_toggle block-data TRUE" ); } - + g_object_set(encodebin->video_queue, "empty-buffers", TRUE , NULL); GST_INFO_OBJECT( encodebin, "video_queue empty-buffers TRUE" ); if(encodebin->audio_queue != NULL) @@ -2637,13 +2637,13 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) break; case GST_ENCODE_BIN_PROFILE_AUDIO: if(encodebin->audio_queue == NULL) { - goto block_fail; + goto block_fail; } else { - if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), "empty-buffers") == NULL) { GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); goto block_fail; - } + } g_object_set(encodebin->audio_queue, "empty-buffers", TRUE , NULL); GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers TRUE" ); } @@ -2655,11 +2655,11 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) g_object_set(encodebin->image_toggle, "block_data", TRUE, NULL); GST_INFO_OBJECT( encodebin, "image_toggle block_data TRUE" ); } - break; + break; default: GST_WARNING_OBJECT (encodebin,"Invalid profile number = %d", encodebin->profile); goto block_fail; - break; + break; } } else { //release blocked-stream switch(encodebin->profile) { @@ -2667,19 +2667,19 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) if(encodebin->audio_queue == NULL && encodebin->video_queue == NULL) { goto unblock_fail; } else { - if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), "empty-buffers") == NULL) { GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); goto unblock_fail; - } + } if( encodebin->video_toggle ) { g_object_set(encodebin->video_toggle, "block-data", FALSE , NULL); GST_INFO_OBJECT( encodebin, "video_toggle block-data FALSE" ); } - + if(encodebin->audio_queue != NULL) - { + { g_object_set(encodebin->audio_queue, "empty-buffers", FALSE , NULL); GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers FALSE" ); } @@ -2689,13 +2689,13 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) break; case GST_ENCODE_BIN_PROFILE_AUDIO: if(encodebin->audio_queue == NULL) { - goto unblock_fail; - } else { - if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), + goto unblock_fail; + } else { + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), "empty-buffers") == NULL) { GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); goto unblock_fail; - } + } g_object_set(encodebin->audio_queue, "empty-buffers", FALSE , NULL); GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers FALSE" ); } @@ -2703,16 +2703,16 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) case GST_ENCODE_BIN_PROFILE_IMAGE: if(encodebin->image_toggle == NULL) { goto unblock_fail; - } else { + } else { g_object_set(encodebin->image_toggle, "block_data", FALSE, NULL); GST_INFO_OBJECT( encodebin, "image_toggle block_data FALSE" ); } - break; + break; default: GST_WARNING_OBJECT (encodebin,"Invalid profile number = %d", encodebin->profile); goto unblock_fail; - break; - } + break; + } } encodebin->block = value; return TRUE; @@ -2720,17 +2720,17 @@ static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) block_fail: GST_ERROR_OBJECT(encodebin, "encodebin block failed"); return FALSE; - -unblock_fail: - GST_ERROR_OBJECT(encodebin, "encodebin unblock failed"); - return FALSE; + +unblock_fail: + GST_ERROR_OBJECT(encodebin, "encodebin unblock failed"); + return FALSE; } static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) { GstClock *clock = NULL; - if(value) { + if(value) { /* pause stream*/ //Block src of encode bin if (!gst_encode_bin_block(encodebin, TRUE)) @@ -2751,7 +2751,7 @@ static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) base_time = gst_element_get_base_time(GST_ELEMENT(encodebin)); encodebin->paused_time = current_time - base_time; - + GST_INFO_OBJECT (encodebin, "Encodebin is in running-pause at [%"GST_TIME_FORMAT"]." , GST_TIME_ARGS(encodebin->paused_time)); } @@ -2759,15 +2759,15 @@ static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) { encodebin->paused_time = 0; encodebin->total_offset_time = 0; - + GST_WARNING_OBJECT (encodebin, "There is no clock in Encodebin."); } } -#if 0 //def GST_ENCODE_BIN_SIGNAL_ENABLE +#if 0 //def TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, TRUE); -#endif +#endif } - else { + else { /* release paused-stream*/ if (encodebin->paused_time != 0) { @@ -2780,10 +2780,10 @@ static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) current_time = gst_clock_get_time(clock); base_time = gst_element_get_base_time(GST_ELEMENT(encodebin)); paused_gap = current_time - base_time - encodebin->paused_time; - + encodebin->total_offset_time += paused_gap; encodebin->paused_time = 0; - + GST_INFO_OBJECT (encodebin, "Encodebin now resumes. Offset delay [%"GST_TIME_FORMAT"], Total offset delay [%"GST_TIME_FORMAT"]" , GST_TIME_ARGS(paused_gap) , GST_TIME_ARGS(encodebin->total_offset_time)); } @@ -2791,7 +2791,7 @@ static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) { encodebin->paused_time = 0; encodebin->total_offset_time = 0; - + GST_WARNING_OBJECT (encodebin, "There is no clock in Encodebin."); } } @@ -2804,26 +2804,26 @@ static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) GST_WARNING_OBJECT (encodebin, "Fail to Unblock Encodebin."); goto resume_fail; } -#if 0 //def GST_ENCODE_BIN_SIGNAL_ENABLE +#if 0 //def TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, TRUE); -#endif +#endif } encodebin->pause = value; return TRUE; pause_fail: GST_WARNING_OBJECT (encodebin, "Fail to pause Encodebin"); -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, FALSE); -#endif +#endif return FALSE; -resume_fail: +resume_fail: GST_WARNING_OBJECT (encodebin, "Fail to resume Encodebin"); -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, FALSE); -#endif - return FALSE; +#endif + return FALSE; } static GstPadProbeReturn @@ -2834,7 +2834,7 @@ gst_encode_bin_video_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *enc GST_WARNING_OBJECT (encodebin, "encodebin is Null."); return GST_PAD_PROBE_OK; } - + //Adjusting timestamp of video source GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; @@ -2849,7 +2849,7 @@ gst_encode_bin_video_probe_hs(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin * GST_WARNING_OBJECT (encodebin, "encodebin is Null."); return GST_PAD_PROBE_OK; } - + GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) *= encodebin->multiple; return GST_PAD_PROBE_OK; } @@ -2862,7 +2862,7 @@ gst_encode_bin_audio_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *enc GST_WARNING_OBJECT (encodebin, "encodebin is Null."); return GST_PAD_PROBE_OK; } - + //Adjusting timestamp of video source GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; @@ -2919,5 +2919,5 @@ plugin_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, encodebin, - "EXT encoder bin", + "EXT encoder bin", plugin_init, VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com/") diff --git a/encodebin/src/gstencodebin.h b/encodebin/src/gstencodebin.h index 899e5b7..6894edf 100644 --- a/encodebin/src/gstencodebin.h +++ b/encodebin/src/gstencodebin.h @@ -46,7 +46,7 @@ GType gst_encode_bin_profile_get_type (void); #define GST_ENCODE_BIN_UNLOCK(encodebin) g_mutex_unlock (GST_ENCODE_BIN_GET_LOCK(encodebin)) /* Signal enable */ -#define GST_ENCODE_BIN_SIGNAL_ENABLE +#define TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE typedef struct _GstEncodeBinPad { GstCollectData *collect; @@ -139,10 +139,10 @@ struct _GstEncodeBinClass { GstBinClass parent_class; -#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +#ifdef TIZEN_FEATURE_ENCODE_BIN_SIGNAL_ENABLE /* signal we fire when stream block/pause function called */ - void (*stream_block) (GstElement * element, gboolean result); - void (*stream_unblock) (GstElement * element, gboolean result); + void (*stream_block) (GstElement * element, gboolean result); + void (*stream_unblock) (GstElement * element, gboolean result); void (*stream_pause) (GstElement * element, gboolean result); void (*stream_resume) (GstElement * element, gboolean result); #endif diff --git a/evasimagesink/src/gstevasimagesink.c b/evasimagesink/src/gstevasimagesink.c index b782777..fcab28b 100755 --- a/evasimagesink/src/gstevasimagesink.c +++ b/evasimagesink/src/gstevasimagesink.c @@ -58,7 +58,7 @@ enum PROP_0, PROP_EVAS_OBJECT, PROP_EVAS_OBJECT_SHOW, -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE PROP_ROTATE_ANGLE, PROP_DISPLAY_GEOMETRY_METHOD, PROP_ENABLE_FLUSH_BUFFER, @@ -77,7 +77,7 @@ enum #define DO_RENDER_FROM_FIMC 1 #define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar) -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE #define MAX_ECOREPIPE_BUFFER_CNT 4 #define DEBUGLOG_DEFAULT_COUNT 8 #define SIZE_FOR_TBM_SUR_INDEX sizeof(gint) @@ -170,7 +170,7 @@ do \ } \ }while(0) -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE #define EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK( x_evas, x_usr_data ) \ do \ { \ @@ -210,7 +210,7 @@ is_evas_image_object (Evas_Object *obj) return FALSE; } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE gint gst_evas_image_sink_ref_count (GstBuffer * buf) { @@ -225,10 +225,10 @@ gst_evas_image_sink_ref_count (GstBuffer * buf) static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE("BGRx"))); #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE ("I420") ";" GST_VIDEO_CAPS_MAKE ("NV12") ";" GST_VIDEO_CAPS_MAKE ("SN12")) @@ -249,7 +249,7 @@ static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event); static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition); static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info); static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static void evas_callback_render_pre (void *data, Evas *e, void *event_info); static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink); static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink); @@ -291,7 +291,7 @@ gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass) g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW, g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE, g_param_spec_int("rotate", "Rotate angle", "Rotate angle of display output", DEGREE_0, DEGREE_NUM, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD, @@ -330,14 +330,14 @@ gst_evas_image_sink_fini (gpointer data, GObject *obj) if (!esink) { return; } -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC if (esink->oldbuf) { gst_buffer_unref (esink->oldbuf); } #endif if (esink->eo) { -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); #endif @@ -345,7 +345,7 @@ gst_evas_image_sink_fini (gpointer data, GObject *obj) GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); evas_object_image_data_set(esink->eo, NULL); } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE if (esink->display_buffer_lock) { g_mutex_clear (esink->display_buffer_lock); g_slice_free (GMutex, esink->display_buffer_lock); @@ -371,7 +371,7 @@ gst_evas_image_sink_fini (gpointer data, GObject *obj) GST_DEBUG ("[LEAVE]"); } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static void gst_evas_image_sink_reset (GstEvasImageSink *esink) { @@ -431,17 +431,17 @@ gst_evas_image_sink_reset (GstEvasImageSink *esink) } #endif -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC static void evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte) #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static void evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) #endif { GstEvasImageSink *esink = data; -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC GstBuffer *buf; GstMapInfo buf_info = GST_MAP_INFO_INIT; void *img_data; @@ -463,13 +463,13 @@ evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) GST_DEBUG ("[LEAVE]"); return; } -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC if (!buffer || nbyte != sizeof (GstBuffer *)) { GST_WARNING ("buffer %p, nbyte : %d, sizeof(GstBuffer *) : %d", buffer, nbyte, sizeof (GstBuffer *)); return; } #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE int index = 0; index = *buffer_index; if ((index<0 || index>=TBM_SURFACE_NUM) || nbyte != SIZE_FOR_TBM_SUR_INDEX) { @@ -482,7 +482,7 @@ evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) return; } -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC memcpy (&buf, buffer, sizeof (GstBuffer *)); if (!buf) { GST_ERROR ("There is no buffer"); @@ -495,7 +495,7 @@ evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) return; } #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE g_mutex_lock(esink->display_buffer_lock); if(esink->tbm_surface_format == TBM_FORMAT_NV12) { if (!esink->displaying_buffer[index].tbm_surf) { @@ -622,7 +622,7 @@ evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) esink->sent_buffer_cnt--; } #endif -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { evas_object_image_size_set (esink->eo, esink->w, esink->h); GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)", esink->w, esink->h); @@ -654,12 +654,12 @@ evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) esink->oldbuf = buf; } #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE g_mutex_unlock(esink->display_buffer_lock); #endif GST_DEBUG ("[LEAVE]"); } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static void gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result) { @@ -785,11 +785,11 @@ gst_evas_image_sink_init (GstEvasImageSink *esink) esink->object_show = FALSE; esink->update_visibility = UPDATE_FALSE; esink->is_evas_object_size_set = FALSE; -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC esink->gl_zerocopy = FALSE; esink->present_data_addr = -1; #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE esink->display_buffer_lock = g_slice_new (GMutex); esink->flow_lock = g_slice_new (GMutex); g_mutex_init (esink->display_buffer_lock); @@ -841,14 +841,14 @@ evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info if (!esink) { return; } -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC if (esink->oldbuf) { gst_buffer_unref (esink->oldbuf); esink->oldbuf = NULL; } #endif if (esink->eo) { -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); #endif @@ -878,7 +878,7 @@ evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_i if (!w || !h) { GST_WARNING ("evas object size (w:%d,h:%d) was not set", w, h); } else { -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE esink->eo_size.x = x; esink->eo_size.y = y; esink->eo_size.w = w; @@ -886,14 +886,14 @@ evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_i GST_WARNING ("resize (x:%d, y:%d, w:%d, h:%d)", x, y, w, h); gst_evas_image_sink_apply_geometry(esink); #endif -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC evas_object_image_fill_set(esink->eo, 0, 0, w, h); GST_DEBUG ("evas object fill set (w:%d,h:%d)", w, h); #endif } GST_DEBUG ("[LEAVE]"); } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static void evas_callback_render_pre (void *data, Evas *e, void *event_info) { @@ -1085,7 +1085,7 @@ evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h) return 0; } -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC static gboolean is_zerocopy_supported (Evas *e) { @@ -1147,7 +1147,7 @@ evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event) static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event) { -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC GstEvasImageSink *esink = GST_EVASIMAGESINK (sink); #endif switch (GST_EVENT_TYPE (event)) { @@ -1160,7 +1160,7 @@ gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event) case GST_EVENT_EOS: GST_DEBUG ("GST_EVENT_EOS"); break; -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: if(!evas_image_sink_event_parse_data(esink, event)) { GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr); @@ -1184,7 +1184,7 @@ gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition { GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS; GstEvasImageSink *esink = NULL; -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE GstFlowReturn ret=GST_FLOW_OK; #endif esink = GST_EVASIMAGESINK(element); @@ -1197,7 +1197,7 @@ gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: GST_WARNING ("*** STATE_CHANGE_NULL_TO_READY ***"); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE g_mutex_lock (esink->flow_lock); if (!is_evas_image_object (esink->eo)) { GST_ERROR_OBJECT (esink, "There is no evas image object.."); @@ -1211,7 +1211,7 @@ gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition GST_WARNING ("*** STATE_CHANGE_READY_TO_PAUSED ***"); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE /* Print debug log for 8 frame */ esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT; esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT; @@ -1230,7 +1230,7 @@ gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_READY ***"); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE Eina_Bool r; /* flush buffer, we will copy last buffer to keep image data and reset buffer list */ GST_WARNING("esink->enable_flush_buffer : %d", esink->enable_flush_buffer); @@ -1261,7 +1261,7 @@ gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition break; case GST_STATE_CHANGE_READY_TO_NULL: GST_WARNING ("*** STATE_CHANGE_READY_TO_NULL ***"); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE if(esink->flush_buffer) _release_flush_buffer(esink); EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); @@ -1294,7 +1294,7 @@ gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue * if (is_evas_image_object (eo)) { if (eo != esink->eo) { Eina_Bool r; -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); #endif /* delete evas object callbacks registrated on a previous evas image object */ @@ -1303,13 +1303,13 @@ gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue * /* add evas object callbacks on a new evas image object */ EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE GST_WARNING("register render callback [esink : %p, esink->eo : %p]", esink, esink->eo); EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo), esink); evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); GST_WARNING ("evas object size (x:%d, y:%d, w:%d, h:%d)", esink->eo_size.x, esink->eo_size.y, esink->eo_size.w, esink->eo_size.h); #endif -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo)); if (esink->gl_zerocopy) { evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); @@ -1350,7 +1350,7 @@ gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue * } break; } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE case PROP_ROTATE_ANGLE: { int rotate = 0; @@ -1434,7 +1434,7 @@ gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, case PROP_EVAS_OBJECT_SHOW: g_value_set_boolean (value, esink->object_show); break; -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE case PROP_ROTATE_ANGLE: g_value_set_int (value, esink->rotate_angle); break; @@ -1482,7 +1482,7 @@ gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps) } GST_DEBUG_OBJECT(esink, "source color format is %s", format); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE if (!strcmp (format, "SN12") || !strcmp (format, "NV12")) esink->tbm_surface_format = TBM_FORMAT_NV12; else if (!strcmp (format, "I420")) @@ -1504,7 +1504,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) GstMapInfo buf_info = GST_MAP_INFO_INIT; GST_LOG("[ENTER] show frame"); -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE if (!gst_evas_image_sink_ref_count (buf)) { GST_WARNING("ref count is 0.. skip show frame"); @@ -1512,7 +1512,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) } #endif g_mutex_lock (instance_lock); -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC if (esink->present_data_addr == -1) { /* if present_data_addr is -1, we don't use this member variable */ } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) { @@ -1538,7 +1538,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) } GST_DEBUG("ecore-pipe create success"); } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE int i = 0; int index = -1; SCMN_IMGB *scmn_imgb = NULL; @@ -1718,7 +1718,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) } #endif if (esink->object_show) { //if (esink->object_show && index != -1) -#ifdef USE_FIMCC +#ifdef TIZEN_FEATURE_USE_FIMCC gst_buffer_ref (buf); r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *)); if (r == EINA_FALSE) { @@ -1727,7 +1727,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) gst_buffer_unref (buf); } #endif -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE int old_curidx=esink->cur_index ; static int skip_count=0; g_mutex_lock(esink->display_buffer_lock); @@ -1803,7 +1803,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) #endif GST_DEBUG ("ecore_pipe_write() was called with gst_buf= %p.. gst_buf size=%d, mallocdata= %p", buf, buf_info.size, buf_info.memory); } else { -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d) index %d", esink->object_show, index); #else GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d)", esink->object_show); @@ -1815,7 +1815,7 @@ gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) return GST_FLOW_OK; } -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink) { diff --git a/evasimagesink/src/gstevasimagesink.h b/evasimagesink/src/gstevasimagesink.h index acc1882..7c62d46 100644 --- a/evasimagesink/src/gstevasimagesink.h +++ b/evasimagesink/src/gstevasimagesink.h @@ -24,14 +24,14 @@ #ifndef __GST_EVASIMAGESINK_H__ #define __GST_EVASIMAGESINK_H__ -//#define USE_TBM_SURFACE -#define USE_FIMCC +//#define TIZEN_FEATURE_USE_TBM_SURFACE +#define TIZEN_FEATURE_USE_FIMCC #include #include #include #include -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE #include #include #endif @@ -51,7 +51,7 @@ G_BEGIN_DECLS typedef struct _GstEvasImageSink GstEvasImageSink; typedef struct _GstEvasImageSinkClass GstEvasImageSinkClass; -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE typedef struct _GstEvasImageDisplayingBuffer GstEvasImageDisplayingBuffer; typedef struct _GstEvasImageFlushBuffer GstEvasImageFlushBuffer; typedef enum { @@ -132,7 +132,7 @@ struct _GstEvasImageSink gboolean is_evas_object_size_set; guint present_data_addr; -#ifdef USE_TBM_SURFACE +#ifdef TIZEN_FEATURE_USE_TBM_SURFACE GMutex *display_buffer_lock; GMutex *flow_lock; GstEvasImageDisplayingBuffer displaying_buffer[TBM_SURFACE_NUM]; diff --git a/fimcconvert/src/gstfimcconvert.c b/fimcconvert/src/gstfimcconvert.c index f7f9aaa..73190ce 100755 --- a/fimcconvert/src/gstfimcconvert.c +++ b/fimcconvert/src/gstfimcconvert.c @@ -241,7 +241,7 @@ gst_fimcconvert_buffer_finalize(GstFimcConvertBuffer *buffer) { GstFimcConvert *fimcconvert = NULL; SCMN_IMGB *imgb = NULL; -#ifdef USE_DETECT_JPEG +#ifdef TIZEN_FEATURE_USE_DETECT_JPEG GstMemory *imgb_memory = NULL; GstMapInfo imgb_info = GST_MAP_INFO_INIT; #endif @@ -268,7 +268,7 @@ gst_fimcconvert_buffer_finalize(GstFimcConvertBuffer *buffer) } } -#ifdef USE_DETECT_JPEG +#ifdef TIZEN_FEATURE_USE_DETECT_JPEG /* free memory for JPEG data */ if (gst_buffer_n_memory(buffer->buffer) > 2) { imgb_memory = gst_buffer_peek_memory(buffer->buffer, 1); @@ -1148,7 +1148,7 @@ gst_fimcconvert_set_imgb_info_for_dst(GstFimcConvert *fimcconvert, GstBuffer *bu GST_DEBUG_OBJECT (fimcconvert, "OutBuf :: y_bo(%p), cb_bo(%p), cr_bo(%p)",imgb->bo[SCMN_Y_PLANE],imgb->bo[SCMN_CB_PLANE],imgb->bo[SCMN_CR_PLANE]); } -#ifdef USE_DETECT_JPEG +#ifdef TIZEN_FEATURE_USE_DETECT_JPEG /* allocation memory and setting for JPEG */ if (fimcconvert->jpeg_data && fimcconvert->jpeg_data_size != 0) { imgb->jpeg_data = malloc((size_t)fimcconvert->jpeg_data_size); @@ -1580,9 +1580,9 @@ gst_fimcconvert_get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *siz gint bytes_per_pixel; gint stride; GstFimcConvert *fimcconvert; - + fimcconvert = GST_FIMCCONVERT(trans); - + structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "width", &width) ||!gst_structure_get_int (structure, "height", &height)) { return FALSE; @@ -1640,7 +1640,7 @@ gst_fimcconvert_get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *siz return TRUE; } -static GstFlowReturn +static GstFlowReturn gst_fimcconvert_prepare_output_buffer(GstBaseTransform *trans, GstBuffer *in_buf, GstBuffer **out_buf) { gboolean ret = TRUE; @@ -1983,7 +1983,7 @@ gst_fimcconvert_drm_prepare_src_buf(GstFimcConvert *fimcconvert, GstBuffer *inbu /* determine buf_share_method_type */ if (!fimcconvert->is_drm_inited) { if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_src_normal_fmt[src_idx].gem_handle, &fimcconvert->gem_info_src_normal_fmt[src_idx].phy_addr)) { -#ifdef USE_TBM +#ifdef TIZEN_FEATURE_USE_TBM fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_TIZEN_BUFFER; GST_WARNING_OBJECT (fimcconvert, "InBuf :: buf_share_method_type = TIZEN_BUFFER"); #else @@ -2386,7 +2386,7 @@ gst_fimcconvert_transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer * GST_WARNING_OBJECT (fimcconvert, "failed to get SCMN_IMGB"); goto SKIP_CONVERTING; } else { -#ifdef USE_DETECT_JPEG +#ifdef TIZEN_FEATURE_USE_DETECT_JPEG /* detect JPEG data */ imgb_memory = gst_buffer_peek_memory(inbuf, 1); gst_memory_map(imgb_memory, &imgb_info, GST_MAP_READ); diff --git a/fimcconvert/src/gstfimcconvert.h b/fimcconvert/src/gstfimcconvert.h index 9d16856..07c81d5 100755 --- a/fimcconvert/src/gstfimcconvert.h +++ b/fimcconvert/src/gstfimcconvert.h @@ -283,8 +283,8 @@ typedef struct /* Dump raw img (src and dst) */ //#define DUMP_IMG -//#define USE_TBM -#define USE_DETECT_JPEG +//#define TIZEN_FEATURE_USE_TBM +#define TIZEN_FEATURE_USE_DETECT_JPEG #define MEM_OP_NONCACHE_NONCONTIG ( TBM_BO_DEFAULT | TBM_BO_NONCACHABLE ) #define MEM_OP_NONCACHE_CONTIG ( TBM_BO_SCANOUT | TBM_BO_NONCACHABLE ) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index c73b558..3d9c0e9 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 26 +Release: 27 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ @@ -55,7 +55,7 @@ GStreamer tizen plugins (common) %build -export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS -DGST_EXT_XV_ENHANCEMENT -DGST_WLSINK_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " +export CFLAGS+=" -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " %if "%{tizen_target_name}" == "TM1" export CFLAGS="$CFLAGS -DTIZEN_PROFILE_LITE" %endif -- 2.7.4 From a6c3d154edc81e384860f7267f156f677a7e4ee9 Mon Sep 17 00:00:00 2001 From: NAMJEONGYOON Date: Thu, 3 Nov 2016 15:06:49 +0900 Subject: [PATCH 04/16] remove evasimagesink Change-Id: Ie5f131cfe5ab3fdc628b92a1259b461cd8d4eb7d --- Makefile.am | 8 - PLUGINS | 1 - configure.ac | 31 - evasimagesink/Makefile.am | 1 - evasimagesink/src/Makefile.am | 26 - evasimagesink/src/gstevasimagesink.c | 2026 ---------------------------------- evasimagesink/src/gstevasimagesink.h | 170 --- packaging/gst-plugins-tizen.spec | 2 - 8 files changed, 2265 deletions(-) delete mode 100644 evasimagesink/Makefile.am delete mode 100644 evasimagesink/src/Makefile.am delete mode 100755 evasimagesink/src/gstevasimagesink.c delete mode 100644 evasimagesink/src/gstevasimagesink.h diff --git a/Makefile.am b/Makefile.am index a0b7a94..d566336 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,10 +9,6 @@ if GST_TIZEN_USE_ENCODEBIN SUBDIRS += encodebin endif -if GST_TIZEN_USE_EVASIMAGESINK -SUBDIRS += evasimagesink -endif - if GST_TIZEN_USE_TOGGLE SUBDIRS += toggle endif @@ -59,10 +55,6 @@ if GST_TIZEN_USE_ENCODEBIN DIST_SUBDIRS += encodebin endif -if GST_TIZEN_USE_EVASIMAGESINK -DIST_SUBDIRS += evasimagesink -endif - if GST_TIZEN_USE_TOGGLE DIST_SUBDIRS += toggle endif diff --git a/PLUGINS b/PLUGINS index 438a7d3..02d69f2 100644 --- a/PLUGINS +++ b/PLUGINS @@ -10,7 +10,6 @@ audioeq audioeq audiotp audiotp drmdecryptor drm_decryptor encodebin encodebin Extension encoder bin plugin -evasimagesink evasimagesink Evas video sink plugin fimcconvert fimcconvert pdpushsrc pdpushsrc Progressive download src plugin tizenipc tizenipcsrc,tizenipcsink diff --git a/configure.ac b/configure.ac index 1111f3f..856019e 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,6 @@ dnl versions of gstreamer and plugins-base GST_MAJORMINOR=1.0 GST_REQUIRED=1.2.0 GSTPB_REQUIRED=1.2.0 -EFL_REQUIRED=1.0.0 dnl fill in your package name and version here dnl the fourth (nano) number should be 0 for a release, 1 for CVS, @@ -171,22 +170,6 @@ AC_SUBST(TBM_LIBS) PKG_CHECK_MODULES(MMCOMMON,mm-common) AC_SUBST(MMCOMMON_CFLAGS) -dnl required package for evasimagesink -PKG_CHECK_MODULES(EFL, [ - evas >= $EFL_REQUIRED - ecore >= $EFL_REQUIRED -], [ - AC_SUBST(EFL_CFLAGS) - AC_SUBST(EFL_LIBS) -], [ - AC_MSG_ERROR([ - You need to install or upgrade the EFL development - packages on your system. On debian-based systems these are - libevas-dev and libecore-dev. - The minimum version required is $EFL_REQUIRED. - ]) -]) - dnl belows are related to wfdtsdemux AG_GST_ARG_WITH_PACKAGE_NAME AG_GST_ARG_WITH_PACKAGE_ORIGIN @@ -212,18 +195,6 @@ AC_ARG_ENABLE(encodebin, AC_HELP_STRING([--enable-encodebin], [using encodebin]) [GST_TIZEN_USE_ENCODEBIN=yes]) AM_CONDITIONAL(GST_TIZEN_USE_ENCODEBIN, test "x$GST_TIZEN_USE_ENCODEBIN" = "xyes") -dnl use evasimagesink -------------------------------------------------------------------------- -AC_ARG_ENABLE(evasimagesink, AC_HELP_STRING([--enable-evasimagesink], [using evasimagesink]), - [ - case "${enableval}" in - yes) GST_TIZEN_USE_EVASIMAGESINK=yes ;; - no) GST_TIZEN_USE_EVASIMAGESINK=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-evasimagesink) ;; - esac - ], - [GST_TIZEN_USE_EVASIMAGESINK=yes]) -AM_CONDITIONAL(GST_TIZEN_USE_EVASIMAGESINK, test "x$GST_TIZEN_USE_EVASIMAGESINK" = "xyes") - dnl use toggle -------------------------------------------------------------------------- AC_ARG_ENABLE(toggle, AC_HELP_STRING([--enable-toggle], [using toggle]), [ @@ -371,8 +342,6 @@ pdpushsrc/Makefile pdpushsrc/src/Makefile encodebin/Makefile encodebin/src/Makefile -evasimagesink/Makefile -evasimagesink/src/Makefile toggle/Makefile toggle/src/Makefile audiotp/Makefile diff --git a/evasimagesink/Makefile.am b/evasimagesink/Makefile.am deleted file mode 100644 index 308a09c..0000000 --- a/evasimagesink/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = src diff --git a/evasimagesink/src/Makefile.am b/evasimagesink/src/Makefile.am deleted file mode 100644 index 239a0c6..0000000 --- a/evasimagesink/src/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# Note: plugindir is set in configure - -############################################################################## -# TODO: change libgstevasimagesink.la to something else, e.g. libmysomething.la # -############################################################################## -plugin_LTLIBRARIES = libgstevasimagesink.la - -############################################################################## -# TODO: for the next set of variables, name the prefix if you named the .la, # -# e.g. libmysomething.la => libmysomething_la_SOURCES # -# libmysomething_la_CFLAGS # -# libmysomething_la_LIBADD # -# libmysomething_la_LDFLAGS # -############################################################################## - -# sources used to compile this plug-in -libgstevasimagesink_la_SOURCES = gstevasimagesink.c gstevasimagesink.h - -# compiler and linker flags used to compile this plugin, set in configure.ac -libgstevasimagesink_la_CFLAGS = $(GST_CFLAGS) $(GST_VIDEO_CFLAGS) $(EFL_CFLAGS) $(TBM_CFLAGS) $(ECORE_X_CFLAGS) -libgstevasimagesink_la_LIBADD = $(GST_LIBS) $(GST_VIDEO_LIBS) $(EFL_LIBS) $(TBM_LIBS) $(ECORE_X_LIBS) -libgstevasimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstevasimagesink_la_LIBTOOLFLAGS = --tag=disable-static - -# headers we need but don't want installed -noinst_HEADERS = gstevasimagesink.h diff --git a/evasimagesink/src/gstevasimagesink.c b/evasimagesink/src/gstevasimagesink.c deleted file mode 100755 index fcab28b..0000000 --- a/evasimagesink/src/gstevasimagesink.c +++ /dev/null @@ -1,2026 +0,0 @@ -/* - * evasimagesink - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Sangchul Lee - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/** - * SECTION:element-evasimagesink - * Gstreamer Evas Video Sink - draw video on the given Evas Image Object - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "gstevasimagesink.h" - -#define CAP_WIDTH "width" -#define CAP_HEIGHT "height" -//#define DUMP_IMG - -GST_DEBUG_CATEGORY_STATIC (gst_evas_image_sink_debug); -#define GST_CAT_DEFAULT gst_evas_image_sink_debug - -/* Enumerations */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_EVAS_OBJECT, - PROP_EVAS_OBJECT_SHOW, -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - PROP_ROTATE_ANGLE, - PROP_DISPLAY_GEOMETRY_METHOD, - PROP_ENABLE_FLUSH_BUFFER, - PROP_FLIP -#endif -}; - -enum -{ - UPDATE_FALSE, - UPDATE_TRUE -}; - -#define COLOR_DEPTH 4 -#define GL_X11_ENGINE "gl_x11" -#define DO_RENDER_FROM_FIMC 1 -#define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar) - -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -#define MAX_ECOREPIPE_BUFFER_CNT 4 -#define DEBUGLOG_DEFAULT_COUNT 8 -#define SIZE_FOR_TBM_SUR_INDEX sizeof(gint) - -/* max channel count *********************************************************/ -#define SCMN_IMGB_MAX_PLANE (4) - -/* image buffer definition *************************************************** - - +------------------------------------------+ --- - | | ^ - | a[], p[] | | - | +---------------------------+ --- | | - | | | ^ | | - | |<---------- w[] ---------->| | | | - | | | | | | - | | | | - | | | h[] | e[] - | | | | - | | | | | | - | | | | | | - | | | v | | - | +---------------------------+ --- | | - | | v - +------------------------------------------+ --- - - |<----------------- s[] ------------------>| -*/ - -typedef struct -{ - /* width of each image plane */ - int w[SCMN_IMGB_MAX_PLANE]; - /* height of each image plane */ - int h[SCMN_IMGB_MAX_PLANE]; - /* stride of each image plane */ - int s[SCMN_IMGB_MAX_PLANE]; - /* elevation of each image plane */ - int e[SCMN_IMGB_MAX_PLANE]; - /* user space address of each image plane */ - void *a[SCMN_IMGB_MAX_PLANE]; - /* physical address of each image plane, if needs */ - void *p[SCMN_IMGB_MAX_PLANE]; - /* color space type of image */ - int cs; - /* left postion, if needs */ - int x; - /* top position, if needs */ - int y; - /* to align memory */ - int __dummy2; - /* arbitrary data */ - int data[16]; - /* dma buf fd */ - int fd[SCMN_IMGB_MAX_PLANE]; - /* buffer share method */ - int buf_share_method; - /* Y plane size in case of ST12 */ - int y_size; - /* UV plane size in case of ST12 */ - int uv_size; - /* Tizen buffer object */ - void *bo[SCMN_IMGB_MAX_PLANE]; - /* JPEG data */ - void *jpeg_data; - /* JPEG size */ - int jpeg_size; - /* TZ memory buffer */ - int tz_enable; -} SCMN_IMGB; -#endif - -#define EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object, x_usr_data ) \ -do \ -{ \ - if (x_evas_image_object) { \ - GST_LOG("object callback add"); \ - evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event, x_usr_data); \ - evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, x_usr_data); \ - } \ -}while(0) - -#define EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object ) \ -do \ -{ \ - if (x_evas_image_object) { \ - GST_LOG("object callback del"); \ - evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event); \ - evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); \ - } \ -}while(0) - -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -#define EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK( x_evas, x_usr_data ) \ -do \ -{ \ - if (x_evas) { \ - GST_DEBUG("callback add... evas_callback_render_pre.. evas : %p esink : %p", x_evas, x_usr_data); \ - evas_event_callback_add (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre, x_usr_data); \ - } \ -}while(0) - -#define EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK( x_evas ) \ -do \ -{ \ - if (x_evas) { \ - GST_DEBUG("callback del... evas_callback_render_pre"); \ - evas_event_callback_del (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre); \ - } \ -}while(0) -#endif - -GMutex *instance_lock; -guint instance_lock_count; - -static inline gboolean -is_evas_image_object (Evas_Object *obj) -{ - const char *type; - if (!obj) { - return FALSE; - } - type = evas_object_type_get (obj); - if (!type) { - return FALSE; - } - if (strcmp (type, "image") == 0) { - return TRUE; - } - return FALSE; -} - -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -gint -gst_evas_image_sink_ref_count (GstBuffer * buf) -{ - return GST_OBJECT_REFCOUNT_VALUE(GST_BUFFER_CAST(buf)); -} -#endif - -/* the capabilities of the inputs. - * - * BGRx format - */ -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, -#ifdef TIZEN_FEATURE_USE_FIMCC - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE("BGRx"))); -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE ("I420") ";" - GST_VIDEO_CAPS_MAKE ("NV12") ";" - GST_VIDEO_CAPS_MAKE ("SN12")) -); -#endif -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "evasimagesink element"); -#define gst_evas_image_sink_parent_class parent_class - -G_DEFINE_TYPE_WITH_CODE (GstEvasImageSink, gst_evas_image_sink, GST_TYPE_VIDEO_SINK, _do_init); - -static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void gst_evas_image_sink_finalize (GObject * object); -static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps); -static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf); -static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event); -static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition); -static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info); -static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static void evas_callback_render_pre (void *data, Evas *e, void *event_info); -static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink); -static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink); -static void _release_flush_buffer(GstEvasImageSink *esink); -static void gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result); -static void gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink); -#endif -#ifdef DUMP_IMG -int util_write_rawdata (const char *file, const void *data, unsigned int size); -int g_cnt = 0; -#endif - -static void -gst_evas_image_sink_finalize (GObject * object) -{ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass) -{ - GObjectClass *gobject_class; - GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *gstvideosink_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstbasesink_class = GST_BASE_SINK_CLASS (klass); - gstvideosink_class = GST_VIDEO_SINK_CLASS (klass); - gstelement_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_evas_image_sink_set_property; - gobject_class->get_property = gst_evas_image_sink_get_property; - gobject_class->finalize = gst_evas_image_sink_finalize; - - g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT, - g_param_spec_pointer ("evas-object", "Destination Evas Object", - "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW, - g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE, - g_param_spec_int("rotate", "Rotate angle", "Rotate angle of display output", DEGREE_0, DEGREE_NUM, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD, - g_param_spec_int("display-geometry-method", "Display geometry method", - "Geometrical method for display", DISP_GEO_METHOD_LETTER_BOX, DISP_GEO_METHOD_NUM, DISP_GEO_METHOD_LETTER_BOX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER, - g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism", - "Enable flush buffer mechanism when state change(PAUSED_TO_READY)", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property(gobject_class, PROP_FLIP, - g_param_spec_int("flip", "Display flip", - "Flip for display", FLIP_NONE, FLIP_NUM, FLIP_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -#endif - gst_element_class_set_static_metadata (gstelement_class, - "EvasImageSink", - "VideoSink", - "Video sink element for evas image object", - "Samsung Electronics "); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sink_factory)); - - gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state); - - gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame); - gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps); - gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event); -} - -static void -gst_evas_image_sink_fini (gpointer data, GObject *obj) -{ - GST_INFO ("[ENTER]"); - - GstEvasImageSink *esink = GST_EVASIMAGESINK (obj); - if (!esink) { - return; - } -#ifdef TIZEN_FEATURE_USE_FIMCC - if (esink->oldbuf) { - gst_buffer_unref (esink->oldbuf); - } -#endif - - if (esink->eo) { -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); - GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); -#endif - EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); - GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); - evas_object_image_data_set(esink->eo, NULL); - } -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - if (esink->display_buffer_lock) { - g_mutex_clear (esink->display_buffer_lock); - g_slice_free (GMutex, esink->display_buffer_lock); - esink->display_buffer_lock = NULL; - } - if (esink->flow_lock) { - g_mutex_clear (esink->flow_lock); - g_slice_free (GMutex, esink->flow_lock); - esink->flow_lock = NULL; - } - esink->eo = NULL; - esink->epipe = NULL; -#endif - g_mutex_lock (instance_lock); - instance_lock_count--; - g_mutex_unlock (instance_lock); - if (instance_lock_count == 0) { - g_mutex_clear (instance_lock); - g_slice_free (GMutex, instance_lock); - instance_lock = NULL; - } - - GST_DEBUG ("[LEAVE]"); -} - -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static void -gst_evas_image_sink_reset (GstEvasImageSink *esink) -{ - int i = 0; - tbm_bo_handle bo_handle; - - GST_DEBUG("gst_evas_image_sink_reset start"); - - g_mutex_lock(esink->display_buffer_lock); - - for(i=0; idisplaying_buffer[i].tbm_surf) - { - tbm_surface_destroy(esink->displaying_buffer[i].tbm_surf); - esink->displaying_buffer[i].tbm_surf = NULL; - } - if(esink->displaying_buffer[i].buffer) - { - if(esink->displaying_buffer[i].ref_count) - { - if(esink->displaying_buffer[i].bo) { - bo_handle = tbm_bo_map(esink->displaying_buffer[i].bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); - if (!bo_handle.ptr) { - GST_WARNING("failed to map bo [%p]", esink->displaying_buffer[i].bo); - } - else - tbm_bo_unmap(esink->displaying_buffer[i].bo); - } - else - GST_WARNING("there is no bo information. so skip to map bo"); - - GST_WARNING("[reset] unreffing gst %p", esink->displaying_buffer[i].buffer); - - while(esink->displaying_buffer[i].ref_count) - { - GST_WARNING("index[%d]'s buffer ref count=%d",i,gst_evas_image_sink_ref_count (esink->displaying_buffer[i].buffer)); - esink->displaying_buffer[i].ref_count--; - gst_buffer_unref(esink->displaying_buffer[i].buffer); - } - } - esink->displaying_buffer[i].buffer = NULL; - } - if(esink->displaying_buffer[i].bo) - esink->displaying_buffer[i].bo = NULL; - } - esink->prev_buf = NULL; - esink->prev_index = -1; - esink->cur_index = -1; - - esink->eo_size.x = esink->eo_size.y = - esink->eo_size.w = esink->eo_size.h = 0; - esink->use_ratio = FALSE; - esink->sent_buffer_cnt = 0; - - g_mutex_unlock(esink->display_buffer_lock); -} -#endif - -#ifdef TIZEN_FEATURE_USE_FIMCC -static void -evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte) -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static void -evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) -#endif -{ - GstEvasImageSink *esink = data; -#ifdef TIZEN_FEATURE_USE_FIMCC - GstBuffer *buf; - GstMapInfo buf_info = GST_MAP_INFO_INIT; - void *img_data; -#endif - GST_DEBUG ("[ENTER]"); - if (!esink || !esink->eo) { - GST_WARNING ("esink : %p, or eo is NULL returning", esink); - return; - } - GST_LOG("esink : %p, esink->eo : %p", esink, esink->eo); - if (nbyte == SIZE_FOR_UPDATE_VISIBILITY) { - if(!esink->object_show) { - evas_object_hide(esink->eo); - GST_INFO ("object hide.."); - } else { - evas_object_show(esink->eo); - GST_INFO ("object show.."); - } - GST_DEBUG ("[LEAVE]"); - return; - } -#ifdef TIZEN_FEATURE_USE_FIMCC - if (!buffer || nbyte != sizeof (GstBuffer *)) { - GST_WARNING ("buffer %p, nbyte : %d, sizeof(GstBuffer *) : %d", buffer, nbyte, sizeof (GstBuffer *)); - return; - } -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - int index = 0; - index = *buffer_index; - if ((index<0 || index>=TBM_SURFACE_NUM) || nbyte != SIZE_FOR_TBM_SUR_INDEX) { - GST_WARNING ("index : %d, nbyte : %d", index, nbyte); - return; - } -#endif - if (GST_STATE(esink) < GST_STATE_PAUSED) { - GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink)); - return; - } - -#ifdef TIZEN_FEATURE_USE_FIMCC - memcpy (&buf, buffer, sizeof (GstBuffer *)); - if (!buf) { - GST_ERROR ("There is no buffer"); - return; - } - if (esink->present_data_addr == -1) { - /* if present_data_addr is -1, we don't use this member variable */ - } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) { - GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC); - return; - } -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - g_mutex_lock(esink->display_buffer_lock); - if(esink->tbm_surface_format == TBM_FORMAT_NV12) { - if (!esink->displaying_buffer[index].tbm_surf) { - GST_ERROR("the index's nbuffer was already NULL, so return"); - g_mutex_unlock(esink->display_buffer_lock); - return; - } - GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index); - } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { - GST_LOG("received (bo %p) index num : %d", esink->displaying_buffer[index].bo, index); - } - - Evas_Native_Surface surf; - surf.type = EVAS_NATIVE_SURFACE_TBM; - surf.version = EVAS_NATIVE_SURFACE_VERSION; - surf.data.tizen.buffer = esink->displaying_buffer[index].tbm_surf; - surf.data.tizen.rot = esink->rotate_angle; - surf.data.tizen.flip = esink->flip; - - GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index); - - GstVideoRectangle result = {0}; - - evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); - if (!esink->eo_size.w || !esink->eo_size.h) { - GST_ERROR ("there is no information for evas object size"); - g_mutex_unlock(esink->display_buffer_lock); - return; - } - gst_evas_image_sink_update_geometry(esink, &result); - if(!result.w || !result.h) - { - GST_ERROR("no information about geometry (%d, %d)", result.w, result.h); - g_mutex_unlock(esink->display_buffer_lock); - return; - } - - if(esink->use_ratio) - { - surf.data.tizen.ratio = (float) esink->w / esink->h; - GST_LOG("set ratio for letter mode"); - } - evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { - evas_object_image_size_set(esink->eo, esink->w, esink->h); - esink->is_evas_object_size_set = TRUE; - } -#ifdef DUMP_IMG - int ret = 0; - char file_name[128]; - GST_INFO("[DUMP]"); - if(g_cnt<20) - { - sprintf(file_name, "DUMP_IMG_%2.2d.dump", g_cnt); - char *dump_data; - tbm_bo_handle vaddr_dump; - guint size = esink->w*esink->h + (esink->w/2*esink->h/2)*2; //this size is for I420 format - GST_WARNING ("DUMP IMG_%2.2d : buffer size(%d)", g_cnt, size); - dump_data = g_malloc(size); - vaddr_dump = tbm_bo_get_handle(esink->displaying_buffer[index].bo, TBM_DEVICE_CPU); - if (vaddr_dump.ptr) { - tbm_bo_unmap(esink->displaying_buffer[index].bo); - } - memcpy (dump_data, vaddr_dump.ptr, size); - ret = util_write_rawdata(file_name, dump_data, size); - if (ret) { - GST_ERROR_OBJECT (esink, "util_write_rawdata() failed"); - } else - g_cnt++; - g_free(dump_data); - } -#endif - evas_object_image_native_surface_set(esink->eo, &surf); - GST_DEBUG("native surface set finish"); - - if(result.x || result.y) - GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); - evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); - - evas_object_image_pixels_dirty_set(esink->eo, EINA_TRUE); - GST_DEBUG_OBJECT (esink, "GEO_METHOD : src(%dx%d), dst(%dx%d), dst_x(%d), dst_y(%d), rotate(%d), flip(%d)", - esink->w, esink->h, esink->eo_size.w, esink->eo_size.h, esink->eo_size.x, esink->eo_size.y, esink->rotate_angle, esink->flip); - - /* unref previous buffer */ - if(esink->tbm_surface_format == TBM_FORMAT_NV12) { - if(esink->prev_buf && esink->displaying_buffer[esink->prev_index].ref_count) - { - GST_DEBUG("before index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf); - esink->displaying_buffer[esink->prev_index].ref_count--; - GST_DEBUG("after index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf); - /* Print debug log for 8 frame */ - if(esink->debuglog_cnt_ecoreCbPipe > 0) - { - GST_WARNING("(%d) ecore_cb_pipe unref index[%d] .. gst_buf %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), esink->prev_index, esink->prev_buf); - esink->debuglog_cnt_ecoreCbPipe--; - } - if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT) - GST_WARNING("sent buffer cnt 4->3 so skip will be stop"); - - esink->sent_buffer_cnt--; - GST_DEBUG("prev gst_buffer %p's unref Start!!", esink->prev_buf); - gst_buffer_unref(esink->prev_buf); - GST_DEBUG("prev gst_buffer %p's unref End!!", esink->prev_buf); - } else { - GST_DEBUG("ref_count=%d unref prev gst_buffer %p", esink->displaying_buffer[esink->prev_index].ref_count,esink->prev_buf); - } - - GST_DEBUG("Current gst_buf %p and index=%d is overwrited to Prev gst_buf %p & index %d", - esink->displaying_buffer[index].buffer, index, esink->prev_buf, esink->prev_index ); - esink->prev_buf = esink->displaying_buffer[index].buffer; - esink->prev_index = index; - }else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { - /* Print debug log for 8 frame */ - if(esink->debuglog_cnt_ecoreCbPipe > 0) - { - GST_WARNING("(%d) ecore_cb_pipe set index [%d] tbm_surf[%p]", - DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), index, esink->displaying_buffer[index].tbm_surf); - esink->debuglog_cnt_ecoreCbPipe--; - } - if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT) - GST_WARNING("sent buffer cnt 4->3 so skip will be stop"); - - esink->sent_buffer_cnt--; - } -#endif -#ifdef TIZEN_FEATURE_USE_FIMCC - if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { - evas_object_image_size_set (esink->eo, esink->w, esink->h); - GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)", esink->w, esink->h); - esink->is_evas_object_size_set = TRUE; - } - if (esink->gl_zerocopy) { - img_data = evas_object_image_data_get (esink->eo, EINA_TRUE); - gst_buffer_map(buf, &buf_info, GST_MAP_READ); - if (!img_data || !buf_info.data) { - GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data"); - evas_object_image_data_set(esink->eo, img_data); - } else { - GST_DEBUG ("img_data(%p), buf_info.data:%p, esink->w(%d),esink->h(%d), esink->eo(%p)",img_data,buf_info.data,esink->w,esink->h,esink->eo); - memcpy (img_data, buf_info.data, esink->w * esink->h * COLOR_DEPTH); - evas_object_image_pixels_dirty_set (esink->eo, 1); - evas_object_image_data_set(esink->eo, img_data); - } - gst_buffer_unmap(buf, &buf_info); - gst_buffer_unref (buf); - } else { - gst_buffer_map(buf, &buf_info, GST_MAP_READ); - GST_DEBUG ("buf_info.data(buf):%p, esink->eo(%p)",buf_info.data,esink->eo); - evas_object_image_data_set (esink->eo, buf_info.data); - gst_buffer_unmap(buf, &buf_info); - evas_object_image_pixels_dirty_set (esink->eo, 1); - if (esink->oldbuf) { - gst_buffer_unref(esink->oldbuf); - } - esink->oldbuf = buf; - } -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - g_mutex_unlock(esink->display_buffer_lock); -#endif - GST_DEBUG ("[LEAVE]"); -} -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static void -gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result) -{ - if (!esink || !esink->eo) { - GST_WARNING("there is no esink"); - return; - } - - result->x = 0; - result->y = 0; - - switch (esink->display_geometry_method) - { - case DISP_GEO_METHOD_LETTER_BOX: // 0 - /* set black padding for letter box mode */ - GST_DEBUG("letter box mode"); - esink->use_ratio = TRUE; - result->w = esink->eo_size.w; - result->h = esink->eo_size.h; - break; - case DISP_GEO_METHOD_ORIGIN_SIZE: // 1 - GST_DEBUG("origin size mode"); - esink->use_ratio = FALSE; - /* set coordinate for each case */ - result->x = (esink->eo_size.w-esink->w) / 2; - result->y = (esink->eo_size.h-esink->h) / 2; - result->w = esink->w; - result->h = esink->h; - break; - case DISP_GEO_METHOD_FULL_SCREEN: // 2 - GST_DEBUG("full screen mode"); - esink->use_ratio = FALSE; - result->w = esink->eo_size.w; - result->h = esink->eo_size.h; - break; - case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: // 3 - GST_DEBUG("cropped full screen mode"); - esink->use_ratio = FALSE; - /* compare evas object's ratio with video's */ - if((esink->eo_size.w/esink->eo_size.h) > (esink->w/esink->h)) - { - result->w = esink->eo_size.w; - result->h = esink->eo_size.w * esink->h / esink->w; - result->y = -(result->h-esink->eo_size.h) / 2; - } - else - { - result->w = esink->eo_size.h * esink->w / esink->h; - result->h = esink->eo_size.h; - result->x = -(result->w-esink->eo_size.w) / 2; - } - break; - case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: // 4 - GST_DEBUG("origin size or letter box mode"); - /* if video size is smaller than evas object's, it will be set to origin size mode */ - if((esink->eo_size.w > esink->w) && (esink->eo_size.h > esink->h)) - { - GST_DEBUG("origin size mode"); - esink->use_ratio = FALSE; - /* set coordinate for each case */ - result->x = (esink->eo_size.w-esink->w) / 2; - result->y = (esink->eo_size.h-esink->h) / 2; - result->w = esink->w; - result->h = esink->h; - } - else - { - GST_DEBUG("letter box mode"); - esink->use_ratio = TRUE; - result->w = esink->eo_size.w; - result->h = esink->eo_size.h; - } - break; - default: - GST_WARNING("unsupported mode."); - break; - } - GST_DEBUG("geometry result [%d, %d, %d, %d]", result->x, result->y, result->w, result->h); -} -static void -gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink) -{ - if (!esink || !esink->eo) { - GST_WARNING("there is no esink"); - return; - } - - Evas_Native_Surface *surf = evas_object_image_native_surface_get(esink->eo); - GstVideoRectangle result = {0}; - - if(surf) - { - GST_DEBUG("native surface exists"); - surf->data.tizen.rot = esink->rotate_angle; - surf->data.tizen.flip = esink->flip; - evas_object_image_native_surface_set(esink->eo, surf); - - gst_evas_image_sink_update_geometry(esink, &result); - - if(esink->use_ratio) - { - surf->data.tizen.ratio = (float) esink->w / esink->h; - GST_LOG("set ratio for letter mode"); - } - - if(result.x || result.y) - GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); - - evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); - } - else - GST_WARNING("there is no surf"); -} -#endif - -static void -gst_evas_image_sink_init (GstEvasImageSink *esink) -{ - GST_INFO ("[ENTER]"); - - esink->eo = NULL; - esink->epipe = NULL; - esink->object_show = FALSE; - esink->update_visibility = UPDATE_FALSE; - esink->is_evas_object_size_set = FALSE; -#ifdef TIZEN_FEATURE_USE_FIMCC - esink->gl_zerocopy = FALSE; - esink->present_data_addr = -1; -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - esink->display_buffer_lock = g_slice_new (GMutex); - esink->flow_lock = g_slice_new (GMutex); - g_mutex_init (esink->display_buffer_lock); - g_mutex_init (esink->flow_lock); - int i = 0; - for (i=0; idisplaying_buffer[i].tbm_surf = NULL; - esink->displaying_buffer[i].buffer = NULL; - esink->displaying_buffer[i].bo = NULL; - esink->displaying_buffer[i].ref_count = 0; - } - esink->prev_buf = NULL; - esink->prev_index = -1; - esink->cur_index = -1; - esink->enable_flush_buffer = TRUE; - esink->need_flush = FALSE; - esink->display_geometry_method = DISP_GEO_METHOD_LETTER_BOX; - esink->flip = FLIP_NONE; - esink->eo_size.x = esink->eo_size.y = - esink->eo_size.w = esink->eo_size.h = 0; - esink->use_ratio = FALSE; - esink->sent_buffer_cnt = 0; - esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT; - esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT; - - esink->src_buf_idx = 0; - esink->is_buffer_allocated = FALSE; -#endif - if(!instance_lock) { - instance_lock = g_slice_new (GMutex); - g_mutex_init(instance_lock); - } - g_mutex_lock (instance_lock); - instance_lock_count++; - g_mutex_unlock (instance_lock); - - g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL); - - GST_DEBUG ("[LEAVE]"); -} - -static void -evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - GST_INFO ("enter"); - - GstEvasImageSink *esink = data; - if (!esink) { - return; - } -#ifdef TIZEN_FEATURE_USE_FIMCC - if (esink->oldbuf) { - gst_buffer_unref (esink->oldbuf); - esink->oldbuf = NULL; - } -#endif - if (esink->eo) { -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); - GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); -#endif - EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); - GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %p", esink, esink->eo); - - evas_object_image_data_set(esink->eo, NULL); - esink->eo = NULL; - } - GST_DEBUG ("[LEAVE]"); -} - -static void -evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - int x, y, w, h; - x = y = w = h = 0; - - GST_DEBUG ("[ENTER]"); - - GstEvasImageSink *esink = data; - if (!esink || !esink->eo) { - return; - } - - evas_object_geometry_get(esink->eo, &x, &y, &w, &h); - if (!w || !h) { - GST_WARNING ("evas object size (w:%d,h:%d) was not set", w, h); - } else { -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - esink->eo_size.x = x; - esink->eo_size.y = y; - esink->eo_size.w = w; - esink->eo_size.h = h; - GST_WARNING ("resize (x:%d, y:%d, w:%d, h:%d)", x, y, w, h); - gst_evas_image_sink_apply_geometry(esink); -#endif -#ifdef TIZEN_FEATURE_USE_FIMCC - evas_object_image_fill_set(esink->eo, 0, 0, w, h); - GST_DEBUG ("evas object fill set (w:%d,h:%d)", w, h); -#endif - } - GST_DEBUG ("[LEAVE]"); -} -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static void -evas_callback_render_pre (void *data, Evas *e, void *event_info) -{ - GstEvasImageSink *esink = data; - if (!esink || !esink->eo) { - GST_WARNING("there is no esink info.... esink : %p, or eo is NULL returning", esink); - return; - } - if(esink->need_flush && esink->flush_buffer) - { - g_mutex_lock(esink->display_buffer_lock); - Evas_Native_Surface surf; - GstVideoRectangle result = {0}; - - evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); - if (!esink->eo_size.w || !esink->eo_size.h) { - GST_ERROR ("there is no information for evas object size"); - return; - } - gst_evas_image_sink_update_geometry(esink, &result); - if(!result.w || !result.h) - { - GST_ERROR("no information about geometry (%d, %d)", result.w, result.h); - return; - } - - if(esink->use_ratio) - { - surf.data.tizen.ratio = (float) esink->w / esink->h; - GST_LOG("set ratio for letter mode"); - } - evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { - evas_object_image_size_set(esink->eo, esink->w, esink->h); - esink->is_evas_object_size_set = TRUE; - } - - if(result.x || result.y) - GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); - - evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); - - surf.type = EVAS_NATIVE_SURFACE_TBM; - surf.version = EVAS_NATIVE_SURFACE_VERSION; - surf.data.tizen.buffer = esink->flush_buffer->tbm_surf; - surf.data.tizen.rot = esink->rotate_angle; - surf.data.tizen.flip = esink->flip; - GST_DEBUG("use esink->flush buffer->tbm_surf (%p), rotate(%d), flip(%d)", - esink->flush_buffer->tbm_surf, esink->rotate_angle, esink->flip); - evas_object_image_native_surface_set(esink->eo, &surf); - g_mutex_unlock(esink->display_buffer_lock); - esink->need_flush = FALSE; - } - evas_object_image_pixels_dirty_set (esink->eo, EINA_TRUE); - GST_LOG("dirty set finish"); -} - -static gboolean -gst_evas_image_sink_release_source_buffer(GstEvasImageSink *esink) -{ - int i = 0; - tbm_bo_handle bo_handle; - g_mutex_lock(esink->display_buffer_lock); - - for(i = 0; i < TBM_SURFACE_NUM; i++) { - GST_WARNING("[reset] reset gst %p", esink->displaying_buffer[i].buffer); - esink->displaying_buffer[i].bo = NULL; - esink->displaying_buffer[i].tbm_surf = NULL; - esink->displaying_buffer[i].ref_count = 0; - } - - for(i = 0; i < SOURCE_BUFFER_NUM; i++) { - if(esink->src_buffer_info[i].bo) { - tbm_bo_unmap(esink->src_buffer_info[i].bo); - esink->src_buffer_info[i].bo = NULL; - } - - if (esink->src_buffer_info[i].tbm_surf) { - tbm_surface_destroy(esink->src_buffer_info[i].tbm_surf); - esink->src_buffer_info[i].tbm_surf = NULL; - } - } - - esink->is_buffer_allocated = FALSE; - esink->src_buf_idx = 0; - esink->prev_buf = NULL; - esink->prev_index = -1; - esink->cur_index = -1; - - esink->eo_size.x = esink->eo_size.y = - esink->eo_size.w = esink->eo_size.h = 0; - esink->use_ratio = FALSE; - esink->sent_buffer_cnt = 0; - - g_mutex_unlock(esink->display_buffer_lock); - - return TRUE; -} - -static gboolean -gst_evas_image_sink_allocate_source_buffer(GstEvasImageSink *esink) -{ - int size = 0; - int idx = 0; - tbm_bo bo; - tbm_bo_handle vaddr; - GstFlowReturn ret=GST_FLOW_OK; - - if (esink == NULL) { - GST_ERROR("handle is NULL"); - return FALSE; - } - - for(idx=0; idx < SOURCE_BUFFER_NUM; idx++) { - if(!esink->src_buffer_info[idx].tbm_surf) { - /* create tbm surface */ - esink->src_buffer_info[idx].tbm_surf = tbm_surface_create(esink->w, esink->h, esink->tbm_surface_format); - } - if(!esink->src_buffer_info[idx].tbm_surf) - { - GST_ERROR("tbm_surf is NULL!!"); - goto ALLOC_FAILED; - } - - /* get bo and size */ - bo = tbm_surface_internal_get_bo(esink->src_buffer_info[idx].tbm_surf, 0); - size = tbm_bo_size(bo); - if(!bo || !size) - { - GST_ERROR("bo(%p), size(%d)", bo, size); - goto ALLOC_FAILED; - } - esink->src_buffer_info[idx].bo = bo; - - vaddr = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); - if (!vaddr.ptr) { - GST_WARNING_OBJECT(esink, "get vaddr failed pointer = %p", vaddr.ptr); - tbm_bo_unmap(bo); - goto ALLOC_FAILED; - } else { - memset (vaddr.ptr, 0x0, size); - GST_LOG_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr.ptr); - } - - esink->src_buffer_info[idx].usr_addr = vaddr.ptr; - - GST_WARNING_OBJECT(esink, "src buffer index:%d , tbm surface : %p", idx, esink->src_buffer_info[idx].tbm_surf); - } - - return TRUE; - -ALLOC_FAILED: - gst_evas_image_sink_release_source_buffer(esink); - return FALSE; -} -#endif - -static int -evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h) -{ - gboolean r; - int width, height; - GstStructure *s; - - if (!caps || !w || !h) { - return -1; - } - s = gst_caps_get_structure (caps, 0); - if (!s) { - return -1; - } - - r = gst_structure_get_int (s, CAP_WIDTH, &width); - if (r == FALSE) { - GST_DEBUG("fail to get width from caps"); - return -1; - } - - r = gst_structure_get_int (s, CAP_HEIGHT, &height); - if (r == FALSE) { - GST_DEBUG("fail to get height from caps"); - return -1; - } - - *w = width; - *h = height; - GST_DEBUG ("size w(%d), h(%d)", width, height); - - return 0; -} -#ifdef TIZEN_FEATURE_USE_FIMCC -static gboolean -is_zerocopy_supported (Evas *e) -{ - Eina_List *engines, *l; - int cur_id; - int id; - char *name; - - if (!e) { - return FALSE; - } - - engines = evas_render_method_list (); - if (!engines) { - return FALSE; - } - - cur_id = evas_output_method_get (e); - - EINA_LIST_FOREACH (engines, l, name) { - id = evas_render_method_lookup (name); - if (name && id == cur_id) { - if (!strcmp (name, GL_X11_ENGINE)) { - return TRUE; - } - break; - } - } - return FALSE; -} - -static int -evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event) -{ - const GstStructure *st; - guint st_data_addr = 0; - - g_return_val_if_fail (event != NULL, FALSE); - g_return_val_if_fail (esink != NULL, FALSE); - - if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) { - GST_WARNING ("it's not a custom downstream oob event"); - return -1; - } - st = gst_event_get_structure (event); - if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) { - GST_WARNING ("structure in a given event is not proper"); - return -1; - } - if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) { - GST_WARNING ("parsing data-addr failed"); - return -1; - } - esink->present_data_addr = st_data_addr; - - return 0; -} -#endif -static gboolean -gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event) -{ -#ifdef TIZEN_FEATURE_USE_FIMCC - GstEvasImageSink *esink = GST_EVASIMAGESINK (sink); -#endif - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - GST_DEBUG ("GST_EVENT_FLUSH_START"); - break; - case GST_EVENT_FLUSH_STOP: - GST_DEBUG ("GST_EVENT_FLUSH_STOP"); - break; - case GST_EVENT_EOS: - GST_DEBUG ("GST_EVENT_EOS"); - break; -#ifdef TIZEN_FEATURE_USE_FIMCC - case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: - if(!evas_image_sink_event_parse_data(esink, event)) { - GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr); - } else { - GST_ERROR ("evas_image_sink_event_parse_data() failed"); - } - break; -#endif - default: - break; - } - if (GST_BASE_SINK_CLASS (gst_evas_image_sink_parent_class)->event) { - return GST_BASE_SINK_CLASS (gst_evas_image_sink_parent_class)->event (sink, event); - } else { - return TRUE; - } -} - -static GstStateChangeReturn -gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition) -{ - GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS; - GstEvasImageSink *esink = NULL; -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - GstFlowReturn ret=GST_FLOW_OK; -#endif - esink = GST_EVASIMAGESINK(element); - - if(!esink) { - GST_ERROR("can not get evasimagesink from element"); - return GST_STATE_CHANGE_FAILURE; - } - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - GST_WARNING ("*** STATE_CHANGE_NULL_TO_READY ***"); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - g_mutex_lock (esink->flow_lock); - if (!is_evas_image_object (esink->eo)) { - GST_ERROR_OBJECT (esink, "There is no evas image object.."); - g_mutex_unlock (esink->flow_lock); - return GST_STATE_CHANGE_FAILURE; - } - g_mutex_unlock (esink->flow_lock); -#endif - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_WARNING ("*** STATE_CHANGE_READY_TO_PAUSED ***"); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - /* Print debug log for 8 frame */ - esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT; - esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT; -#endif - GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***"); - break; - default: - break; - } - - ret_state = GST_ELEMENT_CLASS (gst_evas_image_sink_parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - GST_WARNING ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***"); - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_READY ***"); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - Eina_Bool r; - /* flush buffer, we will copy last buffer to keep image data and reset buffer list */ - GST_WARNING("esink->enable_flush_buffer : %d", esink->enable_flush_buffer); - if(esink->enable_flush_buffer && esink->tbm_surface_format == TBM_FORMAT_NV12) - { - if (gst_esink_make_flush_buffer(esink) == FALSE) { - ret = gst_esink_epipe_reset(esink); - if(ret) { - GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); - return GST_STATE_CHANGE_FAILURE; - } - gst_evas_image_sink_reset(esink); - } - } - else { - ret = gst_esink_epipe_reset(esink); - if(ret) { - GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); - return GST_STATE_CHANGE_FAILURE; - } - if(esink->tbm_surface_format == TBM_FORMAT_NV12) { - gst_evas_image_sink_reset(esink); - } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { - gst_evas_image_sink_release_source_buffer(esink); - } - } -#endif - break; - case GST_STATE_CHANGE_READY_TO_NULL: - GST_WARNING ("*** STATE_CHANGE_READY_TO_NULL ***"); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - if(esink->flush_buffer) - _release_flush_buffer(esink); - EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); -#endif - EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); - if (esink->epipe) { - GST_DEBUG("ecore-pipe will delete"); - ecore_pipe_del (esink->epipe); - esink->epipe = NULL; - } - break; - default: - break; - } - - return ret_state; -} - -static void -gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - GstEvasImageSink *esink = GST_EVASIMAGESINK (object); - Evas_Object *eo; - - g_mutex_lock (instance_lock); - - switch (prop_id) { - case PROP_EVAS_OBJECT: - eo = g_value_get_pointer (value); - if (is_evas_image_object (eo)) { - if (eo != esink->eo) { - Eina_Bool r; -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); -#endif - /* delete evas object callbacks registrated on a previous evas image object */ - EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); - esink->eo = eo; - - /* add evas object callbacks on a new evas image object */ - EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - GST_WARNING("register render callback [esink : %p, esink->eo : %p]", esink, esink->eo); - EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo), esink); - evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); - GST_WARNING ("evas object size (x:%d, y:%d, w:%d, h:%d)", esink->eo_size.x, esink->eo_size.y, esink->eo_size.w, esink->eo_size.h); -#endif -#ifdef TIZEN_FEATURE_USE_FIMCC - esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo)); - if (esink->gl_zerocopy) { - evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); - GST_DEBUG("Enable gl zerocopy"); - } -#endif - GST_DEBUG("Evas Image Object(%p) is set", esink->eo); - esink->is_evas_object_size_set = FALSE; - esink->object_show = TRUE; - esink->update_visibility = UPDATE_TRUE; - if (esink->epipe) { - r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY); - if (r == EINA_FALSE) { - GST_WARNING ("Failed to ecore_pipe_write() for updating visibility\n"); - } - } - } - } else { - GST_ERROR ("Cannot set evas-object property: value is not an evas image object"); - } - break; - - case PROP_EVAS_OBJECT_SHOW: - { - Eina_Bool r; - esink->object_show = g_value_get_boolean (value); - if( !is_evas_image_object(esink->eo) ) { - GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n"); - break; - } - esink->update_visibility = UPDATE_TRUE; - GST_LOG("esink->update_visibility : %d", esink->update_visibility); - if (esink->epipe) { - r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY); - if (r == EINA_FALSE) { - GST_WARNING ("Failed to ecore_pipe_write() for updating visibility)\n"); - } - } - break; - } -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - case PROP_ROTATE_ANGLE: - { - int rotate = 0; - rotate = g_value_get_int (value); - switch(rotate) - { - case DEGREE_0: - esink->rotate_angle = 0; - break; - case DEGREE_90: - esink->rotate_angle = 90; - break; - case DEGREE_180: - esink->rotate_angle = 180; - break; - case DEGREE_270: - esink->rotate_angle = 270; - break; - default: - break; - } - GST_INFO("update rotate_angle : %d", esink->rotate_angle); - break; - } - case PROP_DISPLAY_GEOMETRY_METHOD: - { - Eina_Bool r; - guint geometry = g_value_get_int (value); - if (esink->display_geometry_method != geometry) { - esink->display_geometry_method = geometry; - GST_INFO_OBJECT (esink, "Overlay geometry method update, display_geometry_method(%d)", esink->display_geometry_method); - } - - g_mutex_lock(esink->display_buffer_lock); - - if(esink->cur_index!=-1 && esink->epipe) - { - GST_WARNING("apply property esink->cur_index =%d",esink->cur_index); - esink->displaying_buffer[esink->cur_index].ref_count++; - gst_buffer_ref(esink->displaying_buffer[esink->cur_index].buffer); - esink->sent_buffer_cnt++; - r = ecore_pipe_write (esink->epipe, &esink->cur_index, SIZE_FOR_TBM_SUR_INDEX); - - if (r == EINA_FALSE) { - GST_WARNING("ecore_pipe_write fail"); - esink->displaying_buffer[esink->cur_index].ref_count--; - gst_buffer_unref(esink->displaying_buffer[esink->cur_index].buffer); - esink->sent_buffer_cnt--; - } - } - g_mutex_unlock(esink->display_buffer_lock); - break; - } - case PROP_ENABLE_FLUSH_BUFFER: - esink->enable_flush_buffer = g_value_get_boolean(value); - break; - case PROP_FLIP: - { - esink->flip = g_value_get_int(value); - GST_INFO("update flip : %d", esink->flip); - break; - } -#endif - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - g_mutex_unlock (instance_lock); -} - -static void -gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - GstEvasImageSink *esink = GST_EVASIMAGESINK (object); - - switch (prop_id) { - case PROP_EVAS_OBJECT: - g_value_set_pointer (value, esink->eo); - break; - case PROP_EVAS_OBJECT_SHOW: - g_value_set_boolean (value, esink->object_show); - break; -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - case PROP_ROTATE_ANGLE: - g_value_set_int (value, esink->rotate_angle); - break; - case PROP_DISPLAY_GEOMETRY_METHOD: - g_value_set_int (value, esink->display_geometry_method); - break; - case PROP_ENABLE_FLUSH_BUFFER: - g_value_set_boolean(value, esink->enable_flush_buffer); - break; - case PROP_FLIP: - g_value_set_int(value, esink->flip); - break; -#endif - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps) -{ - int r; - int w, h; - GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink); - GstStructure *structure = NULL; - const gchar *format = NULL; - - esink->is_evas_object_size_set = FALSE; - r = evas_image_sink_get_size_from_caps (caps, &w, &h); - if (!r) { - esink->w = w; - esink->h = h; - GST_DEBUG ("set size w(%d), h(%d)", w, h); - } - - structure = gst_caps_get_structure (caps, 0); - if (!structure) { - return FALSE; - } - - if ((format = gst_structure_get_string (structure, "format"))) { - - GST_DEBUG ("format(dst) is not set...it may be rgb series"); - } - - GST_DEBUG_OBJECT(esink, "source color format is %s", format); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - if (!strcmp (format, "SN12") || !strcmp (format, "NV12")) - esink->tbm_surface_format = TBM_FORMAT_NV12; - else if (!strcmp (format, "I420")) - esink->tbm_surface_format = TBM_FORMAT_YUV420; - else { - GST_ERROR("cannot parse fourcc format from caps."); - return FALSE; - } -#endif - - return TRUE; -} - -static GstFlowReturn -gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) -{ - GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink); - Eina_Bool r; - GstMapInfo buf_info = GST_MAP_INFO_INIT; - - GST_LOG("[ENTER] show frame"); -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - if (!gst_evas_image_sink_ref_count (buf)) - { - GST_WARNING("ref count is 0.. skip show frame"); - return GST_FLOW_OK; - } -#endif - g_mutex_lock (instance_lock); -#ifdef TIZEN_FEATURE_USE_FIMCC - if (esink->present_data_addr == -1) { - /* if present_data_addr is -1, we don't use this member variable */ - } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) { - GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", - esink->present_data_addr, DO_RENDER_FROM_FIMC); - g_mutex_unlock (instance_lock); - return GST_FLOW_OK; - } -#endif - if (!esink->epipe) { - esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink); - if (!esink->epipe) { - GST_ERROR ("ecore-pipe create failed"); - g_mutex_unlock (instance_lock); - return GST_FLOW_ERROR; - } else { - /* If PROP_EVAS_OBJECT_SHOW is set before the first frame, - * evas_object_show() is not called - * Because the first freme is not recieved, ecore pipe is not created. - */ - if(esink->object_show && esink->eo) - evas_object_show(esink->eo); - } - GST_DEBUG("ecore-pipe create success"); - } -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - int i = 0; - int index = -1; - SCMN_IMGB *scmn_imgb = NULL; - gboolean exist_bo = FALSE; - gst_buffer_map(buf, &buf_info, GST_MAP_READ); - - GST_LOG ("BUF: gst_buf= %p dts= %" GST_TIME_FORMAT " pts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p", - buf, GST_TIME_ARGS(GST_BUFFER_DTS (buf)), GST_TIME_ARGS(GST_BUFFER_PTS (buf)), buf_info.size, buf_info.memory); - - if(esink->tbm_surface_format == TBM_FORMAT_NV12) { - /* get received buffer informations */ - scmn_imgb = (SCMN_IMGB *)buf_info.memory; - if (!scmn_imgb) { - GST_WARNING("scmn_imgb is NULL. Skip..." ); - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - return GST_FLOW_OK; - } - if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) - { - /* check whether bo is new or not */ - for(i=0; idisplaying_buffer[i].bo==scmn_imgb->bo[0]) - { - GST_DEBUG("it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i); - index = i; - exist_bo = TRUE; - break; - } - else - exist_bo = FALSE; - } - /* keep bo */ - if(!exist_bo) - { - /* find empty buffer space for indexing */ - for(i=0; idisplaying_buffer[i].bo) - { - index = i; - break; - } - } - if(index!=-1) - { - /* keep informations */ - esink->displaying_buffer[index].buffer = buf; - esink->displaying_buffer[index].bo = scmn_imgb->bo[0]; - GST_WARNING("TBM bo %p / gst_buf %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); - - /* create new tbm surface */ - esink->displaying_buffer[index].tbm_surf = tbm_surface_internal_create_with_bos(esink->w, esink->h, - TBM_FORMAT_NV12, esink->displaying_buffer[index].bo, TBM_BO_DEFAULT); - if(!esink->displaying_buffer[index].tbm_surf) - { - GST_WARNING("there is no tbm surface.. bo : %p, gst_buf : %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - return GST_FLOW_OK; - } - - GST_WARNING("create tbm surface : %p", esink->displaying_buffer[index].tbm_surf); - } - } - /* because it has same bo, use existing tbm surface */ - else - { - if(index!=-1) - { - esink->displaying_buffer[index].buffer = buf; - GST_DEBUG("existing tbm surface %p.. bo %p, gst_buf %p", esink->displaying_buffer[index].tbm_surf, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); - exist_bo = FALSE; - } - } - - /* if it couldn't find proper index */ - if(index == -1) - GST_WARNING("all spaces are using!!!"); - else - GST_DEBUG("selected buffer index %d", index); - - } - else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) - { - /* flush buffer, we will copy last buffer to keep image data and reset buffer list */ - GST_WARNING_OBJECT(esink, "FLUSH_BUFFER: gst_buf= %p dts= %" GST_TIME_FORMAT " pts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p", - buf, GST_TIME_ARGS(GST_BUFFER_DTS (buf)), GST_TIME_ARGS(GST_BUFFER_PTS (buf)), buf_info.size, buf_info.memory); - gst_buffer_ref (buf); - if (gst_esink_make_flush_buffer(esink)) - GST_WARNING("made flush buffer"); - gst_buffer_unref (buf); - } - else - { - GST_ERROR("it is not TBM buffer.. %d", scmn_imgb->buf_share_method); - } - } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { - static int skip_count_i420=0; - if(esink->sent_buffer_cnt >= MAX_ECOREPIPE_BUFFER_CNT) { - if(!(skip_count_i420++%20)) { - GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count_i420); - } - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - return GST_FLOW_OK; - } - - if(!esink->is_buffer_allocated) { - /* Allocate TBM buffer for non-zero copy case */ - if(!gst_evas_image_sink_allocate_source_buffer(esink)) { - GST_ERROR_OBJECT(esink, "Buffer allocation failed"); - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - return GST_FLOW_ERROR; - } - esink->is_buffer_allocated = TRUE; - } - - skip_count_i420 = 0; //for skip log in I420 - - /* check whether bo is new or not */ - for(i=0; idisplaying_buffer[i].bo == esink->src_buffer_info[esink->src_buf_idx].bo) { - GST_DEBUG_OBJECT(esink, "it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i); - index = i; - exist_bo = TRUE; - break; - } - else - exist_bo = FALSE; - } - - /* keep bo */ - if(!exist_bo) { - /* find empty buffer space for indexing */ - for(i=0; idisplaying_buffer[i].bo) { - index = i; - break; - } - } - - if(index!=-1) { - /* keep informations */ - esink->displaying_buffer[index].bo = esink->src_buffer_info[esink->src_buf_idx].bo; - esink->displaying_buffer[index].tbm_surf = esink->src_buffer_info[esink->src_buf_idx].tbm_surf; - - GST_DEBUG_OBJECT(esink, "gst_buf %p, TBM bo %p.. gst_buf vaddr %p .. src data size(%lu)", - buf, esink->displaying_buffer[index].bo, buf_info.data, buf_info.size); - - memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, buf_info.data, buf_info.size); - } - } else { - /* because it has same bo, use existing tbm surface */ - if(index!=-1) { - memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, buf_info.data, buf_info.size); - - GST_DEBUG_OBJECT(esink, "existing tbm surface %p.. gst_buf %p, bo %p, gst_buf vaddr %p", - esink->displaying_buffer[index].tbm_surf, buf, esink->displaying_buffer[index].bo, buf_info.data); - exist_bo = FALSE; - } - } - - /* if it couldn't find proper index */ - if(index == -1) - GST_WARNING_OBJECT(esink, "all spaces are being used!!!"); - else - GST_DEBUG_OBJECT(esink, "selected buffer index %d", index); - - } else { - GST_ERROR_OBJECT(esink, "unsupported color format"); - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - return GST_FLOW_ERROR; - } -#endif - if (esink->object_show) { //if (esink->object_show && index != -1) -#ifdef TIZEN_FEATURE_USE_FIMCC - gst_buffer_ref (buf); - r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *)); - if (r == EINA_FALSE) { - //add error handling - GST_WARNING("ecore_pipe_write fail"); - gst_buffer_unref (buf); - } -#endif -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - int old_curidx=esink->cur_index ; - static int skip_count=0; - g_mutex_lock(esink->display_buffer_lock); - - if(esink->tbm_surface_format == TBM_FORMAT_NV12 && scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) { - if (esink->sent_buffer_cnt < MAX_ECOREPIPE_BUFFER_CNT) { - GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); - gst_buffer_ref (buf); - esink->displaying_buffer[index].ref_count++; - esink->cur_index = index; - GST_LOG("index %d set refcount increase as %d", index,esink->displaying_buffer[index].ref_count); - GST_LOG("[show_frame] after refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); - - /* Print debug log for 8 frame */ - if(esink->debuglog_cnt_showFrame > 0) - { - GST_WARNING("(%d) ecore_pipe_write index[%d] gst_buf : %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame), - esink->cur_index, esink->displaying_buffer[esink->cur_index].buffer); - esink->debuglog_cnt_showFrame--; - } - - esink->sent_buffer_cnt++; - skip_count =0 ; - - r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_TBM_SUR_INDEX); - - if (r == EINA_FALSE) { - GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); - esink->cur_index = old_curidx; - if(esink->displaying_buffer[index].ref_count) - { - esink->displaying_buffer[index].ref_count--; - esink->sent_buffer_cnt--; - gst_buffer_unref(buf); - GST_ERROR("finish unreffing"); - } - } - } else { - /* If buffer count which is sent to ecore pipe, is upper 3, Print Error log */ - if(!(skip_count++%20)) { - GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count); - } - } - } else if (esink->tbm_surface_format == TBM_FORMAT_YUV420) { - esink->cur_index = index; - GST_LOG("index %d", index); - GST_LOG("[show_frame] gst_buf vaddr %p", esink->src_buffer_info[esink->src_buf_idx].usr_addr); - - /* Print debug log for 8 frame */ - if(esink->debuglog_cnt_showFrame > 0) - { - GST_WARNING("(%d) ecore_pipe_write : index[%d], bo[%p], tbm_surf[%p], gst_buf[%p], gst_buf vaddr [%p]", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame), - esink->cur_index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, buf, esink->src_buffer_info[esink->src_buf_idx].usr_addr); - esink->debuglog_cnt_showFrame--; - } - - esink->sent_buffer_cnt++; - - esink->src_buf_idx++; - r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_TBM_SUR_INDEX); - - if (r == EINA_FALSE) { - esink->cur_index = old_curidx; - esink->sent_buffer_cnt--; - esink->src_buf_idx--; - GST_ERROR("ecore_pipe_write is failed. index[%d], bo[%p], tbm_surf[%p], gst_buf vaddr [%p]", - index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, esink->src_buffer_info[esink->src_buf_idx].usr_addr); - } - esink->src_buf_idx = esink->src_buf_idx % SOURCE_BUFFER_NUM; - } - - g_mutex_unlock(esink->display_buffer_lock); -#endif - GST_DEBUG ("ecore_pipe_write() was called with gst_buf= %p.. gst_buf size=%d, mallocdata= %p", buf, buf_info.size, buf_info.memory); - } else { -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d) index %d", esink->object_show, index); -#else - GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d)", esink->object_show); -#endif - } - gst_buffer_unmap(buf, &buf_info); - g_mutex_unlock (instance_lock); - GST_DEBUG ("Leave"); - return GST_FLOW_OK; -} - -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -static GstFlowReturn -gst_esink_epipe_reset(GstEvasImageSink *esink) -{ - if (esink == NULL) { - GST_ERROR("handle is NULL"); - return GST_FLOW_ERROR; - } - - if (esink->epipe) { - GST_DEBUG("ecore-pipe will delete"); - ecore_pipe_del (esink->epipe); - esink->epipe = NULL; - } - - if (!esink->epipe) { - esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink); - if (!esink->epipe) { - GST_ERROR ("ecore-pipe create failed"); - return GST_FLOW_ERROR; - } - GST_DEBUG("ecore-pipe create success"); - } - - return GST_FLOW_OK; -} - - -static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink) -{ - GstEvasImageFlushBuffer *flush_buffer = NULL; - GstEvasImageDisplayingBuffer *display_buffer = NULL; - int size = 0; - tbm_bo bo; - tbm_bo_handle vaddr_src; - tbm_bo_handle vaddr_dst; - GstFlowReturn ret=GST_FLOW_OK; - int src_size = 0; - - if (esink == NULL) { - GST_ERROR("handle is NULL"); - return FALSE; - } - - if (esink->cur_index == -1) { - GST_WARNING_OBJECT(esink, "there is no remained buffer"); - return FALSE; - } - - if(esink->flush_buffer) - _release_flush_buffer(esink); - - /* malloc buffer */ - flush_buffer = (GstEvasImageFlushBuffer *)malloc(sizeof(GstEvasImageFlushBuffer)); - if (flush_buffer == NULL) { - GST_ERROR_OBJECT(esink, "GstEvasImageFlushBuffer alloc failed"); - return FALSE; - } - - memset(flush_buffer, 0x0, sizeof(GstEvasImageFlushBuffer)); - - display_buffer = &(esink->displaying_buffer[esink->cur_index]); - GST_WARNING_OBJECT(esink, "cur_index [%d]", - esink->cur_index); - if(!display_buffer || !display_buffer->bo) - { - GST_WARNING("display_buffer(%p) or bo (%p) is NULL!!", display_buffer, display_buffer->bo); - goto FLUSH_BUFFER_FAILED; - } - - /* create tbm surface */ - flush_buffer->tbm_surf = tbm_surface_create(esink->w, esink->h, TBM_FORMAT_NV12); - - if(!flush_buffer->tbm_surf) - { - GST_ERROR("tbm_surf is NULL!!"); - goto FLUSH_BUFFER_FAILED; - } - - /* get bo and size */ - bo = tbm_surface_internal_get_bo(flush_buffer->tbm_surf, 0); - size = tbm_bo_size(bo); - if(!bo || !size) - { - GST_ERROR("bo(%p), size(%d)", bo, size); - goto FLUSH_BUFFER_FAILED; - } - flush_buffer->bo = bo; - - src_size = gst_buffer_get_size(display_buffer->buffer); - - vaddr_src = tbm_bo_map(display_buffer->bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); - vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); - if (!vaddr_src.ptr || !vaddr_dst.ptr) { - GST_WARNING_OBJECT(esink, "get vaddr failed src %p, dst %p", vaddr_src.ptr, vaddr_dst.ptr); - if (vaddr_src.ptr) { - tbm_bo_unmap(display_buffer->bo); - } - if (vaddr_dst.ptr) { - tbm_bo_unmap(bo); - } - goto FLUSH_BUFFER_FAILED; - } else { - memset (vaddr_dst.ptr, 0x0, size); - GST_WARNING_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr_dst.ptr); - } - - /* copy buffer */ - memcpy(vaddr_dst.ptr, vaddr_src.ptr, src_size); - - tbm_bo_unmap(display_buffer->bo); - tbm_bo_unmap(bo); - - GST_WARNING_OBJECT(esink, "copy done.. tbm surface : %p src_size : %d", flush_buffer->tbm_surf, src_size); - - esink->flush_buffer = flush_buffer; - - /* initialize buffer list */ - if (esink->object_show) - esink->need_flush = TRUE; - - ret = gst_esink_epipe_reset(esink); - if(ret) { - GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); - return FALSE; - } else { - GST_ERROR_OBJECT(esink, "evas epipe reset success"); - } - - gst_evas_image_sink_reset(esink); - - - return TRUE; - -FLUSH_BUFFER_FAILED: - if (flush_buffer) { - if(flush_buffer->tbm_surf) - { - tbm_surface_destroy(flush_buffer->tbm_surf); - flush_buffer->tbm_surf = NULL; - } - - free(flush_buffer); - flush_buffer = NULL; - } - return FALSE; -} - - static void _release_flush_buffer(GstEvasImageSink *esink) -{ - if (esink == NULL || - esink->flush_buffer == NULL) { - GST_WARNING("handle is NULL"); - return; - } - - GST_WARNING_OBJECT(esink, "release FLUSH BUFFER start"); - if (esink->flush_buffer->bo) { - esink->flush_buffer->bo = NULL; - } - if(esink->flush_buffer->tbm_surf) { - tbm_surface_destroy(esink->flush_buffer->tbm_surf); - esink->flush_buffer->tbm_surf = NULL; - } - - GST_WARNING_OBJECT(esink, "release FLUSH BUFFER done"); - - free(esink->flush_buffer); - esink->flush_buffer = NULL; - - return; -} -#endif -#ifdef DUMP_IMG -int util_write_rawdata(const char *file, const void *data, unsigned int size) -{ - FILE *fp; - fp = fopen(file, "wb"); - if (fp == NULL) - return -1; - fwrite((char*)data, sizeof(char), size, fp); - fclose(fp); - return 0; -} -#endif - -static gboolean -evas_image_sink_init (GstPlugin *evasimagesink) -{ - GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink"); - - return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK); -} - -#ifndef PACKAGE -#define PACKAGE "gstevasimagesink-plugin-package" -#endif - -GST_PLUGIN_DEFINE ( - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - evasimagesink, - "Evas image object based videosink", - evas_image_sink_init, - VERSION, - "LGPL", - "Samsung Electronics Co", - "http://www.samsung.com/" -) diff --git a/evasimagesink/src/gstevasimagesink.h b/evasimagesink/src/gstevasimagesink.h deleted file mode 100644 index 7c62d46..0000000 --- a/evasimagesink/src/gstevasimagesink.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * evasimagesink - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Sangchul Lee - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., 51 - * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __GST_EVASIMAGESINK_H__ -#define __GST_EVASIMAGESINK_H__ - -//#define TIZEN_FEATURE_USE_TBM_SURFACE -#define TIZEN_FEATURE_USE_FIMCC - -#include -#include -#include -#include -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -#include -#include -#endif -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_EVASIMAGESINK \ - (gst_evas_image_sink_get_type()) -#define GST_EVASIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EVASIMAGESINK,GstEvasImageSink)) -#define GST_EVASIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EVASIMAGESINK,GstEvasImageSinkClass)) -#define GST_IS_EVASIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EVASIMAGESINK)) -#define GST_IS_EVASIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EVASIMAGESINK)) - -typedef struct _GstEvasImageSink GstEvasImageSink; -typedef struct _GstEvasImageSinkClass GstEvasImageSinkClass; -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE -typedef struct _GstEvasImageDisplayingBuffer GstEvasImageDisplayingBuffer; -typedef struct _GstEvasImageFlushBuffer GstEvasImageFlushBuffer; -typedef enum { - BUF_SHARE_METHOD_NONE = -1, - BUF_SHARE_METHOD_PADDR = 0, - BUF_SHARE_METHOD_FD, - BUF_SHARE_METHOD_TIZEN_BUFFER, - BUF_SHARE_METHOD_FLUSH_BUFFER -} buf_share_method_t; - -enum { - DEGREE_0 = 0, - DEGREE_90, - DEGREE_180, - DEGREE_270, - DEGREE_NUM, -}; - -enum { - DISP_GEO_METHOD_LETTER_BOX = 0, - DISP_GEO_METHOD_ORIGIN_SIZE, - DISP_GEO_METHOD_FULL_SCREEN, - DISP_GEO_METHOD_CROPPED_FULL_SCREEN, - DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX, - DISP_GEO_METHOD_CUSTOM_DST_ROI, - DISP_GEO_METHOD_NUM, -}; - -enum { - FLIP_NONE = 0, - FLIP_HORIZONTAL, - FLIP_VERTICAL, - FLIP_BOTH, - FLIP_NUM -}; - -struct buffer_info { - uint64_t usr_addr; - uint64_t size; - void *bo; - tbm_surface_h tbm_surf; -}; - -/* _GstEvasDisplayingBuffer - * - * buffer : manage ref count by got index through comparison - * bo : compare with buffer from codec for getting index - * n_buffer : compare with buffer from evas for getting index - * ref_count : decide whether it unref buffer or not in gst_evas_image_sink_fini/reset - */ -struct _GstEvasImageDisplayingBuffer { - GstBuffer *buffer; - void *bo; - tbm_surface_h tbm_surf; - int ref_count; -}; - -struct _GstEvasImageFlushBuffer { - void *bo; - tbm_surface_h tbm_surf; -}; -#define TBM_SURFACE_NUM 20 -#define SOURCE_BUFFER_NUM 8 -#endif -struct _GstEvasImageSink -{ - GstVideoSink element; - - Evas_Object *eo; - Ecore_Pipe *epipe; - Evas_Coord w; - Evas_Coord h; - gboolean object_show; - gchar update_visibility; - gboolean gl_zerocopy; - - GstBuffer *oldbuf; - - gboolean is_evas_object_size_set; - guint present_data_addr; -#ifdef TIZEN_FEATURE_USE_TBM_SURFACE - GMutex *display_buffer_lock; - GMutex *flow_lock; - GstEvasImageDisplayingBuffer displaying_buffer[TBM_SURFACE_NUM]; - GstVideoRectangle eo_size; - gboolean use_ratio; - guint rotate_angle; - guint display_geometry_method; - guint flip; - GstBuffer *prev_buf; - gint prev_index; - gint cur_index; - gboolean need_flush; - gboolean enable_flush_buffer; - GstEvasImageFlushBuffer *flush_buffer; - gint sent_buffer_cnt; - gint debuglog_cnt_showFrame; - gint debuglog_cnt_ecoreCbPipe; - - tbm_format tbm_surface_format; - struct buffer_info src_buffer_info[TBM_SURFACE_NUM]; - guint src_buf_idx; - gboolean is_buffer_allocated; -#endif -}; - -struct _GstEvasImageSinkClass -{ - GstVideoSinkClass parent_class; -}; - -GType gst_evas_image_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_EVASIMAGESINK_H__ */ diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 3d9c0e9..3d74bb5 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -12,8 +12,6 @@ License: LGPL-2.1+ Source0: %{name}-%{version}.tar.gz #BuildRequires: pkgconfig(camsrcjpegenc) -BuildRequires: pkgconfig(ecore) -BuildRequires: pkgconfig(evas) BuildRequires: pkgconfig(gstreamer-audio-1.0) BuildRequires: pkgconfig(gstreamer-video-1.0) BuildRequires: pkgconfig(gstreamer-plugins-base-1.0) -- 2.7.4 From cb65884863e65bba9fea0a34b8a6cd76c8990024 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Tue, 8 Nov 2016 13:41:21 +0900 Subject: [PATCH 05/16] Add notification parameter of screenshot event listener [Version] 1.0.0.28 [Profile] Common [Issue Type] Add parameter of event listener [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161101.3] Change-Id: If1250e10dde6925ca658ab5cf44d0d64d2e46be0 Signed-off-by: Hyunsoo, Park --- packaging/gst-plugins-tizen.spec | 2 +- waylandsrc/src/gstwaylandsrc.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 3d74bb5..a32c467 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 27 +Release: 28 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/waylandsrc/src/gstwaylandsrc.c b/waylandsrc/src/gstwaylandsrc.c index 53904af..0d5bed3 100644 --- a/waylandsrc/src/gstwaylandsrc.c +++ b/waylandsrc/src/gstwaylandsrc.c @@ -586,9 +586,18 @@ shoooter_handle_format(void *data, GST_INFO ("Format : %c%c%c%c", FOURCC_STR (format)); } +static void +shoooter_handle_noti(void *data, + struct tizen_screenshooter *shooter, + uint32_t noti) +{ + GST_INFO ("Noti privilege : %d, shoooter_handle_noti is called (0:denied, 1:available)", noti); +} + static const struct tizen_screenshooter_listener shooter_listener = { - shoooter_handle_format + shoooter_handle_format, + shoooter_handle_noti }; static void -- 2.7.4 From bb653e371d0f7ddaaf4f9ae6bc457228e20d4d03 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Fri, 28 Oct 2016 15:58:43 +0900 Subject: [PATCH 06/16] Add AL-FEC feature [Version] 1.6.1 [Profile] Common [Issue Type] Add feature [Dependency module] N/A [Depends-on] https://review.tizen.org/gerrit/#/c/94310/ (Change-Id: I534d3acf3aa5f0114c2282b3ea80a7b0f51216cc) [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161025.2] Change-Id: Iec3ba16bd8b61b96415e39126e25c4286cd02dc4 Signed-off-by: Hyunsoo, Park --- Makefile.am | 32 + alfec/Makefile.am | 41 + alfec/feccodes/FECCodes.c | 286 +++++ alfec/feccodes/FecDecoder.c | 126 ++ alfec/feccodes/FecEncoder.c | 122 ++ alfec/feccodes/RS/RSBase.c | 449 +++++++ alfec/feccodes/RS/RSDecoder.c | 369 ++++++ alfec/feccodes/RS/RSEncoder.c | 163 +++ alfec/feccodes/include/FECCodes.h | 128 ++ alfec/feccodes/include/FecDecoder.h | 99 ++ alfec/feccodes/include/FecEncoder.h | 114 ++ alfec/feccodes/include/RS/RSBase.h | 109 ++ alfec/feccodes/include/RS/RSDecoder.h | 96 ++ alfec/feccodes/include/RS/RSEncoder.h | 96 ++ alfec/gst_source_blocking_algorithm.c | 245 ++++ alfec/gst_source_blocking_algorithm.h | 115 ++ alfec/gst_source_deblocking_algorithm.c | 312 +++++ alfec/gst_source_deblocking_algorithm.h | 118 ++ alfec/gstalfec.c | 73 ++ alfec/gstalfecbufferpool.c | 156 +++ alfec/gstalfecbufferpool.h | 78 ++ alfec/gstalfecdecaps.c | 183 +++ alfec/gstalfecdecaps.h | 107 ++ alfec/gstalfecdecoder.c | 595 +++++++++ alfec/gstalfecdecoder.h | 100 ++ alfec/gstalfecencaps.c | 202 +++ alfec/gstalfecencaps.h | 106 ++ alfec/gstalfecencoder.c | 592 +++++++++ alfec/gstalfecencoder.h | 105 ++ alfec/gstalfecheader.h | 66 + alfec/gstnetsim.c | 415 ++++++ alfec/gstnetsim.h | 72 ++ configure.ac | 53 + packaging/gst-plugins-tizen.spec | 5 +- rtpresender/Makefile.am | 1 + rtpresender/src/Makefile.am | 29 + rtpresender/src/gstrtpresender.c | 869 +++++++++++++ rtpresender/src/gstrtpresender.h | 92 ++ wfdextmanager/Makefile.am | 15 + wfdextmanager/gstwfdextmanager.c | 71 ++ wfdextmanager/gstwfdextmessage.c | 1235 ++++++++++++++++++ wfdextmanager/gstwfdextmessage.h | 359 ++++++ wfdextmanager/gstwfdextsrc.c | 2124 +++++++++++++++++++++++++++++++ wfdextmanager/gstwfdextsrc.h | 113 ++ wfdextmanager/gstwfdrtprequester.c | 977 ++++++++++++++ wfdextmanager/gstwfdrtprequester.h | 102 ++ wfdmanager/wfdbase/gstwfdbasesrc.c | 53 + wfdmanager/wfdbase/gstwfdbasesrc.h | 3 + wfdtizenmanager/Makefile.am | 15 + wfdtizenmanager/gstwfdtizenmanager.c | 68 + wfdtizenmanager/gstwfdtizenmessage.c | 586 +++++++++ wfdtizenmanager/gstwfdtizenmessage.h | 104 ++ wfdtizenmanager/gstwfdtizensrc.c | 1476 +++++++++++++++++++++ wfdtizenmanager/gstwfdtizensrc.h | 108 ++ 54 files changed, 14327 insertions(+), 1 deletion(-) mode change 100644 => 100755 Makefile.am create mode 100755 alfec/Makefile.am create mode 100755 alfec/feccodes/FECCodes.c create mode 100755 alfec/feccodes/FecDecoder.c create mode 100755 alfec/feccodes/FecEncoder.c create mode 100755 alfec/feccodes/RS/RSBase.c create mode 100755 alfec/feccodes/RS/RSDecoder.c create mode 100755 alfec/feccodes/RS/RSEncoder.c create mode 100755 alfec/feccodes/include/FECCodes.h create mode 100755 alfec/feccodes/include/FecDecoder.h create mode 100755 alfec/feccodes/include/FecEncoder.h create mode 100755 alfec/feccodes/include/RS/RSBase.h create mode 100755 alfec/feccodes/include/RS/RSDecoder.h create mode 100755 alfec/feccodes/include/RS/RSEncoder.h create mode 100755 alfec/gst_source_blocking_algorithm.c create mode 100755 alfec/gst_source_blocking_algorithm.h create mode 100755 alfec/gst_source_deblocking_algorithm.c create mode 100755 alfec/gst_source_deblocking_algorithm.h create mode 100755 alfec/gstalfec.c create mode 100755 alfec/gstalfecbufferpool.c create mode 100755 alfec/gstalfecbufferpool.h create mode 100755 alfec/gstalfecdecaps.c create mode 100755 alfec/gstalfecdecaps.h create mode 100755 alfec/gstalfecdecoder.c create mode 100755 alfec/gstalfecdecoder.h create mode 100755 alfec/gstalfecencaps.c create mode 100755 alfec/gstalfecencaps.h create mode 100755 alfec/gstalfecencoder.c create mode 100755 alfec/gstalfecencoder.h create mode 100755 alfec/gstalfecheader.h create mode 100755 alfec/gstnetsim.c create mode 100755 alfec/gstnetsim.h mode change 100644 => 100755 configure.ac mode change 100644 => 100755 packaging/gst-plugins-tizen.spec create mode 100755 rtpresender/Makefile.am create mode 100755 rtpresender/src/Makefile.am create mode 100644 rtpresender/src/gstrtpresender.c create mode 100755 rtpresender/src/gstrtpresender.h create mode 100755 wfdextmanager/Makefile.am create mode 100644 wfdextmanager/gstwfdextmanager.c create mode 100755 wfdextmanager/gstwfdextmessage.c create mode 100755 wfdextmanager/gstwfdextmessage.h create mode 100755 wfdextmanager/gstwfdextsrc.c create mode 100755 wfdextmanager/gstwfdextsrc.h create mode 100755 wfdextmanager/gstwfdrtprequester.c create mode 100755 wfdextmanager/gstwfdrtprequester.h mode change 100644 => 100755 wfdmanager/wfdbase/gstwfdbasesrc.c mode change 100644 => 100755 wfdmanager/wfdbase/gstwfdbasesrc.h create mode 100755 wfdtizenmanager/Makefile.am create mode 100644 wfdtizenmanager/gstwfdtizenmanager.c create mode 100755 wfdtizenmanager/gstwfdtizenmessage.c create mode 100755 wfdtizenmanager/gstwfdtizenmessage.h create mode 100755 wfdtizenmanager/gstwfdtizensrc.c create mode 100755 wfdtizenmanager/gstwfdtizensrc.h diff --git a/Makefile.am b/Makefile.am old mode 100644 new mode 100755 index a0b7a94..1286d69 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,22 @@ if GST_TIZEN_USE_TIZENIPC SUBDIRS += tizenipc endif +if GST_TIZEN_USE_WFDEXTMANAGER +SUBDIRS += wfdextmanager +endif + +if GST_TIZEN_USE_WFDTIZENMANAGER +SUBDIRS += wfdtizenmanager +endif + +if GST_TIZEN_USE_ALFEC +SUBDIRS += alfec +endif + +if GST_TIZEN_USE_RTPRESENDER +SUBDIRS += rtpresender +endif + DIST_SUBDIRS = common if GST_TIZEN_USE_ENCODEBIN @@ -88,6 +104,22 @@ if GST_TIZEN_USE_DRMDECRYPTOR DIST_SUBDIRS += drmdecryptor endif +if GST_TIZEN_USE_WFDEXTMANAGER +DIST_SUBDIRS += wfdextmanager +endif + +if GST_TIZEN_USE_WFDTIZENMANAGER +DIST_SUBDIRS += wfdtizenmanager +endif + +if GST_TIZEN_USE_ALFEC +DIST_SUBDIRS += alfec +endif + +if GST_TIZEN_USE_RTPRESENDER +DIST_SUBDIRS += rtpresender +endif + EXTRA_DIST = \ gstreamer.spec gstreamer.spec.in \ configure.ac autogen.sh depcomp \ diff --git a/alfec/Makefile.am b/alfec/Makefile.am new file mode 100755 index 0000000..f74c1c8 --- /dev/null +++ b/alfec/Makefile.am @@ -0,0 +1,41 @@ +plugin_LTLIBRARIES = libgstalfec.la + +libgstalfec_la_SOURCES = gstalfec.c \ + gstalfecencoder.c \ + gstalfecdecoder.c \ + gst_source_blocking_algorithm.c \ + gstalfecencaps.c \ + gst_source_deblocking_algorithm.c \ + gstalfecdecaps.c \ + gstnetsim.c + +libgstalfec_la_SOURCES += feccodes/FECCodes.c \ + feccodes/FecEncoder.c \ + feccodes/FecDecoder.c \ + feccodes/RS/RSBase.c \ + feccodes/RS/RSDecoder.c \ + feccodes/RS/RSEncoder.c + +libgstalfec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) $(GST_CFLAGS) \ + -I$(srcdir)/feccodes/include +libgstalfec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) +libgstalfec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstalfec_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) + +noinst_HEADERS = gstalfecencoder.h \ + gstalfecdecoder.h \ + gst_source_blocking_algorithm.h \ + gstalfecencaps.h \ + gst_source_deblocking_algorithm.h \ + gstalfecdecaps.h \ + gstnetsim.h + +noinst_HEADERS += feccodes/include/FECCodes.h \ + feccodes/include/FecEncoder.h \ + feccodes/include/FecDecoder.h \ + feccodes/include/RS/RSBase.h \ + feccodes/include/RS/RSEncoder.h \ + feccodes/include/RS/RSDecoder.h diff --git a/alfec/feccodes/FECCodes.c b/alfec/feccodes/FECCodes.c new file mode 100755 index 0000000..9621b63 --- /dev/null +++ b/alfec/feccodes/FECCodes.c @@ -0,0 +1,286 @@ +/* + * FECCodes + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "FECCodes.h" +#include "FecEncoder.h" +#include "FecDecoder.h" +#include "RS/RSEncoder.h" +#include "RS/RSDecoder.h" + +GList *fecEncoders = NULL; ///< List of FEC Encoders +GList *fecDecoders = NULL; ///< List of FEC Decoders +GstRSBase *rs_base = NULL; + +#define ERROR -1 +#define ZERO 0 +#define ONE 1 + +#define OBJ_MAX_COUNT 99 +/** + * @brief Function for FEC code instance initialization + * @exception N/A + */ +guint8 +FECCodes_Initialize(guint8 const *kmax, guint8 const *pmax, + guint32 const *t, guint8 const *isEncoder, + guint8 const *codeTypeID, void *additionalData) +{ + if (((*isEncoder==ONE) && (g_list_length (fecEncoders) >= OBJ_MAX_COUNT)) || + ((*isEncoder==ZERO) && (g_list_length (fecDecoders) >= OBJ_MAX_COUNT))) { + return ZERO; + } + + guint32 _kmax = *kmax, _pmax = *pmax, _t = *t; + + switch(*codeTypeID) + { + case CODE_ID_RS: + { + if (*isEncoder==ONE) { + GST_INFO ("Initialize RS encoder. Parameters: kmax = %d," + " pmax = %d, t = %d", _kmax, _pmax, _t); + GstRSEncoder *rsEncoder = gst_rs_encoder_new (_kmax, _pmax, _t); + if (rs_base == NULL) { + rs_base = g_object_new (GST_TYPE_RS_BASE, NULL); + } + rsEncoder->rs = rs_base; + fecEncoders = g_list_append(fecEncoders, rsEncoder); + return g_list_length (fecEncoders); + } else { + GST_INFO ("Initialize RS decoder. Parameters: kmax = %d," + " pmax = %d, t = %d\n", _kmax, _pmax, _t); + GstRSDecoder *rsDecoder = gst_rs_decoder_new (_kmax, _pmax, _t); + if (rs_base == NULL) { + rs_base = g_object_new (GST_TYPE_RS_BASE, NULL); + } + rsDecoder->rs = rs_base; + fecDecoders = g_list_append(fecDecoders, rsDecoder); + + return OBJ_MAX_COUNT + g_list_length(fecDecoders); + } + break; + } + default: + { + break; + } + } + + return ZERO; +} + + +void FECCodes_set_parity_block (guint8 **parityBlock, guint8 const *k, + guint8 const *p, const guint8 *encoderObjectID) +{ + GstFECEncoder *enc = NULL; + GstFECEncoderClass *enc_class = NULL; + + if (*encoderObjectID > g_list_length(fecEncoders)) { + GST_ERROR ("ID of encoder is not valid"); + return; + } + + guint32 _k = *k, _p = *p; + + enc = GST_FEC_ENCODER (g_list_nth_data (fecEncoders, *encoderObjectID-1)); + if (enc == NULL) { + GST_ERROR ("Can't find encoder"); + return; + } + + enc_class = GST_FEC_ENCODER_GET_CLASS (enc); + if (enc_class == NULL) { + GST_ERROR ("Can't find encoder"); + return; + } + if (enc_class->set_parity_block == NULL) { + GST_ERROR ("No set_parity_block vfuncition implementation"); + return; + } + + enc_class->set_parity_block (enc, _k, _p, parityBlock); + return; +} + +/** + * @brief Function for FEC block encoding + * exception N/A + */ +gboolean FECCodes_Encode_single_symbol(guint8 *sourceSymbol, + gboolean *is_computed, const guint8 *encoderObjectID) +{ + GstFECEncoder *enc = NULL; + GstFECEncoderClass *enc_class = NULL; + if (*encoderObjectID > g_list_length(fecEncoders)) { + return FALSE; + } + + enc = GST_FEC_ENCODER (g_list_nth_data (fecEncoders, *encoderObjectID-1)); + if (enc == NULL) { + GST_ERROR ("Can't find encoder"); + return FALSE; + } + + enc_class = GST_FEC_ENCODER_GET_CLASS (enc); + if (enc_class == NULL) { + GST_ERROR ("Can't find encoder"); + return FALSE; + } + if (enc_class->EncodeData == NULL) { + GST_ERROR ("No EncodeData vfuncition implementation"); + return FALSE; + } + + return enc_class->EncodeData(enc, sourceSymbol, is_computed); +} + +/** + * @brief Get number of last processed symbol + * exception N/A + */ +guint8 FECCodes_get_encoder_symbol_number(const guint8 *encoderObjectID) +{ + GstFECEncoder *enc = NULL; + GstFECEncoderClass *enc_class = NULL; + if (*encoderObjectID > g_list_length(fecEncoders)) { + GST_ERROR ("ID of encoder is not valid"); + return 0; + } + + enc = GST_FEC_ENCODER (g_list_nth_data (fecEncoders, *encoderObjectID-1)); + if (enc == NULL) { + GST_ERROR ("Can't find encoder"); + return 0; + } + + enc_class = GST_FEC_ENCODER_GET_CLASS (enc); + if (enc_class == NULL) { + GST_ERROR ("Can't find encoder"); + return 0; + } + if (enc_class->get_symbol_number == NULL) { + GST_ERROR ("No EncodeData vfuncition implementation"); + return 0; + } + + return enc_class->get_symbol_number(enc); +} + +/** + * @brief Function for FEC block decoding + * @exception N/A + */ +gchar +FECCodes_DecodeData(guint8 **sourceBlock, guint8 **parityBlock, + guint8 *infoArray, guint8 const *k, guint8 const *p, + guint8 const *decoderObjectID, void *additionalData, gboolean reorder) +{ + GstFECDecoder *dec = NULL; + GstFECDecoderClass *dec_class = NULL; + + guint8 offset = 100; + guint8 decIndex = *decoderObjectID - offset; + if (decIndex >= g_list_length(fecDecoders)) { + return ERROR; + } + guint32 _k = *k, _p = *p; + + dec = GST_FEC_DECODER (g_list_nth_data (fecDecoders, decIndex)); + if (dec == NULL) { + GST_ERROR ("Can't find decoder"); + return ERROR; + } + dec_class = GST_FEC_DECODER_GET_CLASS (dec); + if (dec_class == NULL) { + GST_ERROR ("Can't find decoder"); + return ERROR; + } + if (dec_class->DecodeData == NULL) { + GST_ERROR ("No DecodeData vfuncition implementation"); + return ERROR; + } + + return dec_class->DecodeData(dec, sourceBlock, parityBlock, infoArray, _k, _p, additionalData, reorder); +} + +/** + * @brief Function for FEC code instance deinitialization + * @exception N/A + */ +gboolean +FECCodes_Deinitialize(guint8 const *codeInstanseID) +{ + guint8 offset = 100; + if (*codeInstanseID >= offset) {//decoder + guint8 decIndex = *codeInstanseID - offset; + if (g_list_length(fecDecoders) > decIndex) { + GList *link = g_list_nth (fecDecoders, decIndex); + if (link != NULL) { + fecDecoders = g_list_delete_link (fecDecoders, link); + return TRUE; + } else { + return FALSE; + } + } else { + return FALSE; + } + } else { + guint8 encIndex = *codeInstanseID - ONE; + if (g_list_length(fecEncoders) > encIndex) { + GList *link = g_list_nth (fecEncoders, encIndex); + if (link != NULL) { + fecEncoders = g_list_delete_link (fecEncoders, link); + return TRUE; + } else { + return FALSE; + } + } else { + return FALSE; + } + } + return TRUE; +} diff --git a/alfec/feccodes/FecDecoder.c b/alfec/feccodes/FecDecoder.c new file mode 100755 index 0000000..009a7eb --- /dev/null +++ b/alfec/feccodes/FecDecoder.c @@ -0,0 +1,126 @@ +/* + * FecDecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "FecDecoder.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_fec_decoder_debug); +#define GST_CAT_DEFAULT gst_fec_decoder_debug + +G_DEFINE_TYPE (GstFECDecoder, gst_fec_decoder, + G_TYPE_OBJECT); + +static void +gst_fec_decoder_finalize (GObject * gobject) +{ + G_OBJECT_CLASS (gst_fec_decoder_parent_class)-> + finalize (gobject); +} + +static void +gst_fec_decoder_init (GstFECDecoder * dec) +{ +} + +static void +gst_fec_decoder_class_init (GstFECDecoderClass * + dec) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (dec); + + gobject_class->finalize = gst_fec_decoder_finalize; + GST_DEBUG_CATEGORY_INIT (gst_fec_decoder_debug, "gst_fecdecoder", 0, + "Base FEC decoder object"); + dec->DecodeData = NULL; +} + +gboolean +CheckInputParametersDecoder(GstFECDecoder *dec, guint8 **sourceBlock, + guint8 **parityBlock, guint8 *infoArray, + const guint32 k, const guint32 p, void *additionalData) +{ + // Check the source symbol block + if (sourceBlock == NULL) + { + GST_ERROR_OBJECT (dec, "Source symbol block is equal to NULL"); + return FALSE; + } + + // Check the parity symbol block + if (parityBlock == NULL) + { + GST_ERROR_OBJECT (dec, "Parity symbol block is equal to NULL"); + return FALSE; + } + + // Check the info array + if (infoArray == NULL) + { + GST_ERROR_OBJECT (dec, "Info array block is equal to NULL"); + return FALSE; + } + + // Check the number of source symbols in the source symbol block + if (k > dec->kmax) + { + GST_ERROR_OBJECT (dec, "Size of input source symbol block (%d)" + " is more than maximum size of source symbol block (%d)", k, dec->kmax); + return FALSE; + } + + // Check the number of repair symbols in the repair symbol block + if (p > dec->pmax) + { + GST_ERROR_OBJECT (dec, "Size of required parity symbol block (%d)" + " is more than maximum size of parity symbol block (%d)", p, dec->pmax); + return FALSE; + } + + // This parameter is for future usage + dec->initialData = additionalData; + + return TRUE; +} diff --git a/alfec/feccodes/FecEncoder.c b/alfec/feccodes/FecEncoder.c new file mode 100755 index 0000000..b2ace7c --- /dev/null +++ b/alfec/feccodes/FecEncoder.c @@ -0,0 +1,122 @@ +/* + * FecEncoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "FecEncoder.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_fec_encoder_debug); +#define GST_CAT_DEFAULT gst_fec_encoder_debug + +G_DEFINE_TYPE (GstFECEncoder, gst_fec_encoder, + G_TYPE_OBJECT); + +static void +gst_fec_encoder_finalize (GObject * gobject) +{ + /* GstFECEncoder *enc = GST_FEC_ENCODER (gobject); */ + G_OBJECT_CLASS (gst_fec_encoder_parent_class)-> + finalize (gobject); +} + +static void +gst_fec_encoder_init (GstFECEncoder * enc) +{ +} + +static void +gst_fec_encoder_class_init (GstFECEncoderClass * + enc) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (enc); + + gobject_class->finalize = gst_fec_encoder_finalize; + GST_DEBUG_CATEGORY_INIT (gst_fec_encoder_debug, "gst_fecencoder", 0, + "Base FEC encoder object"); + /* make EncodeData, set_parity_block and get_symbol_number pure virtual */ + enc->EncodeData = NULL; + enc->set_parity_block = NULL; + enc->get_symbol_number = NULL; +} + +/** + * @brief Function checks that input parameters are correct. + */ +gboolean +CheckInputParameters(GstFECEncoder * enc, guint8 **sourceSymbolBlock, + guint8 **parityBlock, const guint32 k, const guint32 p) +{ + // Check the source symbol block + if (sourceSymbolBlock == NULL) + { + GST_ERROR_OBJECT (enc, "Source symbol block is equal to NULL"); + return FALSE; + } + + // Check the parity symbol block + if (parityBlock == NULL) + { + GST_ERROR_OBJECT (enc, "Parity symbol block is equal to NULL"); + return FALSE; + } + + // Check the number of source symbols in the source symbol block + if (k > enc->kmax) + { + GST_ERROR_OBJECT (enc, "Size of input source symbol block (%d) is" + " more than maximum size of source symbol block (%d)", k, enc->kmax); + return FALSE; + } + + // Check the number of repair symbols in the repair symbol block + if (p > enc->pmax) + { + GST_ERROR_OBJECT (enc, "Size of required parity symbol block (%d) is" + " more than maximum size of parity symbol block (%d)", p, enc->pmax); + return FALSE; + } + + return TRUE; +} diff --git a/alfec/feccodes/RS/RSBase.c b/alfec/feccodes/RS/RSBase.c new file mode 100755 index 0000000..eeafd87 --- /dev/null +++ b/alfec/feccodes/RS/RSBase.c @@ -0,0 +1,449 @@ +/* + * RSBase + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "RS/RSBase.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_rs_base_debug); +#define GST_CAT_DEFAULT gst_rs_base_debug + +G_DEFINE_TYPE (GstRSBase, gst_rs_base, + G_TYPE_OBJECT); + +#define GST_RS_BASE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RS_BASE, GstRSBasePrivate)) + +#define NO_INSTANCE 0 + +struct _GstRSBasePrivate +{ + guint8 *gfExp; ///< Table for fast exponent calculation in the Galois field (exp(a) = gfExp[a]) + guint8 *gfLog; ///< Table for fast natural logarithm calculation in the Galois field (ln(a) = gfExp[a]) +}; + +static void GenerateGF(GstRSBase *base); +static void InitMulTable(GstRSBase *base); +static void InitDivlTable(GstRSBase *base); + +static void +gst_rs_base_finalize (GObject * gobject) +{ + GstRSBase *base = GST_RS_BASE (gobject); + guint32 i = 0; + + // Delete memory for auxiliary arrays + g_free (base->priv->gfExp); + g_free (base->priv->gfLog); + g_free (base->X); + g_free (base->Y); + + // Delete memory for gfDivTable + for (i = 0; i < TABLE_SIZE; i++) + { + g_free (base->gfDivTable[i]); + } + g_free (base->gfDivTable); + + // Delete memory for gfMullTable + for (i = 0; i < TABLE_SIZE; i++) + { + g_free (base->gfMullTable[i]); + } + g_free (base->gfMullTable); + + // Delete memory for Cauchy matrix + for (i = 0; i < CAUCHY_MATRIX_SIZE; i++) + { + g_free (base->cauchyMatrix[i]); + } + g_free (base->cauchyMatrix); + + G_OBJECT_CLASS (gst_rs_base_parent_class)-> + finalize (gobject); +} + +static void +gst_rs_base_init (GstRSBase * base) +{ + GstRSBasePrivate *priv = + GST_RS_BASE_GET_PRIVATE (base); + base->priv = priv; + + guint32 i = 0; + // Allocate memory for gfExp and gfLog + base->priv->gfExp = g_malloc (sizeof (guint8) * GF_EXP_TABLE_SIZE); + base->priv->gfLog = g_malloc (sizeof (guint8) * TABLE_SIZE); + + // Allocate memory for auxiliary arrays + base->X = g_malloc (sizeof (guint8) * GF_SIZE); + base->Y = g_malloc (sizeof (guint8) * GF_SIZE); + + // Allocate memory for gfMullTable + base->gfMullTable = g_malloc (sizeof (guint8*) * TABLE_SIZE); + for (i = 0; i < TABLE_SIZE; i++) + { + base->gfMullTable[i] = g_malloc (sizeof (guint8) * TABLE_SIZE); + } + + // Allocate memory for gfDivTable + base->gfDivTable = g_malloc (sizeof (guint8*) * TABLE_SIZE); + for (i = 0; i < TABLE_SIZE; i++) + { + base->gfDivTable[i] = g_malloc (sizeof (guint8) * TABLE_SIZE); + } + + // Allocate memory for Cauchy matrix + base->cauchyMatrix = g_malloc (sizeof (guint8*) * CAUCHY_MATRIX_SIZE); + for (i = 0; i < CAUCHY_MATRIX_SIZE; i++) + { + base->cauchyMatrix[i] = g_malloc (sizeof (guint8) * CAUCHY_MATRIX_SIZE - i); + } + + GenerateGF(base); +} + +static void +gst_rs_base_class_init (GstRSBaseClass * + base) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (base); + g_type_class_add_private (base, sizeof (GstRSBasePrivate)); + + gobject_class->finalize = gst_rs_base_finalize; + GST_DEBUG_CATEGORY_INIT (gst_rs_base_debug, "gst_rsbase", 0, + "Read-Solomon base object"); +} + + +guint8 +gfDiv(GstRSBase *base, const guint8 dividend, const guint8 divisor) +{ + return base->gfDivTable[dividend][divisor]; +} + +guint8 +gfMul(GstRSBase *base, const guint8 mul1, const guint8 mul2) +{ + return base->gfMullTable[mul1][mul2]; +} + + +#define UNROLL 16 +#define UNROLL_DEC (UNROLL - 1) +#define UNROLL_ELEMENT_0 0 +#define UNROLL_ELEMENT_1 1 +#define UNROLL_ELEMENT_2 2 +#define UNROLL_ELEMENT_3 3 +#define UNROLL_ELEMENT_4 4 +#define UNROLL_ELEMENT_5 5 +#define UNROLL_ELEMENT_6 6 +#define UNROLL_ELEMENT_7 7 +#define UNROLL_ELEMENT_8 8 +#define UNROLL_ELEMENT_9 9 +#define UNROLL_ELEMENT_10 10 +#define UNROLL_ELEMENT_11 11 +#define UNROLL_ELEMENT_12 12 +#define UNROLL_ELEMENT_13 13 +#define UNROLL_ELEMENT_14 14 +#define UNROLL_ELEMENT_15 15 + + +void +AddMul(GstRSBase *base, guint8 **dst1, const guint8 *src1, + const guint8 c, const gint32 sz) +{ + + guint8 *dst = *dst1; + const guint8 *SRC = src1; + guint8 *lim = &dst[ (gint32)sz - UNROLL_DEC]; + guint8 *mullTableRow = base->gfMullTable[c]; +#if (UNROLL > UNROLL_ELEMENT_1) + for (; dst < lim ; dst += UNROLL, SRC += UNROLL ) + { + dst[UNROLL_ELEMENT_0] ^= mullTableRow[SRC[UNROLL_ELEMENT_0]]; + dst[UNROLL_ELEMENT_1] ^= mullTableRow[SRC[UNROLL_ELEMENT_1]]; + dst[UNROLL_ELEMENT_2] ^= mullTableRow[SRC[UNROLL_ELEMENT_2]]; + dst[UNROLL_ELEMENT_3] ^= mullTableRow[SRC[UNROLL_ELEMENT_3]]; +#if (UNROLL > UNROLL_ELEMENT_4) + dst[UNROLL_ELEMENT_4] ^= mullTableRow[SRC[UNROLL_ELEMENT_4]]; + dst[UNROLL_ELEMENT_5] ^= mullTableRow[SRC[UNROLL_ELEMENT_5]]; + dst[UNROLL_ELEMENT_6] ^= mullTableRow[SRC[UNROLL_ELEMENT_6]]; + dst[UNROLL_ELEMENT_7] ^= mullTableRow[SRC[UNROLL_ELEMENT_7]]; +#endif +#if (UNROLL > UNROLL_ELEMENT_8) + dst[UNROLL_ELEMENT_8] ^= mullTableRow[SRC[UNROLL_ELEMENT_8]]; + dst[UNROLL_ELEMENT_9] ^= mullTableRow[SRC[UNROLL_ELEMENT_9]]; + dst[UNROLL_ELEMENT_10] ^= mullTableRow[SRC[UNROLL_ELEMENT_10]]; + dst[UNROLL_ELEMENT_11] ^= mullTableRow[SRC[UNROLL_ELEMENT_11]]; + dst[UNROLL_ELEMENT_12] ^= mullTableRow[SRC[UNROLL_ELEMENT_12]]; + dst[UNROLL_ELEMENT_13] ^= mullTableRow[SRC[UNROLL_ELEMENT_13]]; + dst[UNROLL_ELEMENT_14] ^= mullTableRow[SRC[UNROLL_ELEMENT_14]]; + dst[UNROLL_ELEMENT_15] ^= mullTableRow[SRC[UNROLL_ELEMENT_15]]; +#endif + } +#endif + lim += UNROLL_DEC; + for (; dst < lim; dst++, SRC++ ) + { + *dst ^= mullTableRow[*SRC]; + } +} + +void +Xor32(GstRSBase *base, guint8 **dst1, const guint8 *src1, const gint32 sz) +{ + guint32 i = 0; + gint32 j = 0; + guint32 n_32 = sz / sizeof(guint32); + guint32 n_8 = sz % sizeof(guint32); + guint32 *p_32_dst = (guint32 *)(*dst1); + const guint32 *P_32_SRC = (const guint32 *)src1; + + guint32 n_unroll = n_32 / UNROLL; + guint32 n_roll=n_32 % UNROLL; + + for(i = 0; i < n_unroll; i++, p_32_dst += UNROLL, P_32_SRC += UNROLL) + { + p_32_dst[UNROLL_ELEMENT_0] ^= P_32_SRC[UNROLL_ELEMENT_0]; + p_32_dst[UNROLL_ELEMENT_1 ]^= P_32_SRC[UNROLL_ELEMENT_1]; + p_32_dst[UNROLL_ELEMENT_2] ^= P_32_SRC[UNROLL_ELEMENT_2]; + p_32_dst[UNROLL_ELEMENT_3] ^= P_32_SRC[UNROLL_ELEMENT_3]; + p_32_dst[UNROLL_ELEMENT_4] ^= P_32_SRC[UNROLL_ELEMENT_4]; + p_32_dst[UNROLL_ELEMENT_5] ^= P_32_SRC[UNROLL_ELEMENT_5]; + p_32_dst[UNROLL_ELEMENT_6] ^= P_32_SRC[UNROLL_ELEMENT_6]; + p_32_dst[UNROLL_ELEMENT_7] ^= P_32_SRC[UNROLL_ELEMENT_7]; + + p_32_dst[UNROLL_ELEMENT_8] ^= P_32_SRC[UNROLL_ELEMENT_8]; + p_32_dst[UNROLL_ELEMENT_9] ^= P_32_SRC[UNROLL_ELEMENT_9]; + p_32_dst[UNROLL_ELEMENT_10] ^= P_32_SRC[UNROLL_ELEMENT_10]; + p_32_dst[UNROLL_ELEMENT_11] ^= P_32_SRC[UNROLL_ELEMENT_11]; + p_32_dst[UNROLL_ELEMENT_12] ^= P_32_SRC[UNROLL_ELEMENT_12]; + p_32_dst[UNROLL_ELEMENT_13] ^= P_32_SRC[UNROLL_ELEMENT_13]; + p_32_dst[UNROLL_ELEMENT_14] ^= P_32_SRC[UNROLL_ELEMENT_14]; + p_32_dst[UNROLL_ELEMENT_15] ^= P_32_SRC[UNROLL_ELEMENT_15]; + } + + for(i = 0; i < n_roll; i++) + { + p_32_dst[i] ^= P_32_SRC[i]; + } + + for(j = sz - n_8; j < sz; j++) + { + *dst1[j] ^= src1[j]; + } +} + +void +AssMul(GstRSBase *base, guint8 *dst1, const guint8 *src1, + const guint8 c, const gint32 sz) +{ + guint8 *dst = dst1; + const guint8 *SRC = (const guint8*)src1; + guint8 *lim = &dst[ (gint32)sz - UNROLL_DEC]; + guint8 *mullTableRow = base->gfMullTable[c]; +#if (UNROLL > UNROLL_ELEMENT_1) + for (; dst < lim ; dst += UNROLL, SRC += UNROLL ) + { + dst[UNROLL_ELEMENT_0] = mullTableRow[SRC[UNROLL_ELEMENT_0]]; + dst[UNROLL_ELEMENT_1] = mullTableRow[SRC[UNROLL_ELEMENT_1]]; + dst[UNROLL_ELEMENT_2] = mullTableRow[SRC[UNROLL_ELEMENT_2]]; + dst[UNROLL_ELEMENT_3] = mullTableRow[SRC[UNROLL_ELEMENT_3]]; +#if (UNROLL > UNROLL_ELEMENT_4) + dst[UNROLL_ELEMENT_4] = mullTableRow[SRC[UNROLL_ELEMENT_4]]; + dst[UNROLL_ELEMENT_5] = mullTableRow[SRC[UNROLL_ELEMENT_5]]; + dst[UNROLL_ELEMENT_6] = mullTableRow[SRC[UNROLL_ELEMENT_6]]; + dst[UNROLL_ELEMENT_7] = mullTableRow[SRC[UNROLL_ELEMENT_7]]; +#endif +#if (UNROLL > UNROLL_ELEMENT_8) + dst[UNROLL_ELEMENT_8] = mullTableRow[SRC[UNROLL_ELEMENT_8]]; + dst[UNROLL_ELEMENT_9] = mullTableRow[SRC[UNROLL_ELEMENT_9]]; + dst[UNROLL_ELEMENT_10] = mullTableRow[SRC[UNROLL_ELEMENT_10]]; + dst[UNROLL_ELEMENT_11] = mullTableRow[SRC[UNROLL_ELEMENT_11]]; + dst[UNROLL_ELEMENT_12] = mullTableRow[SRC[UNROLL_ELEMENT_12]]; + dst[UNROLL_ELEMENT_13] = mullTableRow[SRC[UNROLL_ELEMENT_13]]; + dst[UNROLL_ELEMENT_14] = mullTableRow[SRC[UNROLL_ELEMENT_14]]; + dst[UNROLL_ELEMENT_15] = mullTableRow[SRC[UNROLL_ELEMENT_15]]; +#endif + } +#endif + lim += UNROLL_DEC; + for (; dst < lim; dst++, SRC++ ) + { + *dst = mullTableRow[*SRC]; + } +} + +void +Mull(GstRSBase *base, guint8 *dst1, const guint8 c, const gint32 sz) +{ + guint8 *dst = dst1; + guint8 *lim = &dst[ (gint32)sz - UNROLL_DEC]; + guint8 *mullTableRow = base->gfMullTable[c]; +#if (UNROLL > UNROLL_ELEMENT_1) + for (; dst < lim; dst += UNROLL ) + { + dst[UNROLL_ELEMENT_0] = mullTableRow[dst[UNROLL_ELEMENT_0]]; + dst[UNROLL_ELEMENT_1] = mullTableRow[dst[UNROLL_ELEMENT_1]]; + dst[UNROLL_ELEMENT_2] = mullTableRow[dst[UNROLL_ELEMENT_2]]; + dst[UNROLL_ELEMENT_3] = mullTableRow[dst[UNROLL_ELEMENT_3]]; +#if (UNROLL > UNROLL_ELEMENT_4) + dst[UNROLL_ELEMENT_4] = mullTableRow[dst[UNROLL_ELEMENT_4]]; + dst[UNROLL_ELEMENT_5] = mullTableRow[dst[UNROLL_ELEMENT_5]]; + dst[UNROLL_ELEMENT_6] = mullTableRow[dst[UNROLL_ELEMENT_6]]; + dst[UNROLL_ELEMENT_7] = mullTableRow[dst[UNROLL_ELEMENT_7]]; +#endif +#if (UNROLL > UNROLL_ELEMENT_8) + dst[UNROLL_ELEMENT_8] = mullTableRow[dst[UNROLL_ELEMENT_8]]; + dst[UNROLL_ELEMENT_9] = mullTableRow[dst[UNROLL_ELEMENT_9]]; + dst[UNROLL_ELEMENT_10] = mullTableRow[dst[UNROLL_ELEMENT_10]]; + dst[UNROLL_ELEMENT_11] = mullTableRow[dst[UNROLL_ELEMENT_11]]; + dst[UNROLL_ELEMENT_12] = mullTableRow[dst[UNROLL_ELEMENT_12]]; + dst[UNROLL_ELEMENT_13] = mullTableRow[dst[UNROLL_ELEMENT_13]]; + dst[UNROLL_ELEMENT_14] = mullTableRow[dst[UNROLL_ELEMENT_14]]; + dst[UNROLL_ELEMENT_15] = mullTableRow[dst[UNROLL_ELEMENT_15]]; +#endif + } +#endif + lim += UNROLL_DEC; + for (; dst < lim; dst++ ) + { + *dst = mullTableRow[*dst]; + } +} + +static void +InitMulTable(GstRSBase *base) +{ + guint32 i = 0; + guint32 i2 = 0; + + for (i = 0; i < TABLE_SIZE; i++) + { + for (i2 = 0; i2 < TABLE_SIZE; i2++) + { + base->gfMullTable[i][i2] = base->priv->gfExp[ base->priv->gfLog[i] + base->priv->gfLog[i2] ]; + } + } + + memset(base->gfMullTable[0], GF_ZERO, TABLE_SIZE); + + for (i = 0; i < TABLE_SIZE; i++) + { + base->gfMullTable[i][0] = GF_ZERO; + } +} + +static void +InitDivlTable(GstRSBase *base) +{ + guint32 i = 0; + guint32 i2 = 0; + + for (i = 0; i < TABLE_SIZE; i++) + { + for (i2 = 0; i2 < TABLE_SIZE; i2++) + { + base->gfDivTable[ base->gfMullTable[i][i2] ][i] = i2; + } + } + + memset(base->gfDivTable[0], GF_ZERO, TABLE_SIZE); + + for (i = 0; i < TABLE_SIZE; i++) + { + base->gfDivTable[i][0] = GF_ZERO; + } +} + +static void +GenerateGF(GstRSBase *base) +{ + guint32 i = 0; + + // Create logarithm and exponential tables + guint32 mask = GF_ONE << GF_BITS; + guint32 alpha = 1; + base->priv->gfLog[0] = GF_SIZE; + for (i = 0; i < GF_SIZE; i++) + { + base->priv->gfExp[i] = alpha; + base->priv->gfLog[alpha] = i; + alpha <<= GF_ONE; + if (mask & alpha) + { + alpha ^= GF_POLYNOMIAL; + } + } + memcpy(&base->priv->gfExp[GF_SIZE], base->priv->gfExp, GF_SIZE); + + InitMulTable(base); + InitDivlTable(base); + + for (i = 0; i < GF_SIZE; i++) + { + base->X[i] = i; + base->Y[i] = CAUCHY_MATRIX_SIZE - i; + } + + InitCauchyMatrix(base); +} + +void +InitCauchyMatrix(GstRSBase *base) +{ + guint32 i = 0; + guint32 i2 = 0; + + // Calculate elements of Cauchy matrix + for (i = 0; i < CAUCHY_MATRIX_SIZE; i++) + { + for (i2 = 0; i2 < CAUCHY_MATRIX_SIZE - i; i2++) + { + base->cauchyMatrix[i][i2] = gfDiv(base, GF_ONE, base->X[i] ^ base->Y[i2]); + } + } +} diff --git a/alfec/feccodes/RS/RSDecoder.c b/alfec/feccodes/RS/RSDecoder.c new file mode 100755 index 0000000..29fe97c --- /dev/null +++ b/alfec/feccodes/RS/RSDecoder.c @@ -0,0 +1,369 @@ +/* + * RSDecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "RS/RSDecoder.h" +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_rs_decoder_debug); +#define GST_CAT_DEFAULT gst_rs_decoder_debug + +G_DEFINE_TYPE (GstRSDecoder, gst_rs_decoder, + GST_TYPE_FEC_DECODER); + +#define GST_RS_DECODER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RS_DECODER, GstRSDecoderPrivate)) + +#define MIN_ERASES_NUMBER 1 + +struct _GstRSDecoderPrivate +{ + guint8 **decodeMatrix; ///< Matrix for erased symbols recovering + guint32 *erasedDataSymbolPosition; ///< Array with positions of erased source symbols + guint32 *receivedDataSymbolPosition; ///< Array with positions of received source symbols + guint32 *receiveParitySymbolPosition; ///< Array with positions of erased repair symbols + guint8 *temp_arr; ///< Array to store intermediate results of calculations + guint8 decodeX[GF_SIZE]; ///< Subarray of X that is used for decode matrix construction + guint8 decodeY[GF_SIZE]; ///< Subarray of Y that is used for decode matrix construction + + guint8 *a; ///< Auxiliary array for Cauchy matrix inversion + guint8 *b; ///< Auxiliary array for Cauchy matrix inversion + guint8 *e; ///< Auxiliary array for Cauchy matrix inversion + guint8 *f; ///< Auxiliary array for Cauchy matrix inversion +}; + +static gboolean gst_rs_decoder_decode_data (GstFECDecoder *fec_dec, + guint8 **sourceSymbolsBlock, guint8 **parityBlock, guint8 *info_array, + const guint32 k, const guint32 p, void *additionalData, gboolean reorder); + +static void +gst_rs_decoder_finalize (GObject * gobject) +{ + GstRSDecoder *dec = GST_RS_DECODER(gobject); + guint32 i = 0; + + g_free (dec->priv->a); + g_free (dec->priv->b); + g_free (dec->priv->e); + g_free (dec->priv->f); + + for (i = 0; i < GST_FEC_DECODER(dec)->pmax; i++) + { + g_free (dec->priv->decodeMatrix[i]); + } + g_free (dec->priv->decodeMatrix); + g_free (dec->priv->temp_arr); + g_free (dec->priv->erasedDataSymbolPosition); + g_free (dec->priv->receivedDataSymbolPosition); + g_free (dec->priv->receiveParitySymbolPosition); + + G_OBJECT_CLASS (gst_rs_decoder_parent_class)-> + finalize (gobject); +} + +static void +gst_rs_decoder_init (GstRSDecoder * dec) +{ + GstRSDecoderPrivate *priv = + GST_RS_DECODER_GET_PRIVATE (dec); + dec->priv = priv; +} + +static void +gst_rs_decoder_class_init (GstRSDecoderClass * + dec) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (dec); + GstFECDecoderClass *fec_decoder_class = GST_FEC_DECODER_CLASS (dec); + + g_type_class_add_private (dec, sizeof (GstRSDecoderPrivate)); + + gobject_class->finalize = gst_rs_decoder_finalize; + GST_DEBUG_CATEGORY_INIT (gst_rs_decoder_debug, "gst_rsdecoder", 0, + "Read-Soloman decoder object"); + + fec_decoder_class->DecodeData = gst_rs_decoder_decode_data; +} + +GstRSDecoder * +gst_rs_decoder_new (const guint32 _kmax, const guint32 _pmax, const guint32 _t) +{ + GstRSDecoder *result = NULL; + GstFECDecoder *parent = NULL; + guint32 i = 0; + + result = g_object_new (GST_TYPE_RS_DECODER, NULL); + // Write input parameters to FECEncoder object + parent = GST_FEC_DECODER(result); + parent->kmax = _kmax; + parent->pmax = _pmax; + parent->t = _t; + + // Allocate memory for decode matrix + result->priv->decodeMatrix = g_malloc (sizeof (guint8*) * parent->pmax); + for (i = 0; i < parent->pmax; i++) + { + result->priv->decodeMatrix[i] = g_malloc (sizeof (guint8) * parent->pmax); + } + result->priv->temp_arr = g_malloc (sizeof (guint8) * parent->t); + + result->priv->erasedDataSymbolPosition = g_malloc (sizeof (guint32) * parent->kmax); + result->priv->receivedDataSymbolPosition = g_malloc (sizeof (guint32) * parent->kmax); + result->priv->receiveParitySymbolPosition = g_malloc (sizeof (guint32) * parent->pmax); + + result->priv->a = g_malloc (sizeof (guint8) * GF_SIZE); + result->priv->b = g_malloc (sizeof (guint8) * GF_SIZE); + result->priv->e = g_malloc (sizeof (guint8) * GF_SIZE); + result->priv->f = g_malloc (sizeof (guint8) * GF_SIZE); + + return result; +} + +void +InvertCauchyMatrix(GstRSDecoder *dec, const guint32 sz, guint8 **res) +{ + guint32 i = 0; + guint32 i2 = 0; + + guint8 mul1 = GF_ONE; + guint8 mul2 = GF_ONE; + guint8 mul3 = GF_ONE; + guint8 mul4 = GF_ONE; + guint8 num = GF_ONE; + guint8 den = GF_ONE; + // Method for inversion of Cauchy sub-matrixes is implemented. + for (i = 0; i < sz; i++) + { + mul1 = GF_ONE; + mul2 = GF_ONE; + mul3 = GF_ONE; + mul4 = GF_ONE; + for (i2 = 0; i2 < sz; i2++) + { + if (i2 != i) + { + mul1 = gfMul(dec->rs, dec->priv->decodeX[i2] ^ dec->priv->decodeX[i], mul1); + mul2 = gfMul(dec->rs, dec->priv->decodeY[i2] ^ dec->priv->decodeY[i], mul2); + } + mul3 = gfMul(dec->rs, dec->priv->decodeY[i2] ^ dec->priv->decodeX[i], mul3); + mul4 = gfMul(dec->rs, dec->priv->decodeX[i2] ^ dec->priv->decodeY[i], mul4); + } + dec->priv->a[i] = mul1; + dec->priv->b[i] = mul2; + dec->priv->e[i] = mul3; + dec->priv->f[i] = mul4; + } + + for (i = 0; i < sz; i++) + { + for (i2 = 0; i2 < sz; i2++) + { + num = gfMul(dec->rs, dec->priv->e[i2], dec->priv->f[i]); + den = gfMul(dec->rs, dec->priv->decodeX[i2] ^ dec->priv->decodeY[i], + dec->priv->b[i]); + den = gfMul(dec->rs, den, dec->priv->a[i2]); + res[i][i2] = gfDiv(dec->rs, num, den); + } + } +} + +gboolean +gst_rs_decoder_decode_data(GstFECDecoder *fec_dec, + guint8 **sourceSymbolsBlock, guint8 **parityBlock, guint8 *info_array, + const guint32 k, const guint32 p, void *additionalData, gboolean reorder) +{ + GstRSDecoder *dec = GST_RS_DECODER (fec_dec); + guint32 dataErrorsAmount = 0; + guint32 dataRecAmount = 0; + guint32 allErrorsAmount = 0; + guint8 *matrixRow = NULL; + guint32 i = 0; + guint32 j = 0; + guint32 i2 = 0; + + GST_INFO_OBJECT (dec, "Start RS decoding. Parameters: k = %d, p = %d\n", k, p); + if (!CheckInputParametersDecoder(fec_dec, sourceSymbolsBlock, parityBlock, + info_array, k, p, additionalData)) + { + GST_ERROR_OBJECT (dec, "Decoding was failure! Input parameters are not correct\n"); + return FALSE; + } + + /* 1. Calculate amount of errors and determine positions of erased symbols */ + for (i = 0; i < k; i++) + { + if (info_array[i] == ERASED_SYMBOL) + { + dec->priv->decodeY[dataErrorsAmount] = dec->rs->Y[i]; + dec->priv->erasedDataSymbolPosition[dataErrorsAmount++] = i; + } + else + { + dec->priv->receivedDataSymbolPosition[dataRecAmount++] = i; + } + } + + if (!dataErrorsAmount) + { + return TRUE; + } + + // Visual positions of erased symbols + GST_DEBUG_OBJECT (dec, "Positions of erased symbols:"); + for (i = 0; i < k + p; i++) + { + if (info_array[i] == ERASED_SYMBOL) + { + GST_DEBUG_OBJECT (dec, "Positions of erased symbols: %d", i); + } + } + + allErrorsAmount = dataErrorsAmount; + for (i = 0, i2 = 0; i < p; i++) + { + if(info_array[k + i] == RECEIVED_SYMBOL) + { + dec->priv->decodeX[i2] = dec->rs->X[i]; + dec->priv->receiveParitySymbolPosition[i2++] = i; + } + else + { + allErrorsAmount++; + } + } + + if (allErrorsAmount > p) + { + GST_ERROR_OBJECT (dec, "Decoding was failure! Number of erased symbols (%d) is" + " more than number of repair symbols (%d)\n", allErrorsAmount, p); + return FALSE; + } + + /* 3. Invert Cauchy sub-matrix */ + InvertCauchyMatrix(dec, dataErrorsAmount, dec->priv->decodeMatrix); + + if (dataErrorsAmount > MIN_ERASES_NUMBER) + { + // 4. Update parity symbols + for (i = 0; i < dataErrorsAmount; i++) + { + matrixRow = dec->rs->cauchyMatrix[dec->priv->receiveParitySymbolPosition[i]]; + + guint8 r0 = dec->priv->receivedDataSymbolPosition[0]; + guint8 r1 = dec->priv->receivedDataSymbolPosition[1]; + guint8 mult_koeff = dec->rs->gfDivTable[matrixRow[r0]][matrixRow[r1]]; + + AssMul(dec->rs, dec->priv->temp_arr, sourceSymbolsBlock[r0], mult_koeff, + fec_dec->t); + Xor32(dec->rs, &dec->priv->temp_arr, sourceSymbolsBlock[r1], fec_dec->t); + for (j = 2; j < dataRecAmount; j++) + { + r0 = dec->priv->receivedDataSymbolPosition[j - MIN_ERASES_NUMBER]; + r1 = dec->priv->receivedDataSymbolPosition[j]; + mult_koeff=dec->rs->gfDivTable[matrixRow[r0]][matrixRow[r1]]; + + Mull(dec->rs, dec->priv->temp_arr, mult_koeff, fec_dec->t); + Xor32(dec->rs, &dec->priv->temp_arr, sourceSymbolsBlock[r1],fec_dec->t); + } + mult_koeff = matrixRow[dec->priv->receivedDataSymbolPosition[dataRecAmount - MIN_ERASES_NUMBER]]; + Mull(dec->rs, dec->priv->temp_arr,mult_koeff, fec_dec->t); + Xor32(dec->rs, &parityBlock[dec->priv->receiveParitySymbolPosition[i]], + dec->priv->temp_arr, fec_dec->t); + } + + // 5. Reconstruct erasure symbols + for (i = 0; i < dataErrorsAmount; i++) + { + matrixRow = dec->priv->decodeMatrix[i]; + guint8 *restored_symbol=sourceSymbolsBlock[dec->priv->erasedDataSymbolPosition[i]]; + guint8 r0 = dec->priv->receiveParitySymbolPosition[0]; + guint8 r1 = dec->priv->receiveParitySymbolPosition[1]; + guint8 mult_koeff = dec->rs->gfDivTable[matrixRow[0]][matrixRow[1]]; + + AssMul(dec->rs, restored_symbol, parityBlock[r0],mult_koeff, fec_dec->t); + Xor32(dec->rs, &restored_symbol, parityBlock[r1], fec_dec->t); + for (j = 2; j < dataErrorsAmount; j++) + { + r1=dec->priv->receiveParitySymbolPosition[j]; + mult_koeff = dec->rs->gfDivTable[matrixRow[j - MIN_ERASES_NUMBER]][matrixRow[j]]; + Mull(dec->rs, restored_symbol,mult_koeff, fec_dec->t); + Xor32(dec->rs, &restored_symbol, parityBlock[r1], fec_dec->t); + } + mult_koeff = matrixRow[dataErrorsAmount - MIN_ERASES_NUMBER]; + Mull(dec->rs, restored_symbol, mult_koeff, fec_dec->t); + } + } + else + { + // 4. Update parity symbols + matrixRow = dec->rs->cauchyMatrix[dec->priv->receiveParitySymbolPosition[0]]; + for (i = 0; i < dataRecAmount; i++) + { + guint32 i2 = dec->priv->receivedDataSymbolPosition[i]; + AddMul(dec->rs, &parityBlock[dec->priv->receiveParitySymbolPosition[0]], + sourceSymbolsBlock[i2], matrixRow[i2], fec_dec->t); + } + // 5. Reconstruct erasure symbols + memset(sourceSymbolsBlock[dec->priv->erasedDataSymbolPosition[0]], GF_ZERO, + fec_dec->t); + matrixRow = dec->priv->decodeMatrix[0]; + AddMul(dec->rs, &sourceSymbolsBlock[dec->priv->erasedDataSymbolPosition[0]], + parityBlock[dec->priv->receiveParitySymbolPosition[0]],matrixRow[0], fec_dec->t); + } + + GST_INFO_OBJECT (dec, "Decoding was successful\n"); + if (!reorder) { + return TRUE; + } + + // 6. Update info array + for (i = 0; i < dataErrorsAmount; i++) + { + info_array[dec->priv->erasedDataSymbolPosition[i]] = RECEIVED_SYMBOL; + } + + return TRUE; +} diff --git a/alfec/feccodes/RS/RSEncoder.c b/alfec/feccodes/RS/RSEncoder.c new file mode 100755 index 0000000..62251ca --- /dev/null +++ b/alfec/feccodes/RS/RSEncoder.c @@ -0,0 +1,163 @@ +/* + * RSEncoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "RS/RSEncoder.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_rs_encoder_debug); +#define GST_CAT_DEFAULT gst_rs_encoder_debug + +G_DEFINE_TYPE (GstRSEncoder, gst_rs_encoder, + GST_TYPE_FEC_ENCODER); + +static void gst_rs_encoder_set_parity_block(GstFECEncoder *enc, const guint32 k, + const guint32 p, guint8 **parityBlock); + +static gboolean gst_rs_encoder_encode_data(GstFECEncoder *enc, + guint8 *sourceSymbol, gboolean *is_computed); + +static guint8 gst_rs_encoder_get_symbol_number(GstFECEncoder *enc); + +static void +gst_rs_encoder_finalize (GObject * gobject) +{ + G_OBJECT_CLASS (gst_rs_encoder_parent_class)-> + finalize (gobject); +} + +static void +gst_rs_encoder_init (GstRSEncoder * enc) +{ +} + +static void +gst_rs_encoder_class_init (GstRSEncoderClass * + enc) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (enc); + GstFECEncoderClass *fec_encoder_class = GST_FEC_ENCODER_CLASS (enc); + + gobject_class->finalize = gst_rs_encoder_finalize; + + GST_DEBUG_CATEGORY_INIT (gst_rs_encoder_debug, "gst_rsencoder", 0, + "Read-Solomon encoder object"); + + fec_encoder_class->EncodeData = gst_rs_encoder_encode_data; + fec_encoder_class->set_parity_block = gst_rs_encoder_set_parity_block; + fec_encoder_class->get_symbol_number = gst_rs_encoder_get_symbol_number; +} + +GstRSEncoder * +gst_rs_encoder_new (const guint32 _kmax, const guint32 _pmax, const guint32 _t) +{ + GstRSEncoder *result = NULL; + GstFECEncoder *parent = NULL; + + result = g_object_new (GST_TYPE_RS_ENCODER, NULL); + // Write input parameters to FECEncoder object + parent = GST_FEC_ENCODER(result); + parent->kmax = _kmax; + parent->pmax = _pmax; + parent->t = _t; + + return result; +} + +void gst_rs_encoder_set_parity_block(GstFECEncoder *enc, const guint32 k, const guint32 p, + guint8 **parityBlock) +{ + GstRSEncoder *rs_enc = GST_RS_ENCODER (enc); + guint i = 0; + rs_enc->current_k = k; + rs_enc->current_p = p; + rs_enc->parityBlock = parityBlock; + rs_enc->number_of_symbol = 0; + for (i = 0; i < p; i++) { + memset(rs_enc->parityBlock[i], GF_ZERO, enc->t * sizeof(guint8)); + } +} + + +static gboolean +gst_rs_encoder_encode_data(GstFECEncoder *enc, + guint8 *sourceSymbol, gboolean *is_computed) +{ + guint32 i = 0; + GstRSEncoder *rs_enc = GST_RS_ENCODER (enc); + GstRSBase *rs = rs_enc->rs; + // Check if input parameters are correct + if (!CheckInputParameters(enc, &sourceSymbol, rs_enc->parityBlock, rs_enc->current_k, rs_enc->current_p)) { + return FALSE; + } + + if (rs_enc->number_of_symbol == rs_enc->current_k) { + GST_WARNING_OBJECT (enc, "Symbol block is full, pass new parity block for processing"); + return FALSE; + } + + // Construct parity symbol block + for (i = 0; i < rs_enc->current_p; i++) + { + guint8 *matrixRow = NULL; + matrixRow = rs->cauchyMatrix[i]; + AddMul(rs, &rs_enc->parityBlock[i], sourceSymbol, matrixRow[rs_enc->number_of_symbol], enc->t); + } + + rs_enc->number_of_symbol++; + if (rs_enc->number_of_symbol == rs_enc->current_k) { + *is_computed = TRUE; + } else { + *is_computed = FALSE; + } + + return TRUE; +} + +static guint8 gst_rs_encoder_get_symbol_number (GstFECEncoder *enc) +{ + GstRSEncoder *rs_enc = GST_RS_ENCODER (enc); + return rs_enc->number_of_symbol; +} diff --git a/alfec/feccodes/include/FECCodes.h b/alfec/feccodes/include/FECCodes.h new file mode 100755 index 0000000..76fdd01 --- /dev/null +++ b/alfec/feccodes/include/FECCodes.h @@ -0,0 +1,128 @@ +/* + * FECCodes + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _FECCODES_H_ +#define _FECCODES_H_ + +#include + +#define CODE_ID_RS 0 + +/** + * @brief Function for FEC code instance initialization + * @param [in] kmax - maximum number of source symbol in a block (kmax>0) + * @param [in] pmax - maximum number of parity symbols in a block (pmax>=0) + * @param [in] t - length of block symbol in bytes (t>0) + * @param [in] isEncoder - role of initialized FEC code (0 - decoder; 1 - encoder) + * @param [in] codeTypeID - type of FEC code + * CODE_ID_RS = 0 + * @param [in] additionalData - additional data for FEC code initialization + * @return id > 0 of the created FEC code instance, 0 if some error was occurred + * @exception N/A + */ +guint8 FECCodes_Initialize(guint8 const *kmax, guint8 const *pmax, guint32 const *t, + guint8 const *isEncoder, guint8 const *codeTypeID, void *additionalData); + +/** + * @brief Set parity block for further encoding with FECCodes_Encode_single_symbol + * @param parityBlock pointer to repair symbol block + * @param k - number of source symbols in the block (k<=kmax) + * @param p - required number of generated repair symbols (p<=pmax) + * @param encoderObjectID - id of used FEC code instance + * @exception N/A + */ +void FECCodes_set_parity_block (guint8 **parityBlock, guint8 const *k, + guint8 const *p, const guint8 *encoderObjectID); + +/** + * @brief Function for FEC block encoding + * you should pass parity_block with FECCodes_set_parity_block before + * processing symbol block; + * then consequently pass source packets, after last packet + * passed is_computed is set to true + * @param sourceSymbol - pointer to Source symbol + * @param is_computed - set to true if last packet was processed + * @param encoderObjectID - id of used FEC code instance + * @return true if encoding was succesful, false - otherwise + * @exception N/A + */ +gboolean FECCodes_Encode_single_symbol(guint8 *sourceSymbol, + gboolean *is_computed, const guint8 *encoderObjectID); + +/** + * @brief Get current number of processed symbols for encoder + * @param encoderObjectID - id of used FEC code instance + * @return current number of processed symbols + * @exception N/A + */ +guint8 FECCodes_get_encoder_symbol_number(const guint8 *encoderObjectID); + +/** + * @brief Function for FEC block decoding + * @param [in,out] sourceBlock - pointer to Source Symbols block + * @param [in,out] parityBlock - pointer to Repair Symbols block + * @param [in,out] infoArray - array with information about existing of the corresponding symbols in FEC block. + * Size of infoArray is k+p, infoArray[i] = 1 if i-th symbol is existed, 0 if not + * @param [in] k - number of source symbols in the block (k<=kmax) + * @param [in] p - required number of generated repair symbols (p<=pmax) + * @param [in] decoderObjectID - id of used FEC code instance + * @param [in] additionalData - additional data for decoding. + * @return 1 if all lost Source Symbols were recovered, 0 if not all lost Source Symbols were recovered, + * -1 if some error was occurred + * @exception N/A + */ +gchar FECCodes_DecodeData(guint8 **sourceBlock, guint8 **parityBlock, guint8 *infoArray, const guint8 *k, + guint8 const *p, guint8 const *decoderObjectID, void *additionalData, gboolean reorder); + +/** + * @brief Function for FEC code instance deinitialization + * @param [in] codeInstanseID - id of the deinitialized FEC code instance + * @return 0 if FEC code instance was deinitialized, -1 if some error was occurred + * @exception N/A + */ +gboolean FECCodes_Deinitialize(guint8 const *codeInstanseID); + +#endif /* _FECCODES_H_ */ diff --git a/alfec/feccodes/include/FecDecoder.h b/alfec/feccodes/include/FecDecoder.h new file mode 100755 index 0000000..b16840f --- /dev/null +++ b/alfec/feccodes/include/FecDecoder.h @@ -0,0 +1,99 @@ +/* + * FecDecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _FECDECODER_H_ +#define _FECDECODER_H_ + +#include + +G_BEGIN_DECLS + +#define ERASED_SYMBOL 0 +#define RECEIVED_SYMBOL 1 + +#define GST_TYPE_FEC_DECODER\ + (gst_fec_decoder_get_type ()) +#define GST_FEC_DECODER(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FEC_DECODER, GstFECDecoder)) +#define GST_IS_FEC_DECODEF(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FEC_DECODER)) +#define GST_FEC_DECODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FEC_DECODER, GstFECDecoderClass)) +#define GST_IS_FEC_DECODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FEC_DECODER)) +#define GST_FEC_DECODER_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_FEC_DECODER, GstFECDecoderClass)) + +typedef struct _GstFECDecoder GstFECDecoder; +typedef struct _GstFECDecoderClass GstFECDecoderClass; + +struct _GstFECDecoder +{ + GObject parent_instance; + guint32 kmax; ///< Maximum number of source symbols in a source symbol block + + guint32 pmax; ///< Maximum number of repair symbols in a repair symbol block + + guint32 t; ///< Length of source/repair symbol in bytes + + void *initialData; ///< Additional data for decoder initialization for future usage +}; + +struct _GstFECDecoderClass +{ + GObjectClass parent_class; + gboolean (*DecodeData)(GstFECDecoder *dec, guint8 **sourceBlock, guint8 **parityBlock, guint8 *infoArray, + const guint32 k, const guint32 p, void *additionalData, gboolean reorder); +}; + +GType gst_fec_decoder_get_type (void); + +gboolean CheckInputParametersDecoder(GstFECDecoder *dec, guint8 **sourceBlock, guint8 **parityBlock, guint8 *infoArray, + const guint32 k, const guint32 p, void *additionalData); + +G_END_DECLS + +#endif /* _FECDECODER_H_ */ diff --git a/alfec/feccodes/include/FecEncoder.h b/alfec/feccodes/include/FecEncoder.h new file mode 100755 index 0000000..267d0c4 --- /dev/null +++ b/alfec/feccodes/include/FecEncoder.h @@ -0,0 +1,114 @@ +/* + * FecEncoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _FECENCODER_H_ +#define _FECENCODER_H_ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_FEC_ENCODER\ + (gst_fec_encoder_get_type ()) +#define GST_FEC_ENCODER(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FEC_ENCODER, GstFECEncoder)) +#define GST_IS_FEC_ENCODEF(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FEC_ENCODER)) +#define GST_FEC_ENCODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FEC_ENCODER, GstFECEncoderClass)) +#define GST_IS_FEC_ENCODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FEC_ENCODER)) +#define GST_FEC_ENCODER_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_FEC_ENCODER, GstFECEncoderClass)) + +typedef struct _GstFECEncoder GstFECEncoder; +typedef struct _GstFECEncoderClass GstFECEncoderClass; + +struct _GstFECEncoder +{ + GObject parent_instance; + /** + * Maximum number of source symbols in a source symbol block + */ + guint32 kmax; + + /** + * Maximum number of repair symbols in a repair symbol block + */ + guint32 pmax; + + /** + * Length of source/repair symbol in bytes + */ + guint32 t; +}; + +struct _GstFECEncoderClass +{ + GObjectClass parent_class; + /* vmethods */ + void (*set_parity_block) (GstFECEncoder *enc, const guint32 k, const guint32 p, + guint8 **parityBlock); + gboolean (*EncodeData) (GstFECEncoder *enc, guint8 *sourceSymbol, + gboolean *is_computed); + guint8 (*get_symbol_number) (GstFECEncoder *enc); +}; + +GType gst_fec_encoder_get_type (void); + +/** + * @brief Function checks that input parameters are correct. + * @param [in] sourceSymbolBlock Source symbol block + * @param [in] k Number of source symbols in the source symbol block + * @param [in] p Number of repair symbols in the repair symbol block + * @return TRUE if input parameters are correct, FALSE - otherwise + * @exception N/A + */ +gboolean CheckInputParameters(GstFECEncoder *enc, guint8 **sourceSymbolBlock, + guint8 **parityBlock, const guint32 k, const guint32 p); + +G_END_DECLS +#endif /* _FECENCODER_H_ */ diff --git a/alfec/feccodes/include/RS/RSBase.h b/alfec/feccodes/include/RS/RSBase.h new file mode 100755 index 0000000..0a7f580 --- /dev/null +++ b/alfec/feccodes/include/RS/RSBase.h @@ -0,0 +1,109 @@ +/* + * RSBase + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _RSBASE_H_ +#define _RSBASE_H_ + +#include + +G_BEGIN_DECLS + +#include + +#define GF_BITS 8 ///< Number of bits for element of the Galois field +#define GF_SIZE ((1 << GF_BITS) - 1) ///< Maximal value of element of the Galois field +#define TABLE_SIZE (GF_SIZE + 1) ///< Number of elements in the Galois field +#define GF_POLYNOMIAL 0x011d ///< Polynomial for Galois field construction +#define CAUCHY_MATRIX_SIZE (GF_SIZE - 1) ///< Number of rows in the Cauchy matrix +#define GF_EXP_TABLE_SIZE (2 * TABLE_SIZE) ///< Size of exponential table +#define GF_ZERO 0 ///< Value of zero element in the Galois field +#define GF_ONE 1 ///< Value of identity element in the Galois field + +#define GST_TYPE_RS_BASE\ + (gst_rs_base_get_type ()) +#define GST_RS_BASE(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RS_BASE, GstRSBase)) +#define GST_IS_RS_BASE(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RS_BASE)) +#define GST_RS_BASE_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RS_BASE, GstRSBaseClass)) +#define GST_IS_RS_BASE_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RS_BASE)) +#define GST_RS_BASE_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RS_BASE, GstRSBaseClass)) + +typedef struct _GstRSBase GstRSBase; +typedef struct _GstRSBaseClass GstRSBaseClass; +typedef struct _GstRSBasePrivate GstRSBasePrivate; + +struct _GstRSBase +{ + GObject parent_instance; + guint8 **gfMullTable; ///< Table for fast multiplication of two elements in the Galois field ( a*b = gfMullTable[a][b]) + guint8 **gfDivTable; ///< Table for fast division of two elements in the Galois field (a/b = gfMullTable[a][b]) + guint8 *X; ///< Array for Cauchy matrix construction + guint8 *Y; ///< Array for Cauchy matrix construction + guint8 **cauchyMatrix; ///< Cauchy matrix + GstRSBasePrivate *priv; +}; + +struct _GstRSBaseClass +{ + GObjectClass parent_class; +}; + +GType gst_rs_base_get_type (void); + +guint8 gfDiv(GstRSBase *base, const guint8 dividend, const guint8 divisor); +guint8 gfMul(GstRSBase *base, const guint8 mul1, const guint8 mul2); +void AddMul(GstRSBase *base, guint8 **dst1, const guint8 *src1, const guint8 c, const gint32 sz); +void Xor32(GstRSBase *base, guint8 **dst1, const guint8 *src1, const gint32 sz); +void Mull(GstRSBase *base, guint8 *dst1, const guint8 c, const gint32 sz); +void AssMul(GstRSBase *base, guint8 *dst1, const guint8 *src1, const guint8 c, const gint32 sz); +void InitCauchyMatrix(GstRSBase *base); + +G_END_DECLS +#endif /* _RSBASE_H_ */ diff --git a/alfec/feccodes/include/RS/RSDecoder.h b/alfec/feccodes/include/RS/RSDecoder.h new file mode 100755 index 0000000..625548d --- /dev/null +++ b/alfec/feccodes/include/RS/RSDecoder.h @@ -0,0 +1,96 @@ +/* + * RSDecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _RSDECODER_H_ +#define _RSDECODER_H_ + +// Include base parent class of FEC decoder +#include "FecDecoder.h" + +// Include base parent class with implementation of the Galois field operations +#include "RSBase.h" +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RS_DECODER\ + (gst_rs_decoder_get_type ()) +#define GST_RS_DECODER(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RS_DECODER, GstRSDecoder)) +#define GST_IS_RS_DECODEF(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RS_DECODER)) +#define GST_RS_DECODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RS_DECODER, GstRSDecoderClass)) +#define GST_IS_RS_DECODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RS_DECODER)) +#define GST_RS_DECODER_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RS_DECODER, GstRSDecoderClass)) + +typedef struct _GstRSDecoder GstRSDecoder; +typedef struct _GstRSDecoderClass GstRSDecoderClass; +typedef struct _GstRSDecoderPrivate GstRSDecoderPrivate; + +struct _GstRSDecoder +{ + GstFECDecoder parent_instance; + GstRSBase *rs; + GstRSDecoderPrivate *priv; +}; + +struct _GstRSDecoderClass +{ + GstFECDecoderClass parent_class; +}; + +GType gst_rs_decoder_get_type (void); + +GstRSDecoder * gst_rs_decoder_new (const guint32 _kmax, const guint32 _pmax, const guint32 _t); + +void InvertCauchyMatrix(GstRSDecoder *dec, const guint32 sz, guint8 **res); + +G_END_DECLS + +#endif /* _RSDECODER_H_ */ diff --git a/alfec/feccodes/include/RS/RSEncoder.h b/alfec/feccodes/include/RS/RSEncoder.h new file mode 100755 index 0000000..35fd8ee --- /dev/null +++ b/alfec/feccodes/include/RS/RSEncoder.h @@ -0,0 +1,96 @@ +/* + * RSEncoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _RSENCODER_H_ +#define _RSENCODER_H_ + +// Include base parent class of FEC encoder +#include "FecEncoder.h" + +// Include base parent class with implementation of the Galois field operations +#include "RSBase.h" +#include + +G_BEGIN_DECLS + +#define GST_TYPE_RS_ENCODER\ + (gst_rs_encoder_get_type ()) +#define GST_RS_ENCODER(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RS_ENCODER, GstRSEncoder)) +#define GST_IS_RS_ENCODEF(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RS_ENCODER)) +#define GST_RS_ENCODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RS_ENCODER, GstRSEncoderClass)) +#define GST_IS_RS_ENCODER_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RS_ENCODER)) +#define GST_RS_ENCODER_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RS_ENCODER, GstRSEncoderClass)) + +typedef struct _GstRSEncoder GstRSEncoder; +typedef struct _GstRSEncoderClass GstRSEncoderClass; + +struct _GstRSEncoder +{ + GstFECEncoder parent_instance; + GstRSBase *rs; + guint32 current_k; + guint32 current_p; + guint32 number_of_symbol; + guint8 **parityBlock; +}; + +struct _GstRSEncoderClass +{ + GstFECEncoderClass parent_class; +}; + +GType gst_rs_encoder_get_type (void); + +GstRSEncoder * gst_rs_encoder_new (const guint32 _kmax, const guint32 _pmax, const guint32 _t); + +G_END_DECLS + +#endif /* _RSENCODER_H_ */ diff --git a/alfec/gst_source_blocking_algorithm.c b/alfec/gst_source_blocking_algorithm.c new file mode 100755 index 0000000..56a0607 --- /dev/null +++ b/alfec/gst_source_blocking_algorithm.c @@ -0,0 +1,245 @@ +/* + * gst_source_blocking_algorithm + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst_source_blocking_algorithm.h" +#include "string.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_source_blocking_debug); +#define GST_CAT_DEFAULT gst_source_blocking_debug + +G_DEFINE_TYPE (GstSourceBlockingAlgorithm, gst_source_blocking_algorithm, + G_TYPE_OBJECT); + +#define GST_SOURCE_BLOCKING_ALGORITHM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SOURCE_BLOCKING_ALGORITHM, GstSourceBlockingAlgorithmPrivate)) + + +struct _GstSourceBlockingAlgorithmPrivate +{ + GstBuffer **buffers; //block for storing consecutive buffers + GstMapInfo *buf_info_array; //info array for mapping buffers into guint8** + guint32 t_max; //max size of processed packet + guint8 number_of_processed_packets; //current number of processed packets + guint8 k_max; //max number of packets in block + guint8 k_current; //number of packets that will be included in current block + guint8 k_next; //number of packets that will be included in next block + gst_source_block_cb get_block_cb; //callback for processing source block + //(when it is filled with packets) + void *user_data; //user data passed to callback +}; + +static void +gst_source_blocking_algorithm_finalize (GObject * gobject) +{ + GstSourceBlockingAlgorithm *self = GST_SOURCE_BLOCKING_ALGORITHM (gobject); + + if (self->priv->buffers != NULL) { + int i = 0; + for (i = 0; i < self->priv->number_of_processed_packets; ++i) { + gst_buffer_unref (self->priv->buffers[i]); + } + g_free (self->priv->buffers); + g_free (self->priv->buf_info_array); + } + + G_OBJECT_CLASS (gst_source_blocking_algorithm_parent_class)-> + finalize (gobject); +} + +static void +gst_source_blocking_algorithm_init (GstSourceBlockingAlgorithm * self) +{ + GstSourceBlockingAlgorithmPrivate *priv = + GST_SOURCE_BLOCKING_ALGORITHM_GET_PRIVATE (self); + self->priv = priv; + + self->priv->buffers = NULL; + self->priv->buf_info_array = NULL; + self->priv->t_max = 0; + self->priv->k_current = 0; + self->priv->k_max = 0; + self->priv->k_next = 0; + self->priv->get_block_cb = NULL; + self->priv->user_data = NULL; + + self->priv->number_of_processed_packets = 0; +} + +static void +gst_source_blocking_algorithm_class_init (GstSourceBlockingAlgorithmClass * + self) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (self); + g_type_class_add_private (self, sizeof (GstSourceBlockingAlgorithmPrivate)); + + gobject_class->finalize = gst_source_blocking_algorithm_finalize; + GST_DEBUG_CATEGORY_INIT (gst_source_blocking_debug, "gst_sourceblocking", 0, + "GstSource Blocking Algorithm for FEC"); +} + +gboolean +gst_SBA_set_initial_parameters (GstSourceBlockingAlgorithm * self, guint32 t_max, + guint8 k, gst_source_block_cb get_block_cb, void *user_data) +{ + if (self->priv->buffers != NULL) { + GST_WARNING_OBJECT (self, "initial parameters are already set"); + return FALSE; + } + + if (t_max != 0 && k != 0) { + self->priv->buffers = g_malloc (sizeof (GstBuffer *) * k); + if (self->priv->buffers == NULL) { + GST_ERROR_OBJECT (self, "g_malloc didn't allocate memory"); + return FALSE; + } + self->priv->buf_info_array = g_malloc (sizeof (GstMapInfo) * k); + if (self->priv->buf_info_array == NULL) { + GST_ERROR_OBJECT (self, "g_malloc didn't allocate memory"); + return FALSE; + } + + self->priv->k_max = k; + self->priv->k_current = k; + self->priv->k_next = k; + self->priv->t_max = t_max; + self->priv->get_block_cb = get_block_cb; + self->priv->user_data = user_data; + } else { + GST_WARNING_OBJECT (self, "input parameters should be non-zero"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, + "source blocking algorithm initial parameters are set"); + return TRUE; +} + +gboolean +gst_SBA_set_next_number_of_packets (GstSourceBlockingAlgorithm * self, guint8 k) +{ + if (k > 0 && k <= self->priv->k_max) { + self->priv->k_next = k; + } else { + GST_WARNING_OBJECT (self, "k parameter should be in [1..k_max] range"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, "k parameter is set for next source block"); + + return TRUE; +} + +void +process_buffer_block (GstSourceBlockingAlgorithm *self) +{ + int i = 0; + guint8 **source_block = g_malloc (self->priv->number_of_processed_packets * + sizeof (guint8 *)); + for (i = 0; i < self->priv->number_of_processed_packets; ++i) { + gst_buffer_map (self->priv->buffers[i], &self->priv->buf_info_array[i], + GST_MAP_READ); + source_block[i] = self->priv->buf_info_array[i].data; + } + + self->priv->get_block_cb (source_block, + self->priv->number_of_processed_packets, self->priv->user_data); + + for (i = 0; i < self->priv->number_of_processed_packets; ++i) { + gst_buffer_unmap (self->priv->buffers[i], &self->priv->buf_info_array[i]); + gst_buffer_unref (self->priv->buffers[i]); + } + + self->priv->number_of_processed_packets = 0; + + g_free (source_block); +} + + +gboolean +gst_SBA_pass_next_packet (GstSourceBlockingAlgorithm * self, GstBuffer *buffer) +{ + if (self->priv->buffers == NULL) { + GST_ERROR_OBJECT (self, + "initial parameters should be set before passing packets"); + return FALSE; + } + + if (gst_buffer_get_size(buffer) != self->priv->t_max) { + GST_ERROR_OBJECT (self, "size of packet is not equal t_max"); + return FALSE; + } + + //copy buffer to source block + self->priv->buffers[self->priv-> + number_of_processed_packets] = buffer; + self->priv->number_of_processed_packets++; + + //if source block is full, process it with callback + if (self->priv->number_of_processed_packets == self->priv->k_current) { + GST_DEBUG_OBJECT (self, "%d packets passed, source block is completed", + self->priv->k_current); + process_buffer_block (self); + self->priv->k_current = self->priv->k_next; + } + + GST_DEBUG_OBJECT (self, "packet is passed"); + + return TRUE; +} + +gboolean gst_SBA_set_eos (GstSourceBlockingAlgorithm *self) +{ + if (self->priv->number_of_processed_packets == 0) { + //there is no unsent packets + return TRUE; + } + + GST_DEBUG_OBJECT (self, "only %d packets passed due to EOS", + self->priv->number_of_processed_packets); + process_buffer_block (self); + return TRUE; +} diff --git a/alfec/gst_source_blocking_algorithm.h b/alfec/gst_source_blocking_algorithm.h new file mode 100755 index 0000000..1a148df --- /dev/null +++ b/alfec/gst_source_blocking_algorithm.h @@ -0,0 +1,115 @@ +/* + * gst_source_blocking_algorithm + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_SOURCE_BLOCKING_ALGORITHM_H__ +#define __GST_SOURCE_BLOCKING_ALGORITHM_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_SOURCE_BLOCKING_ALGORITHM\ + (gst_source_blocking_algorithm_get_type ()) +#define GST_SOURCE_BLOCKING_ALGORITHM(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SOURCE_BLOCKING_ALGORITHM, GstSourceBlockingAlgorithm)) +#define GST_IS_SOURCE_BLOCKING_ALGORITHM(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SOURCE_BLOCKING_ALGORITHM)) +#define GST_SOURCE_BLOCKING_ALGORITHM_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SOURCE_BLOCKING_ALGORITHM, GstSourceBlockingAlgorithmClass)) +#define GST_IS_SOURCE_BLOCKING_ALGORITHM_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SOURCE_BLOCKING_ALGORITHM)) +#define GST_SOURCE_BLOCKING_ALGORITHM_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SOURCE_BLOCKING_ALGORITHM, GstSourceBlockingAlgorithmClass)) + +typedef struct _GstSourceBlockingAlgorithm GstSourceBlockingAlgorithm; +typedef struct _GstSourceBlockingAlgorithmClass GstSourceBlockingAlgorithmClass; +typedef struct _GstSourceBlockingAlgorithmPrivate GstSourceBlockingAlgorithmPrivate; +typedef void (*gst_source_block_cb)( + guint8 **gst_source_symbol_block, + guint8 k, + void *user_data); + +struct _GstSourceBlockingAlgorithm +{ + GObject parent_instance; + + GstSourceBlockingAlgorithmPrivate *priv; +}; + +struct _GstSourceBlockingAlgorithmClass +{ + GObjectClass parent_class; +}; + +/* used by GST_TYPE_SOURCE_BLOCKING_ALGORITHM */ +GType gst_source_blocking_algorithm_get_type (void); + +/* Set initial parameters for algorithm. + This function should be called one time */ +gboolean gst_SBA_set_initial_parameters( + GstSourceBlockingAlgorithm *self, + guint32 t_max, + guint8 k_max, + gst_source_block_cb get_block_cb, + void *user_data); + +/* Set k number (number of packets in source block) for next source block */ +gboolean gst_SBA_set_next_number_of_packets( + GstSourceBlockingAlgorithm *self, + guint8 k_next); + +/* Pass packet to source block, data is copied */ +gboolean gst_SBA_pass_next_packet( + GstSourceBlockingAlgorithm *self, + GstBuffer *buffer); + +/* trigger source block sending due to end of stream */ +gboolean gst_SBA_set_eos( + GstSourceBlockingAlgorithm *self); + +G_END_DECLS + +#endif /* __GST_SOURCE_BLOCKING_ALGORITHM_H__ */ diff --git a/alfec/gst_source_deblocking_algorithm.c b/alfec/gst_source_deblocking_algorithm.c new file mode 100755 index 0000000..2973a2a --- /dev/null +++ b/alfec/gst_source_deblocking_algorithm.c @@ -0,0 +1,312 @@ +/* + * gst_source_deblocking_algorithm + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst_source_deblocking_algorithm.h" +#include "string.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_source_deblocking_debug); +#define GST_CAT_DEFAULT gst_source_deblocking_debug + +G_DEFINE_TYPE (GstSourceDeblockingAlgorithm, gst_source_deblocking_algorithm, + G_TYPE_OBJECT); + +#define GST_SOURCE_DEBLOCKING_ALGORITHM_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM, GstSourceDeblockingAlgorithmPrivate)) + +const guint8 max_block_delay = 3; + + +struct _GstSourceDeblockingAlgorithmPrivate +{ + GstBuffer **source_symbol_block; //block for storing original packets + GstBuffer **repair_symbol_block; //block for storing repair packets + guint8 *info_array; //array of indices of transmitted packets; + //1 - for transmitted packets, 0 - for lost + guint32 t_max; //max size of processed packet + guint8 number_of_block; //current number of processed symbol block, + //-1 if there wasn't any block passed yet + guint8 k_max; //max number of packets in source block + guint8 k_current; //current number of packets in soure block + guint8 p_max; //max number of packets in repair block + guint8 p_current; //current number of packets in repair block + gst_SDA_block_cb get_block_cb; //callback for processing source and repair block + GstBufferPool *pool; // buffer pool for allocating lost buffers + //(when it is filled with packets) + void *user_data; //user data passed to callback +}; + +static void +gst_source_deblocking_algorithm_finalize (GObject * gobject) +{ + GstSourceDeblockingAlgorithm *self = + GST_SOURCE_DEBLOCKING_ALGORITHM (gobject); + + g_object_unref(self->priv->pool); + if (self->priv->source_symbol_block != NULL) { + + g_free (self->priv->source_symbol_block); + g_free (self->priv->repair_symbol_block); + g_free (self->priv->info_array); + } + + G_OBJECT_CLASS (gst_source_deblocking_algorithm_parent_class)->finalize + (gobject); +} + +static void +gst_source_deblocking_algorithm_init (GstSourceDeblockingAlgorithm * self) +{ + GstSourceDeblockingAlgorithmPrivate *priv = + GST_SOURCE_DEBLOCKING_ALGORITHM_GET_PRIVATE (self); + self->priv = priv; + + self->priv->source_symbol_block = NULL; + self->priv->repair_symbol_block = NULL; + self->priv->info_array = NULL; + self->priv->number_of_block = 0; + self->priv->t_max = 0; + self->priv->k_max = 0; + self->priv->k_current = 0; + self->priv->p_max = 0; + self->priv->p_current = 0; + self->priv->get_block_cb = NULL; + self->priv->user_data = NULL; + self->priv->pool = gst_buffer_pool_new (); +} + +static void +gst_source_deblocking_algorithm_class_init (GstSourceDeblockingAlgorithmClass * + self) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (self); + g_type_class_add_private (self, sizeof (GstSourceDeblockingAlgorithmPrivate)); + + gobject_class->finalize = gst_source_deblocking_algorithm_finalize; + GST_DEBUG_CATEGORY_INIT (gst_source_deblocking_debug, "gst_sourcedeblocking", + 0, "GstSource Deblocking Algorithm for FEC"); +} + +gboolean +gst_SDA_set_initial_parameters (GstSourceDeblockingAlgorithm * self, + guint32 t_max, guint8 k_max, guint8 p_max, + gst_SDA_block_cb get_block_cb, void *user_data) +{ + if (self->priv->source_symbol_block != NULL) { + GST_WARNING_OBJECT (self, "initial parameters are already set"); + return FALSE; + } + + if (t_max != 0 && k_max != 0 && p_max != 0) { + self->priv->source_symbol_block = g_malloc (sizeof (GstBuffer *) * k_max); + if (self->priv->source_symbol_block == NULL) { + GST_ERROR_OBJECT (self, "g_malloc didn't allocate memory"); + return FALSE; + } + + self->priv->repair_symbol_block = g_malloc (sizeof (GstBuffer *) * p_max); + if (self->priv->repair_symbol_block == NULL) { + GST_ERROR_OBJECT (self, "g_malloc didn't allocate memory"); + return FALSE; + } + + self->priv->info_array = g_malloc0 (sizeof (guint8) * (k_max + p_max)); + if (self->priv->info_array == NULL) { + GST_ERROR_OBJECT (self, "g_malloc didn't allocate memory"); + return FALSE; + } + + self->priv->k_max = k_max; + self->priv->k_current = k_max; + self->priv->t_max = t_max; + self->priv->p_max = p_max; + self->priv->p_current = p_max; + self->priv->get_block_cb = get_block_cb; + self->priv->user_data = user_data; + } else { + GST_WARNING_OBJECT (self, "input parameters should be non-zero"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, + "source deblocking algorithm initial parameters are set"); + return TRUE; +} + +void +fill_empty_packets (GstSourceDeblockingAlgorithm *self) +{ + if (!gst_buffer_pool_is_active (self->priv->pool)) { + GstStructure *conf = gst_buffer_pool_get_config (self->priv->pool); + GstCaps *caps = gst_caps_new_empty_simple ("fec"); + gst_buffer_pool_config_set_params (conf, caps, self->priv->t_max, 1, self->priv->k_max); + gst_buffer_pool_set_config (self->priv->pool, conf); + + if (!gst_buffer_pool_set_active (self->priv->pool, TRUE)) { + GST_ERROR_OBJECT (self, "activation failed"); + return; + } + } + + int i = 0; + GstBuffer *buf; + GstClockTime first_pts = GST_CLOCK_TIME_NONE; + for (i = 0; i < self->priv->k_max; ++i) { + if (self->priv->info_array[i] == 0) { + if (gst_buffer_pool_acquire_buffer (self->priv->pool, &buf, NULL) != GST_FLOW_OK) { + GST_ERROR_OBJECT (self, "gst_buffer_pool_acquire_buffer failed"); + return; + } + self->priv->source_symbol_block[i] = buf; + } else { + if (first_pts == GST_CLOCK_TIME_NONE) { + first_pts = GST_BUFFER_PTS (self->priv->source_symbol_block[i]); + } + } + } + + if (first_pts == GST_CLOCK_TIME_NONE) { + GST_ERROR_OBJECT (self, "none of source packets in block are passed"); + } + + //set pts for lost packets same as last passed packet + //if first packets are lost set timestamp same as first passed packet + GstClockTime last_pts = first_pts; + if (first_pts != GST_CLOCK_TIME_NONE) { + for (i = 0; i < self->priv->k_current; ++i) { + GST_BUFFER_DTS (self->priv->source_symbol_block [i]) = GST_CLOCK_TIME_NONE; + if (self->priv->info_array[i] == 0) { + GST_BUFFER_PTS (self->priv->source_symbol_block[i]) = last_pts; + } else { + last_pts = GST_BUFFER_PTS (self->priv->source_symbol_block[i]); + } + } + } +} + +gboolean +gst_SDA_pass_next_packet (GstSourceDeblockingAlgorithm * self, + guint8 number_of_packet, guint8 number_of_block, + gboolean is_packet_repair, guint8 k_current, guint8 p_current, GstBuffer *buffer) +{ + if (self->priv->source_symbol_block == NULL) { + GST_ERROR_OBJECT (self, + "initial parameters should be set before passing packets"); + return FALSE; + } + + if (buffer == NULL) { + GST_ERROR_OBJECT (self, "passed buffer is NULL"); + return FALSE; + } + + if (gst_buffer_get_size (buffer) > self->priv->t_max) { + GST_ERROR_OBJECT (self, "size of packet is bigger than t_max"); + return FALSE; + } + + if (number_of_block != self->priv->number_of_block) { + //check if it is late arrival of packet from several previous blocks + if ((guint8) (self->priv->number_of_block - number_of_block) <= + max_block_delay) { + GST_WARNING_OBJECT (self, "passed packet is from some previous block"); + return FALSE; + } + + fill_empty_packets (self); + self->priv->get_block_cb (self->priv->source_symbol_block, + self->priv->repair_symbol_block, self->priv->info_array, + self->priv->k_current, self->priv->p_current, self->priv->user_data); + self->priv->number_of_block = number_of_block; + memset (self->priv->info_array, 0, sizeof (guint8) * + (self->priv->k_max + self->priv->p_max)); + } + + if (k_current > self->priv->k_max) { + GST_ERROR_OBJECT (self, "current k is bigger than k max"); + return FALSE; + } + self->priv->k_current = k_current; + + if (p_current > self->priv->p_max) { + GST_ERROR_OBJECT (self, "current p is bigger than p max"); + return FALSE; + } + self->priv->p_current = p_current; + + if (is_packet_repair) { + if (number_of_packet > self->priv->p_current) { + GST_ERROR_OBJECT (self, "number of repair packet is greater than p_current"); + return FALSE; + } + + self->priv->repair_symbol_block[number_of_packet] = buffer; + self->priv->info_array[number_of_packet + self->priv->k_current] = 1; + } else { + if (number_of_packet > self->priv->k_current) { + GST_ERROR_OBJECT (self, "%d number of source packet is greater than k_current", number_of_packet); + return FALSE; + } + + self->priv->source_symbol_block[number_of_packet] = buffer; + self->priv->info_array[number_of_packet] = 1; + } + + GST_DEBUG_OBJECT (self, "packet is passed"); + + return TRUE; +} + +gboolean gst_SDA_set_eos (GstSourceDeblockingAlgorithm *self) +{ + gboolean ret = TRUE; + GST_DEBUG_OBJECT (self, "EOS, last block is processed"); + fill_empty_packets (self); + self->priv->get_block_cb (self->priv->source_symbol_block, + self->priv->repair_symbol_block, self->priv->info_array, + self->priv->k_current, self->priv->p_current, self->priv->user_data); + return ret; +} diff --git a/alfec/gst_source_deblocking_algorithm.h b/alfec/gst_source_deblocking_algorithm.h new file mode 100755 index 0000000..909f39a --- /dev/null +++ b/alfec/gst_source_deblocking_algorithm.h @@ -0,0 +1,118 @@ +/* + * gst_source_deblocking_algorithm + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_SOURCE_DEBLOCKING_ALGORITHM_H__ +#define __GST_SOURCE_DEBLOCKING_ALGORITHM_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM\ + (gst_source_deblocking_algorithm_get_type ()) +#define GST_SOURCE_DEBLOCKING_ALGORITHM(obj)\ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM, GstSourceDeblockingAlgorithm)) +#define GST_IS_SOURCE_DEBLOCKING_ALGORITHM(obj)\ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM)) +#define GST_SOURCE_DEBLOCKING_ALGORITHM_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM, GstSourceDeblockingAlgorithmClass)) +#define GST_IS_SOURCE_DEBLOCKING_ALGORITHM_CLASS(klass)\ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM)) +#define GST_SOURCE_DEBLOCKING_ALGORITHM_GET_CLASS(obj)\ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM, GstSourceDeblockingAlgorithmClass)) + +typedef struct _GstSourceDeblockingAlgorithm GstSourceDeblockingAlgorithm; +typedef struct _GstSourceDeblockingAlgorithmClass GstSourceDeblockingAlgorithmClass; +typedef struct _GstSourceDeblockingAlgorithmPrivate GstSourceDeblockingAlgorithmPrivate; +typedef void (*gst_SDA_block_cb)( + GstBuffer **source_symbol_block, + GstBuffer **repair_symbol_block, + guint8 *info_array, + guint8 k, + guint8 p, + void *user_data); + +struct _GstSourceDeblockingAlgorithm +{ + GObject parent_instance; + + GstSourceDeblockingAlgorithmPrivate *priv; +}; + +struct _GstSourceDeblockingAlgorithmClass +{ + GObjectClass parent_class; +}; + +/* used by GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM */ +GType gst_source_deblocking_algorithm_get_type (void); + +/* Set initial parameters for algorithm. + This function should be called one time */ +gboolean gst_SDA_set_initial_parameters( + GstSourceDeblockingAlgorithm *self, + guint32 t_max, + guint8 k_max, + guint8 p_max, + gst_SDA_block_cb get_block_cb, + void *user_data); + +/* Pass packet to source block */ +gboolean gst_SDA_pass_next_packet( + GstSourceDeblockingAlgorithm *self, + guint8 number_of_packet, + guint8 number_of_block, + gboolean is_packet_repair, + guint8 k_current, + guint8 p_current, + GstBuffer *buffer); + +/* Triger source block sending as no more packets are available */ +gboolean gst_SDA_set_eos(GstSourceDeblockingAlgorithm *self); + +G_END_DECLS + +#endif /* __GST_SOURCE_DEBLOCKING_ALGORITHM_H__ */ diff --git a/alfec/gstalfec.c b/alfec/gstalfec.c new file mode 100755 index 0000000..e6391da --- /dev/null +++ b/alfec/gstalfec.c @@ -0,0 +1,73 @@ +/* + * gstalfec + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstalfecencoder.h" +#include "gstalfecdecoder.h" +#include "gstnetsim.h" + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "alfecencoder", GST_RANK_NONE, GST_TYPE_AL_FEC_ENCODER)) + return FALSE; + if (!gst_element_register (plugin, "alfecdecoder", GST_RANK_NONE, GST_TYPE_AL_FEC_DECODER)) + return FALSE; + if (!gst_element_register (plugin, "netsim", GST_RANK_MARGINAL, GST_TYPE_NET_SIM)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + alfec, + "Application Level Forward Error Correction coder", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/alfec/gstalfecbufferpool.c b/alfec/gstalfecbufferpool.c new file mode 100755 index 0000000..d5f8025 --- /dev/null +++ b/alfec/gstalfecbufferpool.c @@ -0,0 +1,156 @@ +/* + * gstalfecbufferpool + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Author: Hyunjun Ko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gstalfecbufferpool.h" + +GST_DEBUG_CATEGORY_EXTERN (alfec_debug); +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE); +#define GST_CAT_DEFAULT alfec_debug + +static void +gst_al_fec_buffer_pool_dispose (GObject * object) +{ + GstALFECBufferPool *pool = GST_ALFEC_BUFFER_POOL (object); + gint i; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (pool->buffers[i]) + gst_buffer_replace (&(pool->buffers[i]), NULL); + } + + if (pool->vallocator) + gst_object_unref (pool->vallocator); + pool->vallocator = NULL; + + if (pool->allocator) + gst_object_unref (pool->allocator); + pool->allocator = NULL; + + if (pool->other_pool) + gst_object_unref (pool->other_pool); + pool->other_pool = NULL; + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_al_fec_buffer_pool_finalize (GObject * object) +{ + GstALFECBufferPool *pool = GST_ALFEC_BUFFER_POOL (object); + + if (pool->video_fd >= 0) + al_fec_close (pool->video_fd); + + gst_poll_free (pool->poll); + + /* FIXME Is this required to keep around ? + * * This can't be done in dispose method because we must not set pointer + * * to NULL as it is part of the al_fecobject and dispose could be called + * * multiple times */ + gst_object_unref (pool->obj->element); + + /* FIXME have we done enough here ? */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_al_fec_buffer_pool_init (GstALFECBufferPool * pool) +{ + pool->poll = gst_poll_new (TRUE); + pool->can_poll_device = TRUE; + g_cond_init (&pool->empty_cond); + pool->empty = TRUE; +} + +static void +gst_al_fec_buffer_pool_reset_buffer (GstBufferPool *pool, GstBuffer *buffer) +{ + GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE; + GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE; +} + +static void +gst_al_fec_buffer_pool_class_init (GstALFECBufferPoolClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass); + + //object_class->dispose = gst_al_fec_buffer_pool_dispose; + //object_class->finalize = gst_al_fec_buffer_pool_finalize; + + //bufferpool_class->start = gst_al_fec_buffer_pool_start; + //bufferpool_class->stop = gst_al_fec_buffer_pool_stop; + //bufferpool_class->set_config = gst_al_fec_buffer_pool_set_config; + //bufferpool_class->alloc_buffer = gst_al_fec_buffer_pool_alloc_buffer; + //bufferpool_class->acquire_buffer = gst_al_fec_buffer_pool_acquire_buffer; + //bufferpool_class->release_buffer = gst_al_fec_buffer_pool_release_buffer; + //bufferpool_class->flush_start = gst_al_fec_buffer_pool_flush_start; + //bufferpool_class->flush_stop = gst_al_fec_buffer_pool_flush_stop; + bufferpool_class->reset_buffer = gst_al_fec_buffer_pool_reset_buffer; +} + +GstBufferPool * +gst_al_fec_buffer_pool_new () +{ + GstALFECBufferPool *pool; + GstStructure *config; + + pool = (GstALFECBufferPool *) g_object_new (GST_TYPE_ALFEC_BUFFER_POOL, NULL); + + config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + gst_buffer_pool_config_set_params (config, NULL, 0, 0); + + /* This will simply set a default config, but will not configure the pool + * because min and max are not valid */ + gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); + + return GST_BUFFER_POOL (pool); +} diff --git a/alfec/gstalfecbufferpool.h b/alfec/gstalfecbufferpool.h new file mode 100755 index 0000000..9b17173 --- /dev/null +++ b/alfec/gstalfecbufferpool.h @@ -0,0 +1,78 @@ +/* + * gstalfecbufferpool + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Author: Hyunjun Ko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_BUFFER_POOL_H__ +#define __GST_AL_FEC_BUFFER_POOL_H__ + +#include +#include "gstalfecencaps.h" + +G_BEGIN_DECLS + +typedef struct _GstALFECBufferPool GstALFECBufferPool; +typedef struct _GstALFECBufferPoolClass GstALFECBufferPoolClass; + +#define GST_TYPE_ALFEC_BUFFER_POOL (gst_al_fec_buffer_pool_get_type()) +#define GST_IS_ALFEC_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_ALFEC_BUFFER_POOL)) +#define GST_ALFEC_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ALFEC_BUFFER_POOL, GstALFECBufferPool)) +#define GST_ALFEC_BUFFER_POOL_CAST(obj) ((GstALFECBufferPool*)(obj)) + +/* Definition of structure storing data for this element. */ +typedef struct _GstALFECBufferPool { + GstBufferPool pool; +} GstALFECBufferPool; + +/* Standard definition defining a class for this element. */ +typedef struct _GstALFECBufferPoolClass { + GstBufferPoolClass parent_class; +} GstALFECBufferPoolClass; + +/* Standard function returning type information. */ +GType gst_al_fec_buffer_pool_get_type (void); + +G_END_DECLS + +#endif /* __GST_AL_FEC_BUFFER_POOL_H__ */ diff --git a/alfec/gstalfecdecaps.c b/alfec/gstalfecdecaps.c new file mode 100755 index 0000000..63bdc8f --- /dev/null +++ b/alfec/gstalfecdecaps.c @@ -0,0 +1,183 @@ +/* + * gstalfecdecaps + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstalfecdecaps.h" +#include "gstalfecheader.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_al_fec_decapsulator_debug); +#define GST_CAT_DEFAULT gst_al_fec_decapsulator_debug + +#define gst_al_fec_decapsulator_parent_class parent_class +G_DEFINE_TYPE (GstALFECDecapsulator, gst_al_fec_decapsulator, GST_TYPE_ELEMENT); + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, +}; + +/* object */ +static void gst_al_fec_decapsulator_finalize (GObject * object); + +/* element */ + +static void +gst_al_fec_decapsulator_class_init (GstALFECDecapsulatorClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->finalize = gst_al_fec_decapsulator_finalize; + + gst_element_class_set_static_metadata (gstelement_class, + "The AL-FEC Decapsulator", "Codec/Decapsulator/FEC", + "Read and remove headers from FEC packets", + "Samsung Electronics "); + + GST_DEBUG_CATEGORY_INIT (gst_al_fec_decapsulator_debug, "alfecdecapsulator", + 0, + "Application Level Forward Error Correction packets Decapsulator"); +} + +static void +gst_al_fec_decapsulator_init (GstALFECDecapsulator * alfecdecaps) +{ + alfecdecaps->send_packet_cb = NULL; + alfecdecaps->cb_user_data = NULL; +} + +static void +gst_al_fec_decapsulator_finalize (GObject * object) +{ + /* GstALFECDecapsulator *alfecdecaps = GST_AL_FEC_DECAPSULATOR (object); */ + + G_OBJECT_CLASS (gst_al_fec_decapsulator_parent_class)->finalize (object); +} + +void +gst_al_fec_decapsulator_set_send_cb (GstALFECDecapsulator * alfecdecaps, + decapsulator_send_cb send_packet, void *user_data) +{ + alfecdecaps->send_packet_cb = send_packet; + alfecdecaps->cb_user_data = user_data; + GST_INFO_OBJECT (alfecdecaps, "Sending callbask set"); +} + +void +gst_al_fec_decapsulator_process_packet (GstALFECDecapsulator * + alfecdecaps, GstBuffer *buffer) +{ + if (alfecdecaps->send_packet_cb == NULL) { + GST_ERROR_OBJECT (alfecdecaps, "callback is not set"); + return; + } + + guint8 block_number = 0; + guint8 packet_number = 0; + gboolean is_repair_packet = 0; + guint8 k_current = 0; + guint8 p_current = 0; + GstMapInfo info; + gst_buffer_map (buffer, &info, GST_MAP_READ); + + if (gst_buffer_get_size (buffer) < DEFAULT_HEADER_SIZE) { + GST_ERROR_OBJECT (alfecdecaps, "packet is too small"); + } + + memcpy (&block_number, info.data + BLOCK_NUMBER, 1); + memcpy (&packet_number, info.data + PACKAGE_NUMBER, 1); + memcpy (&k_current, info.data + SOURCE_NUMBER, 1); + memcpy (&p_current, info.data + PARITY_NUMBER, 1); + + if (packet_number < k_current) { + is_repair_packet = FALSE; + } else { + packet_number -= k_current; + is_repair_packet = TRUE; + } + + gst_buffer_unmap (buffer, &info); + + if (is_repair_packet) { + gst_buffer_resize (buffer, DEFAULT_HEADER_SIZE, -1); + } + + alfecdecaps->send_packet_cb (buffer, block_number, packet_number, + is_repair_packet, k_current, p_current, alfecdecaps->cb_user_data); + + if (is_repair_packet) { + GST_INFO_OBJECT (alfecdecaps, "Parity packet processed"); + } + else { + GST_INFO_OBJECT (alfecdecaps, "Source packet processed"); + } +} + +void +gst_al_fec_decapsulator_restore_buffer (GstALFECDecapsulator *alfecdecaps, + GstBuffer *buffer) +{ + if (gst_buffer_get_size (buffer) < DEFAULT_HEADER_SIZE) { + GST_ERROR_OBJECT (alfecdecaps, "packet is too small"); + } + + GstMapInfo info; + guint32 actual_size; + + gst_buffer_map (buffer, &info, GST_MAP_READ); + memcpy (&actual_size, info.data + PACKAGE_SIZE, + sizeof (guint32)); + gst_buffer_unmap (buffer, &info); + + gst_buffer_resize (buffer, DEFAULT_HEADER_SIZE, actual_size); + GST_INFO_OBJECT (alfecdecaps, "Header removed"); +} diff --git a/alfec/gstalfecdecaps.h b/alfec/gstalfecdecaps.h new file mode 100755 index 0000000..17d9347 --- /dev/null +++ b/alfec/gstalfecdecaps.h @@ -0,0 +1,107 @@ +/* + * gstalfecdecaps + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_DECAPS_H__ +#define __GST_AL_FEC_DECAPS_H__ + +#include + +G_BEGIN_DECLS + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_AL_FEC_DECAPSULATOR (gst_al_fec_decapsulator_get_type()) +#define GST_AL_FEC_DECAPSULATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AL_FEC_DECAPSULATOR,GstALFECDecapsulator)) +#define GST_AL_FEC_DECAPSULATOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AL_FEC_DECAPSULATOR,GstALFECDecapsulatorClass)) +#define GST_IS_AL_FEC_DECAPSULATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AL_FEC_DECAPSULATOR)) +#define GST_IS_AL_FEC_DECAPSULATOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AL_FEC_DECAPSULATOR)) +#define GST_AL_FEC_DECAPSULATOR_CAST(obj) ((GstALFECDecapsulator *)(obj)) + +typedef struct _GstALFECDecapsulator GstALFECDecapsulator; +typedef struct _GstALFECDecapsulatorClass GstALFECDecapsulatorClass; + +typedef void (*decapsulator_send_cb)( + GstBuffer *buffer, + + guint8 block_number, + guint8 packet_number, + gboolean is_repair_packet, + guint8 k_current, + guint8 p_current, + void *user_data); + +/* Definition of structure storing data for this element. */ +struct _GstALFECDecapsulator { + GstElement element; + + decapsulator_send_cb send_packet_cb; + void *cb_user_data; + +}; + +/* Standard definition defining a class for this element. */ +struct _GstALFECDecapsulatorClass { + GstElementClass parent_class; +}; + +/* Standard function returning type information. */ +GType gst_al_fec_decapsulator_get_type (void); + +void gst_al_fec_decapsulator_process_packet (GstALFECDecapsulator *alfecdecaps, + GstBuffer *buffer); + +void gst_al_fec_decapsulator_set_send_cb (GstALFECDecapsulator * alfecdecaps, + decapsulator_send_cb send_packet, void *user_data); + +void gst_al_fec_decapsulator_restore_buffer (GstALFECDecapsulator *alfecdecaps, + GstBuffer *buffer); + +G_END_DECLS + +#endif /* __GST_AL_FEC_DECAPSULATOR_H__ */ diff --git a/alfec/gstalfecdecoder.c b/alfec/gstalfecdecoder.c new file mode 100755 index 0000000..d56d16a --- /dev/null +++ b/alfec/gstalfecdecoder.c @@ -0,0 +1,595 @@ +/* + * gstalfecdecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstalfecdecoder.h" +#include "FECCodes.h" +#include "gstalfecheader.h" + +GST_DEBUG_CATEGORY_STATIC (gst_al_fec_decoder_debug); +#define GST_CAT_DEFAULT gst_al_fec_decoder_debug + +#define gst_al_fec_decoder_parent_class parent_class +G_DEFINE_TYPE (GstALFECDecoder, gst_al_fec_decoder, GST_TYPE_ELEMENT); + + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_DO_FEC, + PROP_MAX_SIZE_K, + PROP_MAX_SIZE_P, + PROP_SYMBOL_LENGTH, + PROP_REORDER +}; + +/* default property values */ +#define DEFAULT_DO_FEC TRUE +#define DEFAULT_MAX_SIZE_K 10 +#define DEFAULT_MAX_SIZE_P 10 +#define DEFAULT_SYMBOL_LENGTH 200 +#define DEFAULT_REORDER TRUE + + +/* object */ +static void gst_al_fec_decoder_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_al_fec_decoder_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_al_fec_decoder_finalize (GObject *object); + +static GstFlowReturn gst_al_fec_decoder_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer); + +static gboolean gst_al_fec_decoder_handle_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); + +static gboolean gst_al_fec_decoder_handle_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); + + +static gboolean gst_al_fec_decoder_src_activate_mode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active); +static gboolean gst_al_fec_decoder_sink_activate_mode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active); + +static void gst_al_fec_decoder_init_fec(GstALFECDecoder *alfecdec); +static void gst_al_fec_decoder_store_data (GstBuffer *package, guint8 block_number, + guint8 packet_number, gboolean is_repair_packet, guint8 k_current, guint8 p_current, void *user_data); +static void gst_al_fec_decoder_decode_data (GstBuffer **source_symbol_block, GstBuffer **repair_symbol_block, + guint8 *info_array, guint8 k, guint8 p, void *user_data); +static void gst_al_fec_decoder_finalize_fec (GstALFECDecoder *alfecdec); + +/* element */ +static GstStateChangeReturn gst_al_fec_decoder_change_state (GstElement * element, + GstStateChange transition); + +//static guint gst_al_fec_decoder_signals[LAST_SIGNAL] = { 0 }; + +static void +gst_al_fec_decoder_class_init (GstALFECDecoderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_al_fec_decoder_set_property; + gobject_class->get_property = gst_al_fec_decoder_get_property; + gobject_class->finalize = gst_al_fec_decoder_finalize; + + g_object_class_install_property (gobject_class, PROP_DO_FEC, + g_param_spec_boolean ("do-fec", "Perform Forward Error Correction", + "Perform Forward Error Correction or just push buffers without touching", + DEFAULT_DO_FEC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MAX_SIZE_K, + g_param_spec_uint ("max-size-k", "Max. size (k)", + "Max. number of source symbol in a block", 1, G_MAXUINT, + DEFAULT_MAX_SIZE_K, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MAX_SIZE_P, + g_param_spec_uint ("max-size-p", "Max. size (p)", + "Max. number of parity symbol in a block", 0, G_MAXUINT, + DEFAULT_MAX_SIZE_P, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SYMBOL_LENGTH, + g_param_spec_uint ("symbol-length", "Symbol length", + "Length of block symbol in bytes", 0, G_MAXUINT, + DEFAULT_SYMBOL_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_REORDER, + g_param_spec_boolean ("do-reorder", "Reorder packets", + "Send source packet without decoding", DEFAULT_REORDER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_set_static_metadata (gstelement_class, + "The AL-FEC Decoder", "Codec/Decoder/FEC", + "Decode FEC packets for restoring", + "Samsung Electronics "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_al_fec_decoder_change_state); + + GST_DEBUG_CATEGORY_INIT (gst_al_fec_decoder_debug, "alfecdecoder", 0, + "Application Level Forward Error Correction Decoder"); +} + +static void +gst_al_fec_decoder_init (GstALFECDecoder * alfecdec) +{ + alfecdec->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); + + gst_pad_set_chain_function (alfecdec->sinkpad, gst_al_fec_decoder_chain); + gst_pad_set_activatemode_function (alfecdec->sinkpad, + gst_al_fec_decoder_sink_activate_mode); + gst_pad_set_event_function (alfecdec->sinkpad, gst_al_fec_decoder_handle_sink_event); + gst_element_add_pad (GST_ELEMENT (alfecdec), alfecdec->sinkpad); + + alfecdec->srcpad = gst_pad_new_from_static_template (&srctemplate, "src"); + + gst_pad_set_activatemode_function (alfecdec->srcpad, + gst_al_fec_decoder_src_activate_mode); + gst_pad_set_event_function (alfecdec->srcpad, gst_al_fec_decoder_handle_src_event); + gst_element_add_pad (GST_ELEMENT (alfecdec), alfecdec->srcpad); + + alfecdec->do_fec = DEFAULT_DO_FEC; + alfecdec->max_k = DEFAULT_MAX_SIZE_K; + alfecdec->max_p = DEFAULT_MAX_SIZE_P; + alfecdec->symbol_length = DEFAULT_SYMBOL_LENGTH + DEFAULT_HEADER_SIZE; + alfecdec->reorder = DEFAULT_REORDER; + + alfecdec->srcresult = GST_FLOW_FLUSHING; + alfecdec->source_buf_info = NULL; + alfecdec->repair_buf_info = NULL; + alfecdec->source_data = NULL; + alfecdec->repair_data = NULL; +} + +static void +gst_al_fec_decoder_finalize (GObject * object) +{ + /* GstALFECDecoder * alfecdec = GST_AL_FEC_DECODER (object); */ + G_OBJECT_CLASS(gst_al_fec_decoder_parent_class)->finalize(object); +} + +static GstFlowReturn +gst_al_fec_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER (parent); + + if (G_LIKELY (alfecdec->eos)) + goto out_eos; + + if (G_UNLIKELY (!alfecdec->do_fec)) + return gst_pad_push (alfecdec->srcpad, buffer); + + gst_al_fec_decapsulator_process_packet (alfecdec->decapsulator, buffer); + + return ret; + +out_eos: + { + GST_LOG_OBJECT (alfecdec, "exit because we received EOS"); + + gst_buffer_unref (buffer); + return GST_FLOW_EOS; + } + +} + +static gboolean +gst_al_fec_decoder_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean res = TRUE; + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER (parent); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + break; + case GST_EVENT_FLUSH_STOP: + break; + case GST_EVENT_EOS: + if (alfecdec->eos != TRUE) { + alfecdec->eos = TRUE; + gst_SDA_set_eos(alfecdec->alg); + } + res = gst_pad_push_event (alfecdec->srcpad, event); + break; + default: + res = gst_pad_push_event (alfecdec->srcpad, event); + break; + } + + return res; +} + +static gboolean +gst_al_fec_decoder_handle_src_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean res = TRUE; + /* GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER (parent); */ + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + break; + case GST_EVENT_FLUSH_STOP: + break; + default: + res = gst_pad_event_default (pad, parent, event); + break; + } + + return res; +} + +static GstStateChangeReturn +gst_al_fec_decoder_change_state (GstElement * element, GstStateChange transition) +{ + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + gst_al_fec_decoder_init_fec (alfecdec); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_al_fec_decoder_finalize_fec (alfecdec); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + goto done; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + +done: + return ret; +} + +static gboolean +gst_al_fec_decoder_sink_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, + gboolean active) +{ + gboolean result = FALSE; + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER_CAST (parent); + + switch (mode) { + case GST_PAD_MODE_PUSH: + if (active) { + alfecdec->srcresult = GST_FLOW_OK; + alfecdec->eos = FALSE; + } else { + /* step 1, unblock chain function */ + alfecdec->srcresult = GST_FLOW_FLUSHING; + + /* step 2, wait until streaming thread stopped */ + GST_PAD_STREAM_LOCK (pad); + GST_PAD_STREAM_UNLOCK (pad); + } + result = TRUE; + break; + default: + result = FALSE; + break; + } + return result; +} + + +static gboolean +gst_al_fec_decoder_src_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, + gboolean active) +{ + gboolean result = FALSE; + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER_CAST (parent); + + switch (mode) { + case GST_PAD_MODE_PUSH: + if (active) { + alfecdec->srcresult = GST_FLOW_OK; + alfecdec->eos = FALSE; + result = TRUE; + } else { + /* step 1, unblock loop function */ + alfecdec->srcresult = GST_FLOW_FLUSHING; + + /* step 2, make sure streaming finishes */ + result = TRUE; + } + break; + default: + result = FALSE; + break; + } + return result; +} + +static void +gst_al_fec_decoder_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER_CAST (object); + + switch (prop_id) { + case PROP_DO_FEC: + alfecdec->do_fec = g_value_get_boolean (value); + GST_DEBUG_OBJECT(alfecdec, "set fec %d", alfecdec->do_fec); + break; + case PROP_MAX_SIZE_K: + alfecdec->max_k = g_value_get_uint (value); + break; + case PROP_MAX_SIZE_P: + alfecdec->max_p = g_value_get_uint (value); + break; + case PROP_SYMBOL_LENGTH: + alfecdec->symbol_length = g_value_get_uint (value) + DEFAULT_HEADER_SIZE; + break; + case PROP_REORDER: + alfecdec->reorder = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +gst_al_fec_decoder_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstALFECDecoder *alfecdec = GST_AL_FEC_DECODER_CAST (object); + + switch (prop_id) { + case PROP_DO_FEC: + g_value_set_boolean (value, alfecdec->do_fec); + break; + case PROP_MAX_SIZE_K: + g_value_set_uint (value, alfecdec->max_k); + break; + case PROP_MAX_SIZE_P: + g_value_set_uint (value, alfecdec->max_p); + break; + case PROP_SYMBOL_LENGTH: + g_value_set_uint (value, alfecdec->symbol_length); + break; + case PROP_REORDER: + g_value_set_boolean (value, alfecdec->reorder); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_al_fec_decoder_init_fec(GstALFECDecoder *alfecdec) +{ + /* TODO: Init FEC codes. Init SBA */ + guint8 isEncoder = 0; //affirmative value for encoder + guint8 codeTypeID = CODE_ID_RS; + alfecdec->fec_dec_id = FECCodes_Initialize(&alfecdec->max_k, &alfecdec->max_p, &alfecdec->symbol_length, + &isEncoder, &codeTypeID, NULL); + alfecdec->alg = g_object_new (GST_TYPE_SOURCE_DEBLOCKING_ALGORITHM, NULL); + alfecdec->decapsulator = g_object_new (GST_TYPE_AL_FEC_DECAPSULATOR, NULL); + /* Only for testing with k_max = 5 and following pipeline: + * gst-launch-1.0 filesrc blocksize=200 location ... ! + * alfecdec ! fakesink dump=true */ + if (!gst_SDA_set_initial_parameters(alfecdec->alg, + alfecdec->symbol_length, alfecdec->max_k, alfecdec->max_p, + gst_al_fec_decoder_decode_data, alfecdec)) { + GST_ERROR_OBJECT (alfecdec, "SDA not inited sucess"); + return; + } + + gst_al_fec_decapsulator_set_send_cb (alfecdec->decapsulator, gst_al_fec_decoder_store_data, alfecdec); + alfecdec->source_buf_info = g_malloc (alfecdec->max_k * sizeof (GstMapInfo)); + alfecdec->repair_buf_info = g_malloc (alfecdec->max_p * sizeof (GstMapInfo)); + alfecdec->source_data = g_malloc (alfecdec->max_k * sizeof (guint8 *)); + alfecdec->repair_data = g_malloc (alfecdec->max_p * sizeof (guint8 *)); + + GST_INFO_OBJECT (alfecdec, "FEC Codes init sucess"); +} + +static void +gst_al_fec_decoder_store_data (GstBuffer *buffer, guint8 block_number, + guint8 packet_number, gboolean is_repair_packet, guint8 k_current, guint8 p_current, void *user_data) +{ + + GstALFECDecoder *dec = GST_AL_FEC_DECODER (user_data); + GstBuffer *out; + + if (!is_repair_packet && !dec->reorder) { + out = gst_buffer_copy (buffer); + gst_al_fec_decapsulator_restore_buffer (dec->decapsulator, out); + gst_pad_push (dec->srcpad, out); + } + + gst_SDA_pass_next_packet(dec->alg, packet_number, block_number, + is_repair_packet, k_current, p_current, buffer); +} + +static void +gst_al_fec_decoder_decode_data (GstBuffer **source_symbol_block, GstBuffer **repair_symbol_block, + guint8 *info_array, guint8 k, guint8 p, void *user_data) +{ + GstALFECDecoder *dec = GST_AL_FEC_DECODER (user_data); + gboolean ret = FALSE; + guint i = 0; + for (i = 0; i < k; ++i) { + gst_buffer_map (source_symbol_block[i], &dec->source_buf_info[i], GST_MAP_WRITE); + dec->source_data[i] = dec->source_buf_info[i].data; + } + + for (i = 0; i < p; ++i) { + if (info_array[i + k] != 0) { + gst_buffer_map (repair_symbol_block[i], &dec->repair_buf_info[i], GST_MAP_WRITE); + dec->repair_data[i] = dec->repair_buf_info[i].data; + } + } + + ret = FECCodes_DecodeData (dec->source_data, dec->repair_data, + info_array, &k, &p, &dec->fec_dec_id, NULL, dec->reorder); + + for (i = 0; i < k; ++i) { + gst_buffer_unmap (source_symbol_block[i], &dec->source_buf_info[i]); + } + + for (i = 0; i < p; ++i) { + if (info_array[i + k] != 0) { + gst_buffer_unmap (repair_symbol_block[i], &dec->repair_buf_info[i]); + gst_buffer_unref (repair_symbol_block[i]); + } + } + + if (!ret) { + GST_WARNING_OBJECT (dec, "FEC codes failed to decode data"); + if (!dec->reorder) { + for (i = 0; i < k; i++) { + gst_buffer_unref (source_symbol_block[i]); + } + return; + } + } + + for (i = 0; i < k; i++) { + if (!dec->reorder) { + if (info_array[i] == 1) { + gst_buffer_unref (source_symbol_block[i]); + continue; + } + } + else { + if (info_array[i] == 0) { + gst_buffer_unref (source_symbol_block[i]); + continue; + } + } + + gst_al_fec_decapsulator_restore_buffer (dec->decapsulator, source_symbol_block[i]); + gst_pad_push (dec->srcpad, source_symbol_block[i]); + } +} + +static void +gst_al_fec_decoder_finalize_fec (GstALFECDecoder *alfecdec) +{ + /* TODO: Add fec destroy func */ + g_object_unref (alfecdec->alg); + alfecdec->alg = NULL; + g_object_unref (alfecdec->decapsulator); + alfecdec->decapsulator = NULL; + if (!FECCodes_Deinitialize (&alfecdec->fec_dec_id)) { + GST_ERROR_OBJECT (alfecdec, "FEC code instance can't be deinitialized"); + } + + if (alfecdec->source_buf_info != NULL) { + g_free (alfecdec->source_buf_info); + } + + if (alfecdec->repair_buf_info != NULL) { + g_free (alfecdec->repair_buf_info); + } + + if (alfecdec->source_data != NULL) { + g_free (alfecdec->source_data); + } + + if (alfecdec->repair_data != NULL) { + g_free (alfecdec->repair_data); + } + +} diff --git a/alfec/gstalfecdecoder.h b/alfec/gstalfecdecoder.h new file mode 100755 index 0000000..f57a3a9 --- /dev/null +++ b/alfec/gstalfecdecoder.h @@ -0,0 +1,100 @@ +/* + * gstalfecdecoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_DECODER_H__ +#define __GST_AL_FEC_DECODER_H__ + +#include +#include "gst_source_deblocking_algorithm.h" +#include "gstalfecdecaps.h" + +G_BEGIN_DECLS + +/* Definition of structure storing data for this element. */ +typedef struct _GstALFECDecoder { + GstElement element; + + GstPad *sinkpad, *srcpad; + GstFlowReturn srcresult; + gboolean eos; + + guint8 max_k; + guint8 max_p; + guint32 symbol_length; + gboolean reorder; + gboolean do_fec; + guint8 fec_dec_id; + GstSourceDeblockingAlgorithm *alg; + GstALFECDecapsulator *decapsulator; + GstMapInfo *source_buf_info; + GstMapInfo *repair_buf_info; + guint8 **source_data; + guint8 **repair_data;; +} GstALFECDecoder; + +/* Standard definition defining a class for this element. */ +typedef struct _GstALFECDecoderClass { + GstElementClass parent_class; +} GstALFECDecoderClass; + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_AL_FEC_DECODER (gst_al_fec_decoder_get_type()) +#define GST_AL_FEC_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AL_FEC_DECODER,GstALFECDecoder)) +#define GST_AL_FEC_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AL_FEC_DECODER,GstALFECDecoderClass)) +#define GST_IS_AL_FEC_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AL_FEC_DECODER)) +#define GST_IS_AL_FEC_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AL_FEC_DECODER)) +#define GST_AL_FEC_DECODER_CAST(obj) ((GstALFECDecoder *)(obj)) + +/* Standard function returning type information. */ +GType gst_al_fec_decoder_get_type (void); + +G_END_DECLS + +#endif /* __GST_AL_FEC_DECODER_H__ */ diff --git a/alfec/gstalfecencaps.c b/alfec/gstalfecencaps.c new file mode 100755 index 0000000..c6d2e61 --- /dev/null +++ b/alfec/gstalfecencaps.c @@ -0,0 +1,202 @@ +/* + * gstalfecencaps + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstalfecencaps.h" +#include "gstalfecheader.h" +#include + +GST_DEBUG_CATEGORY_STATIC (gst_al_fec_encapsulator_debug); +#define GST_CAT_DEFAULT gst_al_fec_encapsulator_debug + +#define gst_al_fec_encapsulator_parent_class parent_class +G_DEFINE_TYPE (GstALFECEncapsulator, gst_al_fec_encapsulator, GST_TYPE_ELEMENT); + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, +}; + +/* object */ +static void gst_al_fec_encapsulator_finalize (GObject * object); + +/* element */ + +//static guint gst_al_fec_enCAPSULATOR_signals[LAST_SIGNAL] = { 0 }; + +static void +gst_al_fec_encapsulator_class_init (GstALFECEncapsulatorClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->finalize = gst_al_fec_encapsulator_finalize; + + gst_element_class_set_static_metadata (gstelement_class, + "The AL-FEC Encapsulator", "Codec/Encapsulator/FEC", + "Add headers to FEC parity packages and source packets", + "Samsung Electronics "); + + GST_DEBUG_CATEGORY_INIT (gst_al_fec_encapsulator_debug, "alfecencapsulator", + 0, + "Application Level Forward Error Correction packets Encapsulator"); +} + +static void +gst_al_fec_encapsulator_init (GstALFECEncapsulator * alfecencaps) +{ + alfecencaps->block_id = 0; + alfecencaps->repair_id = 0; + alfecencaps->source_id = 0; + alfecencaps->send_cb = NULL; + alfecencaps->cb_user_data = NULL; +} + +static void +gst_al_fec_encapsulator_finalize (GObject * object) +{ + /* GstALFECEncapsulator *alfecencaps = GST_AL_FEC_ENCAPSULATOR (object); */ + + G_OBJECT_CLASS (gst_al_fec_encapsulator_parent_class)->finalize (object); +} + +void +gst_al_fec_encapsulator_set_send_cb (GstALFECEncapsulator * alfecencaps, + encapsulator_send_cb send_package, void *user_data) +{ + alfecencaps->send_cb = send_package; + alfecencaps->cb_user_data = user_data; + GST_INFO_OBJECT (alfecencaps, "Sending callback set"); +} + +static void +write_header (GstALFECEncapsulator * alfecencaps, guint8 * package, + guint32 actual_size, guint8 k, gboolean is_repair, guint8 p) +{ + GST_DEBUG_OBJECT (alfecencaps, "Add header to packet"); + + memcpy (package + BLOCK_NUMBER, &alfecencaps->block_id, 1); + + if (is_repair) { + guint8 id = alfecencaps->repair_id + k; + memcpy (package + PACKAGE_NUMBER, &id, 1); + alfecencaps->repair_id++; + } else { + memcpy (package + PACKAGE_NUMBER, &alfecencaps->source_id, 1); + alfecencaps->source_id++; + } + + memcpy (package + PACKAGE_SIZE, &actual_size, sizeof (guint32)); + memcpy (package + SOURCE_NUMBER, &k, 1); + memcpy (package + PARITY_NUMBER, &p, 1); +} + +void +gst_al_fec_encapsulator_process_parity_block (GstALFECEncapsulator * + alfecencaps, GstBuffer ** parity_block, guint8 p, guint32 t, guint8 k) +{ + if (alfecencaps->send_cb == NULL) { + GST_ERROR_OBJECT (alfecencaps, "callback is not set"); + } + + gint i = 0; + for (i = 0; i < p; i++) { + GstMapInfo buf_info; + gst_buffer_map (parity_block[i], &buf_info, GST_MAP_WRITE); + write_header (alfecencaps, buf_info.data, gst_buffer_get_size (parity_block[i]), k, TRUE, p); + gst_buffer_unmap (parity_block[i], &buf_info); + alfecencaps->send_cb (parity_block[i], TRUE, + alfecencaps->cb_user_data); + } + + alfecencaps->block_id++; + alfecencaps->source_id = 0; + alfecencaps->repair_id = 0; + + GST_INFO_OBJECT (alfecencaps, "Parity block processed"); + +} + +//t is size of packet (according to FEC notions), but real size of packet +//is in actual_size variable; (t - actual_size) last bytes is filled with 0 +gboolean +gst_al_fec_encapsulator_process_source_buffer (GstALFECEncapsulator * + alfecencaps, GstBuffer *buffer, guint8 k, guint8 p, guint32 t) +{ + if (gst_buffer_get_size(buffer) + DEFAULT_HEADER_SIZE > t) { + GST_ERROR_OBJECT (alfecencaps, "buffer size is too big"); + return FALSE; + } + + GstMemory *memory; + GstMapInfo mem_info; + + memory = gst_allocator_alloc (NULL, DEFAULT_HEADER_SIZE, NULL); + gst_memory_map (memory, &mem_info, GST_MAP_WRITE); + write_header (alfecencaps, mem_info.data, gst_buffer_get_size (buffer), + k, FALSE, p); + gst_memory_unmap (memory, &mem_info); + gst_buffer_prepend_memory (buffer, memory); + + if (gst_buffer_get_size(buffer) < t) { + memory = gst_allocator_alloc (NULL, t - gst_buffer_get_size (buffer), NULL); + gst_memory_map (memory, &mem_info, GST_MAP_WRITE); + memset (mem_info.data, 0, mem_info.size); + gst_memory_unmap (memory, &mem_info); + gst_buffer_append_memory (buffer, memory); + } + + alfecencaps->send_cb (buffer, FALSE, + alfecencaps->cb_user_data); + + GST_INFO_OBJECT (alfecencaps, "source packet processed"); + return TRUE; +} diff --git a/alfec/gstalfecencaps.h b/alfec/gstalfecencaps.h new file mode 100755 index 0000000..3cb03a1 --- /dev/null +++ b/alfec/gstalfecencaps.h @@ -0,0 +1,106 @@ +/* + * gstalfecencaps + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_ENCAPS_H__ +#define __GST_AL_FEC_ENCAPS_H__ + +#include + +G_BEGIN_DECLS + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_AL_FEC_ENCAPSULATOR (gst_al_fec_encapsulator_get_type()) +#define GST_AL_FEC_ENCAPSULATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AL_FEC_ENCAPSULATOR,GstALFECEncapsulator)) +#define GST_AL_FEC_ENCAPSULATOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AL_FEC_ENCAPSULATOR,GstALFECEncapsulatorClass)) +#define GST_IS_AL_FEC_ENCAPSULATOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AL_FEC_ENCAPSULATOR)) +#define GST_IS_AL_FEC_ENCAPSULATOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AL_FEC_ENCAPSULATOR)) +#define GST_AL_FEC_ENCAPSULATOR_CAST(obj) ((GstALFECEncapsulator *)(obj)) + +typedef struct _GstALFECEncapsulator GstALFECEncapsulator; +typedef struct _GstALFECEncapsulatorClass GstALFECEncapsulatorClass; + +typedef void (*encapsulator_send_cb)( + GstBuffer *buffer, + gboolean is_parity, + void *user_data); + +/* Definition of structure storing data for this element. */ +struct _GstALFECEncapsulator { + GstElement element; + + guint8 repair_id; + guint8 source_id; + guint8 block_id; + + encapsulator_send_cb send_cb; + void *cb_user_data; + +}; + +/* Standard definition defining a class for this element. */ +struct _GstALFECEncapsulatorClass { + GstElementClass parent_class; +}; + +/* Standard function returning type information. */ +GType gst_al_fec_encapsulator_get_type (void); + +void gst_al_fec_encapsulator_process_parity_block (GstALFECEncapsulator *alfecencaps, + GstBuffer **parity_block, guint8 p, guint32 t, guint8 k); + +gboolean gst_al_fec_encapsulator_process_source_buffer (GstALFECEncapsulator *alfecencaps, + GstBuffer *buffer, guint8 k, guint8 p, guint32 t); + +void gst_al_fec_encapsulator_set_send_cb (GstALFECEncapsulator * alfecencaps, + encapsulator_send_cb send_package, void *user_data); + +G_END_DECLS + +#endif /* __GST_AL_FEC_ENCAPSULATOR_H__ */ diff --git a/alfec/gstalfecencoder.c b/alfec/gstalfecencoder.c new file mode 100755 index 0000000..78330d0 --- /dev/null +++ b/alfec/gstalfecencoder.c @@ -0,0 +1,592 @@ +/* + * gstalfecencoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstalfecencoder.h" +#include "FECCodes.h" +#include "gstalfecheader.h" + +GST_DEBUG_CATEGORY_STATIC (gst_al_fec_encoder_debug); +#define GST_CAT_DEFAULT gst_al_fec_encoder_debug + +#define gst_al_fec_encoder_parent_class parent_class +G_DEFINE_TYPE (GstALFECEncoder, gst_al_fec_encoder, GST_TYPE_ELEMENT); + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_MAX_SIZE_K, + PROP_MAX_SIZE_P, + PROP_NEXT_K, + PROP_NEXT_P, + PROP_SYMBOL_LENGTH +}; + +/* default property values */ +#define DEFAULT_MAX_SIZE_K 10 +#define DEFAULT_MAX_SIZE_P 10 +#define DEFAULT_SYMBOL_LENGTH 200 + +/* object */ +static void gst_al_fec_encoder_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_al_fec_encoder_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_al_fec_encoder_finalize (GObject *object); + +static GstFlowReturn gst_al_fec_encoder_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer); + +static gboolean gst_al_fec_encoder_handle_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); + +static gboolean gst_al_fec_encoder_handle_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); + + +static gboolean gst_al_fec_encoder_src_activate_mode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active); +static gboolean gst_al_fec_encoder_sink_activate_mode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active); + +static void gst_al_fec_encoder_init_fec(GstALFECEncoder *alfecenc); +static void gst_al_fec_encoder_process_parity_block (GstALFECEncoder *enc, guint8 k); +static void gst_send_package_cb(GstBuffer *buffer, + gboolean is_parity, void *user_data); +static void gst_al_fec_encoder_finalize_fec (GstALFECEncoder *alfecenc); + + +/* element */ +static GstStateChangeReturn gst_al_fec_encoder_change_state (GstElement * element, + GstStateChange transition); + +//static guint gst_al_fec_encoder_signals[LAST_SIGNAL] = { 0 }; + +static void +gst_al_fec_encoder_class_init (GstALFECEncoderClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_al_fec_encoder_set_property; + gobject_class->get_property = gst_al_fec_encoder_get_property; + gobject_class->finalize = gst_al_fec_encoder_finalize; + + g_object_class_install_property (gobject_class, PROP_MAX_SIZE_K, + g_param_spec_uchar ("max-size-k", "Max. size (k)", + "Max. number of source symbol in a block", 1, G_MAXUINT8, + DEFAULT_MAX_SIZE_K, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MAX_SIZE_P, + g_param_spec_uchar ("max-size-p", "Max. size (p)", + "Max. number of parity symbol in a block", 0, G_MAXUINT8, + DEFAULT_MAX_SIZE_P, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_NEXT_K, + g_param_spec_uchar ("next-k", "next size of (k)", + "Value of k in next block", 1, G_MAXUINT8, + DEFAULT_MAX_SIZE_K, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_NEXT_P, + g_param_spec_uchar ("next-p", "next size of (p)", + "Value of p in next block", 0, G_MAXUINT8, + DEFAULT_MAX_SIZE_P, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SYMBOL_LENGTH, + g_param_spec_uint ("symbol-length", "Symbol length", + "Length of block symbol in bytes", 0, G_MAXUINT, + DEFAULT_SYMBOL_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_set_static_metadata (gstelement_class, + "The AL-FEC Encoder", "Codec/Encoder/FEC", + "Encode FEC packets for restoring", + "Samsung Electronics "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_al_fec_encoder_change_state); + + GST_DEBUG_CATEGORY_INIT (gst_al_fec_encoder_debug, "alfecencoder", 0, + "Application Level Forward Error Correction Encoder"); +} + +static void +gst_al_fec_encoder_init (GstALFECEncoder * alfecenc) +{ + alfecenc->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); + + gst_pad_set_chain_function (alfecenc->sinkpad, gst_al_fec_encoder_chain); + gst_pad_set_activatemode_function (alfecenc->sinkpad, + gst_al_fec_encoder_sink_activate_mode); + gst_pad_set_event_function (alfecenc->sinkpad, gst_al_fec_encoder_handle_sink_event); + gst_element_add_pad (GST_ELEMENT (alfecenc), alfecenc->sinkpad); + + alfecenc->srcpad = gst_pad_new_from_static_template (&srctemplate, "src"); + + gst_pad_set_activatemode_function (alfecenc->srcpad, + gst_al_fec_encoder_src_activate_mode); + gst_pad_set_event_function (alfecenc->srcpad, gst_al_fec_encoder_handle_src_event); + gst_element_add_pad (GST_ELEMENT (alfecenc), alfecenc->srcpad); + + alfecenc->max_k = DEFAULT_MAX_SIZE_K; + alfecenc->current_k = DEFAULT_MAX_SIZE_K; + alfecenc->next_k = DEFAULT_MAX_SIZE_K; + alfecenc->max_p = DEFAULT_MAX_SIZE_P; + alfecenc->current_p = DEFAULT_MAX_SIZE_P; + alfecenc->next_p = DEFAULT_MAX_SIZE_P; + alfecenc->symbol_length = DEFAULT_SYMBOL_LENGTH + DEFAULT_HEADER_SIZE; + + alfecenc->srcresult = GST_FLOW_FLUSHING; +} + +static void +gst_al_fec_encoder_finalize (GObject * object) +{ + /* GstALFECEncoder * alfecenc = GST_AL_FEC_ENCODER (object); */ + + G_OBJECT_CLASS(gst_al_fec_encoder_parent_class)->finalize(object); +} + +static GstFlowReturn +gst_al_fec_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER (parent); + + if (alfecenc->eos) + goto out_eos; + + if (!gst_al_fec_encapsulator_process_source_buffer (alfecenc->encapsulator, buffer, + alfecenc->current_k, alfecenc->current_p, alfecenc->symbol_length)) { + GST_ERROR_OBJECT (alfecenc, "can't process buffer with encapsulator"); + return GST_FLOW_ERROR; + } + + return ret; + +out_eos: + { + GST_LOG_OBJECT (alfecenc, "exit because we received EOS"); + + gst_buffer_unref (buffer); + return GST_FLOW_EOS; + } + +} + +static gboolean +gst_al_fec_encoder_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean ret = TRUE; + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER (parent); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + break; + case GST_EVENT_FLUSH_STOP: + break; + case GST_EVENT_EOS: + if (alfecenc->eos != TRUE) { + guint8 number_of_processed_symbols = FECCodes_get_encoder_symbol_number (&alfecenc->fec_enc_id); + if (number_of_processed_symbols == 0) { + GST_DEBUG_OBJECT (alfecenc, "there are no unsend packets in block"); + } else { + gst_al_fec_encoder_process_parity_block (alfecenc, number_of_processed_symbols); + } + alfecenc->eos = TRUE; + } + ret = gst_pad_event_default (pad, parent, event); + break; + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + + +static gboolean +gst_al_fec_encoder_handle_src_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean ret = TRUE; + /* GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER (parent); */ + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + break; + case GST_EVENT_FLUSH_STOP: + break; + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + + +static GstStateChangeReturn +gst_al_fec_encoder_change_state (GstElement * element, GstStateChange transition) +{ + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + gst_al_fec_encoder_init_fec (alfecenc); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_al_fec_encoder_finalize_fec (alfecenc); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + goto done; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + +done: + return ret; +} + +static gboolean +gst_al_fec_encoder_sink_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, + gboolean active) +{ + gboolean result = FALSE; + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER_CAST (parent); + + switch (mode) { + case GST_PAD_MODE_PUSH: + if (active) { + alfecenc->srcresult = GST_FLOW_OK; + alfecenc->eos = FALSE; + } else { + /* step 1, unblock chain function */ + alfecenc->srcresult = GST_FLOW_FLUSHING; + + /* step 2, wait until streaming thread stopped */ + GST_PAD_STREAM_LOCK (pad); + GST_PAD_STREAM_UNLOCK (pad); + } + result = TRUE; + break; + default: + result = FALSE; + break; + } + return result; +} + + +static gboolean +gst_al_fec_encoder_src_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, + gboolean active) +{ + gboolean result = FALSE; + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER_CAST (parent); + + switch (mode) { + case GST_PAD_MODE_PUSH: + if (active) { + alfecenc->srcresult = GST_FLOW_OK; + alfecenc->eos = FALSE; + result = TRUE; + } else { + /* step 1, unblock loop function */ + alfecenc->srcresult = GST_FLOW_FLUSHING; + + /* step 2, make sure streaming finishes */ + result = TRUE; + } + break; + default: + result = FALSE; + break; + } + return result; +} + +static void +gst_al_fec_encoder_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER_CAST (object); + + unsigned char number; + switch (prop_id) { + case PROP_MAX_SIZE_K: + alfecenc->max_k = g_value_get_uchar (value); + if (alfecenc->max_k > MAX_SIZE_K) { + alfecenc->max_k = MAX_SIZE_K; + } + alfecenc->next_k = alfecenc->max_k; + break; + case PROP_MAX_SIZE_P: + alfecenc->max_p = g_value_get_uchar (value); + if (alfecenc->max_p > MAX_SIZE_P) { + alfecenc->max_p = MAX_SIZE_P; + } + alfecenc->next_p = alfecenc->max_p; + break; + case PROP_NEXT_K: + number = g_value_get_uchar (value); + if (number > 0 && number <= alfecenc->max_k) { + alfecenc->next_k = number; + } + break; + case PROP_NEXT_P: + number = g_value_get_uchar (value); + if (number > 0 && number <= alfecenc->max_p) { + alfecenc->next_p = number; + } + break; + case PROP_SYMBOL_LENGTH: + alfecenc->symbol_length = g_value_get_uint (value) + DEFAULT_HEADER_SIZE; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +gst_al_fec_encoder_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstALFECEncoder *alfecenc = GST_AL_FEC_ENCODER_CAST (object); + + switch (prop_id) { + case PROP_MAX_SIZE_K: + g_value_set_uchar (value, alfecenc->max_k); + break; + case PROP_MAX_SIZE_P: + g_value_set_uchar (value, alfecenc->max_p); + break; + case PROP_NEXT_K: + g_value_set_uchar (value, alfecenc->next_k); + break; + case PROP_NEXT_P: + g_value_set_uchar (value, alfecenc->next_p); + break; + case PROP_SYMBOL_LENGTH: + g_value_set_uint (value, alfecenc->symbol_length); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_al_fec_encoder_create_parity_block (GstALFECEncoder *enc, const guint8 *p) +{ + GstBuffer *buffer; + guint i = 0; + if (!gst_buffer_pool_is_active (enc->pool)) { + GstStructure *conf = gst_buffer_pool_get_config (enc->pool); + GstCaps *caps = gst_caps_new_empty_simple ("fec"); + gst_buffer_pool_config_set_params (conf, caps, enc->symbol_length + DEFAULT_HEADER_SIZE, 1, 2 * enc->max_p); + gst_buffer_pool_set_config (enc->pool, conf); + + if (!gst_buffer_pool_set_active (enc->pool, TRUE)) { + GST_ERROR_OBJECT (enc, "activation failed"); + return; + } + } + + for (i = 0; i < enc->current_p; ++i) { + if (gst_buffer_pool_acquire_buffer (enc->pool, &buffer, NULL) != GST_FLOW_OK) { + GST_ERROR_OBJECT (enc, "gst_buffer_pool_acquire_buffer failed"); + return; + } + + if (!gst_buffer_map (buffer, &enc->parity_map[i], GST_MAP_WRITE)) { + GST_ERROR_OBJECT (enc, "gst_buffer_map failed"); + return; + } + enc->parity_blocks[i] = enc->parity_map[i].data + DEFAULT_HEADER_SIZE; + enc->parity_buffer[i] = buffer; + } + + FECCodes_set_parity_block (enc->parity_blocks, &enc->current_k, &enc->current_p, &enc->fec_enc_id); +} + +static void +gst_al_fec_encoder_init_fec(GstALFECEncoder *alfecenc) +{ + /* TODO: Init FEC codes.*/ + guint8 isEncoder = 1; //affirmative value for encoder + guint8 codeTypeID = CODE_ID_RS; + + alfecenc->pool = gst_buffer_pool_new (); + + alfecenc->fec_enc_id = FECCodes_Initialize(&alfecenc->max_k, &alfecenc->max_p, &alfecenc->symbol_length, + &isEncoder, &codeTypeID, NULL); + alfecenc->alg = g_object_new (GST_TYPE_SOURCE_BLOCKING_ALGORITHM, NULL); + alfecenc->encapsulator = g_object_new (GST_TYPE_AL_FEC_ENCAPSULATOR, NULL); + /* Only for testing with k_max = 5 and following pipeline: + * gst-launch-1.0 filesrc blocksize=200 location ... ! + * alfecenc ! fakesink dump=true */ + alfecenc->current_k = alfecenc->next_k; + alfecenc->current_p = alfecenc->next_p; + gst_al_fec_encoder_create_parity_block (alfecenc, &alfecenc->current_p); + + gst_al_fec_encapsulator_set_send_cb (alfecenc->encapsulator, gst_send_package_cb, alfecenc); + GST_INFO_OBJECT (alfecenc, "FEC Codes init sucess"); +} + +static void gst_al_fec_encoder_process_parity_block (GstALFECEncoder *enc, guint8 k) +{ + guint i = 0; + for (i = 0; i < enc->current_p; ++i) { + gst_buffer_unmap (enc->parity_buffer[i], &enc->parity_map[i]); + } + + gst_al_fec_encapsulator_process_parity_block (enc->encapsulator, enc->parity_buffer, enc->current_p, enc->symbol_length, k); +} + +static void +gst_send_package_cb(GstBuffer *buf, + gboolean is_parity, void *user_data) +{ + GstALFECEncoder *enc = GST_AL_FEC_ENCODER (user_data); + + if (!is_parity) { + GstMapInfo buf_info; + gboolean is_computed; + + gst_buffer_map (buf, &buf_info, GST_MAP_READ); + + gst_buffer_ref (buf); + gst_pad_push (enc->srcpad, buf); + + if (!FECCodes_Encode_single_symbol (buf_info.data, &is_computed, &enc->fec_enc_id)) { + GST_WARNING_OBJECT (enc, "FEC can't process source symbol"); + } else { + GST_DEBUG_OBJECT (enc, "FEC encode single symbol"); + } + + gst_buffer_unmap (buf, &buf_info); + gst_buffer_unref (buf); + + if (is_computed) { + gst_al_fec_encoder_process_parity_block (enc, enc->current_k); + + enc->current_p = enc->next_p; + enc->current_k = enc->next_k; + gst_al_fec_encoder_create_parity_block (enc, &enc->current_p); + } + } else { + gst_pad_push (enc->srcpad, buf); + } +} + +static void +gst_al_fec_encoder_finalize_fec (GstALFECEncoder *alfecenc) +{ + /* TODO: Add fec destroy func */ + g_object_unref (alfecenc->alg); + g_object_unref (alfecenc->pool); + alfecenc->alg = NULL; + g_object_unref (alfecenc->encapsulator); + alfecenc->encapsulator = NULL; + if (!FECCodes_Deinitialize (&alfecenc->fec_enc_id)) { + GST_ERROR_OBJECT (alfecenc, "FEC code instance can't be deinitialized"); + } +} diff --git a/alfec/gstalfecencoder.h b/alfec/gstalfecencoder.h new file mode 100755 index 0000000..2d2c486 --- /dev/null +++ b/alfec/gstalfecencoder.h @@ -0,0 +1,105 @@ +/* + * gstalfecencoder + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_ENCODER_H__ +#define __GST_AL_FEC_ENCODER_H__ + +#include +#include "gst_source_blocking_algorithm.h" +#include "gstalfecencaps.h" + +G_BEGIN_DECLS + +#define MAX_SIZE_K 100 +#define MAX_SIZE_P 100 + +/* Definition of structure storing data for this element. */ +typedef struct _GstALFECEncoder { + GstElement element; + GstBufferPool *pool; + GstBuffer *parity_buffer[MAX_SIZE_P]; + GstMapInfo parity_map[MAX_SIZE_P]; + guint8 *parity_blocks[MAX_SIZE_P]; + + GstPad *sinkpad, *srcpad; + GstFlowReturn srcresult; + gboolean eos; + + guint8 max_k; + guint8 max_p; + guint8 current_k; + guint8 next_k; + guint8 current_p; + guint8 next_p; + guint32 symbol_length; + guint8 fec_enc_id; + GstSourceBlockingAlgorithm *alg; + GstALFECEncapsulator *encapsulator; +} GstALFECEncoder; + +/* Standard definition defining a class for this element. */ +typedef struct _GstALFECEncoderClass { + GstElementClass parent_class; +} GstALFECEncoderClass; + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_AL_FEC_ENCODER (gst_al_fec_encoder_get_type()) +#define GST_AL_FEC_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AL_FEC_ENCODER,GstALFECEncoder)) +#define GST_AL_FEC_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AL_FEC_ENCODER,GstALFECEncoderClass)) +#define GST_IS_AL_FEC_ENCODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AL_FEC_ENCODER)) +#define GST_IS_AL_FEC_ENCODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AL_FEC_ENCODER)) +#define GST_AL_FEC_ENCODER_CAST(obj) ((GstALFECEncoder *)(obj)) + +/* Standard function returning type information. */ +GType gst_al_fec_encoder_get_type (void); + +G_END_DECLS + +#endif /* __GST_AL_FEC_ENCODER_H__ */ diff --git a/alfec/gstalfecheader.h b/alfec/gstalfecheader.h new file mode 100755 index 0000000..ec647c4 --- /dev/null +++ b/alfec/gstalfecheader.h @@ -0,0 +1,66 @@ +/* + * gstalfecheader + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Yaroslav Zatsikha + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_AL_FEC_HEADER_H__ +#define __GST_AL_FEC_HEADER_H__ + +enum +{ + BLOCK_NUMBER = 0, ///< sent block number + PACKAGE_NUMBER = 1, ///< number of package in block + PACKAGE_SIZE = 2, ///< size of packet + SOURCE_NUMBER = 6, ///< k number in FEC notation + PARITY_NUMBER = 7, ///< p number in FEC notation +} HEADER_ALLIGMENT; ///< Describe alignment of header fields in a package + +//currently PARITY_NUMBER is not used in header and is predefined in encoder +//and decoder; SOURCE_NUMBER currently changes only in last block as there +//can be different from predefined number of packets + + +#define DEFAULT_HEADER_SIZE 8 + +#endif /* __GST_AL_FEC_HEADER_H__ */ diff --git a/alfec/gstnetsim.c b/alfec/gstnetsim.c new file mode 100755 index 0000000..ca3354b --- /dev/null +++ b/alfec/gstnetsim.c @@ -0,0 +1,415 @@ +/* + * Farsight Voice+Video library + * + * Copyright 2006 Collabora Ltd, + * Copyright 2006 Nokia Corporation + * @author: Philippe Kalaf . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "gstnetsim.h" + +GST_DEBUG_CATEGORY_STATIC (netsim_debug); +#define GST_CAT_DEFAULT (netsim_debug) + +#define gst_net_sim_parent_class parent_class +/* NetSim signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_MIN_DELAY, + ARG_MAX_DELAY, + ARG_DELAY_PROBABILITY, + ARG_DROP_PROBABILITY, + ARG_DUPLICATE_PROBABILITY +}; + +struct _GstNetSimPrivate +{ + GstPad *sinkpad, *srcpad; + + GMainLoop *main_loop; + GMainContext *main_context; + GRand *rand_seed; + gint min_delay; + gint max_delay; + gfloat delay_probability; + gfloat drop_probability; + gfloat duplicate_probability; +}; + +typedef struct +{ + GstNetSim *netsim; + GstBuffer *buffer; +} SourceInfo; + +/* these numbers are nothing but wild guesses and dont reflect any reality */ +#define DEFAULT_MIN_DELAY 200 +#define DEFAULT_MAX_DELAY 400 +#define DEFAULT_DELAY_PROBABILITY 0.5 +#define DEFAULT_DROP_PROBABILITY 0.2 +#define DEFAULT_DUPLICATE_PROBABILITY 0.1 + +#define GST_NET_SIM_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_NET_SIM, \ + GstNetSimPrivate)) + +static GstStaticPadTemplate gst_net_sim_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY +); + +static GstStaticPadTemplate gst_net_sim_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY +); + +static void gst_net_sim_set_property (GObject *object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_net_sim_get_property (GObject *object, + guint prop_id, GValue *value, GParamSpec *pspec); +/* static void gst_net_sim_dispose (GObject *object); */ + +static gboolean +gst_net_sim_src_activate_push (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active); + +static GstStateChangeReturn gst_net_sim_change_state ( + GstElement *element, GstStateChange transition); +static GstFlowReturn gst_net_sim_chain (GstPad *pad, + GstObject *parent, GstBuffer *buffer); +static void gst_net_sim_loop (GstNetSim *netsim); + + +G_DEFINE_TYPE_WITH_CODE (GstNetSim, gst_net_sim, GST_TYPE_ELEMENT, NULL); + +static void +gst_net_sim_class_init (GstNetSimClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_net_sim_set_property; + gobject_class->get_property = gst_net_sim_get_property; + + g_object_class_install_property (gobject_class, ARG_MIN_DELAY, + g_param_spec_int ("min_delay", + "Minimum delay (ms)", + "The minimum delay in ms to apply to buffers", + G_MININT, G_MAXINT, DEFAULT_MIN_DELAY, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_MAX_DELAY, + g_param_spec_int ("max_delay", + "Maximum delay (ms)", + "The maximum delay in ms to apply to buffers", + G_MININT, G_MAXINT, DEFAULT_MAX_DELAY, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + ARG_DELAY_PROBABILITY, g_param_spec_float ("delay_probability", + "Delay Probability", + "The Probability a buffer is delayed", 0.0, 1.0, + DEFAULT_DELAY_PROBABILITY, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + ARG_DROP_PROBABILITY, g_param_spec_float ("drop_probability", + "Drop Probability", + "The Probability a buffer is dropped", 0.0, 1.0, + DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + ARG_DUPLICATE_PROBABILITY, g_param_spec_float ("duplicate_probability", + "Duplicate Probability", + "The Probability a buffer is duplicated", 0.0, 1.0, + DEFAULT_DUPLICATE_PROBABILITY, G_PARAM_READWRITE)); + + gstelement_class->change_state = gst_net_sim_change_state; + gst_element_class_set_static_metadata (gstelement_class, + "Network Simulator", + "Filter/Network", + "An element that simulates network jitter, packet loss and packet duplication", + "Philippe Kalaf "); + + GST_DEBUG_CATEGORY_INIT + (netsim_debug, "netsim", 0, "Network simulator"); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_net_sim_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_net_sim_sink_template)); + + g_type_class_add_private (klass, sizeof (GstNetSimPrivate)); +} + +static void +gst_net_sim_init (GstNetSim *netsim) +{ + GstNetSimPrivate *priv = + GST_NET_SIM_GET_PRIVATE (netsim); + netsim->priv = priv; + + priv->srcpad = + gst_pad_new_from_static_template (&gst_net_sim_src_template, "src"); + priv->sinkpad = + gst_pad_new_from_static_template (&gst_net_sim_sink_template, "sink"); + + gst_element_add_pad (GST_ELEMENT (netsim), priv->srcpad); + gst_element_add_pad (GST_ELEMENT (netsim), priv->sinkpad); + + priv->min_delay = DEFAULT_MIN_DELAY; + priv->max_delay = DEFAULT_MAX_DELAY; + priv->delay_probability = DEFAULT_DELAY_PROBABILITY; + priv->drop_probability = DEFAULT_DROP_PROBABILITY; + priv->duplicate_probability = DEFAULT_DUPLICATE_PROBABILITY; + + priv->rand_seed = g_rand_new (); + + gst_pad_set_chain_function (priv->sinkpad, gst_net_sim_chain); + + gst_pad_set_activatemode_function (priv->srcpad, + GST_DEBUG_FUNCPTR (gst_net_sim_src_activate_push)); +} + +static gboolean +gst_net_sim_src_activate_push (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) +{ + gboolean result = TRUE; + GstNetSim *netsim = NULL; + + netsim = GST_NET_SIM (gst_pad_get_parent (pad)); + + if (active) { +#if 0 + /* we do not start the task yet if the pad is not connected */ + if (gst_pad_is_linked (pad)) + result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); + else { + GST_DEBUG_OBJECT (queue, "not starting task as pad is not linked"); + result = TRUE; + } +#endif + } else { + g_main_loop_quit (netsim->priv->main_loop); + /* NOTE this will hardlock if the state change is called from the src pad + * task thread */ + GST_DEBUG_OBJECT (netsim, "Stopping task on srcpad"); + result = gst_pad_stop_task (pad); + } + + gst_object_unref (netsim); + + return result; +} + +static GstStateChangeReturn +gst_net_sim_change_state (GstElement * element, + GstStateChange transition) +{ + GstNetSim *netsim; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + netsim = GST_NET_SIM (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_DEBUG_OBJECT (netsim, "Starting task on srcpad"); + gst_pad_start_task (netsim->priv->srcpad, + (GstTaskFunction) gst_net_sim_loop, netsim, NULL); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +static gboolean +push_buffer (SourceInfo *info) +{ + GST_DEBUG_OBJECT (info->netsim, "Pushing buffer now"); + gst_pad_push (info->netsim->priv->srcpad, info->buffer); + g_free (info); + + return FALSE; +} + +static GstFlowReturn +gst_net_sim_delay_buffer (GstNetSim *netsim, GstPad *pad, GstBuffer *buffer) +{ + GstNetSimPrivate *priv = netsim->priv; + GSource *source; + + if (priv->delay_probability > 0) + { + if (g_rand_double_range (priv->rand_seed, 0, 1) < priv->delay_probability) + { + SourceInfo *info = g_new0 (SourceInfo, 1); + gint delay; + info->netsim = netsim; + info->buffer = buffer; + delay = g_rand_int_range (priv->rand_seed, priv->min_delay, + priv->max_delay); + GST_DEBUG_OBJECT (netsim, "Delaying packet by %d", delay); + source = g_timeout_source_new (delay); + g_source_set_callback (source, (GSourceFunc)push_buffer, info, NULL); + g_source_attach (source, priv->main_context); + + return GST_FLOW_OK; + } + } + + return gst_pad_push (pad, buffer); +} + +static GstFlowReturn +gst_net_sim_chain (GstPad *pad, GstObject * parent, GstBuffer *buffer) +{ + GstNetSim *netsim; + GstNetSimPrivate *priv; + + netsim = GST_NET_SIM (gst_pad_get_parent (pad)); + priv = netsim->priv; + + if (priv->drop_probability > 0) + { + if ((gfloat)g_rand_double_range (priv->rand_seed, 0, 1) < + priv->drop_probability) + { + GST_DEBUG_OBJECT (netsim, "Dropping packet"); + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } + } + if (priv->duplicate_probability > 0) + { + if ((gfloat)g_rand_double_range (priv->rand_seed, 0, 1) < + priv->duplicate_probability) + { + GST_DEBUG_OBJECT (netsim, "Duplicating packet"); + gst_buffer_ref (buffer); + gst_net_sim_delay_buffer (netsim, priv->srcpad, buffer); + } + } + + return gst_net_sim_delay_buffer (netsim, priv->srcpad, buffer); +} + + +static void +gst_net_sim_loop (GstNetSim *netsim) +{ + GstNetSimPrivate *priv; + + priv = netsim->priv; + + GST_DEBUG_OBJECT (netsim, "Creating mainloop and context"); + priv->main_context = g_main_context_new (); + priv->main_loop = g_main_loop_new (priv->main_context, FALSE); + + g_main_loop_run (priv->main_loop); +} + +static void +gst_net_sim_set_property (GObject *object, + guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstNetSim *netsim = GST_NET_SIM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + case ARG_MIN_DELAY: + netsim->priv->min_delay = g_value_get_int (value); + break; + case ARG_MAX_DELAY: + netsim->priv->max_delay = g_value_get_int (value); + break; + case ARG_DELAY_PROBABILITY: + netsim->priv->delay_probability = g_value_get_float (value); + break; + case ARG_DROP_PROBABILITY: + netsim->priv->drop_probability = g_value_get_float (value); + break; + case ARG_DUPLICATE_PROBABILITY: + netsim->priv->duplicate_probability = g_value_get_float (value); + break; + } +} + +static void +gst_net_sim_get_property (GObject *object, + guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstNetSim *netsim = GST_NET_SIM (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + case ARG_MIN_DELAY: + g_value_set_int (value, netsim->priv->min_delay); + break; + case ARG_MAX_DELAY: + g_value_set_int (value, netsim->priv->max_delay); + break; + case ARG_DELAY_PROBABILITY: + g_value_set_float (value, netsim->priv->delay_probability); + break; + case ARG_DROP_PROBABILITY: + g_value_set_float (value, netsim->priv->drop_probability); + break; + case ARG_DUPLICATE_PROBABILITY: + g_value_set_float (value, netsim->priv->duplicate_probability); + break; + } +} diff --git a/alfec/gstnetsim.h b/alfec/gstnetsim.h new file mode 100755 index 0000000..2147321 --- /dev/null +++ b/alfec/gstnetsim.h @@ -0,0 +1,72 @@ +/* + * Farsight Voice+Video library + * + * Copyright 2006 Collabora Ltd, + * Copyright 2006 Nokia Corporation + * @author: Philippe Kalaf . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GST_NET_SIM_H__ +#define __GST_NET_SIM_H__ + +#include + +G_BEGIN_DECLS + +/* #define's don't like whitespacey bits */ +#define GST_TYPE_NET_SIM \ + (gst_net_sim_get_type()) +#define GST_NET_SIM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_TYPE_NET_SIM,GstNetSim)) +#define GST_NET_SIM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_NET_SIM,GstNetSimClass)) +#define GST_IS_NET_SIM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NET_SIM)) +#define GST_IS_NET_SIM_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NET_SIM)) + +typedef struct _GstNetSim GstNetSim; +typedef struct _GstNetSimClass GstNetSimClass; +typedef struct _GstNetSimPrivate GstNetSimPrivate; + +struct _GstNetSim +{ + GstElement parent; + + GstNetSimPrivate *priv; + + /*< private > */ + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstNetSimClass +{ + GstElementClass parent_class; + + /*< private > */ + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_net_sim_get_type (void); + +G_END_DECLS + +#endif /* __GST_NET_SIM_H__ */ diff --git a/configure.ac b/configure.ac old mode 100644 new mode 100755 index 1111f3f..e551214 --- a/configure.ac +++ b/configure.ac @@ -363,6 +363,54 @@ AC_ARG_ENABLE(tizenipc, AC_HELP_STRING([--enable-tizenipc], [using tizenipc]), [GST_TIZEN_USE_TIZENIPC=yes]) AM_CONDITIONAL(GST_TIZEN_USE_TIZENIPC, test "x$GST_TIZEN_USE_TIZENIPC" = "xyes") +dnl use ext-wfdextmanager -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-wfdextmanager, AC_HELP_STRING([--enable-ext-wfdextmanager], [using wfdextmanager]), +[ + case "${enableval}" in + yes) GST_TIZEN_USE_WFDEXTMANAGER=yes ;; + no) GST_TIZEN_USE_WFDEXTMANAGER=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-wfdextmanager) ;; + esac + ], + [GST_TIZEN_USE_WFDEXTMANAGER=yes]) +AM_CONDITIONAL(GST_TIZEN_USE_WFDEXTMANAGER, test "x$GST_TIZEN_USE_WFDEXTMANAGER" = "xyes") + +dnl use ext-wfdtizenmanager -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-wfdtizenmanager, AC_HELP_STRING([--enable-ext-wfdtizenmanager], [using wfdtizenmanager]), +[ + case "${enableval}" in + yes) GST_TIZEN_USE_WFDTIZENMANAGER=yes ;; + no) GST_TIZEN_USE_WFDTIZENMANAGER=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-wfdtizenmanager) ;; + esac + ], + [GST_TIZEN_USE_WFDTIZENMANAGER=yes]) +AM_CONDITIONAL(GST_TIZEN_USE_WFDTIZENMANAGER, test "x$GST_TIZEN_USE_WFDTIZENMANAGER" = "xyes") + +dnl use ext-alfec -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-alfec, AC_HELP_STRING([--enable-ext-alfec], [using alfec]), +[ + case "${enableval}" in + yes) GST_TIZEN_USE_ALFEC=yes ;; + no) GST_TIZEN_USE_ALFEC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-alfec) ;; + esac + ], + [GST_TIZEN_USE_ALFEC=yes]) +AM_CONDITIONAL(GST_TIZEN_USE_ALFEC, test "x$GST_TIZEN_USE_ALFEC" = "xyes") + +dnl use ext-rtpresender -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-rtpresender, AC_HELP_STRING([--enable-ext-rtpresender], [using rtpresender]), + [ + case "${enableval}" in + yes) GST_TIZEN_USE_RTPRESENDER=yes ;; + no) GST_TIZEN_USE_RTPRESENDER=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-rtpresender) ;; + esac + ], + [GST_TIZEN_USE_RTPRESENDER=yes]) +AM_CONDITIONAL(GST_TIZEN_USE_RTPRESENDER, test "x$GST_TIZEN_USE_RTPRESENDER" = "xyes") + AC_OUTPUT( Makefile common/Makefile @@ -390,4 +438,9 @@ drmdecryptor/Makefile drmdecryptor/src/Makefile tizenipc/Makefile tizenipc/src/Makefile +wfdtizenmanager/Makefile +wfdextmanager/Makefile +alfec/Makefile +rtpresender/Makefile +rtpresender/src/Makefile ) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec old mode 100644 new mode 100755 index 3d9c0e9..3661aba --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -63,6 +63,10 @@ export CFLAGS="$CFLAGS -DTIZEN_PROFILE_LITE" ./autogen.sh --disable-static %configure \ --disable-drmdecryptor\ + --enable-ext-wfdextmanager\ + --enable-ext-wfdtizenmanager\ + --enable-ext-alfec\ + --enable-ext-rtpresender\ --disable-static make %{?jobs:-j%jobs} @@ -73,7 +77,6 @@ rm -rf %{buildroot} mkdir -p %{buildroot}/%{_datadir}/license cp -rf %{_builddir}/%{name}-%{version}/COPYING %{buildroot}%{_datadir}/license/%{name} - %files %manifest gst-plugins-tizen1.0.manifest %defattr(-,root,root,-) diff --git a/rtpresender/Makefile.am b/rtpresender/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/rtpresender/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/rtpresender/src/Makefile.am b/rtpresender/src/Makefile.am new file mode 100755 index 0000000..ca13abb --- /dev/null +++ b/rtpresender/src/Makefile.am @@ -0,0 +1,29 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstrtpresender.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstrtpresender_la_SOURCES = gstrtpresender.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstrtpresender_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstrtpresender_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + $(WIN32_LIBS) +libgstrtpresender_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstrtpresender.h + diff --git a/rtpresender/src/gstrtpresender.c b/rtpresender/src/gstrtpresender.c new file mode 100644 index 0000000..ffac507 --- /dev/null +++ b/rtpresender/src/gstrtpresender.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2000-2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Yejin Cho < cho.yejin@samsung.com > + * + * PROPRIETARY/CONFIDENTIAL + * + * This software is the confidential and proprietary information of + * SAMSUNG ELECTRONICS ("Confidential Information"). + * You shall not disclose such Confidential Information and shall + * use it only in accordance with the terms of the license agreement + * you entered into with SAMSUNG ELECTRONICS. + * SAMSUNG make no representations or warranties about the suitability + * of the software, either express or implied, including but not + * limited to the implied warranties of merchantability, fitness for + * a particular purpose, or non-infringement. + * SAMSUNG shall not be liable for any damages suffered by licensee as + * a result of using, modifying or distributing this software or its derivatives. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "gstrtpresender.h" + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_MAX_RESEND_NUM, + PROP_MAX_SLOT_NUM, + PROP_RTP_FRACTION_LOST, + PROP_PACKETS_RESEND +}; + +#define DEFAULT_MAX_RESEND_NUM 3 +#define DEFAULT_MAX_SLOT_NUM 4096 + +#define GST_RESENDER_MUTEX_LOCK(r) G_STMT_START { \ + g_mutex_lock(&r->qlock); \ +} G_STMT_END + +#define GST_RESENDER_MUTEX_UNLOCK(r) G_STMT_START { \ + g_mutex_unlock(&r->qlock); \ +} G_STMT_END + +/* the capabilities of the inputs and outputs. */ +static GstStaticPadTemplate rtp_sink_template = +GST_STATIC_PAD_TEMPLATE ("rtp_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate rtcp_sink_template = +GST_STATIC_PAD_TEMPLATE ("rtcp_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rctp") + ); + +static GstStaticPadTemplate send_src_template = +GST_STATIC_PAD_TEMPLATE ("send_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate resend_src_template = +GST_STATIC_PAD_TEMPLATE ("resend_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +//////////////////////////////////////////////////////// +// Gstreamer Base Prototype // +//////////////////////////////////////////////////////// + +GST_DEBUG_CATEGORY_STATIC (rtp_resender_debug); +#define GST_CAT_DEFAULT rtp_resender_debug + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT(rtp_resender_debug, "rtpresender", 0, "rtpresender element"); + +G_DEFINE_TYPE_WITH_CODE (GstRTPResender, gst_rtp_resender, GST_TYPE_ELEMENT, + _do_init (G_TYPE_INVALID)); + +static void gst_rtp_resender_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_rtp_resender_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_rtp_resender_rtp_sink_event (GstPad * pad, + GstObject * parent, GstEvent * event); +static GstFlowReturn gst_rtp_resender_chain_recv_rtp (GstPad * pad, + GstObject * parent, GstBuffer * buffer); +static gboolean gst_rtp_resender_insert_rtp (GstRTPResender * resender, + GstBuffer * buf); +static GstBuffer *gst_rtp_resender_extract_rtp (GstRTPResender * resender, + guint16 seqnum, guint16 pid); + +static GstFlowReturn gst_rtp_resender_chain_recv_rtcp (GstPad * pad, + GstObject * parent, GstBuffer * buf); +static gboolean gst_rtp_resender_parse_rtcp (GstRTPResender * resender, + GstBuffer * buf, guint16 * pid, guint16 * blp); + +static void alloc_slots (GstRTPResender * resender); +static void free_slots (GstRTPResender * resender); +static void set_resend_num (GstRTPResender * resender); +static void update_fraction_lost (GstRTPResender * resender, + guint fraction_lost); + +/* GObject vmethod implementations */ +static void +gst_rtp_resender_dispose (GObject * object) +{ + GstRTPResender *resender = GST_RTP_RESENDER (object); + + g_timer_destroy (resender->timer); + g_mutex_clear (&resender->qlock); + free_slots (resender); + + G_OBJECT_CLASS (gst_rtp_resender_parent_class)->dispose (object); +} + +/* initialize the plugin's class */ +static void +gst_rtp_resender_class_init (GstRTPResenderClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_rtp_resender_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_rtp_resender_get_property); + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_rtp_resender_dispose); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtp_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtcp_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&send_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&resend_src_template)); + + gst_element_class_set_static_metadata (gstelement_class, + "RTP resender utility", "Utility/RTP", + "Resends RTP packages based on RTCP packages", + "Samsung Electronics "); + + g_object_class_install_property (gobject_class, PROP_MAX_RESEND_NUM, + g_param_spec_uint ("max-resend-num", "Maximum number of resend", + "Maximum number of resending RTP packet", 0, G_MAXUINT, + DEFAULT_MAX_RESEND_NUM, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_MAX_SLOT_NUM, + g_param_spec_uint ("slot-num", "The number of slots", + "The number of slots", 0, G_MAXUINT, + DEFAULT_MAX_SLOT_NUM, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_RTP_FRACTION_LOST, + g_param_spec_uint ("rtp-fraction-lost", + "The RTP fraction lost value from RTCP RR", + "The RTP fraction lost value from RTCP RR", 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_PACKETS_RESEND, + g_param_spec_uint ("rtp-packets-resend", + "Total number of packets resent in this session", + "Total number of packets resent in this session", 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); +} + +/* initialize the new element + * instantiate pads and add them to element + * set pad calback functions + * initialize instance structure + */ +static void +gst_rtp_resender_init (GstRTPResender * resender) +{ + /* sink pad for handling rtp packets */ + resender->rtp_sinkpad = + gst_pad_new_from_static_template (&rtp_sink_template, "rtp_sink"); + gst_pad_set_event_function (resender->rtp_sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_resender_rtp_sink_event)); + gst_pad_set_chain_function (resender->rtp_sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_resender_chain_recv_rtp)); + gst_element_add_pad (GST_ELEMENT (resender), resender->rtp_sinkpad); + + /* sink pad for handling rtcp packets */ + resender->rtcp_sinkpad = + gst_pad_new_from_static_template (&rtcp_sink_template, "rtcp_sink"); + gst_pad_set_chain_function (resender->rtcp_sinkpad, + GST_DEBUG_FUNCPTR (gst_rtp_resender_chain_recv_rtcp)); + gst_element_add_pad (GST_ELEMENT (resender), resender->rtcp_sinkpad); + + /* sink pad for handling rtcp packets */ + resender->send_srcpad = + gst_pad_new_from_static_template (&send_src_template, "send_src"); + gst_element_add_pad (GST_ELEMENT (resender), resender->send_srcpad); + + resender->resend_srcpad = + gst_pad_new_from_static_template (&resend_src_template, "resend_src"); + gst_element_add_pad (GST_ELEMENT (resender), resender->resend_srcpad); + + resender->timer = g_timer_new (); + + /* properties */ + resender->max_resend_num = DEFAULT_MAX_RESEND_NUM; + resender->max_slot_num = DEFAULT_MAX_SLOT_NUM; + + g_mutex_init (&resender->qlock); + resender->is_set_caps = FALSE; + + resender->prev_rtcp_pid = 0; + resender->prev_rtcp_blp = 0; + resender->rtcp_repeat_time = 0; + resender->resend_seqnum = 0; + resender->packets_resend = 0; + + alloc_slots (resender); +} + +static gboolean +gst_rtp_resender_rtp_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + GstRTPResender *resender; + gboolean ret; + + resender = (GstRTPResender *) GST_OBJECT_PARENT (pad); + + switch (GST_EVENT_TYPE (event)) { + default: + ret = gst_pad_push_event (resender->send_srcpad, event); + break; + } + return ret; +} + +static GstFlowReturn +gst_rtp_resender_chain_recv_rtp (GstPad * pad, GstObject * parent, + GstBuffer * buffer) +{ + GstRTPResender *resender; + + resender = (GstRTPResender *) GST_OBJECT_PARENT (pad); + +/* + * if (!resender->is_set_caps) { + * caps = gst_buffer_get_caps(buffer); + * gst_pad_set_caps(resender->resend_srcpad, caps); + * + * type = gst_caps_to_string(caps); + * + * GST_DEBUG_OBJECT(resender, "set caps if resend_srcpad to %s", type); + * + * g_free(type); + * gst_caps_unref(caps); + * + * resender->is_set_caps = TRUE; + * } + */ + + if (!gst_rtp_resender_insert_rtp (resender, buffer)) + GST_WARNING_OBJECT (resender, "fail to insert rtp packet"); + + /* just push out the incoming buffer without touching it */ + return gst_pad_push (resender->send_srcpad, buffer); +} + +static gboolean +gst_rtp_resender_insert_rtp (GstRTPResender * resender, GstBuffer * buffer) +{ + guint16 seqnum; + guint16 slotnum; + GstRTPBuffer rtp_buf = { NULL }; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + + /* Check if the data pointed to by buf is a valid RTP packet */ + if (G_UNLIKELY (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp_buf))) + goto invalid_buffer; + + /* get rtp packet #seqnum */ + seqnum = gst_rtp_buffer_get_seq (&rtp_buf); + + /* calculate #slotnum for rtp packet to be inserted */ + switch (resender->max_slot_num) { + case 1024: + slotnum = seqnum & 0x03ff; + break; + case 2048: + slotnum = seqnum & 0x07ff; + break; + case 4096: + slotnum = seqnum & 0x0fff; + break; + case 8192: + slotnum = seqnum & 0x1fff; + break; + case 16384: + slotnum = seqnum & 0x3fff; + break; + case 32768: + slotnum = seqnum & 0x7fff; + break; + case 65536: + slotnum = seqnum & 0xffff; + break; + default: + slotnum = seqnum & 0x03ff; + break; + } + + /* insert rtp packet into #slotnum */ + GST_RESENDER_MUTEX_LOCK (resender); + +#if 0 + if (resender->slots[slotnum]) { + //GST_LOG_OBJECT (resender, "free slot #%d for new rtp packet", slotnum); + g_byte_array_free (resender->slots[slotnum], TRUE); + resender->slots[slotnum] = NULL; + } + GST_LOG_OBJECT (resender, "buffer size : %d, data size %d", + sizeof (GstBuffer), buf_size); + + //GST_LOG_OBJECT (resender, "insert rtp packet #%d(%d bytes) into slot #%d", seqnum, buf_size, slotnum); + + resender->slots[slotnum] = g_byte_array_sized_new (buf_size); + if (resender->slots[slotnum] == NULL) { + GST_WARNING_OBJECT (resender, + "fail to allocate slot #%d for rtp packet #%d(%d bytes)", slotnum, + seqnum, buf_size); + GST_RESENDER_MUTEX_UNLOCK (resender); + return FALSE; + } + + resender->slots[slotnum] = + g_byte_array_append (resender->slots[slotnum], buf_data, buf_size); + if (resender->slots[slotnum] == NULL) { + GST_WARNING_OBJECT (resender, + "fail to append rtp packet #%d(%d bytes) to slot #%d", seqnum, buf_size, + slotnum); + GST_RESENDER_MUTEX_UNLOCK (resender); + return FALSE; + } +#else + if (resender->slots[slotnum]) { + //GST_LOG_OBJECT (resender, "free slot #%d for new rtp packet", slotnum); + gst_buffer_unref (resender->slots[slotnum]); + resender->slots[slotnum] = NULL; + } + + resender->slots[slotnum] = buffer; + gst_buffer_ref (buffer); +#endif + + GST_RESENDER_MUTEX_UNLOCK (resender); + + return TRUE; + +invalid_buffer: + GST_ERROR_OBJECT (resender, "invalid buffer"); + return FALSE; +} + +static GstBuffer * +gst_rtp_resender_extract_rtp (GstRTPResender * resender, guint16 seqnum, + guint16 pid) +{ + GstBuffer *out_buffer; + GstMapInfo out_info = GST_MAP_INFO_INIT; + GstMapInfo in_info = GST_MAP_INFO_INIT; + guint16 slotnum; + GstRTPBuffer rtp_buf = { NULL }; + + /* calculate #slotnum for rtp packet to be extracted */ + switch (resender->max_slot_num) { + case 1024: + slotnum = seqnum & 0x03ff; + break; + case 2048: + slotnum = seqnum & 0x07ff; + break; + case 4096: + slotnum = seqnum & 0x0fff; + break; + case 8192: + slotnum = seqnum & 0x1fff; + break; + case 16384: + slotnum = seqnum & 0x3fff; + break; + case 32768: + slotnum = seqnum & 0x7fff; + break; + case 65536: + slotnum = seqnum & 0xffff; + break; + default: + slotnum = seqnum & 0x03ff; + break; + } + + /* extract rtp packet from #slotnum */ + GST_RESENDER_MUTEX_LOCK (resender); +#if 0 + GST_LOG_OBJECT (resender, "extract rtp packet #%d(%d bytes) from slot #%d", + seqnum, resender->slots[slotnum]->len, slotnum); + + /* alloc 2 more bytes for pid between rtp header and rtp payload */ + buffer = gst_buffer_new_and_alloc (resender->slots[slotnum]->len + 2); + if (!buffer) { + GST_WARNING_OBJECT (resender, "fail to alloc for buffer"); + GST_RESENDER_MUTEX_UNLOCK (resender); + return NULL; + } + + /* add rtp header */ + memcpy (GST_BUFFER_DATA (buffer), resender->slots[slotnum]->data, 12); + /* add pid */ + GST_WRITE_UINT16_BE (GST_BUFFER_DATA (buffer) + 12, pid); + /* add rtp payload */ + memcpy (GST_BUFFER_DATA (buffer) + 14, resender->slots[slotnum]->data + 12, + resender->slots[slotnum]->len - 12); +#else + gst_buffer_map (resender->slots[slotnum], &in_info, GST_MAP_READ); + resender->packets_resend++; + GST_ERROR ("RTP Packets resent is %d", resender->packets_resend); + GST_LOG_OBJECT (resender, "extract rtp packet #%d(%d bytes) from slot #%d", + seqnum, in_info.size, slotnum); + + /* alloc 2 more bytes for pid between rtp header and rtp payload */ + out_buffer = gst_buffer_new_and_alloc (in_info.size + 2); + if (!out_buffer) { + GST_WARNING_OBJECT (resender, "fail to alloc for buffer"); + GST_RESENDER_MUTEX_UNLOCK (resender); + return NULL; + } + gst_buffer_map (out_buffer, &out_info, GST_MAP_WRITE); + + /* add rtp header */ + memcpy (out_info.data, in_info.data, 2); + /* add seqnum of resender packet */ + ++resender->resend_seqnum; + GST_WRITE_UINT16_BE (out_info.data + 2, resender->resend_seqnum); + + memcpy (out_info.data + 4, in_info.data + 4, 8); + GST_WRITE_UINT16_BE (out_info.data + 12, seqnum); + /* add rtp payload */ + memcpy (out_info.data + 14, in_info.data + 12, in_info.size - 12); +#endif + + GST_RESENDER_MUTEX_UNLOCK (resender); + + /* Check if the data pointed to by buf is a valid RTP packet */ + if (G_UNLIKELY (!gst_rtp_buffer_map (out_buffer, GST_MAP_READ, &rtp_buf))) + goto invalid_buffer; + + /*seqnum is written by us so there is no need to check it. */ + /* check rtp seqnum of the extracted rtp packet */ + /*if (seqnum != gst_rtp_buffer_get_seq (out_buffer)) { + GST_DEBUG_OBJECT (resender, "requested rtp packet(#%d) could not be extracted (%d)", seqnum, gst_rtp_buffer_get_seq (out_buffer)); + return NULL; + } */ + + return out_buffer; + +invalid_buffer: + GST_ERROR_OBJECT (resender, "invalid buffer"); + return NULL; +} + +static GstFlowReturn +gst_rtp_resender_chain_recv_rtcp (GstPad * pad, GstObject * parent, + GstBuffer * buffer) +{ + GstRTPResender *resender; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *outbuf = NULL; + guint header_len; + guint8 version; + guint data_len; + gboolean padding; + guint8 pad_bytes; + guint8 *data; + guint len; + guint16 seqnum, mask; + guint16 pid = 0, blp = 0; + guint resendnum = 1, i, j; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR); + + gst_buffer_map (buffer, &buf_info, GST_MAP_READ); + data = buf_info.data; + len = buf_info.size; + g_return_val_if_fail (data != NULL, GST_FLOW_ERROR); + + resender = (GstRTPResender *) GST_OBJECT_PARENT (pad); + + GST_DEBUG_OBJECT (resender, "received RTCP packet"); + + /* we need 4 bytes for the type and length */ + if (G_UNLIKELY (len < 4)) + goto wrong_length; + + /* no padding when mask succeeds */ + padding = FALSE; + + /* store len */ + data_len = len; + + while (TRUE) { + /* get packet length */ + header_len = (((data[2] << 8) | data[3]) + 1) << 2; + if (data_len < header_len) + goto wrong_length; + + /* move to next compount packet */ + data += header_len; + data_len -= header_len; + + /* we are at the end now */ + if (data_len < 4) + break; + + /* check version of new packet */ + version = data[0] & 0xc0; + if (version != (GST_RTCP_VERSION << 6)) + goto wrong_version; + + /* padding only allowed on last packet */ + if ((padding = data[0] & 0x20)) + break; + } + if (data_len > 0) { + /* some leftover bytes, check padding */ + if (!padding) + goto wrong_length; + + /* get padding */ + pad_bytes = data[data_len - 1]; + if (data_len != pad_bytes) + goto wrong_padding; + } + + /* parse rtcp packet to get requestd rtp sequence number(#seqnum) */ + if (!gst_rtp_resender_parse_rtcp (resender, buffer, &pid, &blp)) { + GST_WARNING_OBJECT (resender, "fail to parse rtcp packet"); + return GST_FLOW_OK; + } + + /* check this rtcp packet is same as before one */ + if ((resender->prev_rtcp_pid == pid) && (resender->prev_rtcp_blp == blp) + && resender->rtcp_repeat_time < 3) { + resender->rtcp_repeat_time++; + GST_DEBUG_OBJECT (resender, + "this RTCP packet is same as previous one(%d times), ignore it", + resender->rtcp_repeat_time); + return GST_FLOW_OK; + } + resender->prev_rtcp_pid = pid; + resender->prev_rtcp_blp = blp; + resender->rtcp_repeat_time = 0; + + /* extract and send rtp packet using pid */ + seqnum = pid; + + /* extract */ + outbuf = gst_rtp_resender_extract_rtp (resender, seqnum, pid); + if (!outbuf) { + GST_WARNING_OBJECT (resender, "fail to extract rtp packet"); + return GST_FLOW_OK; + } + + /* set resned_num using fraction lost */ + set_resend_num (resender); + + /* push out the buffer as many times as #resendnum */ + for (i = 0; i < resendnum; i++) { + ret = gst_pad_push (resender->resend_srcpad, outbuf); + if (ret < GST_FLOW_OK) { + GST_WARNING_OBJECT (resender, "fail to push requested rtp packet"); + break; + } + } + + /* extract and send rtp packets using blp */ + for (i = 0; i < 16; i++) { + mask = blp & (0x0001 << i); + if (!mask) + continue; + + seqnum = pid + i + 1; + + /* extract rtp packet to be resent */ + outbuf = gst_rtp_resender_extract_rtp (resender, seqnum, pid); + if (!outbuf) { + GST_WARNING_OBJECT (resender, "fail to extract rtp packet"); + return GST_FLOW_OK; + } + + /* push out the buffer as many times as #resendnum */ + for (j = 0; j < resendnum; j++) { + ret = gst_pad_push (resender->resend_srcpad, outbuf); + if (ret < GST_FLOW_OK) { + GST_WARNING_OBJECT (resender, "fail to push requested rtp packet"); + break; + } + } + } + + return ret; + +wrong_length: + { + GST_DEBUG_OBJECT (resender, "len check failed"); + g_object_unref (buffer); + return GST_FLOW_OK; + } +wrong_version: + { + GST_DEBUG_OBJECT (resender, "wrong version (%d < 2)", version >> 6); + g_object_unref (buffer); + return GST_FLOW_OK; + } +wrong_padding: + { + GST_DEBUG_OBJECT (resender, "padding check failed"); + g_object_unref (buffer); + return GST_FLOW_OK; + } +} + +static gboolean +gst_rtp_resender_parse_rtcp (GstRTPResender * resender, GstBuffer * buffer, + guint16 * pid, guint16 * blp) +{ + GstRTCPPacket packet; + gboolean more; + GstRTCPType type; + //GstRTCPFBType fbtype; + //guint32 sender_ssrc; + //guint32 media_ssrc; + guint8 *fci_data; + //guint fci_length; + GstRTCPBuffer rtcp_buf = { NULL }; + + gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp_buf); + + g_return_val_if_fail (buffer != NULL, FALSE); + + /* start processing the compound packet */ + more = gst_rtcp_buffer_get_first_packet (&rtcp_buf, &packet); + while (more) { + /* check feedback type rtcp packet or not */ + type = gst_rtcp_packet_get_type (&packet); + switch (type) { + case GST_RTCP_TYPE_SR: + case GST_RTCP_TYPE_RR: + case GST_RTCP_TYPE_SDES: + case GST_RTCP_TYPE_BYE: + case GST_RTCP_TYPE_APP: + case GST_RTCP_TYPE_PSFB: + GST_WARNING_OBJECT (resender, "got RTCP packet type %d", type); + break; + case GST_RTCP_TYPE_RTPFB: + /* parse feedback type rtcp packet, get the requested rtp seqnum for resending */ + //fbtype = gst_rtcp_packet_fb_get_type (&packet); + //sender_ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet); + //media_ssrc = gst_rtcp_packet_fb_get_media_ssrc (&packet); + fci_data = gst_rtcp_packet_fb_get_fci (&packet); + //fci_length = 4 * gst_rtcp_packet_fb_get_fci_length (&packet); + *pid = GST_READ_UINT16_BE (fci_data); + *blp = GST_READ_UINT16_BE (fci_data + 2); + + GST_DEBUG_OBJECT (resender, "pid is %d, blp is %d", *pid, *blp); + break; + default: + GST_WARNING_OBJECT (resender, "got unknown RTCP packet"); + break; + } + more = gst_rtcp_packet_move_to_next (&packet); + } + + return TRUE; +} + +static void +gst_rtp_resender_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstRTPResender *resender = GST_RTP_RESENDER (object); + + switch (prop_id) { + case PROP_MAX_RESEND_NUM: + resender->max_resend_num = g_value_get_uint (value); + break; + case PROP_MAX_SLOT_NUM: + resender->max_slot_num = g_value_get_uint (value); + alloc_slots (resender); + break; + case PROP_RTP_FRACTION_LOST: + resender->rtp_fraction_lost = g_value_get_uint (value); + update_fraction_lost (resender, resender->rtp_fraction_lost); + break; + case PROP_PACKETS_RESEND: + resender->packets_resend = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_rtp_resender_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstRTPResender *resender = GST_RTP_RESENDER (object); + + switch (prop_id) { + case PROP_MAX_RESEND_NUM: + g_value_set_uint (value, resender->max_resend_num); + break; + case PROP_MAX_SLOT_NUM: + g_value_set_uint (value, resender->max_slot_num); + break; + case PROP_RTP_FRACTION_LOST: + g_value_set_uint (value, resender->rtp_fraction_lost); + break; + case PROP_PACKETS_RESEND: + g_value_set_uint (value, resender->packets_resend); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +alloc_slots (GstRTPResender * resender) +{ + g_return_if_fail (resender->max_slot_num > 0); + +#if 0 + resender->slots = + (GByteArray *) g_malloc0 (sizeof (GByteArray) * resender->max_slot_num); + if (!resender->slots) + GST_WARNING_OBJECT (resender, "fail to allocation memory for slots"); +#else + resender->slots = + (GstBuffer **) g_malloc0 (sizeof (GstBuffer *) * resender->max_slot_num); + if (resender->slots == NULL) + GST_WARNING_OBJECT (resender, "fail to allocation memory for slots"); +#endif +} + +static void +free_slots (GstRTPResender * resender) +{ + gint i; + + i = 0; + while (resender->slots[i]) { +#if 0 + g_byte_array_free (resender->slots[i], TRUE); +#else + gst_buffer_unref (resender->slots[i]); +#endif + i++; + } +} + +static void +set_resend_num (GstRTPResender * resender) +{ + guint resend_num = 1; + + /* update fraction lost rate */ + update_fraction_lost (resender, 0); + + /* Fix me : need to calculate resend num using averaged fraction lost */ + if (resender->fraction_lost_rate == 0) { + resender->resend_num = 1; + } else if (resender->fraction_lost_rate > 1) { + resender->resend_num = 2; + } else { + resender->resend_num = 3; + } + + if (resend_num > resender->max_resend_num) + resend_num = resender->max_resend_num; + + resender->resend_num = resend_num; + + GST_DEBUG_OBJECT (resender, "resend requested RTP packet %d times", + resender->resend_num); +} + +#define TIME_INTERVAL 30 +static void +update_fraction_lost (GstRTPResender * resender, guint fraction_lost) +{ + gdouble elapsed, period = 0; + + if (!resender->timer_started) { + resender->timer_started = TRUE; + g_timer_start (resender->timer); + return; + } + + elapsed = g_timer_elapsed (resender->timer, NULL); + + /* recalc after each interval. */ + if (elapsed - resender->last_elapsed < TIME_INTERVAL) { + period = elapsed - resender->last_elapsed; + resender->fraction_lost += fraction_lost; + resender->fraction_lost_rate = resender->fraction_lost / period; + } else { + resender->fraction_lost = 0; + resender->fraction_lost_rate = 0; + } + + GST_DEBUG_OBJECT (resender, + "fraction lost summation %d, period %f, average rate %f", + resender->fraction_lost, period, resender->fraction_lost_rate); + + /* update last elapsed time */ + resender->last_elapsed = elapsed; +} + +static gboolean +gst_rtp_resender_plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "rtpresender", GST_RANK_NONE, + gst_rtp_resender_get_type ())) { + return FALSE; + } + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + rtpresender, + "RTP resender plugin", + gst_rtp_resender_plugin_init, + VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com") diff --git a/rtpresender/src/gstrtpresender.h b/rtpresender/src/gstrtpresender.h new file mode 100755 index 0000000..9b4269f --- /dev/null +++ b/rtpresender/src/gstrtpresender.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000-2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Yejin Cho < cho.yejin@samsung.com > + * + * PROPRIETARY/CONFIDENTIAL + * + * This software is the confidential and proprietary information of + * SAMSUNG ELECTRONICS ("Confidential Information"). + * You shall not disclose such Confidential Information and shall + * use it only in accordance with the terms of the license agreement + * you entered into with SAMSUNG ELECTRONICS. + * SAMSUNG make no representations or warranties about the suitability + * of the software, either express or implied, including but not + * limited to the implied warranties of merchantability, fitness for + * a particular purpose, or non-infringement. + * SAMSUNG shall not be liable for any damages suffered by licensee as + * a result of using, modifying or distributing this software or its derivatives. + */ + +#ifndef __GST_RTP_RESENDER_H__ +#define __GST_RTP_RESENDER_H__ + +#include + +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_RTP_RESENDER \ + (gst_rtp_resender_get_type()) +#define GST_RTP_RESENDER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_RESENDER,GstRTPResender)) +#define GST_RTP_RESENDER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_RESENDER,GstRTPResenderClass)) +#define GST_IS_RTP_RESENDER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_RESENDER)) +#define GST_IS_RTP_RESENDER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_RESENDER)) + +/* Note : rtp packet max packet = maximum packetsize + 2 bytes */ +#define RESENDER_RTP_PACKET_MAX_SIZE 1502 +#define RESENDER_RTP_PACKET_MAX_NUM 1024 +#define RESENDER_MAX_RESEND_NUM 3 + + +typedef struct _GstRTPResender GstRTPResender; +typedef struct _GstRTPResenderClass GstRTPResenderClass; + +struct _GstRTPResender +{ + GstElement element; + + GstPad *rtp_sinkpad, *rtcp_sinkpad, *send_srcpad, *resend_srcpad; + + GMutex qlock; /* lock for slots */ + //GByteArray **slots; + GstBuffer **slots; + + gboolean is_set_caps; + + /* for measuring average rtp fraction lost*/ + GTimer *timer; + gboolean timer_started; + guint fraction_lost; + gdouble last_elapsed; + gdouble fraction_lost_rate; + + /* properties */ + guint max_resend_num; + guint max_slot_num; + guint rtp_fraction_lost; + + guint resend_num; + + /* Note : Dongle specific feature. the dongle always send same RTCP packet 3 times */ + guint prev_rtcp_pid; + guint prev_rtcp_blp; + guint rtcp_repeat_time; + guint16 resend_seqnum; + gint packets_resend; +}; + +struct _GstRTPResenderClass +{ + GstElementClass parent_class; +}; + +GType gst_rtp_resender_get_type (void); + +G_END_DECLS + +#endif /* __GST_RTP_RESENDER_H__ */ diff --git a/wfdextmanager/Makefile.am b/wfdextmanager/Makefile.am new file mode 100755 index 0000000..8b7a223 --- /dev/null +++ b/wfdextmanager/Makefile.am @@ -0,0 +1,15 @@ +plugin_LTLIBRARIES = libgstwfdextmanager.la + +libgstwfdextmanager_la_SOURCES = gstwfdextmanager.c \ + gstwfdextsrc.c gstwfdrtprequester.c gstwfdextmessage.c + +libgstwfdextmanager_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) + +libgstwfdextmanager_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + $(top_builddir)/wfdmanager/wfdbase/libgstwfdbase.la + +libgstwfdextmanager_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstwfdextmanager_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstwfdextsrc.h gstwfdrtprequester.h gstwfdextmessage.h diff --git a/wfdextmanager/gstwfdextmanager.c b/wfdextmanager/gstwfdextmanager.c new file mode 100644 index 0000000..472616c --- /dev/null +++ b/wfdextmanager/gstwfdextmanager.c @@ -0,0 +1,71 @@ +/* +* wfdextmanager +* +* Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* Alternatively, the contents of this file may be used under the +* GNU Lesser General Public License Version 2.1 (the "LGPL"), in +* which case the following provisions apply instead of the ones +* mentioned above: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstwfdextsrc.h" +#include "gstwfdrtprequester.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "wfdextsrc", GST_RANK_NONE, + GST_TYPE_WFD_EXT_SRC)) + return FALSE; + if (!gst_element_register (plugin, "wfdrtprequester", GST_RANK_NONE, + GST_TYPE_WFD_RTP_REQUESTER)) + return FALSE; + + return TRUE; +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + wfdextmanager, + "Wi-Fi Display management extension plugin library", + plugin_init, + VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com") diff --git a/wfdextmanager/gstwfdextmessage.c b/wfdextmanager/gstwfdextmessage.c new file mode 100755 index 0000000..80702a3 --- /dev/null +++ b/wfdextmanager/gstwfdextmessage.c @@ -0,0 +1,1235 @@ +/* + * wfdextmessage + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include /* for G_OS_WIN32 */ +#include "gstwfdextmessage.h" + +/* FIXME, is currently allocated on the stack */ +#define MAX_LINE_LEN (1024 * 16) + +#define FREE_STRING(field) if (field != NULL) g_free(field); (field) = NULL; +#define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup(val); + +static GstWFDExtMessage *gst_wfd_ext_message_boxed_copy (GstWFDExtMessage * + orig); +static void gst_wfd_ext_message_boxed_free (GstWFDExtMessage * msg); +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE +static GString *_gst_wfd_ext_convert_wfd2_video_formats_to_gstring (const + GstWFDExtMessage * msg); +static GString *_gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (const + GstWFDExtMessage * msg); + +GString * +_gst_wfd_ext_convert_wfd2_video_formats_to_gstring (const GstWFDExtMessage * + msg) +{ + GstWFD2VideoCodec *codec_list = NULL; + GString *str = NULL; + + if (msg->wfd2_video_formats == NULL || + msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) { + return NULL; + } + + str = g_string_new (""); + + codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; + + g_string_append_printf (str, + GST_STRING_EXT_WFD2_VIDEO_FORMATS GST_STRING_WFD_COLON); + g_string_append_printf (str, " %02x", + msg->wfd2_video_formats->sink_video_cap.native); + + while (codec_list) { + g_string_append_printf (str, " %02x %02x %04x", + codec_list->codec, codec_list->profile, codec_list->level); + + g_string_append_printf (str, " %012llx %012llx %012llx %02x %04x %04x %02x", + codec_list->misc_params.CEA_Support, + codec_list->misc_params.VESA_Support, + codec_list->misc_params.HH_Support, + codec_list->misc_params.latency, + codec_list->misc_params.min_slice_size, + codec_list->misc_params.slice_enc_params, + codec_list->misc_params.frame_rate_control_support); + + if (codec_list->next) { + g_string_append_printf (str, GST_STRING_WFD_COMMA); + } + codec_list = codec_list->next; + } + + g_string_append_printf (str, " %02x", + msg->wfd2_video_formats->sink_video_cap.non_transcoding_support); + + if (msg->wfd2_video_formats->portrait_mode == TRUE) { + g_string_append_printf (str, " %s", GST_STRING_EXT_WFD2_PORTRAIT_ENABLED); + } + + g_string_append_printf (str, GST_STRING_WFD_CRLF); + + return str; + +} + +const char * +gst_wfd_ext_peek_wfd2_audio_format_string (const GstWFD2AudioFormatEnum + audio_format) +{ + if (audio_format == GST_WFD2_AUDIO_FORMAT_LPCM) { + return GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM; + } else if (audio_format == GST_WFD2_AUDIO_FORMAT_AAC) { + return GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC; + } else if (audio_format == GST_WFD2_AUDIO_FORMAT_AC3) { + return GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3; + } else { + return NULL; + } +} + +GstWFD2AudioFormatEnum +gst_wfd_ext_get_wfd2_audio_format (gchar * str) +{ + if (!g_strcmp0 ((const char *) str, GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM)) { + return GST_WFD2_AUDIO_FORMAT_LPCM; + } else if (!g_strcmp0 ((const char *) str, + GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC)) { + return GST_WFD2_AUDIO_FORMAT_AAC; + } else if (!g_strcmp0 ((const char *) str, + GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3)) { + return GST_WFD2_AUDIO_FORMAT_AC3; + } else { + return GST_WFD2_AUDIO_FORMAT_UNKNOWN; + } +} + +GString * +_gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (const GstWFDExtMessage * msg) +{ + GstWFD2SinkAudio *sink_audio_list = NULL; + GString *str = NULL; + + if (msg->wfd2_audio_codecs == NULL || + msg->wfd2_audio_codecs->sink_audio_list == NULL) { + return NULL; + } + + str = + g_string_new (GST_STRING_EXT_WFD2_AUDIO_CODECS GST_STRING_WFD_COLON + GST_STRING_WFD_SPACE); + + sink_audio_list = msg->wfd2_audio_codecs->sink_audio_list; + + while (sink_audio_list) { + + g_string_append_printf (str, "%s %08x %02x", + gst_wfd_ext_peek_wfd2_audio_format_string (sink_audio_list-> + audio_format), sink_audio_list->mode, sink_audio_list->latency); + + if (sink_audio_list->next) { + g_string_append_printf (str, GST_STRING_WFD_COMMA GST_STRING_WFD_SPACE); + } + sink_audio_list = sink_audio_list->next; + } + + g_string_append_printf (str, GST_STRING_WFD_CRLF); + + return str; + +} +#endif + +G_DEFINE_BOXED_TYPE (GstWFDExtMessage, gst_wfd_ext_message, + gst_wfd_ext_message_boxed_copy, gst_wfd_ext_message_boxed_free); + +static GstWFDExtMessage * +gst_wfd_ext_message_boxed_copy (GstWFDExtMessage * orig) +{ + GstWFDExtMessage *copy; + + if (gst_wfd_ext_message_copy (orig, ©) == GST_WFD_OK) + return copy; + + return NULL; +} + +static void +gst_wfd_ext_message_boxed_free (GstWFDExtMessage * msg) +{ + gst_wfd_ext_message_free (msg); +} + +/** +* gst_wfd_ext_message_new: +* @msg: pointer to new #GstWFDExtMessage +* +* Allocate a new GstWFDExtMessage and store the result in @msg. +* +* Returns: a #GstWFDExtMessage. +*/ +GstWFDResult +gst_wfd_ext_message_new (GstWFDExtMessage ** msg) +{ + GstWFDExtMessage *newmsg; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + newmsg = g_new0 (GstWFDExtMessage, 1); + + *msg = newmsg; + + return gst_wfd_ext_message_init (newmsg); +} + +/** +* gst_wfd_ext_message_init: +* @msg: a #GstWFDExtMessage +* +* Initialize @msg so that its contents are as if it was freshly allocated +* with gst_wfd_ext_message_new(). This function is mostly used to initialize a message +* allocated on the stack. gst_wfd_ext_message_uninit() undoes this operation. +* +* When this function is invoked on newly allocated data(with malloc or on the +* stack), its contents should be set to 0 before calling this function. +* +* Returns: a #GstWFDExtMessage. +*/ +GstWFDResult +gst_wfd_ext_message_init (GstWFDExtMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + return GST_WFD_OK; +} + +/** +* gst_wfd_ext_message_uninit: +* @msg: a #GstWFDExtMessage +* +* Free all resources allocated in @msg. @msg should not be used anymore after +* this function. This function should be used when @msg was allocated on the +* stack and initialized with gst_wfd_ext_message_init(). +* +*/ +void +gst_wfd_ext_message_uninit (GstWFDExtMessage * msg) +{ + g_return_if_fail (msg != NULL); + + if (msg->client_rtp_ports) { + FREE_STRING (msg->client_rtp_ports->profile); + FREE_STRING (msg->client_rtp_ports->mode); + FREE_STRING (msg->client_rtp_ports); + } + + if (msg->max_buffer_length) { + FREE_STRING (msg->max_buffer_length); + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (msg->wfd2_video_formats) { + GstWFD2VideoCodec *codec_list = NULL; + GstWFD2VideoCodec *temp = NULL; + codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; + while (codec_list) { + temp = codec_list; + codec_list = codec_list->next; + FREE_STRING (temp); + } + FREE_STRING (msg->wfd2_video_formats); + } + + if (msg->wfd2_audio_codecs) { + GstWFD2SinkAudio *codec_list = NULL; + GstWFD2SinkAudio *temp = NULL; + codec_list = msg->wfd2_audio_codecs->sink_audio_list; + while (codec_list) { + temp = codec_list; + codec_list = codec_list->next; + FREE_STRING (temp); + } + FREE_STRING (msg->wfd2_audio_codecs); + } +#endif +} + +/** +* gst_wfd_ext_message_free: +* @msg: a #GstWFDExtMessage +* +* Free all resources allocated by @msg. @msg should not be used anymore after +* this function. This function should be used when @msg was dynamically +* allocated with gst_wfd_ext_message_new(). +* +*/ +void +gst_wfd_ext_message_free (GstWFDExtMessage * msg) +{ + g_return_if_fail (msg != NULL); + + gst_wfd_ext_message_uninit (msg); + g_free (msg); +} + +/** + * gst_wfd_ext_message_copy: + * @msg: a #GstWFDExtMessage + * @copy: (out) (transfer full): pointer to new #GstWFDExtMessage + * + * Allocate a new copy of @msg and store the result in @copy. The value in + * @copy should be release with gst_wfd_ext_message_free function. + * + * Returns: a #GstWFDResult + * + * Since: 1.6 + */ +GstWFDResult +gst_wfd_ext_message_copy (const GstWFDExtMessage * msg, + GstWFDExtMessage ** copy) +{ + GstWFDResult ret; + GstWFDExtMessage *cp; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + ret = gst_wfd_ext_message_new (copy); + if (ret != GST_WFD_OK) + return ret; + + cp = *copy; + + /* TODO-WFD */ + if (msg->client_rtp_ports) { + cp->client_rtp_ports = g_malloc (sizeof (GstWFDClientRtpPorts)); + if (cp->client_rtp_ports) { + cp->client_rtp_ports->profile = g_strdup (msg->client_rtp_ports->profile); + cp->client_rtp_ports->rtp_port0 = msg->client_rtp_ports->rtp_port0; + cp->client_rtp_ports->rtp_port1 = msg->client_rtp_ports->rtp_port1; + cp->client_rtp_ports->mode = g_strdup (msg->client_rtp_ports->mode); + } + } + if (msg->max_buffer_length) { + cp->max_buffer_length->length = msg->max_buffer_length->length; + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (msg->wfd2_video_formats) { + cp->wfd2_video_formats = g_malloc0 (sizeof (GstWFD2VideoFormats)); + memcpy (cp->wfd2_video_formats, msg->wfd2_video_formats, + sizeof (GstWFD2VideoFormats)); + + if (cp->wfd2_video_formats) { + if (msg->wfd2_video_formats->sink_video_cap.video_codec_list) { + GstWFD2VideoCodec *copy = NULL; + GstWFD2VideoCodec *temp = NULL; + cp->wfd2_video_formats->sink_video_cap.video_codec_list = + g_malloc0 (sizeof (GstWFD2VideoCodec)); + memcpy (cp->wfd2_video_formats->sink_video_cap.video_codec_list, + msg->wfd2_video_formats->sink_video_cap.video_codec_list, + sizeof (GstWFD2VideoCodec)); + + copy = cp->wfd2_video_formats->sink_video_cap.video_codec_list; + temp = msg->wfd2_video_formats->sink_video_cap.video_codec_list->next; + while (temp != NULL) { + copy->next = g_malloc0 (sizeof (GstWFD2VideoCodec)); + memcpy (copy->next, temp, sizeof (GstWFD2VideoCodec)); + copy = copy->next; + temp = temp->next; + } + } + } + } + + if (msg->wfd2_audio_codecs) { + cp->wfd2_audio_codecs = g_malloc0 (sizeof (GstWFD2SinkAudioCap)); + memcpy (cp->wfd2_audio_codecs, msg->wfd2_audio_codecs, + sizeof (GstWFD2SinkAudioCap)); + + if (cp->wfd2_audio_codecs) { + if (msg->wfd2_audio_codecs->sink_audio_list) { + GstWFD2SinkAudio *copy = NULL; + GstWFD2SinkAudio *temp = NULL; + cp->wfd2_audio_codecs->sink_audio_list = + g_malloc0 (sizeof (GstWFD2SinkAudio)); + memcpy (cp->wfd2_audio_codecs->sink_audio_list, + msg->wfd2_audio_codecs->sink_audio_list, sizeof (GstWFD2SinkAudio)); + + copy = cp->wfd2_audio_codecs->sink_audio_list; + temp = msg->wfd2_audio_codecs->sink_audio_list->next; + while (temp != NULL) { + copy->next = g_malloc0 (sizeof (GstWFD2SinkAudio)); + memcpy (copy->next, temp, sizeof (GstWFD2SinkAudio)); + copy = copy->next; + temp = temp->next; + } + } + } + } +#endif + + return GST_WFD_OK; +} + +/** +* gst_wfd_ext_message_as_text: +* @msg: a #GstWFDExtMessage +* +* Convert the contents of @msg to a text string. +* +* Returns: A dynamically allocated string representing the WFD description. +*/ +gchar * +gst_wfd_ext_message_as_text (const GstWFDExtMessage * msg) +{ + /* change all vars so they match rfc? */ + GString *lines; + g_return_val_if_fail (msg != NULL, NULL); + + lines = g_string_new (""); + + if (msg->client_rtp_ports) { + g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS); + if (msg->client_rtp_ports->profile) { + g_string_append_printf (lines, GST_STRING_WFD_COLON); + g_string_append_printf (lines, " %s", msg->client_rtp_ports->profile); + g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port0); + g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port1); + g_string_append_printf (lines, " %s", msg->client_rtp_ports->mode); + } + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } + if (msg->max_buffer_length) { + g_string_append_printf (lines, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH); + g_string_append_printf (lines, GST_STRING_WFD_COLON); + g_string_append_printf (lines, " %d", msg->max_buffer_length->length); + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + { + GString *str_result = + _gst_wfd_ext_convert_wfd2_video_formats_to_gstring (msg); + if (str_result != NULL) { + g_string_append_printf (lines, "%s", str_result->str); + g_string_free (str_result, TRUE); + str_result = NULL; + } + + str_result = _gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (msg); + if (str_result != NULL) { + g_string_append_printf (lines, "%s", str_result->str); + g_string_free (str_result, TRUE); + } + } +#endif + return g_string_free (lines, FALSE); +} + +gchar * +gst_wfd_ext_message_parameter_names_as_text (const GstWFDExtMessage * msg) +{ + /* change all vars so they match rfc? */ + GString *lines; + + g_return_val_if_fail (msg != NULL, NULL); + + lines = g_string_new (""); + + if (msg->client_rtp_ports) { + g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS); + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } + if (msg->max_buffer_length) { + g_string_append_printf (lines, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH); + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (msg->wfd2_video_formats) { + g_string_append_printf (lines, GST_STRING_EXT_WFD2_VIDEO_FORMATS); + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } + if (msg->wfd2_audio_codecs) { + g_string_append_printf (lines, GST_STRING_EXT_WFD2_AUDIO_CODECS); + g_string_append_printf (lines, GST_STRING_WFD_CRLF); + } +#endif + return g_string_free (lines, FALSE); +} + +static void +read_string_space_ended (gchar * dest, guint size, gchar * src) +{ + guint idx = 0; + + while (!g_ascii_isspace (*src) && *src != '\0') { + if (idx < size - 1) + dest[idx++] = *src; + src++; + } + + if (size > 0) + dest[idx] = '\0'; +} + +#if 0 +static void +read_string_char_ended (gchar * dest, guint size, gchar del, gchar * src) +{ + guint idx = 0; + + while (*src != del && *src != '\0') { + if (idx < size - 1) + dest[idx++] = *src; + src++; + } + + if (size > 0) + dest[idx] = '\0'; +} +#endif + +static void +read_string_type_and_value (gchar * type, gchar * value, guint tsize, + guint vsize, gchar del, gchar * src) +{ + guint idx; + + idx = 0; + while (*src != del && *src != '\0') { + if (idx < tsize - 1) + type[idx++] = *src; + src++; + } + + if (tsize > 0) + type[idx] = '\0'; + + src++; + idx = 0; + while (*src != '\0') { + if (idx < vsize - 1) + value[idx++] = *src; + src++; + } + if (vsize > 0) + value[idx] = '\0'; +} + +static gboolean +gst_wfd_ext_message_parse_line (GstWFDExtMessage * msg, gchar * buffer) +{ + gchar type[8192] = { 0 }; + gchar value[8192] = { 0 }; + gchar temp[8192] = { 0 }; + gchar *p = buffer; + gchar *v = value; + +#define SKIP_SPACE(q) if (*q && g_ascii_isspace(*q)) q++; +#define SKIP_EQUAL(q) if (*q && *q == '=') q++; +#define SKIP_COMMA(q) if (*q && g_ascii_ispunct(*q)) q++; +#define READ_STRING(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); REPLACE_STRING(field, temp); +#if 0 +#define READ_CHAR_END_STRING(field, del) read_string_char_ended(temp, sizeof(temp), del, v); v += strlen(temp); REPLACE_STRING(field, temp); +#endif +#define READ_UINT32(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); field = strtoul(temp, NULL, 16); +#define READ_UINT32_DIGIT(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); field = strtoul(temp, NULL, 10); + + /*g_print("gst_wfd_ext_config_parse_line input: %s\n", buffer); */ + read_string_type_and_value (type, value, sizeof (type), sizeof (value), ':', + p); + /*g_print("gst_wfd_ext_config_parse_line type:%s value:%s\n", type, value); */ + if (!g_strcmp0 (type, GST_STRING_WFD_CLIENT_RTP_PORTS)) { + msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1); + if (strlen (v)) { + SKIP_SPACE (v); + READ_STRING (msg->client_rtp_ports->profile); + SKIP_SPACE (v); + READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port0); + SKIP_SPACE (v); + READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port1); + SKIP_SPACE (v); + READ_STRING (msg->client_rtp_ports->mode); + } + } + if (!g_strcmp0 (type, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH)) { + msg->max_buffer_length = g_new0 (GstWFDExtMaxBufferLength, 1); + if (strlen (v)) { + SKIP_SPACE (v); + READ_UINT32_DIGIT (msg->max_buffer_length->length); + } + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (!g_strcmp0 (type, GST_STRING_EXT_WFD2_VIDEO_FORMATS)) { + + GstWFD2VideoCodec *codec_list = NULL; + msg->wfd2_video_formats = g_new0 (GstWFD2VideoFormats, 1); + + if (strstr (v, GST_STRING_WFD_NONE) == NULL) { + SKIP_SPACE (v); + READ_UINT32 (msg->wfd2_video_formats->sink_video_cap.native); + + if (strlen (v)) { + char *str_result = NULL; + msg->wfd2_video_formats->sink_video_cap.video_codec_list = + g_new0 (GstWFD2VideoCodec, 1); + codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; + + while (strlen (v)) { + + SKIP_SPACE (v); + READ_UINT32 (codec_list->codec); + SKIP_SPACE (v); + READ_UINT32 (codec_list->profile); + SKIP_SPACE (v); + READ_UINT32 (codec_list->level); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.CEA_Support); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.VESA_Support); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.HH_Support); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.latency); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.min_slice_size); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.slice_enc_params); + SKIP_SPACE (v); + READ_UINT32 (codec_list->misc_params.frame_rate_control_support); + SKIP_SPACE (v); + + str_result = strstr (v, GST_STRING_WFD_COMMA); + if (str_result != NULL) { + v = str_result; + codec_list->next = g_new0 (GstWFD2VideoCodec, 1); + codec_list = codec_list->next; + + SKIP_COMMA (v); + } else { + break; + } + } + + READ_UINT32 (msg->wfd2_video_formats->sink_video_cap. + non_transcoding_support); + + if (strstr (v, GST_STRING_EXT_WFD2_PORTRAIT_ENABLED)) { + msg->wfd2_video_formats->portrait_mode = TRUE; + } + } + } + } + if (!g_strcmp0 (type, GST_STRING_EXT_WFD2_AUDIO_CODECS)) { + + GstWFD2SinkAudio *codec_list = NULL; + gchar *audio_format_str = NULL; + msg->wfd2_audio_codecs = g_new0 (GstWFD2SinkAudioCap, 1); + + if (strstr (v, GST_STRING_WFD_NONE) == NULL) { + + if (strlen (v)) { + char *str_result = NULL; + msg->wfd2_audio_codecs->sink_audio_list = g_new0 (GstWFD2SinkAudio, 1); + codec_list = msg->wfd2_audio_codecs->sink_audio_list; + + while (strlen (v)) { + + SKIP_SPACE (v); + READ_STRING (audio_format_str); + if (audio_format_str != NULL) { + codec_list->audio_format = + gst_wfd_ext_get_wfd2_audio_format (audio_format_str); + if (codec_list->audio_format == GST_WFD2_AUDIO_FORMAT_UNKNOWN) { + g_print ("Invaild audio format [%s] in wfd2_audio_codecs", + audio_format_str); + } + FREE_STRING (audio_format_str); + } else { + g_print ("There is no audio format in wfd2_audio_codecs"); + break; + } + SKIP_SPACE (v); + READ_UINT32 (codec_list->mode); + SKIP_SPACE (v); + READ_UINT32 (codec_list->latency); + + str_result = strstr (v, GST_STRING_WFD_COMMA); + if (str_result != NULL) { + v = str_result; + codec_list->next = g_new0 (GstWFD2SinkAudio, 1); + codec_list = codec_list->next; + + SKIP_COMMA (v); + } else { + break; + } + } + } + } + } +#endif + return TRUE; +} + +/** +* gst_wfd_ext_message_parse_buffer: +* @data: the start of the buffer +* @size: the size of the buffer +* @msg: the result #GstWFDExtMessage +* +* Parse the contents of @size bytes pointed to by @data and store the result in +* @msg. +* +* Returns: #GST_WFD_OK on success. +*/ +GstWFDResult +gst_wfd_ext_message_parse_buffer (const guint8 * data, guint size, + GstWFDExtMessage * msg) +{ + const gchar *p; + gchar buffer[MAX_LINE_LEN] = { 0 }; + guint idx = 0; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (data != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (size != 0, GST_WFD_EINVAL); + + p = (const gchar *) data; + while (TRUE) { + if (*p == '\0') + break; + + idx = 0; + while (*p != '\n' && *p != '\r' && *p != '\0') { + if (idx < sizeof (buffer) - 1) + buffer[idx++] = *p; + p++; + } + buffer[idx] = '\0'; + + gst_wfd_ext_message_parse_line (msg, buffer); + + if (*p == '\0') + break; + p += 2; + } + + return GST_WFD_OK; +} + +/** +* gst_wfd_ext_message_fdump: +* @msg: a #GstWFDExtMessage +* +* Dump the parsed contents of @msg to stdout. +* +* Returns: a #GstWFDExtMessage. +*/ +GstWFDResult +gst_wfd_ext_message_dump (const GstWFDExtMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + g_print ("===========WFD Message dump========="); + + if (msg->client_rtp_ports) { + g_print (" Client RTP Ports : "); + if (msg->client_rtp_ports->profile) { + g_print ("%s", msg->client_rtp_ports->profile); + g_print (" %d", msg->client_rtp_ports->rtp_port0); + g_print (" %d", msg->client_rtp_ports->rtp_port1); + g_print (" %s", msg->client_rtp_ports->mode); + } + } + + if (msg->max_buffer_length) { + g_print (" Max Buffer Length: "); + g_print ("%d", msg->max_buffer_length->length); + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (msg->wfd2_video_formats) { + GString *str = NULL; + str = + _gst_wfd_ext_convert_wfd2_video_formats_to_gstring ((const + GstWFDExtMessage *) msg->wfd2_video_formats); + if (str != NULL) { + g_print ("%s", str->str); + g_string_free (str, TRUE); + } + } + if (msg->wfd2_audio_codecs) { + GString *str = NULL; + str = + _gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring ((const + GstWFDExtMessage *) msg->wfd2_audio_codecs); + if (str != NULL) { + g_print ("%s", str->str); + g_string_free (str, TRUE); + } + } +#endif + + g_print ("==================================="); + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_set_client_RTP_ports (GstWFDExtMessage * msg, + GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1) +{ + GString *lines; + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->client_rtp_ports) + msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1); + + if (trans != GST_WFD_RTSP_TRANS_UNKNOWN) { + lines = g_string_new (""); + if (trans == GST_WFD_RTSP_TRANS_RTP) + g_string_append_printf (lines, GST_STRING_WFD_RTP); + else if (trans == GST_WFD_RTSP_TRANS_RDT) + g_string_append_printf (lines, GST_STRING_WFD_RDT); + + if (profile != GST_WFD_RTSP_PROFILE_UNKNOWN) + g_string_append_printf (lines, GST_STRING_WFD_SLASH); + + if (profile == GST_WFD_RTSP_PROFILE_AVP) + g_string_append_printf (lines, GST_STRING_WFD_AVP); + else if (profile == GST_WFD_RTSP_PROFILE_SAVP) + g_string_append_printf (lines, GST_STRING_WFD_SAVP); + + if (lowertrans != GST_WFD_RTSP_LOWER_TRANS_UNKNOWN) + g_string_append_printf (lines, GST_STRING_WFD_SLASH); + + if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP) { + g_string_append_printf (lines, GST_STRING_WFD_UDP); + g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf (lines, GST_STRING_WFD_UNICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST) { + g_string_append_printf (lines, GST_STRING_WFD_UDP); + g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf (lines, GST_STRING_WFD_MULTICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_TCP) { + g_string_append_printf (lines, GST_STRING_WFD_TCP); + g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf (lines, GST_STRING_WFD_UNICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_HTTP) { + g_string_append_printf (lines, GST_STRING_WFD_TCP_HTTP); + } + + msg->client_rtp_ports->profile = g_string_free (lines, FALSE); + msg->client_rtp_ports->rtp_port0 = rtp_port0; + msg->client_rtp_ports->rtp_port1 = rtp_port1; + msg->client_rtp_ports->mode = g_strdup ("mode=play"); + } + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_get_client_RTP_ports (GstWFDExtMessage * msg, + GstWFDRTSPTransMode * trans, GstWFDRTSPProfile * profile, + GstWFDRTSPLowerTrans * lowertrans, guint32 * rtp_port0, guint32 * rtp_port1) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->client_rtp_ports != NULL, GST_WFD_EINVAL); + + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_RTP)) + *trans = GST_WFD_RTSP_TRANS_RTP; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_RDT)) + *trans = GST_WFD_RTSP_TRANS_RDT; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_AVP)) + *profile = GST_WFD_RTSP_PROFILE_AVP; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_SAVP)) + *profile = GST_WFD_RTSP_PROFILE_SAVP; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UDP) + && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UNICAST)) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UDP) + && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_MULTICAST)) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_TCP) + && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UNICAST)) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP; + if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_TCP_HTTP)) + *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP; + + *rtp_port0 = msg->client_rtp_ports->rtp_port0; + *rtp_port1 = msg->client_rtp_ports->rtp_port1; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_set_max_buffer_length (GstWFDExtMessage * msg, guint length) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->max_buffer_length) + msg->max_buffer_length = g_new0 (GstWFDExtMaxBufferLength, 1); + + msg->max_buffer_length->length = length; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_get_max_buffer_length (GstWFDExtMessage * msg, + guint * length) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->max_buffer_length != NULL, GST_WFD_EINVAL); + + *length = msg->max_buffer_length->length; + + return GST_WFD_OK; +} + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE +GstWFDResult +gst_wfd_ext_add_wfd2_video_format (GstWFDExtMessage * msg, guint native, + GstWFD2VideoCodecEnum codec, + guint profile, guint level, + guint64 CEA_resolution, guint64 VESA_resolution, guint64 HH_resolution, + guint latency, guint min_slice_size, guint slice_enc_params, + guint frame_rate_control_support, guint non_transcoding_support, + guint portrait_mode) +{ + GstWFD2VideoCodec *video_codec = NULL; + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_video_formats == NULL) + msg->wfd2_video_formats = g_new0 (GstWFD2VideoFormats, 1); + + msg->wfd2_video_formats->portrait_mode = portrait_mode; + msg->wfd2_video_formats->sink_video_cap.native = native; + msg->wfd2_video_formats->sink_video_cap.non_transcoding_support = + non_transcoding_support; + msg->wfd2_video_formats->sink_video_cap.video_codec_list = NULL; + + if (msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) { + msg->wfd2_video_formats->sink_video_cap.video_codec_list = + g_new0 (GstWFD2VideoCodec, 1); + video_codec = msg->wfd2_video_formats->sink_video_cap.video_codec_list; + + } else { + GstWFD2VideoCodec *list = + msg->wfd2_video_formats->sink_video_cap.video_codec_list; + while (list->next) { + list = list->next; + } + list->next = g_new0 (GstWFD2VideoCodec, 1); + video_codec = list->next; + } + + video_codec->codec = codec; + video_codec->level = level; + video_codec->profile = profile; + video_codec->misc_params.CEA_Support = CEA_resolution; + video_codec->misc_params.VESA_Support = VESA_resolution; + video_codec->misc_params.HH_Support = HH_resolution; + video_codec->misc_params.frame_rate_control_support = + frame_rate_control_support; + video_codec->misc_params.latency = latency; + video_codec->misc_params.min_slice_size = min_slice_size; + video_codec->misc_params.slice_enc_params = slice_enc_params; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_get_wfd2_video_formats (GstWFDExtMessage * msg, + GstWFD2VideoFormats * video_formats) +{ + GstWFDResult res = GST_WFD_OK; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_video_formats == NULL + || msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) + res = GST_WFD_EINVAL; + + video_formats = msg->wfd2_video_formats; + + return res; +} + +GstWFDResult +gst_wfd_ext_add_wfd2_audio_codec (GstWFDExtMessage * msg, + GstWFD2AudioFormatEnum audio_format, guint mode, guint latency) +{ + GstWFD2SinkAudio *sink_audio = NULL; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_audio_codecs == NULL) + msg->wfd2_audio_codecs = g_new0 (GstWFD2SinkAudioCap, 1); + + if (msg->wfd2_audio_codecs->sink_audio_list == NULL) { + msg->wfd2_audio_codecs->sink_audio_list = g_new0 (GstWFD2SinkAudio, 1); + sink_audio = msg->wfd2_audio_codecs->sink_audio_list; + } else { + sink_audio = msg->wfd2_audio_codecs->sink_audio_list; + while (sink_audio->next) { + sink_audio = sink_audio->next; + } + sink_audio->next = g_new0 (GstWFD2SinkAudio, 1); + sink_audio = sink_audio->next; + } + + sink_audio->audio_format = audio_format; + sink_audio->mode = mode; + sink_audio->latency = latency; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_get_wfd2_audio_codecs (GstWFDExtMessage * msg, + GstWFD2SinkAudioCap * audio_codecs) +{ + GstWFDResult res = GST_WFD_OK; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_audio_codecs == NULL + || msg->wfd2_audio_codecs->sink_audio_list == NULL) + res = GST_WFD_EINVAL; + + audio_codecs = msg->wfd2_audio_codecs; + return res; +} + +GstWFDResult +gst_wfd_ext_message_init_wfd2_video_formats (GstWFDExtMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_video_formats) { + GstWFD2VideoCodec *codec_list = NULL; + GstWFD2VideoCodec *temp = NULL; + codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; + while (codec_list) { + temp = codec_list; + codec_list = codec_list->next; + FREE_STRING (temp); + } + FREE_STRING (msg->wfd2_video_formats); + } + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_init_wfd2_audio_codecs (GstWFDExtMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_audio_codecs) { + GstWFD2SinkAudio *codec_list = NULL; + GstWFD2SinkAudio *temp = NULL; + codec_list = msg->wfd2_audio_codecs->sink_audio_list; + while (codec_list) { + temp = codec_list; + codec_list = codec_list->next; + FREE_STRING (temp); + } + FREE_STRING (msg->wfd2_audio_codecs); + } + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_get_prefered_video_format (GstWFDExtMessage * msg, + GstWFD2VideoCodecEnum * vCodec, + GstWFD2DisplayNativeResolutionEnum * vNative, guint64 * vNativeResolution, + guint64 * vCEAResolution, guint64 * vVESAResolution, + guint64 * vHHResolution, GstWFD2VideoH265ProfileEnum * vProfile, + GstWFD2VideoH265LevelEnum * vLevel, guint32 * vLatency, + guint32 * min_slice_size, guint32 * slice_enc_params, + guint * frame_rate_control) +{ + guint nativeindex = 0; + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->wfd2_video_formats != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->wfd2_video_formats->sink_video_cap. + video_codec_list != NULL, GST_WFD_EINVAL); + + *vCodec = msg->wfd2_video_formats->sink_video_cap.video_codec_list->codec; + *vNative = msg->wfd2_video_formats->sink_video_cap.native & 0x7; + nativeindex = msg->wfd2_video_formats->sink_video_cap.native >> 3; + *vNativeResolution = (guint64) 1 << nativeindex; + *vProfile = msg->wfd2_video_formats->sink_video_cap.video_codec_list->profile; + *vLevel = msg->wfd2_video_formats->sink_video_cap.video_codec_list->level; + *vCEAResolution = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + CEA_Support; + *vVESAResolution = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + VESA_Support; + *vHHResolution = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + HH_Support; + *vLatency = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + latency; + *min_slice_size = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + min_slice_size; + *slice_enc_params = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + slice_enc_params; + *frame_rate_control = + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + frame_rate_control_support; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_ext_message_get_prefered_audio_format (GstWFDExtMessage * msg, + GstWFD2AudioFormatEnum * aCodec, GstWFD2AudioFreq * aFreq, + GstWFD2AudioChannels * aChanels, guint * aBitwidth, guint32 * aLatency) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == + GST_WFD2_AUDIO_FORMAT_LPCM) { + *aCodec = GST_WFD2_AUDIO_FORMAT_LPCM; + + switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { + case GST_WFD2_LPCM_441KH_16B_2C: + *aFreq = 44100; + *aChanels = 2; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_48KH_16B_2C: + *aFreq = 48000; + *aChanels = 2; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_48KH_16B_6C: + *aFreq = 48000; + *aChanels = 6; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_48KH_16B_8C: + *aFreq = 48000; + *aChanels = 8; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_48KH_24B_2C: + *aFreq = 48000; + *aChanels = 2; + *aBitwidth = 24; + break; + case GST_WFD2_LPCM_96KH_16B_2C: + *aFreq = 96000; + *aChanels = 2; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_96KH_24B_2C: + *aFreq = 96000; + *aChanels = 2; + *aBitwidth = 24; + break; + case GST_WFD2_LPCM_96KH_24B_6C: + *aFreq = 96000; + *aChanels = 6; + *aBitwidth = 24; + break; + case GST_WFD2_LPCM_96KH_24B_8C: + *aFreq = 96000; + *aChanels = 8; + *aBitwidth = 24; + break; + default: + break; + } + } else if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == + GST_WFD2_AUDIO_FORMAT_AAC) { + *aCodec = GST_WFD2_AUDIO_FORMAT_AAC; + + switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { + case GST_WFD2_AAC_48KH_16B_2C: + *aFreq = 48000; + *aChanels = 2; + *aBitwidth = 16; + break; + case GST_WFD2_AAC_48KH_16B_4C: + *aFreq = 48000; + *aChanels = 4; + *aBitwidth = 16; + break; + case GST_WFD2_LPCM_48KH_16B_6C: + *aFreq = 48000; + *aChanels = 6; + *aBitwidth = 16; + break; + case GST_WFD2_AAC_48KH_16B_8C: + *aFreq = 48000; + *aChanels = 8; + *aBitwidth = 16; + break; + default: + break; + } + + } else if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == + GST_WFD2_AUDIO_FORMAT_AC3) { + *aCodec = GST_WFD2_AUDIO_FORMAT_AC3; + + switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { + case GST_WFD2_AC3_48KH_16B_2C: + *aFreq = 48000; + *aChanels = 2; + *aBitwidth = 16; + break; + case GST_WFD2_AC3_48KH_16B_4C: + *aFreq = 48000; + *aChanels = 4; + *aBitwidth = 16; + break; + case GST_WFD2_AC3_48KH_16B_6C: + *aFreq = 48000; + *aChanels = 6; + *aBitwidth = 16; + break; + default: + break; + } + + } + *aLatency = msg->wfd2_audio_codecs->sink_audio_list->latency; + return GST_WFD_OK; +} + +#endif diff --git a/wfdextmanager/gstwfdextmessage.h b/wfdextmanager/gstwfdextmessage.h new file mode 100755 index 0000000..be21c2b --- /dev/null +++ b/wfdextmanager/gstwfdextmessage.h @@ -0,0 +1,359 @@ +/* + * wfdextmessage + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _GST_WFD_EXT_MESSAGE_H__ +#define _GST_WFD_EXT_MESSAGE_H__ + +#include +#include +#include "../wfdmanager/wfdbase/gstwfdsinkmessage.h" + +G_BEGIN_DECLS; + +#define GST_TYPE_WFD_SINK_MESSAGE (gst_wfd_ext_message_get_type()) +#define GST_WFD_EXT_MESSAGE_CAST(object) ((GstWFDExtMessage *)(object)) +#define GST_WFD_EXT_MESSAGE(object) (GST_WFD_EXT_MESSAGE_CAST(object)) + +#define ENABLE_WFD2_EXTENDED_CODEC_FEATURE +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE +#define GST_WFD2_CEA_NONE 0 +#define GST_WFD2_CEA_640x480P60 (1 << 0) +#define GST_WFD2_CEA_720x480P60 (1 << 1) +#define GST_WFD2_CEA_720x480I60 (1 << 2) +#define GST_WFD2_CEA_720x576P50 (1 << 3) +#define GST_WFD2_CEA_720x576I50 (1 << 4) +#define GST_WFD2_CEA_1280x720P30 (1 << 5) +#define GST_WFD2_CEA_1280x720P60 (1 << 6) +#define GST_WFD2_CEA_1920x1080P30 (1 << 7) +#define GST_WFD2_CEA_1920x1080P60 (1 << 8) +#define GST_WFD2_CEA_1920x1080I60 (1 << 9) +#define GST_WFD2_CEA_1280x720P25 (1 << 10) +#define GST_WFD2_CEA_1280x720P50 (1 << 11) +#define GST_WFD2_CEA_1920x1080P25 (1 << 12) +#define GST_WFD2_CEA_1920x1080P50 (1 << 13) +#define GST_WFD2_CEA_1920x1080I50 (1 << 14) +#define GST_WFD2_CEA_1280x720P24 (1 << 15) +#define GST_WFD2_CEA_1920x1080P24 (1 << 16) +#define GST_WFD2_CEA_3840x2160P24 (1 << 17) +#define GST_WFD2_CEA_3840x2160P25 (1 << 18) +#define GST_WFD2_CEA_3840x2160P30 (1 << 19) +#define GST_WFD2_CEA_3840x2160P50 (1 << 20) +#define GST_WFD2_CEA_3840x2160P60 (1 << 21) +#define GST_WFD2_CEA_4096x2160P24 (1 << 22) +#define GST_WFD2_CEA_4096x2160P25 (1 << 23) +#define GST_WFD2_CEA_4096x2160P30 (1 << 24) +#define GST_WFD2_CEA_4096x2160P50 (1 << 25) +#define GST_WFD2_CEA_4096x2160P60 (1 << 26) + +#define GST_WFD2_VESA_NONE 0 +#define GST_WFD2_VESA_800x600P30 (1 << 0) +#define GST_WFD2_VESA_800x600P60 (1 << 1) +#define GST_WFD2_VESA_1024x768P30 (1 << 2) +#define GST_WFD2_VESA_1024x768P60 (1 << 3) +#define GST_WFD2_VESA_1152x864P30 (1 << 4) +#define GST_WFD2_VESA_1152x864P60 (1 << 5) +#define GST_WFD2_VESA_1280x768P30 (1 << 6) +#define GST_WFD2_VESA_1280x768P60 (1 << 7) +#define GST_WFD2_VESA_1280x800P30 (1 << 8) +#define GST_WFD2_VESA_1280x800P60 (1 << 9) +#define GST_WFD2_VESA_1360x768P30 (1 << 10) +#define GST_WFD2_VESA_1360x768P60 (1 << 11) +#define GST_WFD2_VESA_1366x768P30 (1 << 12) +#define GST_WFD2_VESA_1366x768P60 (1 << 13) +#define GST_WFD2_VESA_1280x1024P30 (1 << 14) +#define GST_WFD2_VESA_1280x1024P60 (1 << 15) +#define GST_WFD2_VESA_1400x1050P30 (1 << 16) +#define GST_WFD2_VESA_1400x1050P60 (1 << 17) +#define GST_WFD2_VESA_1440x900P30 (1 << 18) +#define GST_WFD2_VESA_1440x900P60 (1 << 19) +#define GST_WFD2_VESA_1600x900P30 (1 << 20) +#define GST_WFD2_VESA_1600x900P60 (1 << 21) +#define GST_WFD2_VESA_1600x1200P30 (1 << 22) +#define GST_WFD2_VESA_1600x1200P60 (1 << 23) +#define GST_WFD2_VESA_1680x1024P30 (1 << 24) +#define GST_WFD2_VESA_1680x1024P60 (1 << 25) +#define GST_WFD2_VESA_1680x1050P30 (1 << 26) +#define GST_WFD2_VESA_1680x1050P60 (1 << 27) +#define GST_WFD2_VESA_1920x1200P30 (1 << 28) +#define GST_WFD2_VESA_1920x1200P60 (1 << 29) +#define GST_WFD2_VESA_2560x1440P30 (1 << 30) +#define GST_WFD2_VESA_2560x1440P60 (1 << 31) +#define GST_WFD2_VESA_2560x1600P30 (1ULL << 32) +#define GST_WFD2_VESA_2560x1600P60 (1ULL << 33) + +#define GST_WFD2_HH_NONE 0 +#define GST_WFD2_HH_800x480P30 (1 << 0) +#define GST_WFD2_HH_800x480P60 (1 << 1) +#define GST_WFD2_HH_854x480P30 (1 << 2) +#define GST_WFD2_HH_854x480P60 (1 << 3) +#define GST_WFD2_HH_864x480P30 (1 << 4) +#define GST_WFD2_HH_864x480P60 (1 << 5) +#define GST_WFD2_HH_640x360P30 (1 << 6) +#define GST_WFD2_HH_640x360P60 (1 << 7) +#define GST_WFD2_HH_960x540P30 (1 << 8) +#define GST_WFD2_HH_960x540P60 (1 << 9) +#define GST_WFD2_HH_848x480P30 (1 << 10) +#define GST_WFD2_HH_848x480P60 (1 << 11) + +typedef enum { + GST_WFD2_VIDEO_CODEC_NONE = 0, + GST_WFD2_VIDEO_CODEC_H264 = (1 << 0), + GST_WFD2_VIDEO_CODEC_H265 = (1 << 1) +} GstWFD2VideoCodecEnum; + +typedef enum { + GST_WFD2_DISPALY_NATIVE_CEA = 0, + GST_WFD2_DISPALY_NATIVE_VESA = 1, + GST_WFD2_DISPALY_NATIVE_HH = 2 +} GstWFD2DisplayNativeResolutionEnum; + +typedef enum { + GST_WFD2_H264_UNKNOWN_PROFILE = 0, + GST_WFD2_H264_CBP = (1 << 0), /* Constrained Baseline Profile */ + GST_WFD2_H264_CHP = (1 << 1), /* Constrained High Profile */ + GST_WFD2_H264_CHP2 = (1 << 2), /* Constrained High Profile2 */ + GST_WFD2_H264_BP = (1 << 3), /* Baseline Profile */ + GST_WFD2_H264_MP = (1 << 4), /* Main Profile */ + GST_WFD2_H264_HP = (1 << 5) /* High Profile */ +} GstWFD2VideoH264ProfileEnum; + +typedef enum { + GST_WFD2_H265_UNKNOWN_PROFILE = 0, + GST_WFD2_H265_MAIN_PROFILE = (1 << 0), + GST_WFD2_H265_MAIN_10_PROFILE = (1 << 1), + GST_WFD2_H265_MAIN_444_PROFILE = (1 << 2), + GST_WFD2_H265_MAIN_STILL_PICTURE_PROFILE = (1 << 3), + GST_WFD2_H265_SCREEN_CONTENT_CODING_PROFILE = (1 << 4), + GST_WFD2_H265_MAIN_444_10_PROFILE = (1 << 5) +} GstWFD2VideoH265ProfileEnum; + +typedef enum { + GST_WFD2_H264_LEVEL_UNKNOWN = 0, + GST_WFD2_H264_LEVEL_3_1 = (1 << 0), + GST_WFD2_H264_LEVEL_3_2 = (1 << 1), + GST_WFD2_H264_LEVEL_4 = (1 << 2), + GST_WFD2_H264_LEVEL_4_1 = (1 << 3), + GST_WFD2_H264_LEVEL_4_2 = (1 << 4), + GST_WFD2_H264_LEVEL_5 = (1 << 5), + GST_WFD2_H264_LEVEL_5_1 = (1 << 6), + GST_WFD2_H264_LEVEL_5_2 = (1 << 7) +} GstWFD2VideoH264LevelEnum; + +typedef enum { + GST_WFD2_H265_LEVEL_UNKNOWN = 0, + GST_WFD2_H265_LEVEL_3_1 = (1 << 1), + GST_WFD2_H265_LEVEL_4 = (1 << 2), + GST_WFD2_H265_LEVEL_4_1 = (1 << 3), + GST_WFD2_H265_LEVEL_5 = (1 << 4), + GST_WFD2_H265_LEVEL_5_1 = (1 << 5) +} GstWFD2VideoH265LevelEnum; + +typedef enum { + GST_WFD2_AUX_STREAM_UNKNOWN = 0, + GST_WFD2_AUX_STREAM_PNG = (1 << 0), + GST_WFD2_AUX_STREAM_JPEG = (1 << 1), + GST_WFD2_AUX_STREAM_H264_CBP = (1 << 2) +} GstWFD2AuxStreamCodecEnum; + +typedef enum { + GST_WFD2_AUDIO_FORMAT_UNKNOWN = 0, + GST_WFD2_AUDIO_FORMAT_LPCM = (1 << 0), + GST_WFD2_AUDIO_FORMAT_AAC = (1 << 1), + GST_WFD2_AUDIO_FORMAT_AC3 = (1 << 2) +} GstWFD2AudioFormatEnum; + +typedef enum { + GST_WFD2_LPCM_UNKNOWN_MODE = 0, + GST_WFD2_LPCM_441KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ + GST_WFD2_LPCM_48KH_16B_2C = (1 << 1), + GST_WFD2_LPCM_48KH_16B_6C = (1 << 2), + GST_WFD2_LPCM_48KH_16B_8C = (1 << 3), + GST_WFD2_LPCM_48KH_24B_2C = (1 << 4), + GST_WFD2_LPCM_96KH_16B_2C = (1 << 5), + GST_WFD2_LPCM_96KH_24B_2C = (1 << 6), + GST_WFD2_LPCM_96KH_24B_6C = (1 << 7), + GST_WFD2_LPCM_96KH_24B_8C = (1 << 8) +} GstWFD2LpcmModeEnum; + +typedef enum { + GST_WFD2_AAC_UNKNOWN_MODE = 0, + GST_WFD2_AAC_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ + GST_WFD2_AAC_48KH_16B_4C = (1 << 1), + GST_WFD2_AAC_48KH_16B_6C = (1 << 2), + GST_WFD2_AAC_48KH_16B_8C = (1 << 3) +} GstWFD2AacModeEnum; + +typedef enum { + GST_WFD2_AC3_UNKNOWN_MODE = 0, + GST_WFD2_AC3_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ + GST_WFD2_AC3_48KH_16B_4C = (1 << 1), + GST_WFD2_AC3_48KH_16B_6C = (1 << 2) +} GstWFD2AC3ModeEnum; + +typedef enum { + GST_WFD2_RCA_LPCM_UNKNOWN_MODE = 0, + GST_WFD2_RCA_LPCM_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ +} GstWFD2RcaLpcmModeEnum; + +typedef enum { + GST_WFD2_FREQ_UNKNOWN = 0, + GST_WFD2_FREQ_44100 = (1 << 0), + GST_WFD2_FREQ_48000 = (1 << 1), + GST_WFD2_FREQ_96000 = (1 << 2) +} GstWFD2AudioFreq; + +typedef enum { + GST_WFD2_CHANNEL_UNKNOWN = 0, + GST_WFD2_CHANNEL_2 = (1 << 0), + GST_WFD2_CHANNEL_4 = (1 << 1), + GST_WFD2_CHANNEL_6 = (1 << 2), + GST_WFD2_CHANNEL_8 = (1 << 3) +} GstWFD2AudioChannels; + +typedef enum { + GST_WFD2_EXTENDED_CAPABILITY_NONE = 0, + GST_WFD2_EXTENDED_CAPABILITY_UIBC = (1 << 0), + GST_WFD2_EXTENDED_CAPABILITY_I2C = (1 << 1), + GST_WFD2_EXTENDED_CAPABILITY_PREFERRED_DISPLAY_MODE = (1 << 2), + GST_WFD2_EXTENDED_CAPABILITY_STANBY_RESUME_CONTROL = (1 << 3), + GST_WFD2_EXTENDED_CAPABILITY_TDLS = (1 << 4), + GST_WFD2_EXTENDED_CAPABILITY_TDLS_BSSID = (1 << 5), + GST_WFD2_EXTENDED_CAPABILITY_RCA_BIDIRECTIONAL_VOICE = (1 << 6), + GST_WFD2_EXTENDED_CAPABILITY_RCA_VOICE_COMMAND = (1 << 7) +} GstWFD2ExtendedCapabilitiesEnum; + +typedef struct _GstWFD2SinkAudio{ + GstWFD2AudioFormatEnum audio_format; + guint mode; + guint latency; + struct _GstWFD2SinkAudio *next; +} GstWFD2SinkAudio; + +typedef struct { + GstWFD2SinkAudio *sink_audio_list; +} GstWFD2SinkAudioCap; + +typedef struct { + guint64 CEA_Support; + guint64 VESA_Support; + guint64 HH_Support; + guint latency; + guint min_slice_size; + guint slice_enc_params; + guint frame_rate_control_support; +} GstWFD2VideoMiscParams; + +typedef struct _GstWFD2VideoCodec { + GstWFD2VideoCodecEnum codec; + guint profile; + guint level; + GstWFD2VideoMiscParams misc_params; + struct _GstWFD2VideoCodec *next; +} GstWFD2VideoCodec; + +typedef struct { + guint native; + GstWFD2VideoCodec *video_codec_list; + guint non_transcoding_support; +} GstWFD2SinkVideoCap; + +typedef struct { + GstWFD2SinkVideoCap sink_video_cap; + gboolean portrait_mode; +} GstWFD2VideoFormats; + +#define GST_STRING_EXT_WFD2_VIDEO_FORMATS "wfd2_video_formats" +#define GST_STRING_EXT_WFD2_AUDIO_CODECS "wfd2_audio_codecs" +#define GST_STRING_EXT_WFD2_PORTRAIT_ENABLED "enabled" +#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM "LPCM" +#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC "AAC" +#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3 "AC3" + +#endif + +#define GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH "wfd_vnd_sec_max_buffer_length" + +typedef struct { + guint32 length; +} GstWFDExtMaxBufferLength; + +typedef struct { + GstWFDClientRtpPorts *client_rtp_ports; + GstWFDExtMaxBufferLength *max_buffer_length; +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + GstWFD2VideoFormats *wfd2_video_formats; + GstWFD2SinkAudioCap *wfd2_audio_codecs; + +#endif +} GstWFDExtMessage; + +GType gst_wfd_ext_message_get_type (void); + +/* Session descriptions */ +GstWFDResult gst_wfd_ext_message_new(GstWFDExtMessage **msg); +GstWFDResult gst_wfd_ext_message_init(GstWFDExtMessage *msg); +void gst_wfd_ext_message_uninit(GstWFDExtMessage *msg); +void gst_wfd_ext_message_free(GstWFDExtMessage *msg); +GstWFDResult gst_wfd_ext_message_copy (const GstWFDExtMessage *msg, GstWFDExtMessage **copy); +GstWFDResult gst_wfd_ext_message_parse_buffer(const guint8 *data, guint size, GstWFDExtMessage *msg); +gchar *gst_wfd_ext_message_as_text(const GstWFDExtMessage *msg); +gchar *gst_wfd_ext_parameter_names_as_text(const GstWFDExtMessage *msg); +GstWFDResult gst_wfd_ext_message_dump(const GstWFDExtMessage *msg); + +GstWFDResult gst_wfd_ext_message_set_max_buffer_length(GstWFDExtMessage *msg, guint length); +GstWFDResult gst_wfd_ext_message_get_max_buffer_length(GstWFDExtMessage *msg, guint *length); +GstWFDResult gst_wfd_ext_message_set_client_RTP_ports(GstWFDExtMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1); +GstWFDResult gst_wfd_ext_message_get_client_RTP_ports(GstWFDExtMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, + GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1); + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE +GstWFDResult gst_wfd_ext_add_wfd2_video_format(GstWFDExtMessage *msg, guint native, + GstWFD2VideoCodecEnum codec, + guint profile, guint level, + guint64 CEA_resolution, guint64 VESA_resolution, guint64 HH_resolution, + guint latency, guint min_slice_size, guint slice_enc_params, guint frame_rate_control_support, + guint non_transcoding_support, guint portrait_mode); +GstWFDResult gst_wfd_ext_get_wfd2_video_formats (GstWFDExtMessage *msg, GstWFD2VideoFormats *video_formats); + +GstWFDResult gst_wfd_ext_add_wfd2_audio_codec(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum audio_format, guint mode, guint latency); +GstWFDResult gst_wfd_ext_get_wfd2_audio_codecs (GstWFDExtMessage *msg, GstWFD2SinkAudioCap *audio_codecs); +GstWFD2AudioFormatEnum gst_wfd_ext_get_wfd2_audio_format(gchar *str); +const char *gst_wfd_ext_peek_wfd2_audio_format_string(const GstWFD2AudioFormatEnum audio_format); +GstWFDResult gst_wfd_ext_message_init_wfd2_video_formats(GstWFDExtMessage *msg); +GstWFDResult gst_wfd_ext_message_init_wfd2_audio_codecs(GstWFDExtMessage *msg); + +GstWFDResult gst_wfd_ext_message_get_prefered_video_format(GstWFDExtMessage *msg, GstWFD2VideoCodecEnum *vCodec, + GstWFD2DisplayNativeResolutionEnum *vNative, guint64 *vNativeResolution, + guint64 *vCEAResolution, guint64 *vVESAResolution, + guint64 *vHHResolution, GstWFD2VideoH265ProfileEnum *vProfile, + GstWFD2VideoH265LevelEnum *vLevel, guint32 *vLatency, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); + +GstWFDResult gst_wfd_ext_message_get_prefered_audio_format(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum *aCodec, GstWFD2AudioFreq *aFreq, GstWFD2AudioChannels *aChanels, + guint *aBitwidth, guint32 *aLatency); + + +#endif + +G_END_DECLS + +#endif /* _GST_WFD_EXT_MESSAGE_H__ */ + diff --git a/wfdextmanager/gstwfdextsrc.c b/wfdextmanager/gstwfdextsrc.c new file mode 100755 index 0000000..6ed2fe9 --- /dev/null +++ b/wfdextmanager/gstwfdextsrc.c @@ -0,0 +1,2124 @@ +/* + * wfdextsrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** +* SECTION:element-wfdextsrc +* +* Makes a connection to an RTSP server and read the data. +* Device recognition is through wifi direct. +* wfdextsrc strictly follows Wifi display specification. +* +* RTSP supports transport over TCP or UDP in unicast or multicast mode. By +* default wfdextsrc will negotiate a connection in the following order: +* UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed +* protocols can be controlled with the #GstWFDExtSrc:protocols property. +* +* wfdextsrc currently understands WFD capability negotiation messages +* +* wfdextsrc will internally instantiate an RTP session manager element +* that will handle the RTCP messages to and from the server, jitter removal, +* packet reordering along with providing a clock for the pipeline. +* This feature is implemented using the gstrtpbin element. +* +* wfdextsrc acts like a live source and will therefore only generate data in the +* PLAYING state. +* +* +* Example launch line +* |[ +* gst-launch wfdextsrc location=rtsp://some.server/url ! fakesink +* ]| Establish a connection to an RTSP server and send the raw RTP packets to a +* fakesink. +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gstwfdextsrc.h" + +GST_DEBUG_CATEGORY_STATIC (wfdextsrc_debug); +#define GST_CAT_DEFAULT (wfdextsrc_debug) + +/* signals and args */ +/* +enum { + LAST_SIGNAL +}; +static guint gst_wfdextsrc_signals[LAST_SIGNAL]; +*/ +enum +{ + PROP_0, + PROP_DO_RTCP, + PROP_LATENCY, + PROP_UDP_BUFFER_SIZE, + PROP_UDP_TIMEOUT, + PROP_DO_REQUEST, +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + PROP_AUDIO_R2_PARAM, + PROP_VIDEO_R2_PARAM, +#endif + PROP_LAST +}; + +#define DEFAULT_DO_RTCP TRUE +#define DEFAULT_LATENCY_MS 2000 +#define DEFAULT_UDP_BUFFER_SIZE 0x80000 +#define DEFAULT_UDP_TIMEOUT 10000000 +#define DEFAULT_DO_REQUEST FALSE + +/* object */ +static void gst_wfd_ext_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_wfd_ext_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_wfd_ext_src_finalize (GObject * object); + +/* wfdbasesrc */ +static GstRTSPResult gst_wfd_ext_src_handle_set_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response); +static GstRTSPResult gst_wfd_ext_src_handle_get_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response); +static GstRTSPResult gst_wfd_ext_src_configure_transport (GstWFDBaseSrc * bsrc, + GstRTSPTransport * transport); +static GstRTSPResult gst_wfd_ext_src_prepare_transport (GstWFDBaseSrc * bsrc, + gint rtpport, gint rtcpport); +static gboolean gst_wfd_ext_src_push_event (GstWFDBaseSrc * bsrc, + GstEvent * event); +static void gst_wfd_ext_src_set_state (GstWFDBaseSrc * src, GstState state); +static void gst_wfd_ext_src_cleanup (GstWFDBaseSrc * bsrc); + +static GstRTSPResult gst_wfd_ext_src_switch_transport (GstWFDExtSrc * src, + GstWFDRTSPLowerTrans lowertrans, guint32 port0, guint32 port1); +static void gst_wfd_ext_src_free_tcp (GstWFDExtSrc * src); + +/* static guint gst_wfd_ext_srcext_signals[LAST_SIGNAL] = { 0 }; */ + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT(wfdextsrc_debug, "wfdextsrc", 0, "Wi-Fi Display Sink Extension source"); + +#define gst_wfd_ext_src_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstWFDExtSrc, gst_wfd_ext_src, GST_TYPE_WFD_BASE_SRC, + _do_init); + +static void +gst_wfd_ext_src_class_init (GstWFDExtSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstWFDBaseSrcClass *gstwfdbasesrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstwfdbasesrc_class = (GstWFDBaseSrcClass *) klass; + + gobject_class->set_property = gst_wfd_ext_src_set_property; + gobject_class->get_property = gst_wfd_ext_src_get_property; + gobject_class->finalize = gst_wfd_ext_src_finalize; + + g_object_class_install_property (gobject_class, PROP_DO_RTCP, + g_param_spec_boolean ("do-rtcp", "Do RTCP", + "Send RTCP packets, disable for old incompatible server.", + DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint ("latency", "Buffer latency in ms", + "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_UDP_BUFFER_SIZE, + g_param_spec_int ("udp-buffer-size", "UDP Buffer Size", + "Size of the kernel UDP receive buffer in bytes, 0=default", + 0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_UDP_TIMEOUT, + g_param_spec_uint64 ("timeout", "Timeout", + "Fail after timeout microseconds on UDP connections (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_UDP_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DO_REQUEST, + g_param_spec_boolean ("do-request", "Enable RTP Retransmission Request", + "Send RTCP FB packets and handel retransmitted RTP packets.", + DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + g_object_class_install_property (gobject_class, PROP_AUDIO_R2_PARAM, + g_param_spec_boxed ("audio-r2-param", "audio r2 parameters", + "A GstStructure mapped for wfd audio parameters, " + "See all attributes in WFD specification(wfd-audio-codecs)." + "\n audio_codec: LPCM:0x01, AAC:0x02, AC3:0x04" + "\n audio_latency: an integer" + "\n audio_channels: 2:0x01, 4:0x02, 6:0x04 8:0x08" + "\n audio_sampling_frequency: 44.1khz:1, 48khz:2\n", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VIDEO_R2_PARAM, + g_param_spec_boxed ("video-r2-param", "video r2 parameters", + "A GstStructure mapped for wfd video parameters, " + "See all attributes in WFD specification(wfd2-video-formats).\n", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); +#endif + + gst_element_class_set_static_metadata (gstelement_class, + "Wi-Fi Display Sink source element", "Source/Network", + "Negotiate the capability and receive the RTP packets from the Wi-Fi Display source", + "YeJin Cho "); + + gstwfdbasesrc_class->handle_set_parameter = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_handle_set_parameter); + gstwfdbasesrc_class->handle_get_parameter = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_handle_get_parameter); + gstwfdbasesrc_class->configure_transport = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_configure_transport); + gstwfdbasesrc_class->prepare_transport = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_prepare_transport); + gstwfdbasesrc_class->push_event = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_push_event); + gstwfdbasesrc_class->set_state = + GST_DEBUG_FUNCPTR (gst_wfd_ext_src_set_state); + gstwfdbasesrc_class->cleanup = GST_DEBUG_FUNCPTR (gst_wfd_ext_src_cleanup); +} + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + +static GstStructure * +gst_wfd_ext_set_default_audio_r2_param () +{ + GstStructure *param = NULL; + param = gst_structure_new ("audio_param", + "audio_codec", G_TYPE_UINT, 0x3, + "audio_lpcm_mode", G_TYPE_UINT, 0x1, + "audio_aac_mode", G_TYPE_UINT, 0x1, + "audio_ac3_mode", G_TYPE_UINT, 0x1, NULL); + + return param; +} + +static GstStructure * +gst_wfd_ext_set_default_video_r2_param () +{ + GstStructure *param = NULL; + param = gst_structure_new ("video_param", + "video_codec", G_TYPE_UINT, 0x1, + "video_native_resolution", G_TYPE_UINT, 0x20, + "video_cea_support", G_TYPE_UINT, 0x194ab, + "video_vesa_support", G_TYPE_UINT, 0x15555555, + "video_hh_support", G_TYPE_UINT, 0x555, + "video_profile", G_TYPE_UINT, 0x1, + "video_level", G_TYPE_UINT, 0x2, + "video_latency", G_TYPE_UINT, 0x0, + "video_vertical_resolution", G_TYPE_INT, 1200, + "video_horizontal_resolution", G_TYPE_INT, 1920, + "video_minimum_slicing", G_TYPE_INT, 0, + "video_slice_enc_param", G_TYPE_INT, 200, + "video_framerate_control_support", G_TYPE_INT, 11, + "video_non_transcoding_support", G_TYPE_INT, 0, NULL); + + return param; +} +#endif + +static void +gst_wfd_ext_src_init (GstWFDExtSrc * src) +{ + gint i; + + src->do_rtcp = DEFAULT_DO_RTCP; + src->latency = DEFAULT_LATENCY_MS; + src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; + src->udp_timeout = DEFAULT_UDP_TIMEOUT; + src->do_request = DEFAULT_DO_REQUEST; + + src->session = NULL; + src->requester = NULL; + src->wfdrtpbuffer = NULL; + for (i = 0; i < 3; i++) { + src->channelpad[i] = NULL; + src->udpsrc[i] = NULL; + src->udpsink[i] = NULL; + } + src->blockid = 0; + src->blockedpad = NULL; + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + src->audio_r2_param = gst_wfd_ext_set_default_audio_r2_param (); + src->video_r2_param = gst_wfd_ext_set_default_video_r2_param (); +#endif + +} + +static void +gst_wfd_ext_src_finalize (GObject * object) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if (src->audio_r2_param) + gst_structure_free (src->audio_r2_param); + src->audio_r2_param = NULL; + if (src->video_r2_param) + gst_structure_free (src->video_r2_param); + src->video_r2_param = NULL; +#endif + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_wfd_ext_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); + + switch (prop_id) { + case PROP_DO_RTCP: + src->do_rtcp = g_value_get_boolean (value); + break; + case PROP_LATENCY: + src->latency = g_value_get_uint (value); + break; + case PROP_UDP_BUFFER_SIZE: + src->udp_buffer_size = g_value_get_int (value); + break; + case PROP_UDP_TIMEOUT: + src->udp_timeout = g_value_get_uint64 (value); + break; + case PROP_DO_REQUEST: + src->do_request = g_value_get_boolean (value); + break; +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + case PROP_AUDIO_R2_PARAM: + { + const GstStructure *s = gst_value_get_structure (value); + if (src->audio_r2_param) + gst_structure_free (src->audio_r2_param); + if (s) + src->audio_r2_param = gst_structure_copy (s); + else + src->audio_r2_param = NULL; + break; + } + case PROP_VIDEO_R2_PARAM: + { + const GstStructure *s = gst_value_get_structure (value); + if (src->video_r2_param) + gst_structure_free (src->video_r2_param); + if (s) + src->video_r2_param = gst_structure_copy (s); + else + src->video_r2_param = NULL; + break; + } +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfd_ext_src_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); + + switch (prop_id) { + case PROP_DO_RTCP: + g_value_set_boolean (value, src->do_rtcp); + break; + case PROP_LATENCY: + g_value_set_uint (value, src->latency); + break; + case PROP_UDP_BUFFER_SIZE: + g_value_set_int (value, src->udp_buffer_size); + break; + case PROP_UDP_TIMEOUT: + g_value_set_uint64 (value, src->udp_timeout); + break; + case PROP_DO_REQUEST: + g_value_set_boolean (value, src->do_request); + break; +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + case PROP_AUDIO_R2_PARAM: + gst_value_set_structure (value, src->audio_r2_param); + break; + case PROP_VIDEO_R2_PARAM: + gst_value_set_structure (value, src->video_r2_param); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE +static GstRTSPResult +gst_wfd_ext_src_get_audio_parameter (GstWFDBaseSrc * src, + GstWFDExtMessage * msg) +{ + guint audio_format = 0; + guint audio_channels = 0; + guint audio_frequency = 0; + guint audio_bitwidth = 0; + guint32 audio_latency = 0; + GstWFDResult wfd_res = GST_WFD_OK; + + wfd_res = + gst_wfd_ext_message_get_prefered_audio_format (msg, &audio_format, + &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); + if (wfd_res != GST_WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to get prefered audio format."); + return GST_RTSP_ERROR; + } + + GST_ERROR_OBJECT (src, "channel:%d, audio_frequency:%d", audio_channels, + audio_frequency); + + GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); + gst_structure_set (stream_info, + "audio_format", G_TYPE_STRING, + gst_wfd_ext_peek_wfd2_audio_format_string (audio_format), + "audio_channels", G_TYPE_UINT, audio_channels, "audio_rate", G_TYPE_UINT, + audio_frequency, "audio_bitwidth", G_TYPE_UINT, audio_bitwidth, NULL); + gst_wfd_base_src_set_streaminfo (GST_WFD_BASE_SRC (src), stream_info); + + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_wfd_ext_src_get_video_parameter (GstWFDBaseSrc * src, + GstWFDExtMessage * msg) +{ + GstWFD2VideoCodecEnum cvCodec = GST_WFD2_VIDEO_CODEC_NONE; + GstWFD2DisplayNativeResolutionEnum cNative = GST_WFD2_DISPALY_NATIVE_CEA; + guint64 cNativeResolution = 0; + guint64 cCEAResolution = GST_WFD_CEA_UNKNOWN; + guint64 cVESAResolution = GST_WFD_VESA_UNKNOWN; + guint64 cHHResolution = GST_WFD_HH_UNKNOWN; + GstWFD2VideoH265ProfileEnum cProfile = GST_WFD2_H265_UNKNOWN_PROFILE; + GstWFD2VideoH265LevelEnum cLevel = GST_WFD2_H265_LEVEL_UNKNOWN; + guint32 cmin_slice_size = 0; + guint32 cslice_enc_params = 0; + guint cframe_rate_control = 0; + guint cvLatency = 0; + GstWFDResult wfd_res = GST_WFD_OK; + + wfd_res = + gst_wfd_ext_message_get_prefered_video_format (msg, &cvCodec, &cNative, + &cNativeResolution, &cCEAResolution, &cVESAResolution, &cHHResolution, + &cProfile, &cLevel, &cvLatency, &cmin_slice_size, &cslice_enc_params, + &cframe_rate_control); + if (wfd_res != GST_WFD_OK) { + GST_ERROR ("Failed to get prefered video format."); + return GST_RTSP_ERROR; + } + + if (cCEAResolution != GST_WFD_CEA_UNKNOWN) { + gst_wfd_base_src_get_cea_resolution_and_set_to_src (src, cCEAResolution); + } else if (cVESAResolution != GST_WFD_VESA_UNKNOWN) { + gst_wfd_base_src_get_vesa_resolution_and_set_to_src (src, cVESAResolution); + } else if (cHHResolution != GST_WFD_HH_UNKNOWN) { + gst_wfd_base_src_get_hh_resolution_and_set_to_src (src, cHHResolution); + } + + return GST_RTSP_OK; +} +#endif + +static GstRTSPResult +gst_wfd_ext_src_handle_set_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + GstRTSPResult res = GST_RTSP_OK; + GstWFDResult wfd_res = GST_WFD_OK; + GstWFDExtMessage *msg = NULL; + GstRTSPMethod method; + GstRTSPVersion version; + const gchar *uri; + guint8 *data = NULL; + guint size = 0; + gchar *msg_str = NULL; + gboolean add_reponse = FALSE; + + GString *body = NULL; + GString *body_length = NULL; + + g_return_val_if_fail (request, GST_RTSP_EINVAL); + g_return_val_if_fail (response, GST_RTSP_EINVAL); + + res = gst_rtsp_message_parse_request (request, &method, &uri, &version); + if (res < 0) + goto error; + + if (G_UNLIKELY (method != GST_RTSP_SET_PARAMETER)) + goto error; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res < 0) + goto error; + + wfd_res = gst_wfd_ext_message_new (&msg); + if (wfd_res != GST_WFD_OK) + goto error; + + wfd_res = gst_wfd_ext_message_parse_buffer (data, size, msg); + if (wfd_res != GST_WFD_OK) + goto error; + + if (msg->max_buffer_length) { + GstWFDRTSPTransMode trans = GST_WFD_RTSP_TRANS_UNKNOWN; + GstWFDRTSPProfile profile = GST_WFD_RTSP_PROFILE_UNKNOWN; + GstWFDRTSPLowerTrans lowertrans = GST_WFD_RTSP_LOWER_TRANS_UNKNOWN; + guint32 rtp_port0 = 0, rtp_port1 = 0; + guint32 length = 0; + + wfd_res = gst_wfd_ext_message_get_max_buffer_length (msg, &length); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "max_buffer_length : %d", length); + + if (msg->client_rtp_ports) { + wfd_res = + gst_wfd_ext_message_get_client_RTP_ports (msg, &trans, &profile, + &lowertrans, &rtp_port0, &rtp_port1); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "rtp_port0 : %d", rtp_port0); + GST_DEBUG_OBJECT (src, "rtp_port1 : %d", rtp_port1); + } + + res = + gst_wfd_ext_src_switch_transport (src, lowertrans, rtp_port0, + rtp_port1); + if (res != GST_RTSP_OK) + goto error; + + add_reponse = TRUE; + } +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + if ((msg->wfd2_video_formats + && msg->wfd2_video_formats->sink_video_cap.video_codec_list) + || (msg->wfd2_audio_codecs && msg->wfd2_audio_codecs->sink_audio_list)) { + + GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); + + if (msg->wfd2_video_formats + && msg->wfd2_video_formats->sink_video_cap.video_codec_list) { + + GST_ERROR_OBJECT (src, "wfd2_video_formats : native[%02x] codec[%02x]" + " profile[%02x] level[%0x4] CEA[%012llx] VESA[%012llx] HH[%012llx]" + " latency[%02x] min_slice_size[%04x] slice_enc_params[%04x] frame_rate_control_support[%02x]" + " non_transcoding_support[%02x] portrait_mode[%d]", + msg->wfd2_video_formats->sink_video_cap.native, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->codec, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->profile, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->level, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + CEA_Support, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + VESA_Support, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + HH_Support, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + latency, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + min_slice_size, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + slice_enc_params, + msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. + frame_rate_control_support, + msg->wfd2_video_formats->sink_video_cap.non_transcoding_support, + msg->wfd2_video_formats->portrait_mode); + + gst_wfd_ext_src_get_video_parameter (GST_WFD_BASE_SRC (src), msg); + + } + + if (msg->wfd2_audio_codecs && msg->wfd2_audio_codecs->sink_audio_list) { + + const char *codec = NULL; + codec = + gst_wfd_ext_peek_wfd2_audio_format_string (msg->wfd2_audio_codecs-> + sink_audio_list->audio_format); + if (codec == NULL) + codec = "INVALID AUDIO CODEC"; + + GST_ERROR_OBJECT (src, "wfd2_audio_codecs: %s %08x %02x", + codec, + msg->wfd2_audio_codecs->sink_audio_list->mode, + msg->wfd2_audio_codecs->sink_audio_list->latency); + + gst_wfd_ext_src_get_audio_parameter (GST_WFD_BASE_SRC (src), msg); + + } + + gst_wfd_base_src_get_streaminfo (GST_WFD_BASE_SRC (src), stream_info); + + GST_DEBUG_OBJECT (src, "Send signal update-media-info"); + g_signal_emit_by_name (src, "update-media-info", stream_info); + } +#endif + + if (!add_reponse) + goto done; + + msg_str = gst_wfd_ext_message_as_text (msg); + if (msg_str == NULL) + goto error; + + data = NULL; + res = gst_rtsp_message_steal_body (response, &data, &size); + if (res != GST_RTSP_OK) + goto error; + + body = g_string_new_len ((const gchar *) data, size); + g_string_append (body, (const gchar *) msg_str); + if (body == NULL) { + GST_ERROR ("gst_wfd_ext_message_as_text is failed"); + goto error; + } + + body_length = g_string_new (""); + g_string_append_printf (body_length, "%d", body->len); + GST_DEBUG_OBJECT (src, "body_length : %s", body_length->str); + + gst_rtsp_message_remove_header (response, GST_RTSP_HDR_CONTENT_LENGTH, -1); + gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONTENT_LENGTH, + (const gchar *) body_length->str); + + GST_DEBUG_OBJECT (src, "body : %s", body->str); + + res = + gst_rtsp_message_set_body (response, (const guint8 *) body->str, + body->len); + if (res < 0) + goto error; + + g_string_free (body, TRUE); + g_string_free (body_length, TRUE); + +done: + if (msg_str) + g_free (msg_str); + if (msg) + gst_wfd_ext_message_free (msg); + + return res; + +/* ERRORS */ +error: + { + g_string_free (body_length, TRUE); + g_string_free (body, TRUE); + + if (msg_str) + g_free (msg_str); + if (msg) + gst_wfd_ext_message_free (msg); + + GST_ERROR_OBJECT (src, "Could not handle message"); + return res; + } +} + +static GstRTSPResult +gst_wfd_ext_src_handle_get_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMethod method; + GstRTSPVersion version; + const gchar *uri; + guint8 *data = NULL; + guint size = 0; + GString *body = NULL; + GString *body_length = NULL; + GString *msg_str = NULL; + + g_return_val_if_fail (request, GST_RTSP_EINVAL); + g_return_val_if_fail (response, GST_RTSP_EINVAL); + + GST_DEBUG_OBJECT (src, ""); + + res = gst_rtsp_message_parse_request (request, &method, &uri, &version); + if (res < 0) + goto error; + + if (G_UNLIKELY (method != GST_RTSP_GET_PARAMETER)) + goto error; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res < 0) + goto error; + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + { + GstWFDExtMessage *parse_msg = NULL; + GstWFDExtMessage *msg = NULL; + GstWFDResult wfd_res = GST_WFD_OK; + gchar *ext_codec_str = NULL; + guint video_native = GST_WFD2_DISPALY_NATIVE_CEA; + guint video_codec = 0; + guint video_native_resolution = 0; + guint video_cea_support = 0; + guint video_vesa_support = 0; + guint video_hh_support = 0; + guint video_profile = 0; + guint video_level = 0; + guint video_latency = 0; + gint video_vertical_resolution = 0; + gint video_horizontal_resolution = 0; + gint video_minimum_slicing = 0; + gint video_slice_enc_param = 0; + gint video_framerate_control_support = 0; + gint video_non_transcoding_support = 0; + guint video_portrait_mode = 0; + + wfd_res = gst_wfd_ext_message_new (&parse_msg); + if (wfd_res != GST_WFD_OK) + goto error; + + wfd_res = gst_wfd_ext_message_parse_buffer (data, size, parse_msg); + if (wfd_res != GST_WFD_OK) { + gst_wfd_ext_message_free (parse_msg); + goto error; + } + + if (parse_msg->wfd2_video_formats) { + + wfd_res = gst_wfd_ext_message_new (&msg); + if (wfd_res != GST_WFD_OK) { + gst_wfd_ext_message_free (parse_msg); + goto error; + } + + if (src->video_r2_param != NULL) { + GstStructure *video_param = src->video_r2_param; + + if (gst_structure_has_field (video_param, "video_codec")) + gst_structure_get_uint (video_param, "video_codec", &video_codec); + if (gst_structure_has_field (video_param, "video_native_resolution")) + gst_structure_get_uint (video_param, "video_native_resolution", + &video_native_resolution); + if (gst_structure_has_field (video_param, "video_cea_support")) + gst_structure_get_uint (video_param, "video_cea_support", + &video_cea_support); + if (gst_structure_has_field (video_param, "video_vesa_support")) + gst_structure_get_uint (video_param, "video_vesa_support", + &video_vesa_support); + if (gst_structure_has_field (video_param, "video_hh_support")) + gst_structure_get_uint (video_param, "video_hh_support", + &video_hh_support); + if (gst_structure_has_field (video_param, "video_profile")) + gst_structure_get_uint (video_param, "video_profile", &video_profile); + if (gst_structure_has_field (video_param, "video_level")) + gst_structure_get_uint (video_param, "video_level", &video_level); + if (gst_structure_has_field (video_param, "video_latency")) + gst_structure_get_uint (video_param, "video_latency", &video_latency); + if (gst_structure_has_field (video_param, "video_vertical_resolution")) + gst_structure_get_int (video_param, "video_vertical_resolution", + &video_vertical_resolution); + if (gst_structure_has_field (video_param, + "video_horizontal_resolution")) + gst_structure_get_int (video_param, "video_horizontal_resolution", + &video_horizontal_resolution); + if (gst_structure_has_field (video_param, "video_minimum_slicing")) + gst_structure_get_int (video_param, "video_minimum_slicing", + &video_minimum_slicing); + if (gst_structure_has_field (video_param, "video_slice_enc_param")) + gst_structure_get_int (video_param, "video_slice_enc_param", + &video_slice_enc_param); + if (gst_structure_has_field (video_param, + "video_framerate_control_support")) + gst_structure_get_int (video_param, "video_framerate_control_support", + &video_framerate_control_support); + if (gst_structure_has_field (video_param, + "video_non_transcoding_support")) + gst_structure_get_int (video_param, "video_non_transcoding_support", + &video_non_transcoding_support); + + } + + wfd_res = gst_wfd_ext_add_wfd2_video_format (msg, video_native, + video_codec, + video_profile, video_level, + video_cea_support, video_vesa_support, video_hh_support, + video_latency, video_minimum_slicing, video_slice_enc_param, + video_framerate_control_support, video_non_transcoding_support, + video_portrait_mode); + + if (wfd_res != GST_WFD_OK) { + gst_wfd_ext_message_free (parse_msg); + gst_wfd_ext_message_free (msg); + goto error; + } + } + + if (parse_msg->wfd2_audio_codecs) { + + guint audio_codec = 0; + guint audio_lpcm_mode = 0; + guint audio_aac_mode = 0; + guint audio_ac3_mode = 0; + + if (msg == NULL) { + wfd_res = gst_wfd_ext_message_new (&msg); + if (wfd_res != GST_WFD_OK) { + gst_wfd_ext_message_free (parse_msg); + goto error; + } + } + + if (src->audio_r2_param != NULL) { + GstStructure *audio_param = src->audio_r2_param; + + if (gst_structure_has_field (audio_param, "audio_codec")) + gst_structure_get_uint (audio_param, "audio_codec", &audio_codec); + if (gst_structure_has_field (audio_param, "audio_lpcm_mode")) + gst_structure_get_uint (audio_param, "audio_lpcm_mode", + &audio_lpcm_mode); + if (gst_structure_has_field (audio_param, "audio_aac_mode")) + gst_structure_get_uint (audio_param, "audio_aac_mode", + &audio_aac_mode); + if (gst_structure_has_field (audio_param, "audio_ac3_mode")) + gst_structure_get_uint (audio_param, "audio_ac3_mode", + &audio_ac3_mode); + } + + if (audio_codec & GST_WFD2_AUDIO_FORMAT_LPCM) + gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_LPCM, + audio_lpcm_mode, 0); + if (audio_codec & GST_WFD2_AUDIO_FORMAT_AAC) + gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_AAC, + audio_aac_mode, 0); + if (audio_codec & GST_WFD2_AUDIO_FORMAT_AC3) + gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_AC3, + audio_ac3_mode, 0); + } + + ext_codec_str = gst_wfd_ext_message_as_text (msg); + if (ext_codec_str != NULL) { + if (msg_str == NULL) + msg_str = g_string_new (""); + g_string_append_printf (msg_str, "%s", ext_codec_str); + g_free (ext_codec_str); + ext_codec_str = NULL; + } + gst_wfd_ext_message_free (msg); + gst_wfd_ext_message_free (parse_msg); + } +#endif + data = NULL; + res = gst_rtsp_message_steal_body (response, &data, &size); + if (res != GST_RTSP_OK) + goto error; + + body = g_string_new_len ((const gchar *) data, size); + if (body == NULL) { + GST_ERROR ("g_string_new is failed"); + goto error; + } + + if (msg_str != NULL) { + g_string_append (body, (const gchar *) msg_str->str); + if (body == NULL) { + GST_ERROR_OBJECT (src, "g_string_append for uibc is failed "); + g_string_free (msg_str, TRUE); + msg_str = NULL; + goto error; + } + g_string_free (msg_str, TRUE); + msg_str = NULL; + } + body_length = g_string_new (""); + g_string_append_printf (body_length, "%d", body->len); + GST_DEBUG_OBJECT (src, "body_length : %s", body_length->str); + + gst_rtsp_message_remove_header (response, GST_RTSP_HDR_CONTENT_LENGTH, -1); + gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONTENT_LENGTH, + (const gchar *) body_length->str); + + GST_DEBUG_OBJECT (src, "body : %s", body->str); + + res = + gst_rtsp_message_set_body (response, (const guint8 *) body->str, + body->len); + if (res < 0) + goto error; + + g_string_free (body, TRUE); + g_string_free (body_length, TRUE); + + return res; + +/* ERRORS */ +error: + { + g_string_free (body_length, TRUE); + g_string_free (body, TRUE); + g_string_free (msg_str, TRUE); + + GST_ERROR_OBJECT (src, "Could not handle message"); + return res; + } +} + +static void +gst_wfd_ext_src_set_state (GstWFDBaseSrc * bsrc, GstState state) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + gint i; + + GST_DEBUG_OBJECT (src, "try to set %s state", + gst_element_state_get_name (state)); + + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], state); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], state); + } + + if (src->session) + gst_element_set_state (src->session, state); + + if (src->requester) + gst_element_set_state (src->requester, state); + + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, state); +} + +static void +gst_wfd_ext_src_cleanup (GstWFDBaseSrc * bsrc) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + gint i; + + GST_DEBUG_OBJECT (src, "cleanup"); + + gst_wfd_ext_src_free_tcp (src); + + for (i = 0; i < 3; i++) { + if (src->channelpad[i]) { + gst_object_unref (src->channelpad[i]); + src->channelpad[i] = NULL; + } + if (src->udpsrc[i]) { + gst_element_set_state (src->udpsrc[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->udpsrc[i]); + gst_object_unref (src->udpsrc[i]); + src->udpsrc[i] = NULL; + } + if (src->udpsink[i]) { + gst_element_set_state (src->udpsink[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->udpsink[i]); + gst_object_unref (src->udpsink[i]); + src->udpsrc[i] = NULL; + } + } + if (src->session) { + gst_element_set_state (src->session, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->session); + gst_object_unref (src->session); + src->session = NULL; + } + if (src->requester) { + gst_element_set_state (src->requester, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->requester); + gst_object_unref (src->requester); + src->requester = NULL; + } + if (src->wfdrtpbuffer) { + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->wfdrtpbuffer); + gst_object_unref (src->wfdrtpbuffer); + src->wfdrtpbuffer = NULL; + } +} + +static GstRTSPResult +gst_wfd_ext_src_prepare_transport (GstWFDBaseSrc * bsrc, gint rtpport, + gint rtcpport) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + GstStateChangeReturn ret; + GstElement *udpsrc0, *udpsrc1, *udpsrc2; + gint tmp_rtp, tmp_rtcp, tmp_rtcp_fb; + const gchar *host; + + udpsrc0 = NULL; + udpsrc1 = NULL; + udpsrc2 = NULL; + + if (bsrc->is_ipv6) + host = "udp://[::0]"; + else + host = "udp://0.0.0.0"; + + /* try to allocate 2 UDP ports */ + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc0 == NULL) + goto no_udp_protocol; + g_object_set (G_OBJECT (udpsrc0), "port", rtpport, "reuse", TRUE, NULL); + + if (src->udp_buffer_size != 0) + g_object_set (G_OBJECT (udpsrc0), "buffer-size", src->udp_buffer_size, + NULL); + + GST_DEBUG_OBJECT (src, "starting RTP on port %d", rtpport); + ret = gst_element_set_state (udpsrc0, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTP port %d", rtpport); + goto no_ports; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp); + + /* check if port is even */ + if ((tmp_rtp & 0x01) != 0) { + GST_DEBUG_OBJECT (src, "RTP port not even"); + /* port not even, free RTP udpsrc */ + goto no_ports; + } + + /* allocate port+1 for RTCP now */ + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc1 == NULL) + goto no_udp_protocol; + + /* set port */ + g_object_set (G_OBJECT (udpsrc1), "port", rtcpport, "reuse", TRUE, NULL); + + GST_DEBUG_OBJECT (src, "starting RTCP on port %d", rtcpport); + ret = gst_element_set_state (udpsrc1, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTCP port %d", rtcpport); + goto no_ports; + } + + /* allocate port #19120 for retransmitted RTP now */ + udpsrc2 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc2 == NULL) + goto no_udp_protocol; + + /* set port */ + g_object_set (G_OBJECT (udpsrc2), "port", RETRANSMITTED_RTP_PORT, "reuse", + TRUE, NULL); + + if (src->udp_buffer_size != 0) + g_object_set (G_OBJECT (udpsrc2), "buffer-size", src->udp_buffer_size, + NULL); + + GST_DEBUG_OBJECT (src, "starting Retransmitted RTP on port %d", + RETRANSMITTED_RTP_PORT); + ret = gst_element_set_state (udpsrc2, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, + "Unable to make udpsrc from Retransmitted RTP port %d", + RETRANSMITTED_RTP_PORT); + goto no_ports; + } + + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &tmp_rtcp, NULL); + g_object_get (G_OBJECT (udpsrc2), "port", &tmp_rtcp_fb, NULL); + + /* this should not happen... */ + if (rtpport != tmp_rtp || rtcpport != tmp_rtcp + || tmp_rtcp_fb != RETRANSMITTED_RTP_PORT) + goto port_error; + + /* we keep these elements, we configure all in configure_transport when the + * server told us to really use the UDP ports. */ + src->udpsrc[0] = gst_object_ref_sink (udpsrc0); + src->udpsrc[1] = gst_object_ref_sink (udpsrc1); + src->udpsrc[2] = gst_object_ref_sink (udpsrc2); + gst_element_set_locked_state (src->udpsrc[0], TRUE); + gst_element_set_locked_state (src->udpsrc[1], TRUE); + gst_element_set_locked_state (src->udpsrc[2], TRUE); + + return GST_RTSP_OK; + + /* ERRORS */ +no_udp_protocol: + { + GST_DEBUG_OBJECT (src, "could not get UDP source"); + goto cleanup; + } +no_ports: + { + GST_DEBUG_OBJECT (src, "could not allocate UDP port pair"); + goto cleanup; + } +port_error: + { + GST_DEBUG_OBJECT (src, + "ports don't match rtp: %d<->%d, rtcp: %d<->%d, retransmitted rtp: %d<->%d", + tmp_rtp, rtpport, tmp_rtcp, rtcpport, tmp_rtcp_fb, + RETRANSMITTED_RTP_PORT); + goto cleanup; + } +cleanup: + { + if (udpsrc0) { + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + } + if (udpsrc1) { + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + } + if (udpsrc2) { + gst_element_set_state (udpsrc2, GST_STATE_NULL); + gst_object_unref (udpsrc2); + } + return GST_RTSP_ERROR; + } +} + +static void +request_idr_by_requester (GstElement * requester, GstWFDExtSrc * src) +{ + GstEvent *event = NULL; + + GST_DEBUG_OBJECT (src, "try to request idr"); + + /* Send IDR request */ + event = + gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, + gst_structure_new ("GstWFDIDRRequest", NULL, NULL)); + + if (!gst_pad_send_event (GST_WFD_BASE_SRC_CAST (src)->srcpad, event)) + GST_WARNING_OBJECT (src, "failed to send event for idr reuest"); +} + +static void +on_bye_ssrc (GObject * session, guint32 ssrc, GstWFDExtSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session received BYE"); + + //gst_wfdextsrc_do_stream_eos (src, manager); +} + +static void +on_new_ssrc (GObject * session, guint32 ssrc, GstWFDExtSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session received NEW"); +} + +static void +on_timeout (GObject * session, guint32 ssrc, GstWFDExtSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session timed out"); + + //gst_wfdextsrc_do_stream_eos (src, manager); +} + +static void +on_ssrc_active (GObject * session, guint32 ssrc, GstWFDExtSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session is active"); +} + +static GstCaps * +request_pt_map_for_wfdrtpbuffer (GstElement * wfdrtpbuffer, guint pt, + GstWFDExtSrc * src) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); + + GST_WFD_BASE_STATE_LOCK (src); + caps = GST_WFD_BASE_SRC_CAST (src)->caps; + if (caps) + gst_caps_ref (caps); + GST_WFD_BASE_STATE_UNLOCK (src); + + return caps; +} + +static GstCaps * +request_pt_map_for_session (GstElement * session, guint pt, GstWFDExtSrc * src) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); + + GST_WFD_BASE_STATE_LOCK (src); + caps = GST_WFD_BASE_SRC_CAST (src)->caps; + if (caps) + gst_caps_ref (caps); + GST_WFD_BASE_STATE_UNLOCK (src); + + return caps; +} + +static gboolean +gst_wfd_ext_src_configure_manager (GstWFDExtSrc * src) +{ + GstPad *pad = NULL; + + /* construct wfdextsrc */ + src->session = gst_element_factory_make ("rtpsession", "wfdextsrc_session"); + if (G_UNLIKELY (src->session == NULL)) { + GST_ERROR_OBJECT (src, "could not create gstrtpsession element"); + return FALSE; + } else { + g_signal_connect (src->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + src); + g_signal_connect (src->session, "on-bye-timeout", (GCallback) on_timeout, + src); + g_signal_connect (src->session, "on-timeout", (GCallback) on_timeout, src); + g_signal_connect (src->session, "on-ssrc-active", + (GCallback) on_ssrc_active, src); + g_signal_connect (src->session, "on-new-ssrc", (GCallback) on_new_ssrc, + src); + g_signal_connect (src->session, "request-pt-map", + (GCallback) request_pt_map_for_session, src); + + g_object_set (G_OBJECT (src->session), "rtcp-min-interval", + (guint64) 1000000000, NULL); + + src->channelpad[0] = + gst_element_get_request_pad (src->session, "recv_rtp_sink"); + if (G_UNLIKELY (src->channelpad[0] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtp channel pad"); + return FALSE; + } + + src->channelpad[1] = + gst_element_get_request_pad (src->session, "recv_rtcp_sink"); + if (G_UNLIKELY (src->channelpad[1] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtcp channel pad"); + return FALSE; + } + + /* we manage session element */ + gst_element_set_locked_state (src->session, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->session)) { + GST_ERROR_OBJECT (src, "failed to add rtpsession to wfdextsrc"); + return FALSE; + } + } + + src->requester = + gst_element_factory_make ("wfdrtprequester", "wfdextsrc_requester"); + if (G_UNLIKELY (src->requester == NULL)) { + GST_ERROR_OBJECT (src, "could not create wfdrtprequester element"); + return FALSE; + } else { + g_signal_connect (src->requester, "request-idr", + (GCallback) request_idr_by_requester, src); + + g_object_set (src->requester, "do-request", src->do_request, NULL); + + GST_DEBUG_OBJECT (src, + "getting retransmitted RTP sink pad of gstrtprequester"); + src->channelpad[2] = + gst_element_get_request_pad (src->requester, "retransmitted_rtp_sink"); + if (!src->channelpad[2]) { + GST_DEBUG_OBJECT (src, + "fail to get retransmitted RTP sink pad of gstrtprequester"); + return FALSE; + } + + /* we manage requester element */ + gst_element_set_locked_state (src->requester, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->requester)) { + GST_ERROR_OBJECT (src, "failed to add wfdrtprequester to wfdextsrc"); + return FALSE; + } + } + + src->wfdrtpbuffer = + gst_element_factory_make ("wfdrtpbuffer", "wfdextsrc_wfdrtpbuffer"); + if (G_UNLIKELY (src->wfdrtpbuffer == NULL)) { + GST_ERROR_OBJECT (src, "could not create wfdrtpbuffer element"); + return FALSE; + } else { + /* configure latency and packet lost */ + g_object_set (src->wfdrtpbuffer, "latency", src->latency, NULL); + + g_signal_connect (src->wfdrtpbuffer, "request-pt-map", + (GCallback) request_pt_map_for_wfdrtpbuffer, src); + + /* we manage wfdrtpbuffer element */ + gst_element_set_locked_state (src->wfdrtpbuffer, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->wfdrtpbuffer)) { + GST_ERROR_OBJECT (src, "failed to add wfdrtpbuffer to wfdextsrc"); + return FALSE; + } + } + + if (!gst_element_link_many (src->session, src->requester, src->wfdrtpbuffer, + NULL)) { + GST_ERROR_OBJECT (src, "failed to link elements for wfdextsrc"); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->session)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", + GST_ELEMENT_NAME (src->session)); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->requester)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", + GST_ELEMENT_NAME (src->requester)); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->wfdrtpbuffer)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", + GST_ELEMENT_NAME (src->wfdrtpbuffer)); + return FALSE; + } + + /* set ghost pad */ + pad = gst_element_get_static_pad (src->wfdrtpbuffer, "src"); + if (G_UNLIKELY (pad == NULL)) { + GST_ERROR_OBJECT (src, + "failed to get src pad of wfdrtpbuffer for setting ghost pad of wfdextsrc"); + return FALSE; + } + + if (!gst_wfd_base_src_set_target (GST_WFD_BASE_SRC (src), pad)) { + GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_wfd_ext_src_configure_udp_sinks (GstWFDExtSrc * src, + GstRTSPTransport * transport) +{ + GstPad *pad = NULL; + GSocket *socket = NULL; + gint rtp_port = -1, rtcp_port = -1, rtcp_fb_port = -1; + gboolean do_rtcp, do_rtcp_fb; + const gchar *destination = NULL; + gchar *uri = NULL; + GstPad *rtcp_fb_pad = NULL; + + /* get transport info */ + gst_wfd_base_src_get_transport_info (GST_WFD_BASE_SRC (src), transport, + &destination, &rtp_port, &rtcp_port); + rtcp_fb_port = RTCP_FB_PORT; + + /* it's possible that the server does not want us to send RTCP in which case + * the port is -1 */ + do_rtcp = (rtcp_port != -1 && src->session != NULL && src->do_rtcp); + do_rtcp_fb = (rtcp_fb_port != -1); + + /* we need a destination when we have RTCP RR and RTCP FB ports */ + if (destination == NULL && (do_rtcp_fb || do_rtcp)) + goto no_destination; + + if (do_rtcp) { + GstPad *rtcppad = NULL; + + GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination, + rtcp_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port); + src->udpsink[1] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (src->udpsink[1] == NULL) + goto no_sink_element; + + /* don't join multicast group, we will have the source socket do that */ + /* no sync or async state changes needed */ + g_object_set (G_OBJECT (src->udpsink[1]), "auto-multicast", FALSE, "loop", + FALSE, "sync", FALSE, "async", FALSE, NULL); + + if (src->udpsrc[1]) { + /* configure socket, we give it the same UDP socket as the udpsrc for RTCP + * because some servers check the port number of where it sends RTCP to identify + * the RTCP packets it receives */ + g_object_get (G_OBJECT (src->udpsrc[1]), "used-socket", &socket, NULL); + GST_DEBUG_OBJECT (src, "RTCP UDP src has sock %p", socket); + /* configure socket and make sure udpsink does not close it when shutting + * down, it belongs to udpsrc after all. */ + g_object_set (G_OBJECT (src->udpsink[1]), "socket", socket, + "close-socket", FALSE, NULL); + g_object_unref (socket); + } + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (src->udpsink[1], GST_ELEMENT_FLAG_SINK); + + /* we keep this playing always */ + gst_element_set_locked_state (src->udpsink[1], TRUE); + gst_element_set_state (src->udpsink[1], GST_STATE_PLAYING); + + gst_object_ref (src->udpsink[1]); + gst_bin_add (GST_BIN_CAST (src), src->udpsink[1]); + + rtcppad = gst_element_get_static_pad (src->udpsink[1], "sink"); + + /* get session RTCP pad */ + pad = gst_element_get_request_pad (src->session, "send_rtcp_src"); + + /* and link */ + if (pad && rtcppad) { + gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + gst_object_unref (rtcppad); + } + } + + if (do_rtcp_fb) { + GST_DEBUG_OBJECT (src, "configure RTCP FB sink for %s:%d", destination, + rtcp_fb_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_fb_port); + src->udpsink[2] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (src->udpsink[2] == NULL) + goto no_sink_element; + + /* don't join multicast group, we will have the source socket do that */ + /* no sync or async state changes needed */ + g_object_set (G_OBJECT (src->udpsink[2]), "auto-multicast", FALSE, + "loop", FALSE, "sync", FALSE, "async", FALSE, NULL); + + g_object_set (G_OBJECT (src->udpsink[2]), "bind-port", rtcp_fb_port, + "close-socket", FALSE, NULL); + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (src->udpsink[2], GST_ELEMENT_FLAG_SINK); + + /* we keep this playing always */ + gst_element_set_locked_state (src->udpsink[2], TRUE); + gst_element_set_state (src->udpsink[2], GST_STATE_PLAYING); + + gst_object_ref (src->udpsink[2]); + gst_bin_add (GST_BIN_CAST (src), src->udpsink[2]); + + /* get RTCP FB sink pad */ + rtcp_fb_pad = gst_element_get_static_pad (src->udpsink[2], "sink"); + + /* get requester RTCP pad */ + pad = gst_element_get_static_pad (src->requester, "rtcp_src"); + + /* and link */ + if (rtcp_fb_pad && pad) { + gst_pad_link (pad, rtcp_fb_pad); + gst_object_unref (pad); + gst_object_unref (rtcp_fb_pad); + } + } + + return TRUE; + + /* ERRORS */ +no_destination: + { + GST_DEBUG_OBJECT (src, "no destination address specified"); + return FALSE; + } +no_sink_element: + { + GST_DEBUG_OBJECT (src, "no UDP sink element found"); + return FALSE; + } +} + +static void +pad_blocked (GstPad * pad, gboolean blocked, GstWFDExtSrc * src) +{ + GST_DEBUG_OBJECT (src, "pad %s:%s blocked, activating streams", + GST_DEBUG_PAD_NAME (pad)); + + if (src->udpsrc[0]) { + /* remove timeout, we are streaming now and timeouts will be handled by + * the session manager and jitter buffer */ + g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", (guint64) 0, NULL); + } + + /* activate the streams */ + gst_wfd_base_src_activate (GST_WFD_BASE_SRC (src)); + + /* unblock all pads */ + if (src->blockedpad && src->blockid != 0) { + GST_DEBUG_OBJECT (src, "unblocking blocked pad"); + gst_pad_remove_probe (src->blockedpad, src->blockid); + src->blockid = 0; + src->blockedpad = NULL; + } +} + +static gboolean +gst_wfd_ext_src_configure_udp (GstWFDExtSrc * src) +{ + GstPad *outpad; + + /* we manage the UDP elements now. For unicast, the UDP sources where + * allocated in the stream when we suggested a transport. */ + if (src->udpsrc[0]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[0], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[0]); + + GST_DEBUG_OBJECT (src, "setting up UDP source"); + + /* configure a timeout on the UDP port. When the timeout message is + * posted */ + g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", + src->udp_timeout * 1000, NULL); + + caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, + "clock-rate", G_TYPE_INT, 90000, NULL); + g_object_set (src->udpsrc[0], "caps", caps, NULL); + gst_caps_unref (caps); + + /* get output pad of the UDP source. */ + outpad = gst_element_get_static_pad (src->udpsrc[0], "src"); + + /* save it so we can unblock */ + src->blockedpad = outpad; + + /* configure pad block on the pad. As soon as there is dataflow on the + * UDP source, we know that UDP is not blocked by a firewall and we can + * configure all the streams to let the application autoplug decoders. */ + src->blockid = + gst_pad_add_probe (src->blockedpad, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | + GST_PAD_PROBE_TYPE_BUFFER_LIST, (GstPadProbeCallback) pad_blocked, src, + NULL); + + if (src->channelpad[0]) { + GST_DEBUG_OBJECT (src, "connecting UDP source 0 to session"); + /* configure for UDP delivery, we need to connect the UDP pads to + * the session plugin. */ + gst_pad_link_full (outpad, src->channelpad[0], + GST_PAD_LINK_CHECK_NOTHING); + /* we connected to pad-added signal to get pads from the manager */ + } else { + /* leave unlinked */ + } + } + + /* RTCP port */ + if (src->udpsrc[1]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[1], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[1]); + + caps = gst_caps_new_empty_simple ("application/x-rtcp"); + g_object_set (src->udpsrc[1], "caps", caps, NULL); + gst_caps_unref (caps); + + if (src->channelpad[1]) { + GstPad *pad; + + GST_DEBUG_OBJECT (src, "connecting UDP source 1 to session"); + + pad = gst_element_get_static_pad (src->udpsrc[1], "src"); + gst_pad_link_full (pad, src->channelpad[1], GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + } else { + /* leave unlinked */ + } + } + + /* Retransmitted RTP port */ + if (src->udpsrc[2]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[2], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[2]); + + caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, + "clock-rate", G_TYPE_INT, 90000, NULL); + g_object_set (src->udpsrc[2], "caps", caps, NULL); + gst_caps_unref (caps); + + if (src->channelpad[2]) { + GstPad *pad; + + GST_DEBUG_OBJECT (src, "connecting UDP source 2 to requester"); + pad = gst_element_get_static_pad (src->udpsrc[2], "src"); + gst_pad_link_full (pad, src->channelpad[2], GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + } else { + /* leave unlinked */ + } + } + + return TRUE; +} + +static GstRTSPResult +gst_wfd_ext_src_configure_transport (GstWFDBaseSrc * bsrc, + GstRTSPTransport * transport) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + const gchar *mime; + + g_return_val_if_fail (transport, GST_RTSP_EINVAL); + + GST_DEBUG_OBJECT (src, "configuring transport"); + + /* get the proper mime type for this manager now */ + if (gst_rtsp_transport_get_mime (transport->trans, &mime) < 0) + goto unknown_transport; + if (!mime) + goto unknown_transport; + + /* configure the final mime type */ + GST_DEBUG_OBJECT (src, "setting mime to %s", mime); + + if (!gst_wfd_ext_src_configure_manager (src)) + goto no_manager; + + switch (transport->lower_transport) { + case GST_RTSP_LOWER_TRANS_TCP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + goto transport_failed; + case GST_RTSP_LOWER_TRANS_UDP: + if (!gst_wfd_ext_src_configure_udp (src)) + goto transport_failed; + if (!gst_wfd_ext_src_configure_udp_sinks (src, transport)) + goto transport_failed; + break; + default: + goto unknown_transport; + } + + return GST_RTSP_OK; + + /* ERRORS */ +unknown_transport: + { + GST_DEBUG_OBJECT (src, "unknown transport"); + return GST_RTSP_ERROR; + } +no_manager: + { + GST_DEBUG_OBJECT (src, "cannot configure manager"); + return GST_RTSP_ERROR; + } +transport_failed: + { + GST_DEBUG_OBJECT (src, "failed to configure transport"); + return GST_RTSP_ERROR; + } +} + +static gboolean +gst_wfd_ext_src_push_event (GstWFDBaseSrc * bsrc, GstEvent * event) +{ + GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); + gboolean res = TRUE; + + if (src->udpsrc[0] && GST_STATE (src->udpsrc[0]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res = gst_element_send_event (src->udpsrc[0], event); + } else if (src->channelpad[0]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[0])) + res = gst_pad_push_event (src->channelpad[0], event); + else + res = gst_pad_send_event (src->channelpad[0], event); + } + + if (src->udpsrc[1] && GST_STATE (src->udpsrc[1]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res &= gst_element_send_event (src->udpsrc[1], event); + } else if (src->channelpad[1]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[1])) + res &= gst_pad_push_event (src->channelpad[1], event); + else + res &= gst_pad_send_event (src->channelpad[1], event); + } + + if (src->udpsrc[2] && GST_STATE (src->udpsrc[2]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res &= gst_element_send_event (src->udpsrc[2], event); + } else if (src->channelpad[2]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[2])) + res &= gst_pad_push_event (src->channelpad[2], event); + else + res &= gst_pad_send_event (src->channelpad[2], event); + } + + gst_event_unref (event); + + return res; +} + +static gboolean +gst_wfd_ext_src_change_udpsrc_uri (GstWFDExtSrc * src, GstElement * udpsrc, + gint port) +{ + GstStateChangeReturn ret; + gint org_port; + + g_object_get (G_OBJECT (udpsrc), "port", &org_port, NULL); + if (port == org_port) + goto done; + + ret = gst_element_set_state (udpsrc, GST_STATE_NULL); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to stop udpsrc"); + goto error; + } + + g_object_set (G_OBJECT (udpsrc), "port", port, NULL); + + GST_DEBUG_OBJECT (src, "starting udpsrc with port %d", port); + ret = gst_element_set_state (udpsrc, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to run udpsrc port %d", port); + goto error; + } + + g_object_get (G_OBJECT (udpsrc), "port", &org_port, NULL); + if (port != org_port) + goto error; + +done: + return TRUE; + + /* ERRORS */ +error: + { + GST_DEBUG_OBJECT (src, "error"); + return FALSE; + } +} + +static void +gst_wfd_ext_src_free_tcp (GstWFDExtSrc * src) +{ + if (src->tcp_task) { + GST_DEBUG_OBJECT (src, "Closing tcp loop"); + if (src->tcp_conn) + gst_rtsp_connection_flush (src->tcp_conn, TRUE); + + gst_task_stop (src->tcp_task); + + g_rec_mutex_lock (&(src->tcp_task_lock)); + g_rec_mutex_unlock (&(src->tcp_task_lock)); + + gst_task_join (src->tcp_task); + gst_object_unref (src->tcp_task); + g_rec_mutex_clear (&(src->tcp_task_lock)); + src->tcp_task = NULL; + if (src->tcp_socket) { + g_object_unref (src->tcp_socket); + src->tcp_socket = NULL; + } + if (src->tcp_conn) { + GST_DEBUG_OBJECT (src, "freeing connection..."); + gst_rtsp_connection_free (src->tcp_conn); + src->tcp_conn = NULL; + } + + GST_DEBUG_OBJECT (src, "Tcp connection closed"); + } +} + +static GstRTSPResult +gst_wfd_ext_src_switch_to_udp (GstWFDExtSrc * src, guint32 port0, guint32 port1) +{ + gint i; + GstEvent *event; + + /* flush stop and send custon event */ + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], GST_STATE_READY); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], GST_STATE_READY); + } + if (src->session) + gst_element_set_state (src->session, GST_STATE_PAUSED); + if (src->requester) + gst_element_set_state (src->requester, GST_STATE_PAUSED); + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PAUSED); + + gst_wfd_ext_src_free_tcp (src); + + /*change udpsrc port */ + if (gst_wfd_ext_src_change_udpsrc_uri (src, src->udpsrc[0], port0) == FALSE) + return GST_RTSP_ERROR; + + /*change udpsrc port */ + if (gst_wfd_ext_src_change_udpsrc_uri (src, src->udpsrc[1], + port0 + 1) == FALSE) + return GST_RTSP_ERROR; + + if (src->requester) + g_object_set (src->requester, "do-request", src->do_request, NULL); + + /* send custon event */ + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, + gst_structure_new ("GstWFDEvent", "reset", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_wfd_ext_src_push_event (GST_WFD_BASE_SRC_CAST (src), event); + + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], GST_STATE_PLAYING); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], GST_STATE_PLAYING); + } + + if (src->session) + gst_element_set_state (src->session, GST_STATE_PLAYING); + if (src->requester) + gst_element_set_state (src->requester, GST_STATE_PLAYING); + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PLAYING); + + GST_DEBUG_OBJECT (src, "Transport change to UDP"); + + return GST_RTSP_OK; +} + +static void +do_timestamp (GstWFDExtSrc * src, GstBuffer * buffer) +{ + GstClockTime base_time; + GstClock *clock; + GstClockTime now = GST_CLOCK_TIME_NONE, dts, pts; + + GST_OBJECT_LOCK (src); + + /* get clock, if no clock, we can't do timestamps */ + if ((clock = GST_ELEMENT_CLOCK (src)) == NULL) + goto no_clock; + else + gst_object_ref (clock); + + base_time = GST_ELEMENT_CAST (src)->base_time; + + GST_OBJECT_UNLOCK (src); + + now = gst_clock_get_time (clock); + pts = dts = now - base_time; + + GST_BUFFER_PTS (buffer) = pts; + GST_BUFFER_DTS (buffer) = dts; + + return; + + /* special cases */ +no_clock: + { + GST_OBJECT_UNLOCK (src); + GST_DEBUG_OBJECT (src, "we have no clock"); + + return; + } +} + +static void +gst_wfd_ext_src_loop_tcp (GstWFDExtSrc * src) +{ + GstRTSPResult res; + GstPad *outpad = NULL; + GstFlowReturn ret = GST_FLOW_OK; + guint8 *sizedata, *datatmp; + gint message_size; + GstBuffer *buf; + GTimeVal tv_timeout; + GstEvent *event; + gint i; + + res = gst_rtsp_connection_accept (src->tcp_socket, &src->tcp_conn, NULL); + if (res < GST_RTSP_OK) + goto error; + + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], GST_STATE_READY); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], GST_STATE_READY); + } + if (src->session) + gst_element_set_state (src->session, GST_STATE_PLAYING); + if (src->requester) + gst_element_set_state (src->requester, GST_STATE_PLAYING); + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PLAYING); + + /* send custon event */ + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, + gst_structure_new ("GstWFDEvent", "reset", G_TYPE_BOOLEAN, TRUE, NULL)); + gst_wfd_ext_src_push_event (GST_WFD_BASE_SRC_CAST (src), event); + + while (TRUE) { + /* get the next timeout interval */ + gst_rtsp_connection_next_timeout (src->tcp_conn, &tv_timeout); + if (tv_timeout.tv_sec == 0) { + gst_rtsp_connection_reset_timeout (src->tcp_conn); + gst_rtsp_connection_next_timeout (src->tcp_conn, &tv_timeout); + GST_DEBUG ("doing receive with timeout %ld seconds, %ld usec", + tv_timeout.tv_sec, tv_timeout.tv_usec); + } + + /*In rtp message over TCP the first 2 bytes are message size. + * So firtstly read rtp message size.*/ + sizedata = (guint8 *) g_malloc (2); + res = gst_rtsp_connection_read (src->tcp_conn, sizedata, 2, &tv_timeout); + if (res < GST_RTSP_OK) { + ret = GST_FLOW_ERROR; + switch (res) { + case GST_RTSP_EINTR: + gst_rtsp_connection_flush (src->tcp_conn, FALSE); + break; + default: + break; + } + g_free (sizedata); + goto error; + } + message_size = ((guint) sizedata[0] << 8) | sizedata[1]; + datatmp = (guint8 *) g_malloc (message_size); + g_free (sizedata); + + res = + gst_rtsp_connection_read (src->tcp_conn, datatmp, message_size, + &tv_timeout); + if (res < GST_RTSP_OK) { + ret = GST_FLOW_ERROR; + switch (res) { + case GST_RTSP_EINTR: + GST_ERROR_OBJECT (src, "interrupted"); + gst_rtsp_connection_flush (src->tcp_conn, FALSE); + break; + default: + break; + } + g_free (datatmp); + goto error; + } + + /*first byte of data is type of payload + * 200 is rtcp type then we need other pad*/ + if (datatmp[0] == 200) + outpad = src->channelpad[1]; + else + outpad = src->channelpad[0]; + + buf = gst_buffer_new (); + gst_buffer_append_memory (buf, gst_memory_new_wrapped (0, datatmp, + message_size, 0, message_size, datatmp, g_free)); + + /* timestamp the buffers */ + do_timestamp (src, buf); + + /* If needed send a new segment, don't forget we are live and buffer are + * timestamped with running time */ + if (src->discont) { + GstSegment segment; + + gst_segment_init (&segment, GST_FORMAT_TIME); + gst_segment_set_running_time (&segment, GST_FORMAT_TIME, + (guint64) GST_BUFFER_DTS (buf)); + if (GST_PAD_IS_SINK (outpad)) + gst_pad_send_event (outpad, gst_event_new_segment (&segment)); + else + gst_pad_push_event (outpad, gst_event_new_segment (&segment)); + + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + src->discont = FALSE; + } + + if (GST_PAD_IS_SINK (outpad)) + ret = gst_pad_chain (outpad, buf); + else + ret = gst_pad_push (outpad, buf); + + if (ret < GST_FLOW_OK) + break; + } + g_assert_not_reached (); + + return; + + /* ERRORS */ +error: + { + GST_ERROR_OBJECT (src, "got error"); + goto pause; + } +pause: + { + if (src->tcp_task) + gst_task_pause (src->tcp_task); + } +} + +static GstRTSPResult +gst_wfd_ext_src_switch_to_tcp (GstWFDExtSrc * src, guint32 port) +{ + GSocket *socket = NULL; + GError *err = NULL; + GSocketAddress *sockaddr = NULL; + GInetAddress *anyaddr; + gint i; + + /* flush start */ + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], GST_STATE_READY); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], GST_STATE_READY); + } + + if (src->session) + gst_element_set_state (src->session, GST_STATE_PAUSED); + if (src->requester) + gst_element_set_state (src->requester, GST_STATE_PAUSED); + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PAUSED); + + if (src->requester) + g_object_set (src->requester, "do-request", FALSE, NULL); + + anyaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); + sockaddr = g_inet_socket_address_new (anyaddr, port); + + /* Open tcp socket */ + socket = + g_socket_new (g_socket_address_get_family (sockaddr), + G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); + if (socket == NULL) + goto error; + + if (!g_socket_bind (socket, sockaddr, TRUE, &err)) + goto bind_error; + g_object_unref (anyaddr); + g_object_unref (sockaddr); + + //g_socket_set_keepalive (socket, TRUE); + //g_socket_set_listen_backlog (socket, 5); + if (!g_socket_listen (socket, &err)) + goto error; + + src->discont = TRUE; + src->tcp_socket = socket; + src->tcp_task = + gst_task_new ((GstTaskFunction) gst_wfd_ext_src_loop_tcp, src, NULL); + if (src->tcp_task == NULL) + goto error; + g_rec_mutex_init (&(src->tcp_task_lock)); + gst_task_set_lock (src->tcp_task, &(src->tcp_task_lock)); + + gst_task_start (src->tcp_task); + + GST_DEBUG_OBJECT (src, "Transport change to TCP"); + + return GST_RTSP_OK; + +/* ERRORS */ +bind_error: + { + GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("bind failed: %s", + err->message)); + g_object_unref (socket); + g_object_unref (anyaddr); + g_object_unref (sockaddr); + return GST_RTSP_ERROR; + } +error: + { + return GST_RTSP_ERROR; + } +} + +static GstRTSPResult +gst_wfd_ext_src_switch_transport (GstWFDExtSrc * src, + GstWFDRTSPLowerTrans lowertrans, guint32 port0, guint32 port1) +{ + GstRTSPResult res = GST_RTSP_OK; + + switch (lowertrans) { + case GST_WFD_RTSP_LOWER_TRANS_TCP: + res = gst_wfd_ext_src_switch_to_tcp (src, port0); + break; + case GST_WFD_RTSP_LOWER_TRANS_UDP: + res = gst_wfd_ext_src_switch_to_udp (src, port0, port1); + break; + default: + break; + } + + return res; +} diff --git a/wfdextmanager/gstwfdextsrc.h b/wfdextmanager/gstwfdextsrc.h new file mode 100755 index 0000000..b1e3f22 --- /dev/null +++ b/wfdextmanager/gstwfdextsrc.h @@ -0,0 +1,113 @@ +/* + * wfdrtspsrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_WFD_EXT_SRC_H__ +#define __GST_WFD_EXT_SRC_H__ + +#include +#include "../wfdmanager/wfdbase/gstwfdbasesrc.h" +#include "gstwfdextmessage.h" + +G_BEGIN_DECLS + +#define GST_TYPE_WFD_EXT_SRC (gst_wfd_ext_src_get_type()) +#define GST_WFD_EXT_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_EXT_SRC,GstWFDExtSrc)) +#define GST_WFD_EXT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_EXT_SRC,GstWFDExtSrcClass)) +#define GST_WFD_EXT_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WFD_EXT_SRC, GstWFDExtSrcClass)) +#define GST_IS_WFD_EXT_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_EXT_SRC)) +#define GST_IS_WFD_EXT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_EXT_SRC)) +#define GST_WFD_EXT_SRC_CAST(obj) ((GstWFDExtSrc *)(obj)) + +typedef struct _GstWFDExtSrc GstWFDExtSrc; +typedef struct _GstWFDExtSrcClass GstWFDExtSrcClass; + +#define RETRANSMITTED_RTP_PORT 19120 +#define RTCP_FB_PORT 19121 + +struct _GstWFDExtSrc { + GstWFDBaseSrc parent; + + /* properties */ + gboolean do_rtcp; + guint latency; + gint udp_buffer_size; + guint64 udp_timeout; + gboolean do_request; + + GstPad *channelpad[3]; + GstElement *udpsrc[3]; + GstElement *udpsink[3]; + GstElement *session; + GstElement *wfdrtpbuffer; + GstElement *requester; + + GstPad *blockedpad; + gulong blockid; + + /*For tcp*/ + GstClockTime base_time; + gboolean discont; + GRecMutex tcp_task_lock; + GstTask *tcp_task; + GSocket *tcp_socket; + GstRTSPConnection *tcp_conn; + +#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE + GstStructure *audio_r2_param; + GstStructure *video_r2_param; +#endif +}; + +struct _GstWFDExtSrcClass { + GstWFDBaseSrcClass parent_class; + +}; + +GType gst_wfd_ext_src_get_type(void); + +G_END_DECLS + +#endif /* __GST_WFD_EXT_SRC_H__ */ diff --git a/wfdextmanager/gstwfdrtprequester.c b/wfdextmanager/gstwfdrtprequester.c new file mode 100755 index 0000000..58386cf --- /dev/null +++ b/wfdextmanager/gstwfdrtprequester.c @@ -0,0 +1,977 @@ +/* + * wfdrtprequester + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "gstwfdrtprequester.h" + +GST_DEBUG_CATEGORY_STATIC (wfdrtprequester_debug); +#define GST_CAT_DEFAULT (wfdrtprequester_debug) + +/* signals and args */ +enum +{ + SIGNAL_REQUEST_IDR, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_DO_REQUEST, + PROP_SSRC, + PROP_PT, + PROP_TIMEOUT +}; + +#define DEFAULT_DO_REQUEST TRUE +#define DEFAULT_SSRC 0x0000 +#define DEFAULT_PT 33 //MP2t-ES payload type +#define DEFAULT_TIMEOUT_MS 0 + + /* sink pads */ +static GstStaticPadTemplate rtp_sink_template = +GST_STATIC_PAD_TEMPLATE ("rtp_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate retransmitted_rtp_sink_template = +GST_STATIC_PAD_TEMPLATE ("retransmitted_rtp_sink", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("application/x-rtp") + ); + +/* src pads */ +static GstStaticPadTemplate rtp_src_template = +GST_STATIC_PAD_TEMPLATE ("rtp_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate rtcp_src_template = +GST_STATIC_PAD_TEMPLATE ("rtcp_src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("application/x-rtcp") + ); + + +#define GST_WFD_RTP_REQUESTER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_WFD_RTP_REQUESTER, GstWFDRTPRequesterPrivate)) + +#define GST_WFD_RTP_REQUESTER_LOCK(requester) g_mutex_lock (&(requester)->priv->lock) +#define GST_WFD_RTP_REQUESTER_UNLOCK(requester) g_mutex_unlock (&(requester)->priv->lock) + +struct _GstWFDRTPRequesterPrivate +{ + GMutex lock; + + gboolean flushing; + + /* the next expected seqnum we receive */ + guint64 next_in_seqnum; +}; + +/* + * The maximum number of missing packets we tollerate. These are packets with a + * sequence number bigger than the last seen packet. + */ +#define REQUESTER_MAX_DROPOUT 17 +/* + * The maximum number of misordered packets we tollerate. These are packets with + * a sequence number smaller than the last seen packet. + */ +#define REQUESTER_MAX_MISORDER 16 + +#define REQUESTER_MTU_SIZE 1400 /* bytes */ + +#define gst_wfd_rtp_requester_parent_class parent_class + +/* GObject vmethods */ +static void gst_wfd_rtp_requester_finalize (GObject * object); +static void gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_wfd_rtp_requester_sink_event (GstPad * pad, + GstObject * parent, GstEvent * event); +static gboolean gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, + GstEvent * event); +static gboolean gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * + pad, GstObject * parent, GstEvent * event); +static gboolean gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, + GstObject * parent, GstEvent * event); + +/* GstElement vmethods */ +static GstFlowReturn gst_wfd_rtp_requester_chain (GstPad * pad, + GstObject * parent, GstBuffer * buf); +static GstPad *gst_wfd_rtp_requester_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name, const GstCaps * caps); +static void gst_wfd_rtp_requester_release_pad (GstElement * element, + GstPad * pad); + +static GstFlowReturn gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * + pad, GstObject * parent, GstBuffer * buf); + +static void gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester); +static void gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester); + +static guint gst_wfd_rtp_requester_signals[LAST_SIGNAL] = { 0 }; + +/* GObject vmethod implementations */ +static void +_do_init (GType wfdrtprequester_type) +{ + GST_DEBUG_CATEGORY_INIT (wfdrtprequester_debug, "wfdrtprequester", 0, + "WFD RTP Requester"); +} + +G_DEFINE_TYPE_WITH_CODE (GstWFDRTPRequester, gst_wfd_rtp_requester, + GST_TYPE_ELEMENT, _do_init ((g_define_type_id))); + +/* initialize the plugin's class */ +static void +gst_wfd_rtp_requester_class_init (GstWFDRTPRequesterClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + g_type_class_add_private (klass, sizeof (GstWFDRTPRequesterPrivate)); + + gobject_class->finalize = gst_wfd_rtp_requester_finalize; + gobject_class->set_property = gst_wfd_rtp_requester_set_property; + gobject_class->get_property = gst_wfd_rtp_requester_get_property; + + g_object_class_install_property (gobject_class, PROP_DO_REQUEST, + g_param_spec_boolean ("do-request", "Do request", + "Request RTP retransmission", + DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SSRC, + g_param_spec_uint ("ssrc", "SSRC", + "The SSRC of the RTP packets", 0, G_MAXUINT32, + DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PT, + g_param_spec_uint ("pt", "payload type", + "The payload type of the RTP packets", 0, 0x80, DEFAULT_PT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstWFDRTPRequester::timeout: + * + * The maximum timeout of the requester. Packets should be retransmitted + * at most this time. Unless, the request-timeout signal will be emit. + */ + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint ("timeout", "Retransmssion timeout in ms", + "Timeout in ms for retransmission", 0, G_MAXUINT, DEFAULT_TIMEOUT_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstWFDRTPRequester::request-timeout: + * @req: a #GstWFDRTPRequester + * + * Notify of timeout which is requesting rtp retransmission. + */ + gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_IDR] = + g_signal_new ("request-idr", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstWFDRTPRequesterClass, request_idr), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + + gst_element_class_set_details_simple (gstelement_class, + "Wi-Fi Display RTP Request Retransmission Element", + "Filter/Network/RTP", + "Receive RTP packet and request RTP retransmission", + "Yejin Cho "); + + gstelement_class->request_new_pad = + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_request_new_pad); + gstelement_class->release_pad = + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_release_pad); + + /* sink pads */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtp_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&retransmitted_rtp_sink_template)); + /* src pads */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtp_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtcp_src_template)); +} + +static void +gst_wfd_rtp_requester_init (GstWFDRTPRequester * requester) +{ + requester->priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); + g_mutex_init (&requester->priv->lock); + requester->priv->flushing = FALSE; + requester->priv->next_in_seqnum = GST_CLOCK_TIME_NONE; + + requester->rtp_sink = + gst_pad_new_from_static_template (&rtp_sink_template, "rtp_sink"); + gst_pad_set_event_function (requester->rtp_sink, + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_sink_event)); + gst_pad_set_chain_function (requester->rtp_sink, + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_chain)); + gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_sink); + + requester->rtp_src = + gst_pad_new_from_static_template (&rtp_src_template, "rtp_src"); + gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_src); + + requester->do_request = DEFAULT_DO_REQUEST; + requester->ssrc = DEFAULT_SSRC; + requester->pt = DEFAULT_PT; + requester->timeout_ms = DEFAULT_TIMEOUT_MS; + requester->timeout_ns = requester->timeout_ms * GST_MSECOND; +} + +static void +gst_wfd_rtp_requester_finalize (GObject * object) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER_CAST (object); + + requester = GST_WFD_RTP_REQUESTER (object); + + g_mutex_clear (&requester->priv->lock); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); + + switch (prop_id) { + case PROP_DO_REQUEST: + requester->do_request = g_value_get_boolean (value); + break; + case PROP_SSRC: + requester->ssrc = g_value_get_uint (value); + break; + case PROP_PT: + requester->pt = g_value_get_uint (value); + break; + case PROP_TIMEOUT: + requester->timeout_ms = g_value_get_uint (value); + requester->timeout_ns = requester->timeout_ms * GST_MSECOND; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); + + switch (prop_id) { + case PROP_DO_REQUEST: + g_value_set_boolean (value, requester->do_request); + break; + case PROP_SSRC: + g_value_set_uint (value, requester->ssrc); + break; + case PROP_PT: + g_value_set_uint (value, requester->pt); + break; + case PROP_TIMEOUT: + g_value_set_uint (value, requester->timeout_ms); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, GstEvent * event) +{ + GstWFDRTPRequester *requester; + gboolean res = TRUE; + GstCaps *caps; + + requester = GST_WFD_RTP_REQUESTER_CAST (gst_pad_get_parent (pad)); + gst_event_parse_caps (event, &caps); + + gst_object_unref (requester); + + return res; +} + +/* GstElement vmethod implementations */ + +/* this function handles sink events */ +static gboolean +gst_wfd_rtp_requester_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + gboolean ret = FALSE; + GstWFDRTPRequester *requester = NULL; + + requester = GST_WFD_RTP_REQUESTER (parent); + + GST_DEBUG_OBJECT (requester, "requester got event %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CUSTOM_DOWNSTREAM:{ + const GstStructure *structure; + + structure = gst_event_get_structure (event); + if (gst_structure_has_name (structure, "GstWFDEvent")) { + gboolean reset = FALSE; + gst_structure_get_boolean (structure, "reset", &reset); + if (reset) { + GST_WFD_RTP_REQUESTER_LOCK (requester); + requester->priv->next_in_seqnum = GST_CLOCK_TIME_NONE; + requester->ssrc = 0; + requester->pt = 0; + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + } + } + ret = gst_pad_event_default (pad, parent, event); + break; + } + case GST_EVENT_FLUSH_START: + gst_wfd_rtp_requester_flush_start (requester); + ret = gst_pad_push_event (requester->rtp_src, event); + break; + case GST_EVENT_FLUSH_STOP: + ret = gst_pad_push_event (requester->rtp_src, event); + gst_wfd_rtp_requester_flush_stop (requester); + break; + case GST_EVENT_CAPS: + gst_wfd_rtp_requester_sink_newcaps (pad, event); + ret = gst_pad_push_event (requester->rtp_src, event); + break; + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + +static void +gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester) +{ + GstWFDRTPRequesterPrivate *priv; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + /* mark ourselves as flushing */ + priv->flushing = TRUE; + GST_DEBUG_OBJECT (requester, "flush start.."); + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); +} + +static void +gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester) +{ + GstWFDRTPRequesterPrivate *priv; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + GST_DEBUG_OBJECT (requester, "flush stop..."); + /* Mark as non flushing */ + priv->flushing = FALSE; + + priv->next_in_seqnum = GST_CLOCK_TIME_NONE; + + requester->ssrc = 0; + requester->pt = 0; + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); +} + +static gboolean +gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * pad, + GstObject * parent, GstEvent * event) +{ + gboolean ret; + GstWFDRTPRequester *requester; + + requester = GST_WFD_RTP_REQUESTER_CAST (parent); + + GST_DEBUG_OBJECT (requester, "requester got event %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + +static gboolean +gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + GstWFDRTPRequester *requester; + gboolean ret; + + requester = GST_WFD_RTP_REQUESTER_CAST (parent); + + GST_DEBUG_OBJECT (requester, "requester got event %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + return ret; +} + +void +wfd_rtp_requester_perform_request (GstWFDRTPRequester * requester, + guint16 expected_seqnum, guint16 received_seqnum) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstRTCPPacket rtcp_fb_packet; + GstBuffer *rtcp_fb_buf; + GstRTCPBuffer rtcp_buf = { NULL }; + guint8 *fci_data; + guint16 pid, blp; + guint rtcp_packet_cnt = 0; + gint gap; + gint i; + + /* can't continue without gap */ + gap = received_seqnum - expected_seqnum; + if (G_UNLIKELY (gap < 1)) + goto no_gap; + + pid = expected_seqnum; + +again: + /* create buffer for rtcp fb packets */ + rtcp_fb_buf = gst_rtcp_buffer_new (REQUESTER_MTU_SIZE); + if (!G_UNLIKELY (rtcp_fb_buf)) + goto fail_buf; + if (!gst_rtcp_buffer_map (rtcp_fb_buf, GST_MAP_READWRITE, &rtcp_buf)) + goto fail_buf; + + /* create rtcp fb packet */ + do { + if (!gst_rtcp_buffer_add_packet (&rtcp_buf, GST_RTCP_TYPE_RTPFB, + &rtcp_fb_packet)) { + if (rtcp_packet_cnt > 0) + goto send_packets; + else { + gst_rtcp_buffer_unmap (&rtcp_buf); + goto fail_packet; + } + } + + /* set rtcp fb header : wfd use RTCPFB with Generick NACK */ + gst_rtcp_packet_fb_set_type (&rtcp_fb_packet, GST_RTCP_RTPFB_TYPE_NACK); + gst_rtcp_packet_fb_set_sender_ssrc (&rtcp_fb_packet, 0); + gst_rtcp_packet_fb_set_media_ssrc (&rtcp_fb_packet, 0); + + /* set rtcp fb fci(feedback control information) : 32bits */ + if (!gst_rtcp_packet_fb_set_fci_length (&rtcp_fb_packet, 1)) { + GST_DEBUG_OBJECT (requester, + "failed to set FCI length to RTCP FB packet"); + gst_rtcp_packet_remove (&rtcp_fb_packet); + return; + } + + fci_data = gst_rtcp_packet_fb_get_fci ((&rtcp_fb_packet)); + + /* set pid */ + GST_WRITE_UINT16_BE (fci_data, pid); + pid += 0x0011; + gap--; + + /* set blp */ + blp = 0x0000; + for (i = 0; i < 16 && gap > 0; i++) { + blp += (0x0001 << i); + gap--; + } + GST_WRITE_UINT16_BE (fci_data + 2, blp); + + rtcp_packet_cnt++; + + GST_DEBUG_OBJECT (requester, "%d RTCP FB packet : pid : %x, blp : %x", + rtcp_packet_cnt, pid - 0x0011, blp); + } while (gap > 0); + +send_packets: + /* end rtcp fb buffer */ + gst_rtcp_buffer_unmap (&rtcp_buf); + + ret = gst_pad_push (requester->rtcp_src, rtcp_fb_buf); + if (ret != GST_FLOW_OK) + GST_WARNING_OBJECT (requester, "fail to pad push RTCP FB buffer"); + + if (gap > 0) + goto again; + + return; + + /* ERRORS */ +no_gap: + { + GST_DEBUG_OBJECT (requester, + "there is no gap, don't need to make the RTSP FB packet"); + return; + } +fail_buf: + { + GST_DEBUG_OBJECT (requester, "fail to make RTSP FB buffer"); + return; + } +fail_packet: + { + GST_DEBUG_OBJECT (requester, "fail to make RTSP FB packet"); + return; + } +} + +/* chain function + * this function does the actual processing + */ +static GstFlowReturn +gst_wfd_rtp_requester_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) +{ + GstWFDRTPRequester *requester; + GstWFDRTPRequesterPrivate *priv; + guint16 seqnum; + guint8 pt; + guint32 ssrc; + GstFlowReturn ret = GST_FLOW_OK; + GstRTPBuffer rtp_buf = GST_RTP_BUFFER_INIT; + + requester = GST_WFD_RTP_REQUESTER_CAST (parent); + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + if (priv->flushing) + goto drop_buffer; + + if (G_UNLIKELY (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp_buf))) + goto invalid_buffer; + + ssrc = gst_rtp_buffer_get_ssrc (&rtp_buf); + pt = gst_rtp_buffer_get_payload_type (&rtp_buf); + seqnum = gst_rtp_buffer_get_seq (&rtp_buf); + gst_rtp_buffer_unmap (&rtp_buf); + + /* check ssrc */ + if (G_LIKELY (!requester->ssrc)) { + GST_DEBUG_OBJECT (requester, "set ssrc as %x using first rtp packet", ssrc); + requester->ssrc = ssrc; + } else if (G_LIKELY (requester->ssrc != ssrc)) { + /* goto invalid_ssrc; */ + GST_ERROR_OBJECT (requester, "ssrc is changed from %x to %x", + requester->ssrc, ssrc); + requester->ssrc = ssrc; + } + + /* check pt : pt should always 33 for MP2T-ES */ + if (G_LIKELY (requester->pt != pt)) { + if (G_LIKELY (!requester->pt)) + requester->pt = pt; + else + goto invalid_pt; + } + + /* now check against our expected seqnum */ + if (G_LIKELY (priv->next_in_seqnum != GST_CLOCK_TIME_NONE)) { + gint gap; + + gap = gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, seqnum); + if (G_UNLIKELY (gap != 0)) { + GST_ERROR_OBJECT (requester, "expected #%d, got #%d, gap of %d", + (guint16) priv->next_in_seqnum, seqnum, gap); + + if (requester->do_request) { + if (G_UNLIKELY (gap < 0)) { + if (G_UNLIKELY (gap < -150)) { + GST_WARNING_OBJECT (requester, + "#%d is too late, just unref the buffer for prevent of resetting jitterbuffer", + seqnum); + gst_buffer_unref (buf); + goto finished; + } else { + GST_DEBUG_OBJECT (requester, "#%d is late, but try to push", + seqnum); + goto skip; + } + } else if (G_UNLIKELY (gap > REQUESTER_MAX_DROPOUT)) { + GST_DEBUG_OBJECT (requester, + "too many dropped packets %d, need to request IDR", gap); + g_signal_emit (requester, + gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_IDR], 0); + } else { + GST_DEBUG_OBJECT (requester, "tolerable gap"); + wfd_rtp_requester_perform_request (requester, priv->next_in_seqnum, + seqnum); + } + } + } + } else { + GST_DEBUG_OBJECT (requester, + "got the first buffer, need to set buffer timestamp 0"); + GST_BUFFER_TIMESTAMP (buf) = 0; + } + + priv->next_in_seqnum = (seqnum + 1) & 0xffff; + +skip: + /* just push out the incoming buffer without touching it */ + ret = gst_pad_push (requester->rtp_src, buf); + if (ret != GST_FLOW_OK) + GST_ERROR_OBJECT (requester, "failed to pad push..reason %s", + gst_flow_get_name (ret)); + +finished: + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + + return ret; + + /* ERRORS */ +drop_buffer: + { + GST_ERROR_OBJECT (requester, + "requeseter is flushing, drop incomming buffers.."); + gst_buffer_unref (buf); + ret = GST_FLOW_OK; + goto finished; + } +invalid_buffer: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("Received invalid RTP payload, dropping")); + gst_buffer_unref (buf); + ret = GST_FLOW_OK; + goto finished; + } +#if 0 +invalid_ssrc: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("ssrc of this rtp packet is differtent from before. dropping")); + gst_buffer_unref (buf); + ret = GST_FLOW_OK; + goto finished; + } +#endif +invalid_pt: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("pt of this rtp packet is differtent from before. dropping")); + gst_buffer_unref (buf); + ret = GST_FLOW_OK; + goto finished; + } +} + +GstBuffer * +wfd_requester_handle_retransmitted_rtp (GstWFDRTPRequester * requester, + GstBuffer * inbuf) +{ + GstBuffer *outbuf = NULL; + GstMapInfo inbuf_mapinfo = GST_MAP_INFO_INIT; + GstRTPBuffer rtp_inbuf = GST_RTP_BUFFER_INIT; + GstMapInfo outbuf_mapinfo = GST_MAP_INFO_INIT; + GstRTPBuffer rtp_outbuf = GST_RTP_BUFFER_INIT; + guint16 seqnum; + guint8 *buf_data; + guint buf_size; + guint8 *payload; + guint payload_len, header_len; + + if (!gst_rtp_buffer_map (inbuf, GST_MAP_READ, &rtp_inbuf)) { + GST_WARNING_OBJECT (requester, + "failed to map for the retransmitted rtp buffer"); + return NULL; + } + + payload = gst_rtp_buffer_get_payload (&rtp_inbuf); + payload_len = gst_rtp_buffer_get_payload_len (&rtp_inbuf); + header_len = gst_rtp_buffer_get_header_len (&rtp_inbuf); + gst_rtp_buffer_unmap (&rtp_inbuf); + + gst_buffer_map (inbuf, &inbuf_mapinfo, GST_MAP_READ); + buf_data = inbuf_mapinfo.data; + buf_size = inbuf_mapinfo.size; + + outbuf = gst_buffer_new_and_alloc (buf_size - 2); + if (!outbuf) { + GST_WARNING_OBJECT (requester, "failed to alloc for rtp buffer"); + gst_buffer_unmap (inbuf, &inbuf_mapinfo); + return NULL; + } + + gst_buffer_map (outbuf, &outbuf_mapinfo, GST_MAP_READWRITE); + /* copy rtp header */ + memcpy (outbuf_mapinfo.data, buf_data, header_len); + /* copy rtp payload */ + memcpy (outbuf_mapinfo.data + header_len, payload + 2, payload_len - 2); + + /* set seqnum to original */ + if (!gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp_outbuf)) { + GST_WARNING_OBJECT (requester, "failed to map rtp result buffer"); + gst_buffer_unmap (inbuf, &inbuf_mapinfo); + gst_buffer_unmap (outbuf, &outbuf_mapinfo); + return NULL; + } + seqnum = GST_READ_UINT16_BE (payload); + gst_rtp_buffer_set_seq (&rtp_outbuf, seqnum); + gst_rtp_buffer_unmap (&rtp_outbuf); + + GST_DEBUG_OBJECT (requester, "restored rtp packet #%d", seqnum); + + gst_buffer_unmap (inbuf, &inbuf_mapinfo); + gst_buffer_unmap (outbuf, &outbuf_mapinfo); + + return outbuf; +} + +static GstFlowReturn +gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * pad, GstObject * parent, + GstBuffer * buf) +{ + GstWFDRTPRequester *requester; + GstWFDRTPRequesterPrivate *priv; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *outbuf; + gint gap = 0; + gint seqnum = 0; + GstRTPBuffer rtp_buf = GST_RTP_BUFFER_INIT; + + requester = GST_WFD_RTP_REQUESTER_CAST (parent); + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); + + if (!requester->do_request) + goto skip_buffer; + + outbuf = wfd_requester_handle_retransmitted_rtp (requester, buf); + if (!outbuf) { + GST_ERROR_OBJECT (requester, + "failed to handle retransmitted rtp packet..."); + return GST_FLOW_OK; + } + + /* check sequence of retransmitted rtp packet. */ + if (G_UNLIKELY (priv->next_in_seqnum == GST_CLOCK_TIME_NONE)) + goto skip_buffer; + + if (G_UNLIKELY (!gst_rtp_buffer_map (outbuf, GST_MAP_READ, &rtp_buf))) + goto skip_buffer; + + seqnum = gst_rtp_buffer_get_seq (&rtp_buf); + gst_rtp_buffer_unmap (&rtp_buf); + + gap = gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, seqnum); + if (G_UNLIKELY (gap > 0)) { + GST_ERROR_OBJECT (requester, "#%d is invalid sequence number, gap of %d", + seqnum, gap); + goto skip_buffer; + } + + ret = gst_wfd_rtp_requester_chain (requester->rtp_sink, parent, outbuf); + if (ret != GST_FLOW_OK) + GST_ERROR_OBJECT (requester, "failed to push retransmitted rtp packet..."); + +finished: + gst_buffer_unref (buf); + + /* just return OK */ + return GST_FLOW_OK; + + /* ERRORS */ +skip_buffer: + { + GST_DEBUG_OBJECT (requester, + "requeseter is set to not handle retransmission, dropping"); + goto finished; + } +} + +static GstPad * +gst_wfd_rtp_requester_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name, const GstCaps * caps) +{ + GstWFDRTPRequester *requester; + GstElementClass *klass; + + requester = GST_WFD_RTP_REQUESTER (element); + klass = GST_ELEMENT_GET_CLASS (element); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + if (templ != gst_element_class_get_pad_template (klass, name)) + goto wrong_template; + + if (requester->retransmitted_rtp_sink != NULL) + goto exists; + + GST_LOG_OBJECT (requester, "Creating new pad for retreansmitted RTP packets"); + + requester->retransmitted_rtp_sink = + gst_pad_new_from_static_template (&retransmitted_rtp_sink_template, + "retransmitted_rtp_sink"); + gst_pad_set_chain_function (requester->retransmitted_rtp_sink, + gst_wfd_rtp_requester_chain_retransmitted_rtp); + gst_pad_set_event_function (requester->retransmitted_rtp_sink, + (GstPadEventFunction) gst_wfd_rtp_requester_sink_event_retransmitted_rtp); + gst_pad_use_fixed_caps (requester->retransmitted_rtp_sink); + gst_pad_set_active (requester->retransmitted_rtp_sink, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (requester), + requester->retransmitted_rtp_sink); + + GST_DEBUG_OBJECT (requester, "creating RTCP src pad for RTCP FB packets"); + requester->rtcp_src = + gst_pad_new_from_static_template (&rtcp_src_template, "rtcp_src"); + gst_pad_set_event_function (requester->rtcp_src, + (GstPadEventFunction) gst_wfd_rtp_requester_src_event_rtcp); + gst_pad_use_fixed_caps (requester->rtcp_src); + gst_pad_set_active (requester->rtcp_src, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (requester), requester->rtcp_src); + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + + return requester->retransmitted_rtp_sink; + +/* ERRORS */ +wrong_template: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: this is not our template"); + return NULL; + } +exists: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: pad already requested"); + return NULL; + } +} + +static void +gst_wfd_rtp_requester_release_pad (GstElement * element, GstPad * pad) +{ + GstWFDRTPRequester *requester; + + g_return_if_fail (GST_IS_WFD_RTP_REQUESTER (element)); + g_return_if_fail (GST_IS_PAD (pad)); + + requester = GST_WFD_RTP_REQUESTER (element); + + GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + if (requester->retransmitted_rtp_sink == pad) { + /* deactivate from source to sink */ + gst_pad_set_active (requester->rtcp_src, FALSE); + gst_pad_set_active (requester->retransmitted_rtp_sink, FALSE); + + /* remove pads */ + GST_DEBUG_OBJECT (requester, "removing retransmitted RTP sink pad"); + gst_element_remove_pad (GST_ELEMENT_CAST (requester), + requester->retransmitted_rtp_sink); + requester->retransmitted_rtp_sink = NULL; + + GST_DEBUG_OBJECT (requester, "removing RTCP src pad"); + gst_element_remove_pad (GST_ELEMENT_CAST (requester), requester->rtcp_src); + requester->rtcp_src = NULL; + } else + goto wrong_pad; + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + + return; + + /* ERRORS */ +wrong_pad: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: asked to release an unknown pad"); + return; + } +} diff --git a/wfdextmanager/gstwfdrtprequester.h b/wfdextmanager/gstwfdrtprequester.h new file mode 100755 index 0000000..46f31be --- /dev/null +++ b/wfdextmanager/gstwfdrtprequester.h @@ -0,0 +1,102 @@ +/* + * wfdrtprequester + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_WFD_RTP_REQUESTER_H__ +#define __GST_WFD_RTP_REQUESTER_H__ + +#include + +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_WFD_RTP_REQUESTER \ + (gst_wfd_rtp_requester_get_type()) +#define GST_WFD_RTP_REQUESTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequester)) +#define GST_WFD_RTP_REQUESTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequesterClass)) +#define GST_IS_WFD_RTP_REQUESTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_RTP_REQUESTER)) +#define GST_IS_WFD_RTP_REQUESTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_RTP_REQUESTER)) +#define GST_WFD_RTP_REQUESTER_CAST(obj) ((GstWFDRTPRequester *)(obj)) + +typedef struct _GstWFDRTPRequester GstWFDRTPRequester; +typedef struct _GstWFDRTPRequesterClass GstWFDRTPRequesterClass; +typedef struct _GstWFDRTPRequesterPrivate GstWFDRTPRequesterPrivate; + +struct _GstWFDRTPRequester +{ + GstElement element; + + GstPad *rtp_sink, *rtp_src; + GstPad *rtcp_src, *retransmitted_rtp_sink; + + /* properties */ + gboolean do_request; + guint32 ssrc; + guint8 pt; + guint timeout_ms; + guint64 timeout_ns; + + GstWFDRTPRequesterPrivate *priv; +}; + +struct _GstWFDRTPRequesterClass +{ + GstElementClass parent_class; + + /* signals */ + void (*request_idr) (GstWFDRTPRequester *requester); +}; + +GType gst_wfd_rtp_requester_get_type (void); + +G_END_DECLS + +#endif /* __GST_WFD_RTP_REQUESTER_H__ */ + diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c old mode 100644 new mode 100755 index bdc4d30..e7eaa87 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -2656,6 +2656,8 @@ gst_wfd_base_src_setup (GstWFDBaseSrc * src) if (res < 0) goto setup_failed; + priv->transport = transport; + /* clean up our transport struct */ gst_rtsp_transport_init (&transport); /* clean up used RTSP messages */ @@ -3594,6 +3596,57 @@ gst_wfd_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data) iface->set_uri = gst_wfd_base_src_uri_set_uri; } +//Added_for_Miracast_R2 +GstRTSPResult gst_wfd_base_src_set_streaminfo(GstWFDBaseSrc *src, GstStructure *stream_info) +{ + GstWFDBaseSrcPrivate *priv = src->priv; + + g_return_val_if_fail (stream_info != NULL,GST_RTSP_EINVAL); + + if (gst_structure_has_field (stream_info, "audio_channels")) + gst_structure_get_uint (stream_info, "audio_channels", &(priv->audio_channels)); + + if (gst_structure_has_field (stream_info, "audio_format")) + priv->audio_format = g_strdup(gst_structure_get_string(stream_info, "audio_format")); + + if (gst_structure_has_field (stream_info, "audio_bitwidth")) + gst_structure_get_uint (stream_info, "audio_bitwidth", &(priv->audio_bitwidth)); + + if (gst_structure_has_field (stream_info, "audio_rate")) + gst_structure_get_uint (stream_info, "audio_rate", &(priv->audio_frequency)); + + if (gst_structure_has_field (stream_info, "video_width")) + gst_structure_get_uint (stream_info, "video_width", &(priv->video_width)); + + if (gst_structure_has_field (stream_info, "video_height")) + gst_structure_get_uint (stream_info, "video_height", &(priv->video_width)); + + if (gst_structure_has_field (stream_info, "video_framerate")) + gst_structure_get_uint (stream_info, "video_framerate", &(priv->video_framerate)); + + return GST_RTSP_OK; +} + +GstRTSPResult gst_wfd_base_src_get_streaminfo(GstWFDBaseSrc *src, GstStructure *stream_info) +{ + GstWFDBaseSrcPrivate *priv = src->priv; + + g_return_if_fail (stream_info != NULL); + + gst_structure_set (stream_info, + "video_format", G_TYPE_STRING, "H265", + "video_width", G_TYPE_INT, priv->video_width, + "video_height", G_TYPE_INT, priv->video_height, + "video_framerate", G_TYPE_INT, priv->video_framerate, + "audio_format", G_TYPE_STRING, priv->audio_format, + "audio_channels", G_TYPE_INT, priv->audio_channels, + "audio_rate", G_TYPE_INT, priv->audio_frequency, + "audio_bitwidth", G_TYPE_INT, priv->audio_bitwidth/16, + NULL); + + return GST_RTSP_OK; +} + GstRTSPResult gst_wfd_base_src_get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution) { GstWFDBaseSrcPrivate *priv = src->priv; diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.h b/wfdmanager/wfdbase/gstwfdbasesrc.h old mode 100644 new mode 100755 index b8a4309..6024b7f --- a/wfdmanager/wfdbase/gstwfdbasesrc.h +++ b/wfdmanager/wfdbase/gstwfdbasesrc.h @@ -146,6 +146,9 @@ struct _GstWFDBaseSrcClass { GType gst_wfd_base_src_get_type(void); +GstRTSPResult gst_wfd_base_src_set_streaminfo(GstWFDBaseSrc *src, GstStructure *stream_info); +GstRTSPResult gst_wfd_base_src_get_streaminfo(GstWFDBaseSrc *src, GstStructure *stream_info); + gboolean gst_wfd_base_src_set_target (GstWFDBaseSrc * src, GstPad *target); gboolean gst_wfd_base_src_activate (GstWFDBaseSrc *src); GstRTSPResult gst_wfd_base_src_get_cea_resolution_and_set_to_src(GstWFDBaseSrc *src, guint64 Resolution); diff --git a/wfdtizenmanager/Makefile.am b/wfdtizenmanager/Makefile.am new file mode 100755 index 0000000..f6678da --- /dev/null +++ b/wfdtizenmanager/Makefile.am @@ -0,0 +1,15 @@ +plugin_LTLIBRARIES = libgstwfdtizenmanager.la + +libgstwfdtizenmanager_la_SOURCES = gstwfdtizenmanager.c \ + gstwfdtizensrc.c gstwfdtizenmessage.c + +libgstwfdtizenmanager_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) + +libgstwfdtizenmanager_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + $(top_builddir)/wfdmanager/wfdbase/libgstwfdbase.la + +libgstwfdtizenmanager_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstwfdtizenmanager_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstwfdtizensrc.h gstwfdtizenmessage.h diff --git a/wfdtizenmanager/gstwfdtizenmanager.c b/wfdtizenmanager/gstwfdtizenmanager.c new file mode 100644 index 0000000..eb5922f --- /dev/null +++ b/wfdtizenmanager/gstwfdtizenmanager.c @@ -0,0 +1,68 @@ +/* +* wfdtizenmanager +* +* Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +* +* Alternatively, the contents of this file may be used under the +* GNU Lesser General Public License Version 2.1 (the "LGPL"), in +* which case the following provisions apply instead of the ones +* mentioned above: +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public +* License along with this library; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstwfdtizensrc.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "wfdtizensrc", GST_RANK_NONE, + GST_TYPE_WFD_TIZEN_SRC)) + return FALSE; + + return TRUE; +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + wfdtizenmanager, + "Wi-Fi Display management plugin library with Tizen features", + plugin_init, + VERSION, + "LGPL", "Samsung Electronics Co", "http://www.samsung.com") diff --git a/wfdtizenmanager/gstwfdtizenmessage.c b/wfdtizenmanager/gstwfdtizenmessage.c new file mode 100755 index 0000000..77a021f --- /dev/null +++ b/wfdtizenmanager/gstwfdtizenmessage.c @@ -0,0 +1,586 @@ +/* + * wfdtizenmessage + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include /* for G_OS_WIN32 */ +#include "gstwfdtizenmessage.h" + +/* FIXME, is currently allocated on the stack */ +#define MAX_LINE_LEN (1024 * 16) + +#define FREE_STRING(field) if (field != NULL) g_free(field); (field) = NULL; +#define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup(val); + +static GstWFDTizenMessage *gst_wfd_tizen_message_boxed_copy (GstWFDTizenMessage + * orig); +static void gst_wfd_tizen_message_boxed_free (GstWFDTizenMessage * msg); + +G_DEFINE_BOXED_TYPE (GstWFDTizenMessage, gst_wfd_tizen_message, + gst_wfd_tizen_message_boxed_copy, gst_wfd_tizen_message_boxed_free); + +static GstWFDTizenMessage * +gst_wfd_tizen_message_boxed_copy (GstWFDTizenMessage * orig) +{ + GstWFDTizenMessage *copy; + + if (gst_wfd_tizen_message_copy (orig, ©) == GST_WFD_OK) + return copy; + + return NULL; +} + +static void +gst_wfd_tizen_message_boxed_free (GstWFDTizenMessage * msg) +{ + gst_wfd_tizen_message_free (msg); +} + +/** + * gst_wfd_tizen_message_new: + * @msg: (out) (transfer full): pointer to new #GstWFDTizenMessage + * + * Allocate a new GstWFDTizenMessage and store the result in @msg. + * + * Returns: a #GstWFDResult. + */ +GstWFDResult +gst_wfd_tizen_message_new (GstWFDTizenMessage ** msg) +{ + GstWFDTizenMessage *newmsg; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + newmsg = g_new0 (GstWFDTizenMessage, 1); + + *msg = newmsg; + + return gst_wfd_tizen_message_init (newmsg); +} + +/** + * gst_wfd_tizen_message_init: + * @msg: a #GstWFDTizenMessage + * + * Initialize @msg so that its contents are as if it was freshly allocated + * with gst_wfd_tizen_message_new(). This function is mostly used to initialize a message + * allocated on the stack. gst_wfd_tizen_message_uninit() undoes this operation. + * + * When this function is invoked on newly allocated data (with malloc or on the + * stack), its contents should be set to 0 before calling this function. + * + * Returns: a #GstWFDResult. + */ +GstWFDResult +gst_wfd_tizen_message_init (GstWFDTizenMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + return GST_WFD_OK; +} + +/** + * gst_wfd_tizen_message_uninit: + * @msg: a #GstWFDTizenMessage + * + * Free all resources allocated in @msg. @msg should not be used anymore after + * this function. This function should be used when @msg was allocated on the + * stack and initialized with gst_wfd_tizen_message_init(). + * + * Returns: a #GstWFDResult. + */ +GstWFDResult +gst_wfd_tizen_message_uninit (GstWFDTizenMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->tizen_retransmission) { + FREE_STRING (msg->tizen_retransmission); + } + + if (msg->tizen_fec) { + FREE_STRING (msg->tizen_fec); + } + + if (msg->tizen_latency_mode) { + FREE_STRING (msg->tizen_latency_mode); + } + + return GST_WFD_OK; +} + +static void +_read_string_space_ended (gchar * dest, guint size, gchar * src) +{ + guint idx = 0; + + while (!g_ascii_isspace (*src) && *src != '\0') { + if (idx < size - 1) + dest[idx++] = *src; + src++; + } + + if (size > 0) + dest[idx] = '\0'; + + return; +} + +#if 0 +static void +_read_string_char_ended (gchar * dest, guint size, gchar del, gchar * src) +{ + guint idx = 0; + + while (*src != del && *src != '\0') { + if (idx < size - 1) + dest[idx++] = *src; + src++; + } + + if (size > 0) + dest[idx] = '\0'; + + return; +} +#endif + +static void +_read_string_attr_and_value (gchar * attr, gchar * value, guint tsize, + guint vsize, gchar del, gchar * src) +{ + guint idx; + + idx = 0; + + while (*src != del && *src != '\0') { + if (idx < tsize - 1) + attr[idx++] = *src; + src++; + } + + if (tsize > 0) + attr[idx] = '\0'; + + src++; + idx = 0; + + while (*src != '\0') { + if (idx < vsize - 1) + value[idx++] = *src; + src++; + } + + if (vsize > 0) + value[idx] = '\0'; + + return; +} + +static void +gst_wfd_tizen_parse_attribute (gchar * buffer, GstWFDTizenMessage * msg) +{ + gchar attr[8192] = { 0 }; + gchar value[8192] = { 0 }; + gchar temp[8192] = { 0 }; + gchar *p = buffer; + gchar *v = value; + +#define WFD_SKIP_SPACE(q) if (*q && g_ascii_isspace (*q)) q++ +#define WFD_SKIP_EQUAL(q) if (*q && *q == '=') q++ +#define WFD_SKIP_COMMA(q) if (*q && g_ascii_ispunct (*q)) q++ +#define WFD_READ_STRING(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); REPLACE_STRING (field, temp) +#if 0 +#define WFD_READ_CHAR_END_STRING(field, del) _read_string_char_ended (temp, sizeof (temp), del, v); v+=strlen(temp); REPLACE_STRING (field, temp) +#endif +#define WFD_READ_UINT32(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 16) +#define WFD_READ_UINT32_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 10) + + _read_string_attr_and_value (attr, value, sizeof (attr), sizeof (value), ':', + p); + + if (!g_strcmp0 (attr, GST_STRING_TIZEN_WFD_RESTRANSMISSION)) { + msg->tizen_retransmission = g_new0 (GstWFDTizenRetransmission, 1); + if (strlen (v)) { + if (!strstr (v, "none")) { + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tizen_retransmission->rtp_port); + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tizen_retransmission->rtcp_port); + } + } + } else if (!g_strcmp0 (attr, GST_STRING_TIZEN_WFD_FEC)) { + msg->tizen_fec = g_new0 (GstWFDTizenFec, 1); + if (strlen (v)) { + if (!strstr (v, "none")) { + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tizen_fec->t_max); + WFD_SKIP_SPACE (v); + WFD_READ_UINT32_DIGIT (msg->tizen_fec->p_max); + } + } + } else if (!g_strcmp0 (attr, GST_STRING_TIZEN_WFD_LATENCY_MODE)) { + msg->tizen_latency_mode = g_new0 (GstWFDTizenLatencyMode, 1); + if (strlen (v)) { + if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_LOW)) { + msg->tizen_latency_mode->latency_mode = WFD_TIZEN_LATENCY_LOW; + } else if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_MID)) { + msg->tizen_latency_mode->latency_mode = WFD_TIZEN_LATENCY_MID; + } else if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_HIGH)) { + msg->tizen_latency_mode->latency_mode = WFD_TIZEN_LATENCY_HIGH; + } else { + msg->tizen_latency_mode->latency_mode = WFD_TIZEN_LATENCY_NONE; + } + } + } + + return; +} + +/** + * gst_wfd_tizen_message_parse_buffer: + * @data: the start of the buffer + * @size: the size of the buffer + * @msg: the result #GstSDPMessage + * + * Parse the contents of @size bytes pointed to by @data and store the result in + * @msg. + * + * Returns: #GST_SDP_OK on success. + */ +GstWFDResult +gst_wfd_tizen_message_parse_buffer (const guint8 * data, guint size, + GstWFDTizenMessage * msg) +{ + gchar *p; + gchar buffer[255] = { 0 }; + guint idx = 0; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (data != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (size != 0, GST_WFD_EINVAL); + + p = (gchar *) data; + while (TRUE) { + + if (*p == '\0') + break; + + idx = 0; + while (*p != '\n' && *p != '\r' && *p != '\0') { + if (idx < sizeof (buffer) - 1) + buffer[idx++] = *p; + p++; + } + buffer[idx] = '\0'; + gst_wfd_tizen_parse_attribute (buffer, msg); + + if (*p == '\0') + break; + p += 2; + } + return GST_WFD_OK; +} + +/** + * gst_wfd_tizen_message_free: + * @msg: a #GstWFDTizenMessage + * + * Free all resources allocated by @msg. @msg should not be used anymore after + * this function. This function should be used when @msg was dynamically + * allocated with gst_wfd_tizen_message_new(). + * + * Returns: a #GstWFDResult. + */ +GstWFDResult +gst_wfd_tizen_message_free (GstWFDTizenMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + gst_wfd_tizen_message_uninit (msg); + g_free (msg); + + return GST_WFD_OK; +} + +/** + * gst_wfd_ext_message_copy: + * @msg: a #GstWFDExtMessage + * @copy: (out) (transfer full): pointer to new #GstWFDExtMessage + * + * Allocate a new copy of @msg and store the result in @copy. The value in + * @copy should be release with gst_wfd_ext_message_free function. + * + * Returns: a #GstWFDResult + * + * Since: 1.6 + */ +GstWFDResult +gst_wfd_tizen_message_copy (const GstWFDTizenMessage * msg, + GstWFDTizenMessage ** copy) +{ + GstWFDResult ret; + GstWFDTizenMessage *cp; + + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + ret = gst_wfd_tizen_message_new (copy); + if (ret != GST_WFD_OK) + return ret; + + cp = *copy; + + /* TODO-WFD */ + if (msg->tizen_retransmission) { + cp->tizen_retransmission = g_malloc (sizeof (GstWFDTizenRetransmission)); + if (cp->tizen_retransmission) { + cp->tizen_retransmission->rtp_port = msg->tizen_retransmission->rtp_port; + cp->tizen_retransmission->rtcp_port = + msg->tizen_retransmission->rtcp_port; + } + } + if (msg->tizen_fec) { + cp->tizen_fec = g_malloc (sizeof (GstWFDTizenFec)); + if (cp->tizen_fec) { + cp->tizen_fec->t_max = msg->tizen_fec->t_max; + cp->tizen_fec->p_max = msg->tizen_fec->p_max; + } + } + if (msg->tizen_latency_mode) { + cp->tizen_latency_mode = g_malloc (sizeof (GstWFDTizenLatencyMode)); + if (cp->tizen_latency_mode) + cp->tizen_latency_mode->latency_mode = + msg->tizen_latency_mode->latency_mode; + } + + return GST_WFD_OK; +} + +/** + * gst_wfd_tizen_message_as_text: + * @msg: a #GstWFDTizenMessage + * + * Convert the contents of @msg to a text string. + * + * Returns: A dynamically allocated string representing the WFD description. + */ +gchar * +gst_wfd_tizen_message_as_text (const GstWFDTizenMessage * msg) +{ + /* change all vars so they match rfc? */ + GString *lines; + + g_return_val_if_fail (msg != NULL, NULL); + + lines = g_string_new (""); + + if (msg->tizen_retransmission) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_RESTRANSMISSION); + g_string_append_printf (lines, ":"); + g_string_append_printf (lines, " %d", msg->tizen_retransmission->rtp_port); + g_string_append_printf (lines, " %d", msg->tizen_retransmission->rtcp_port); + g_string_append_printf (lines, "\r\n"); + } + + if (msg->tizen_fec) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_FEC); + g_string_append_printf (lines, ":"); + g_string_append_printf (lines, " %d", msg->tizen_fec->t_max); + g_string_append_printf (lines, " %d", msg->tizen_fec->p_max); + g_string_append_printf (lines, "\r\n"); + } + + if (msg->tizen_latency_mode) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_LATENCY_MODE); + g_string_append_printf (lines, ":"); + + if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_LOW) + g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_LOW); + else if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_MID) + g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_MID); + else if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_HIGH) + g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_HIGH); + else + g_string_append_printf (lines, " none"); + + g_string_append_printf (lines, "\r\n"); + } + + return g_string_free (lines, FALSE); +} + +gchar * +gst_wfd_tizen_message_param_names_as_text (const GstWFDTizenMessage * msg) +{ + /* change all vars so they match rfc? */ + GString *lines; + g_return_val_if_fail (msg != NULL, NULL); + + lines = g_string_new (""); + + if (msg->tizen_retransmission) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_RESTRANSMISSION); + g_string_append_printf (lines, "\r\n"); + } + if (msg->tizen_fec) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_FEC); + g_string_append_printf (lines, "\r\n"); + } + if (msg->tizen_latency_mode) { + g_string_append_printf (lines, GST_STRING_TIZEN_WFD_LATENCY_MODE); + g_string_append_printf (lines, "\r\n"); + } + + return g_string_free (lines, FALSE); +} + +/** + * gst_wfd_tizen_message_dump: + * @msg: a #GstWFDTizenMessage + * + * Dump the parsed contents of @msg to stdout. + * + * Returns: a #GstWFDResult. + */ +GstWFDResult +gst_wfd_tizen_message_dump (const GstWFDTizenMessage * msg) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (msg->tizen_retransmission) + GST_DEBUG ("tizen_wfd_retransmission: %d %d", + msg->tizen_retransmission->rtp_port, + msg->tizen_retransmission->rtcp_port); + + if (msg->tizen_fec) + GST_DEBUG ("tizen_wfd_fec: %d %d", msg->tizen_fec->t_max, + msg->tizen_fec->p_max); + + if (msg->tizen_latency_mode) { + GST_DEBUG ("tizen_wfd_latency_mode:"); + + if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_LOW) + GST_DEBUG (" low"); + else if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_MID) + GST_DEBUG (" mid"); + else if (msg->tizen_latency_mode->latency_mode == WFD_TIZEN_LATENCY_HIGH) + GST_DEBUG (" high"); + else + GST_DEBUG (" none"); + } + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_set_tizen_retransmission (GstWFDTizenMessage * msg, + guint rtp_port, guint rtcp_port) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->tizen_retransmission) + msg->tizen_retransmission = g_new0 (GstWFDTizenRetransmission, 1); + + msg->tizen_retransmission->rtp_port = rtp_port; + msg->tizen_retransmission->rtcp_port = rtcp_port; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_get_tizen_retransmission (GstWFDTizenMessage * msg, + guint * rtp_port, guint * rtcp_port) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->tizen_retransmission != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (rtp_port != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (rtcp_port != NULL, GST_WFD_EINVAL); + + *rtp_port = msg->tizen_retransmission->rtp_port; + *rtcp_port = msg->tizen_retransmission->rtcp_port; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_set_tizen_fec (GstWFDTizenMessage * msg, guint t_max, + guint p_max) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->tizen_fec) + msg->tizen_fec = g_new0 (GstWFDTizenFec, 1); + + msg->tizen_fec->t_max = t_max; + msg->tizen_fec->p_max = p_max; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_get_tizen_fec (GstWFDTizenMessage * msg, guint * t_max, + guint * p_max) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->tizen_fec != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (t_max != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (p_max != NULL, GST_WFD_EINVAL); + + *t_max = msg->tizen_fec->t_max; + *p_max = msg->tizen_fec->p_max; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_set_tizen_latency_mode (GstWFDTizenMessage * msg, + guint latency_mode) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + + if (!msg->tizen_latency_mode) + msg->tizen_latency_mode = g_new0 (GstWFDTizenLatencyMode, 1); + + msg->tizen_latency_mode->latency_mode = latency_mode; + + return GST_WFD_OK; +} + +GstWFDResult +gst_wfd_tizen_message_get_tizen_latency_mode (GstWFDTizenMessage * msg, + guint * latency_mode) +{ + g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (msg->tizen_latency_mode != NULL, GST_WFD_EINVAL); + g_return_val_if_fail (latency_mode != NULL, GST_WFD_EINVAL); + + *latency_mode = msg->tizen_latency_mode->latency_mode; + + return GST_WFD_OK; +} diff --git a/wfdtizenmanager/gstwfdtizenmessage.h b/wfdtizenmanager/gstwfdtizenmessage.h new file mode 100755 index 0000000..5592fe7 --- /dev/null +++ b/wfdtizenmanager/gstwfdtizenmessage.h @@ -0,0 +1,104 @@ +/* + * wfdtizenmessage + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __GST_WFD_TIZEN_MESSAGE_H__ +#define __GST_WFD_TIZEN_MESSAGE_H__ + +#include +#include +#include "../wfdmanager/wfdbase/gstwfdsinkmessage.h" + +G_BEGIN_DECLS; + + +#define GST_TYPE_WFD_TIZEN_MESSAGE (gst_wfd_tizen_message_get_type()) +#define GST_WFD_TIZEN_MESSAGE_CAST(object) ((GstWFDTizenMessage *)(object)) +#define GST_WFD_TIZEN_MESSAGE(object) (GST_WFD_TIZEN_MESSAGE_CAST(object)) + + +#define GST_STRING_TIZEN_WFD_RESTRANSMISSION "tizen_wfd_retransmission" +#define GST_STRING_TIZEN_WFD_FEC "tizen_wfd_fec" +#define GST_STRING_TIZEN_WFD_LATENCY_MODE "tizen_wfd_latency_mode" +#define GST_STRING_TIZEN_WFD_LATENCY_LOW "low" +#define GST_STRING_TIZEN_WFD_LATENCY_MID "mid" +#define GST_STRING_TIZEN_WFD_LATENCY_HIGH "high" + +typedef enum { + WFD_TIZEN_LATENCY_NONE = 0, + WFD_TIZEN_LATENCY_LOW = 1, + WFD_TIZEN_LATENCY_MID = 2, + WFD_TIZEN_LATENCY_HIGH +} WFDTizenLatencyMode; + +typedef struct { + guint rtp_port; + guint rtcp_port; +} GstWFDTizenRetransmission; + +typedef struct { + guint t_max; /*TMAX is the maximum number of source symbols in a block*/ + guint p_max; /*PMAX is the maximum number of parity symbols in a block*/ +} GstWFDTizenFec; + +typedef struct { + guint latency_mode; +} GstWFDTizenLatencyMode; + +typedef struct { + GstWFDTizenRetransmission *tizen_retransmission; + GstWFDTizenFec *tizen_fec; + GstWFDTizenLatencyMode *tizen_latency_mode; +} GstWFDTizenMessage; + + +GType gst_wfd_tizen_message_get_type (void); + +/* Session descriptions */ +GstWFDResult gst_wfd_tizen_message_new(GstWFDTizenMessage **msg); +GstWFDResult gst_wfd_tizen_message_init(GstWFDTizenMessage *msg); +GstWFDResult gst_wfd_tizen_message_uninit(GstWFDTizenMessage *msg); +GstWFDResult gst_wfd_tizen_message_free(GstWFDTizenMessage *msg); +GstWFDResult gst_wfd_tizen_message_copy (const GstWFDTizenMessage *msg, GstWFDTizenMessage **copy); +GstWFDResult gst_wfd_tizen_message_parse_buffer(const guint8 *data, guint size, GstWFDTizenMessage *msg); +gchar *gst_wfd_tizen_message_as_text(const GstWFDTizenMessage *msg); +gchar *gst_wfd_tizen_message_param_names_as_text(const GstWFDTizenMessage *msg); +GstWFDResult gst_wfd_tizen_message_dump(const GstWFDTizenMessage *msg); + +GstWFDResult gst_wfd_tizen_message_set_tizen_retransmission (GstWFDTizenMessage *msg, + guint rtp_port, guint rtcp_port); +GstWFDResult gst_wfd_tizen_message_get_tizen_retransmission (GstWFDTizenMessage *msg, + guint *rtp_port, guint *rtcp_port); + +GstWFDResult gst_wfd_tizen_message_set_tizen_fec (GstWFDTizenMessage *msg, + guint t_max, guint p_max); +GstWFDResult gst_wfd_tizen_message_get_tizen_fec (GstWFDTizenMessage *msg, + guint *t_max, guint *p_max); + +GstWFDResult gst_wfd_tizen_message_set_tizen_latency_mode (GstWFDTizenMessage *msg, + guint latency_mode); +GstWFDResult gst_wfd_tizen_message_get_tizen_latency_mode (GstWFDTizenMessage *msg, + guint *latency_mode); + + +G_END_DECLS + +#endif /* __GST_WFD_TIZEN_MESSAGE_H__ */ + diff --git a/wfdtizenmanager/gstwfdtizensrc.c b/wfdtizenmanager/gstwfdtizensrc.c new file mode 100755 index 0000000..5984599 --- /dev/null +++ b/wfdtizenmanager/gstwfdtizensrc.c @@ -0,0 +1,1476 @@ +/* + * wfdtizensrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** +* SECTION:element-wfdtizensrc +* +* Makes a connection to an RTSP server and read the data. +* Device recognition is through wifi direct. +* wfdtizensrc strictly follows Wifi display specification. +* +* RTSP supports transport over TCP or UDP in unicast or multicast mode. By +* default wfdtizensrc will negotiate a connection in the following order: +* UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed +* protocols can be controlled with the #GstWFDTizenSrc:protocols property. +* +* wfdtizensrc currently understands WFD capability negotiation messages +* +* wfdtizensrc will internally instantiate an RTP session manager element +* that will handle the RTCP messages to and from the server, jitter removal, +* packet reordering along with providing a clock for the pipeline. +* This feature is implemented using the gstrtpbin element. +* +* wfdtizensrc acts like a live source and will therefore only generate data in the +* PLAYING state. +* +* +* Example launch line +* |[ +* gst-launch wfdtizensrc location=rtsp://some.server/url ! fakesink +* ]| Establish a connection to an RTSP server and send the raw RTP packets to a +* fakesink. +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gstwfdtizensrc.h" + +GST_DEBUG_CATEGORY_STATIC (wfdtizensrc_debug); +#define GST_CAT_DEFAULT (wfdtizensrc_debug) + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_DO_RTCP, + PROP_LATENCY, + PROP_UDP_BUFFER_SIZE, + PROP_UDP_TIMEOUT, + PROP_LATENCY_MODE, + PROP_DO_REQUEST, + PROP_DO_FEC, + PROP_FEC_MAX_K, + PROP_FEC_MAX_P, + PROP_FEC_SYMBOL_LENGTH, + PROP_LAST +}; + +#define DEFAULT_DO_RTCP TRUE +#define DEFAULT_LATENCY_MS 2000 +#define DEFAULT_UDP_BUFFER_SIZE 0x80000 +#define DEFAULT_UDP_TIMEOUT 10000000 +#define DEFAULT_LATENCY_MODE WFD_TIZEN_LATENCY_NONE +#define DEFAULT_DO_REQUEST TRUE +#define DEFAULT_DO_FEC TRUE +#define DEFAULT_FEC_MAX_K 10 +#define DEFAULT_FEC_MAX_P 10 +#define DEFAULT_FEC_SYMBOL_LENGTH 1500 + +/* object */ +static void gst_wfd_tizen_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_wfd_tizen_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +/* wfdbasesrc */ +static GstRTSPResult gst_wfd_tizen_src_handle_set_parameter (GstWFDBaseSrc * + bsrc, GstRTSPMessage * request, GstRTSPMessage * response); +static GstRTSPResult gst_wfd_tizen_src_handle_get_parameter (GstWFDBaseSrc * + bsrc, GstRTSPMessage * request, GstRTSPMessage * response); +static GstRTSPResult gst_wfd_tizen_src_configure_transport (GstWFDBaseSrc * + bsrc, GstRTSPTransport * transport); +static GstRTSPResult gst_wfd_tizen_src_prepare_transport (GstWFDBaseSrc * bsrc, + gint rtpport, gint rtcpport); +static gboolean gst_wfd_tizen_src_push_event (GstWFDBaseSrc * bsrc, + GstEvent * event); +static void gst_wfd_tizen_src_set_state (GstWFDBaseSrc * src, GstState state); +static void gst_wfd_tizen_src_cleanup (GstWFDBaseSrc * bsrc); + +//static guint gst_wfd_ext_srcext_signals[LAST_SIGNAL] = { 0 }; + +GType +wfd_tizen_latency_mode_get_type (void) +{ + static GType wfd_tizen_latency_mode_type = 0; + static const GEnumValue tizen_latency_modes[] = { + {WFD_TIZEN_LATENCY_NONE, "none", "none"}, + {WFD_TIZEN_LATENCY_LOW, "Low latency mode", "low"}, + {WFD_TIZEN_LATENCY_MID, "Mid latency mode", "mid"}, + {WFD_TIZEN_LATENCY_HIGH, "High latency mode", "high"}, + {0, NULL, NULL}, + }; + + if (!wfd_tizen_latency_mode_type) { + wfd_tizen_latency_mode_type = + g_enum_register_static ("WFDTizenLatencyMode", tizen_latency_modes); + } + return wfd_tizen_latency_mode_type; +} + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (wfdtizensrc_debug, "wfdtizensrc", 0, "Wi-Fi Display Sink Tizen source"); + +#define gst_wfd_tizen_src_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstWFDTizenSrc, gst_wfd_tizen_src, + GST_TYPE_WFD_BASE_SRC, _do_init); + +static void +gst_wfd_tizen_src_class_init (GstWFDTizenSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstWFDBaseSrcClass *gstwfdbasesrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstwfdbasesrc_class = (GstWFDBaseSrcClass *) klass; + + gobject_class->set_property = gst_wfd_tizen_src_set_property; + gobject_class->get_property = gst_wfd_tizen_src_get_property; + + g_object_class_install_property (gobject_class, PROP_DO_RTCP, + g_param_spec_boolean ("do-rtcp", "Do RTCP", + "Send RTCP packets, disable for old incompatible server.", + DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint ("latency", "Buffer latency in ms", + "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_UDP_BUFFER_SIZE, + g_param_spec_int ("udp-buffer-size", "UDP Buffer Size", + "Size of the kernel UDP receive buffer in bytes, 0=default", + 0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_UDP_TIMEOUT, + g_param_spec_uint64 ("timeout", "Timeout", + "Fail after timeout microseconds on UDP connections (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_UDP_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_LATENCY_MODE, + g_param_spec_enum ("latency-mode", "Latency Mode", + "Current latency mode", WFD_TIZEN_LATENCY_MODE, + DEFAULT_LATENCY_MODE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DO_REQUEST, + g_param_spec_boolean ("do-request", "Enable RTP Retransmission Request", + "Send RTCP FB packets and handel retransmitted RTP packets.", + DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DO_FEC, + g_param_spec_boolean ("do-fec", "Enable Forward Error Correction", + "Enabel Forward Error Correction decoding", + DEFAULT_DO_FEC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_FEC_MAX_K, + g_param_spec_uint ("fec-max-k", + "Max. size (k) for Forward Error Correction", + "Max. number of source symbol in a block", 1, G_MAXUINT, + DEFAULT_FEC_MAX_K, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_FEC_MAX_P, + g_param_spec_uint ("fec-max-p", + "Max. size (p) for Forward Error Correction", + "Max. number of parity symbol in a block", 0, G_MAXUINT, + DEFAULT_FEC_MAX_P, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_FEC_SYMBOL_LENGTH, + g_param_spec_uint ("fec-symbol-length", + "Symbol length for Forward Error Correction", + "Length of block symbol in bytes", 0, G_MAXUINT, + DEFAULT_FEC_SYMBOL_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_set_static_metadata (gstelement_class, + "Wi-Fi Display Sink source element", "Source/Network", + "Negotiate the capability and receive the RTP packets from the Wi-Fi Display source", + "YeJin Cho "); + + gstwfdbasesrc_class->handle_set_parameter = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_handle_set_parameter); + gstwfdbasesrc_class->handle_get_parameter = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_handle_get_parameter); + gstwfdbasesrc_class->configure_transport = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_configure_transport); + gstwfdbasesrc_class->prepare_transport = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_prepare_transport); + gstwfdbasesrc_class->push_event = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_push_event); + gstwfdbasesrc_class->set_state = + GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_set_state); + gstwfdbasesrc_class->cleanup = GST_DEBUG_FUNCPTR (gst_wfd_tizen_src_cleanup); +} + +static void +gst_wfd_tizen_src_init (GstWFDTizenSrc * src) +{ + gint i; + + src->do_rtcp = DEFAULT_DO_RTCP; + src->latency = DEFAULT_LATENCY_MS; + src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; + src->udp_timeout = DEFAULT_UDP_TIMEOUT; + src->latency_mode = DEFAULT_LATENCY_MODE; + src->do_request = DEFAULT_DO_REQUEST; + src->do_fec = DEFAULT_DO_FEC; + src->fec_max_k = DEFAULT_FEC_MAX_K; + src->fec_max_p = DEFAULT_FEC_MAX_P; + src->fec_symbol_length = DEFAULT_FEC_SYMBOL_LENGTH; + + src->fecdec = NULL; + src->session = NULL; + src->requester = NULL; + src->wfdrtpbuffer = NULL; + for (i = 0; i < 3; i++) { + src->channelpad[i] = NULL; + src->udpsrc[i] = NULL; + src->udpsink[i] = NULL; + } + src->blockid = 0; + src->blockedpad = NULL; +} + +static void +gst_wfd_tizen_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (object); + + switch (prop_id) { + case PROP_DO_RTCP: + src->do_rtcp = g_value_get_boolean (value); + break; + case PROP_LATENCY: + src->latency = g_value_get_uint (value); + break; + case PROP_UDP_BUFFER_SIZE: + src->udp_buffer_size = g_value_get_int (value); + break; + case PROP_UDP_TIMEOUT: + src->udp_timeout = g_value_get_uint64 (value); + break; + case PROP_LATENCY_MODE: + src->latency_mode = g_value_get_enum (value); + break; + case PROP_DO_REQUEST: + src->do_request = g_value_get_boolean (value); + break; + case PROP_DO_FEC: + src->do_fec = g_value_get_boolean (value); + break; + case PROP_FEC_MAX_K: + src->fec_max_k = g_value_get_uint (value); + break; + case PROP_FEC_MAX_P: + src->fec_max_p = g_value_get_uint (value); + break; + case PROP_FEC_SYMBOL_LENGTH: + src->fec_symbol_length = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfd_tizen_src_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (object); + + switch (prop_id) { + case PROP_DO_RTCP: + g_value_set_boolean (value, src->do_rtcp); + break; + case PROP_LATENCY: + g_value_set_uint (value, src->latency); + break; + case PROP_UDP_BUFFER_SIZE: + g_value_set_int (value, src->udp_buffer_size); + break; + case PROP_UDP_TIMEOUT: + g_value_set_uint64 (value, src->udp_timeout); + break; + case PROP_LATENCY_MODE: + g_value_set_enum (value, src->latency_mode); + break; + case PROP_DO_REQUEST: + g_value_set_boolean (value, src->do_request); + break; + case PROP_DO_FEC: + g_value_set_boolean (value, src->do_fec); + break; + case PROP_FEC_MAX_K: + g_value_set_uint (value, src->fec_max_k); + break; + case PROP_FEC_MAX_P: + g_value_set_uint (value, src->fec_max_p); + break; + case PROP_FEC_SYMBOL_LENGTH: + g_value_set_uint (value, src->fec_symbol_length); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstRTSPResult +gst_wfd_tizen_src_handle_mode (GstWFDTizenSrc * src, guint mode) +{ + GstRTSPResult res = GST_RTSP_OK; + + GST_DEBUG_OBJECT (src, "latency mode is %d", mode); + + src->latency_mode = mode; + switch (mode) { + case WFD_TIZEN_LATENCY_LOW: + GST_DEBUG_OBJECT (src, "low latency mode"); + if (src->wfdrtpbuffer) + g_object_set (src->wfdrtpbuffer, "latency", src->latency, NULL); + if (src->fecdec) + g_object_set (src->fecdec, "do-fec", FALSE, NULL); + if (src->requester) + g_object_set (src->requester, "do-request", FALSE, NULL); + break; + case WFD_TIZEN_LATENCY_MID: + GST_DEBUG_OBJECT (src, "mid latency mode"); + if (src->wfdrtpbuffer) + g_object_set (src->wfdrtpbuffer, "latency", src->latency * 2, NULL); + if (src->fecdec && src->do_fec) + g_object_set (src->fecdec, "do-fec", TRUE, NULL); + if (src->requester) + g_object_set (src->requester, "do-request", FALSE, NULL); + break; + case WFD_TIZEN_LATENCY_HIGH: + GST_DEBUG_OBJECT (src, "high latency mode"); + if (src->wfdrtpbuffer) + g_object_set (src->wfdrtpbuffer, "latency", src->latency * 3, NULL); + if (src->fecdec && src->do_fec) + g_object_set (src->fecdec, "do-fec", TRUE, NULL); + if (src->requester && src->do_request) + g_object_set (src->requester, "do-request", TRUE, NULL); + break; + default: + break; + } + + return res; +} + +static GstRTSPResult +gst_wfd_tizen_src_handle_set_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + GstRTSPResult res = GST_RTSP_OK; + GstWFDResult wfd_res = GST_WFD_OK; + GstWFDTizenMessage *msg = NULL; + GstRTSPMethod method; + GstRTSPVersion version; + const gchar *uri; + guint8 *data = NULL; + guint size = 0; + + g_return_val_if_fail (request, GST_RTSP_EINVAL); + g_return_val_if_fail (response, GST_RTSP_EINVAL); + + res = gst_rtsp_message_parse_request (request, &method, &uri, &version); + if (res < 0) + goto error; + + if (G_UNLIKELY (method != GST_RTSP_SET_PARAMETER)) + goto error; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res < 0) + goto error; + + wfd_res = gst_wfd_tizen_message_new (&msg); + if (wfd_res < 0) + goto error; + + wfd_res = gst_wfd_tizen_message_parse_buffer (data, size, msg); + if (wfd_res != GST_WFD_OK) + goto error; + + if (msg->tizen_retransmission) { + guint32 rtp_port = 0, rtcp_port = 0; + + wfd_res = + gst_wfd_tizen_message_get_tizen_retransmission (msg, &rtp_port, + &rtcp_port); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "tizen_retransmission : RTP port %d, RTCP port %d ", + rtp_port, rtcp_port); + } + + if (msg->tizen_fec) { + guint t_max = 0, p_max = 0; + + wfd_res = gst_wfd_tizen_message_get_tizen_fec (msg, &t_max, &p_max); + if (wfd_res != GST_WFD_OK) + goto error; + + src->fec_max_k = t_max; + src->fec_max_p = p_max; + + GST_DEBUG_OBJECT (src, "tizen_fec : t max %d, p max %d ", t_max, p_max); + } + + if (msg->tizen_latency_mode) { + guint mode = WFD_TIZEN_LATENCY_NONE; + + wfd_res = gst_wfd_tizen_message_get_tizen_latency_mode (msg, &mode); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "tizen_latency_mode : %d", mode); + + res = gst_wfd_tizen_src_handle_mode (src, mode); + if (res != GST_RTSP_OK) + goto error; + } + + gst_wfd_tizen_message_free (msg); + + return res; + +/* ERRORS */ +error: + { + GST_ERROR_OBJECT (src, "Could not handle message"); + return res; + } +} + +static GstRTSPResult +gst_wfd_tizen_src_handle_get_parameter (GstWFDBaseSrc * bsrc, + GstRTSPMessage * request, GstRTSPMessage * response) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + GstRTSPResult res = GST_RTSP_OK; + GstWFDResult wfd_res = GST_WFD_OK; + GstWFDTizenMessage *msg = NULL; + GstRTSPMethod method; + GstRTSPVersion version; + const gchar *uri; + guint8 *data = NULL; + guint size = 0; + + GString *body = NULL; + GString *body_length = NULL; + + g_return_val_if_fail (request, GST_RTSP_EINVAL); + g_return_val_if_fail (response, GST_RTSP_EINVAL); + + res = gst_rtsp_message_parse_request (request, &method, &uri, &version); + if (res < 0) + goto error; + + if (G_UNLIKELY (method != GST_RTSP_GET_PARAMETER)) + goto error; + + res = gst_rtsp_message_get_body (request, &data, &size); + if (res < 0) + goto error; + + wfd_res = gst_wfd_tizen_message_new (&msg); + if (wfd_res < 0) + goto error; + + wfd_res = gst_wfd_tizen_message_parse_buffer (data, size, msg); + if (wfd_res != GST_WFD_OK) + goto error; + + if (msg->tizen_retransmission) { + if (src->do_request) { + guint32 rtp_port = RETRANSMITTED_RTP_PORT, rtcp_port = RTCP_FB_PORT; + + wfd_res = + gst_wfd_tizen_message_set_tizen_retransmission (msg, rtp_port, + rtcp_port); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, + "tizen_retransmission : RTP port %d, RTCP port %d ", rtp_port, + rtcp_port); + } + } + + if (msg->tizen_fec) { + if (src->do_fec) { + wfd_res = + gst_wfd_tizen_message_set_tizen_fec (msg, src->fec_max_k, + src->fec_max_p); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "tizen_fec : t max %d, p max %d ", src->fec_max_k, + src->fec_max_p); + } + } + + if (msg->tizen_latency_mode) { + wfd_res = + gst_wfd_tizen_message_set_tizen_latency_mode (msg, + WFD_TIZEN_LATENCY_MID); + if (wfd_res != GST_WFD_OK) + goto error; + + GST_DEBUG_OBJECT (src, "tizen_latency_mode : %d", src->latency_mode); + } + + res = gst_rtsp_message_steal_body (response, &data, &size); + if (res != GST_RTSP_OK) + goto error; + + body = g_string_new ((const gchar *) data); + g_string_append (body, (const gchar *) gst_wfd_tizen_message_as_text (msg)); + if (body == NULL) { + GST_ERROR_OBJECT (src, "gst_wfd_tizen_message_as_text is failed"); + goto error; + } + + body_length = g_string_new (""); + g_string_append_printf (body_length, "%d", body->len); + GST_DEBUG_OBJECT (src, "body_length : %s", body_length->str); + + gst_rtsp_message_remove_header (response, GST_RTSP_HDR_CONTENT_LENGTH, -1); + gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONTENT_LENGTH, + g_string_free (body_length, FALSE)); + + GST_DEBUG_OBJECT (src, "body : %s", body->str); + + res = + gst_rtsp_message_set_body (response, (const guint8 *) body->str, + body->len); + if (res < 0) + goto error; + + g_string_free (body, FALSE); + + gst_wfd_tizen_message_free (msg); + + return res; + +/* ERRORS */ +error: + { + GST_ERROR_OBJECT (src, "Could not handle message"); + return res; + } + +} + +static void +gst_wfd_tizen_src_set_state (GstWFDBaseSrc * bsrc, GstState state) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + gint i; + + GST_DEBUG_OBJECT (src, "try to set %s state", + gst_element_state_get_name (state)); + + for (i = 0; i < 3; i++) { + if (src->udpsrc[i]) + gst_element_set_state (src->udpsrc[i], state); + if (src->udpsink[i]) + gst_element_set_state (src->udpsink[i], state); + } + + if (src->fecdec) + gst_element_set_state (src->fecdec, state); + + if (src->session) + gst_element_set_state (src->session, state); + + if (src->requester) + gst_element_set_state (src->requester, state); + + if (src->wfdrtpbuffer) + gst_element_set_state (src->wfdrtpbuffer, state); +} + +static void +gst_wfd_tizen_src_cleanup (GstWFDBaseSrc * bsrc) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + gint i; + + GST_DEBUG_OBJECT (src, "cleanup"); + + for (i = 0; i < 3; i++) { + if (src->channelpad[i]) { + gst_object_unref (src->channelpad[i]); + src->channelpad[i] = NULL; + } + if (src->udpsrc[i]) { + gst_element_set_state (src->udpsrc[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->udpsrc[i]); + gst_object_unref (src->udpsrc[i]); + src->udpsrc[i] = NULL; + } + if (src->udpsink[i]) { + gst_element_set_state (src->udpsink[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->udpsink[i]); + gst_object_unref (src->udpsink[i]); + src->udpsrc[i] = NULL; + } + } + if (src->fecdec) { + gst_element_set_state (src->fecdec, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->fecdec); + gst_object_unref (src->fecdec); + src->fecdec = NULL; + } + if (src->session) { + gst_element_set_state (src->session, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->session); + gst_object_unref (src->session); + src->session = NULL; + } + if (src->requester) { + gst_element_set_state (src->requester, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->requester); + gst_object_unref (src->requester); + src->requester = NULL; + } + if (src->wfdrtpbuffer) { + gst_element_set_state (src->wfdrtpbuffer, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->wfdrtpbuffer); + gst_object_unref (src->wfdrtpbuffer); + src->wfdrtpbuffer = NULL; + } +} + +static GstRTSPResult +gst_wfd_tizen_src_prepare_transport (GstWFDBaseSrc * bsrc, gint rtpport, + gint rtcpport) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + GstStateChangeReturn ret; + GstElement *udpsrc0, *udpsrc1, *udpsrc2; + gint tmp_rtp, tmp_rtcp, tmp_rtcp_fb; + const gchar *host; + + udpsrc0 = NULL; + udpsrc1 = NULL; + udpsrc2 = NULL; + + if (bsrc->is_ipv6) + host = "udp://[::0]"; + else + host = "udp://0.0.0.0"; + + /* try to allocate 2 UDP ports */ + udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc0 == NULL) + goto no_udp_protocol; + g_object_set (G_OBJECT (udpsrc0), "port", rtpport, "reuse", TRUE, NULL); + + if (src->udp_buffer_size != 0) + g_object_set (G_OBJECT (udpsrc0), "buffer-size", src->udp_buffer_size, + NULL); + + GST_DEBUG_OBJECT (src, "starting RTP on port %d", rtpport); + ret = gst_element_set_state (udpsrc0, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTP port %d", rtpport); + goto no_ports; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp); + + /* check if port is even */ + if ((tmp_rtp & 0x01) != 0) { + GST_DEBUG_OBJECT (src, "RTP port not even"); + /* port not even, free RTP udpsrc */ + goto no_ports; + } + + /* allocate port+1 for RTCP now */ + udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc1 == NULL) + goto no_udp_protocol; + + /* set port */ + g_object_set (G_OBJECT (udpsrc1), "port", rtcpport, "reuse", TRUE, NULL); + + GST_DEBUG_OBJECT (src, "starting RTCP on port %d", rtcpport); + ret = gst_element_set_state (udpsrc1, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTCP port %d", rtcpport); + goto no_ports; + } + + /* allocate port #19120 for retransmitted RTP now */ + udpsrc2 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc2 == NULL) + goto no_udp_protocol; + + /* set port */ + g_object_set (G_OBJECT (udpsrc2), "port", RETRANSMITTED_RTP_PORT, "reuse", + TRUE, NULL); + + if (src->udp_buffer_size != 0) + g_object_set (G_OBJECT (udpsrc2), "buffer-size", src->udp_buffer_size, + NULL); + + GST_DEBUG_OBJECT (src, "starting Retransmitted RTP on port %d", + RETRANSMITTED_RTP_PORT); + ret = gst_element_set_state (udpsrc2, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_ERROR_OBJECT (src, + "Unable to make udpsrc from Retransmitted RTP port %d", + RETRANSMITTED_RTP_PORT); + goto no_ports; + } + + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &tmp_rtcp, NULL); + g_object_get (G_OBJECT (udpsrc2), "port", &tmp_rtcp_fb, NULL); + + /* this should not happen... */ + if (rtpport != tmp_rtp || rtcpport != tmp_rtcp + || tmp_rtcp_fb != RETRANSMITTED_RTP_PORT) + goto port_error; + + /* we keep these elements, we configure all in configure_transport when the + * server told us to really use the UDP ports. */ + src->udpsrc[0] = gst_object_ref_sink (udpsrc0); + src->udpsrc[1] = gst_object_ref_sink (udpsrc1); + src->udpsrc[2] = gst_object_ref_sink (udpsrc2); + gst_element_set_locked_state (src->udpsrc[0], TRUE); + gst_element_set_locked_state (src->udpsrc[1], TRUE); + gst_element_set_locked_state (src->udpsrc[2], TRUE); + + return GST_RTSP_OK; + + /* ERRORS */ +no_udp_protocol: + { + GST_DEBUG_OBJECT (src, "could not get UDP source"); + goto cleanup; + } +no_ports: + { + GST_DEBUG_OBJECT (src, "could not allocate UDP port pair"); + goto cleanup; + } +port_error: + { + GST_DEBUG_OBJECT (src, + "ports don't match rtp: %d<->%d, rtcp: %d<->%d, retransmitted rtp: %d<->%d", + tmp_rtp, rtpport, tmp_rtcp, rtcpport, tmp_rtcp_fb, + RETRANSMITTED_RTP_PORT); + goto cleanup; + } +cleanup: + { + if (udpsrc0) { + gst_element_set_state (udpsrc0, GST_STATE_NULL); + gst_object_unref (udpsrc0); + } + if (udpsrc1) { + gst_element_set_state (udpsrc1, GST_STATE_NULL); + gst_object_unref (udpsrc1); + } + if (udpsrc2) { + gst_element_set_state (udpsrc2, GST_STATE_NULL); + gst_object_unref (udpsrc2); + } + return GST_RTSP_ERROR; + } +} + +static void +request_idr_by_requester (GstElement * requester, GstWFDTizenSrc * src) +{ + GstEvent *event = NULL; + + GST_DEBUG_OBJECT (src, "try to request idr"); + + /* Send IDR request */ + event = + gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, + gst_structure_new ("GstWFDIDRRequest", NULL, NULL)); + + if (!gst_pad_send_event (GST_WFD_BASE_SRC_CAST (src)->srcpad, event)) + GST_WARNING_OBJECT (src, "failed to send event for idr reuest"); +} + +static void +on_bye_ssrc (GObject * session, guint32 ssrc, GstWFDTizenSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session received BYE"); + + //gst_wfdtizensrc_do_stream_eos (src, manager); +} + +static void +on_new_ssrc (GObject * session, guint32 ssrc, GstWFDTizenSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session received NEW"); +} + +static void +on_timeout (GObject * session, guint32 ssrc, GstWFDTizenSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session timed out"); + + //gst_wfdtizensrc_do_stream_eos (src, manager); +} + +static void +on_ssrc_active (GObject * session, guint32 ssrc, GstWFDTizenSrc * src) +{ + GST_DEBUG_OBJECT (src, "source in session is active"); +} + +static GstCaps * +request_pt_map_for_wfdrtpbuffer (GstElement * wfdrtpbuffer, guint pt, + GstWFDTizenSrc * src) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); + + GST_WFD_BASE_STATE_LOCK (src); + caps = GST_WFD_BASE_SRC_CAST (src)->caps; + if (caps) + gst_caps_ref (caps); + GST_WFD_BASE_STATE_UNLOCK (src); + + return caps; +} + +static GstCaps * +request_pt_map_for_session (GstElement * session, guint pt, + GstWFDTizenSrc * src) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); + + GST_WFD_BASE_STATE_LOCK (src); + caps = GST_WFD_BASE_SRC_CAST (src)->caps; + if (caps) + gst_caps_ref (caps); + GST_WFD_BASE_STATE_UNLOCK (src); + + return caps; +} + +static gboolean +gst_wfd_tizen_src_configure_manager (GstWFDTizenSrc * src) +{ + GstPad *pad = NULL; + + /* construct wfdtizensrc */ + src->fecdec = gst_element_factory_make ("alfecdecoder", "wfdtizensrc_fecdec"); + if (G_UNLIKELY (src->fecdec == NULL)) { + GST_ERROR_OBJECT (src, "could not create alfecdecoder element"); + return FALSE; + } else { + gboolean do_fec = FALSE; + + do_fec = (src->latency_mode >= WFD_TIZEN_LATENCY_MID && src->do_fec); + g_object_set (G_OBJECT (src->fecdec), "do-fec", do_fec, NULL); + g_object_set (G_OBJECT (src->fecdec), "max-size-k", src->fec_max_k, NULL); + g_object_set (G_OBJECT (src->fecdec), "max-size-p", src->fec_max_p, NULL); + g_object_set (G_OBJECT (src->fecdec), "do-reorder", TRUE, NULL); + g_object_set (G_OBJECT (src->fecdec), "symbol-length", + src->fec_symbol_length, NULL); + + src->channelpad[0] = gst_element_get_static_pad (src->fecdec, "sink"); + if (G_UNLIKELY (src->channelpad[0] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtp channel pad"); + return FALSE; + } + + /* we manage session element */ + gst_element_set_locked_state (src->fecdec, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->fecdec)) { + GST_ERROR_OBJECT (src, "failed to add alfecdecoder to wfdtizensrc"); + return FALSE; + } + } + + src->session = gst_element_factory_make ("rtpsession", "wfdtizensrc_session"); + if (G_UNLIKELY (src->session == NULL)) { + GST_ERROR_OBJECT (src, "could not create gstrtpsession element"); + return FALSE; + } else { + GstPad *sinkpad; + + g_signal_connect (src->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + src); + g_signal_connect (src->session, "on-bye-timeout", (GCallback) on_timeout, + src); + g_signal_connect (src->session, "on-timeout", (GCallback) on_timeout, src); + g_signal_connect (src->session, "on-ssrc-active", + (GCallback) on_ssrc_active, src); + g_signal_connect (src->session, "on-new-ssrc", (GCallback) on_new_ssrc, + src); + g_signal_connect (src->session, "request-pt-map", + (GCallback) request_pt_map_for_session, src); + + g_object_set (G_OBJECT (src->session), "rtcp-min-interval", + (guint64) 1000000000, NULL); + + sinkpad = gst_element_get_request_pad (src->session, "recv_rtp_sink"); + if (G_UNLIKELY (sinkpad == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtp sink pad"); + return FALSE; + } + + src->channelpad[1] = + gst_element_get_request_pad (src->session, "recv_rtcp_sink"); + if (G_UNLIKELY (src->channelpad[1] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtcp channel pad"); + return FALSE; + } + + /* we manage session element */ + gst_element_set_locked_state (src->session, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->session)) { + GST_ERROR_OBJECT (src, "failed to add rtpsession to wfdtizensrc"); + return FALSE; + } + } + + src->requester = + gst_element_factory_make ("wfdrtprequester", "wfdtizensrc_requester"); + if (G_UNLIKELY (src->requester == NULL)) { + GST_ERROR_OBJECT (src, "could not create wfdrtprequester element"); + return FALSE; + } else { + gboolean do_request = FALSE; + + g_signal_connect (src->requester, "request-idr", + (GCallback) request_idr_by_requester, src); + + do_request = (src->latency_mode == WFD_TIZEN_LATENCY_HIGH + && src->do_request); + g_object_set (src->requester, "do-request", do_request, NULL); + + GST_DEBUG_OBJECT (src, + "getting retransmitted RTP sink pad of gstrtprequester"); + src->channelpad[2] = + gst_element_get_request_pad (src->requester, "retransmitted_rtp_sink"); + if (!src->channelpad[2]) { + GST_DEBUG_OBJECT (src, + "fail to get retransmitted RTP sink pad of gstrtprequester"); + return FALSE; + } + + /* we manage requester element */ + gst_element_set_locked_state (src->requester, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->requester)) { + GST_ERROR_OBJECT (src, "failed to add wfdrtprequester to wfdtizensrc"); + return FALSE; + } + } + + src->wfdrtpbuffer = + gst_element_factory_make ("wfdrtpbuffer", "wfdtizensrc_wfdrtpbuffer"); + if (G_UNLIKELY (src->wfdrtpbuffer == NULL)) { + GST_ERROR_OBJECT (src, "could not create wfdrtpbuffer element"); + return FALSE; + } else { + /* configure latency and packet lost */ + g_object_set (src->wfdrtpbuffer, "latency", src->latency, NULL); + + g_signal_connect (src->wfdrtpbuffer, "request-pt-map", + (GCallback) request_pt_map_for_wfdrtpbuffer, src); + + /* we manage wfdrtpbuffer element */ + gst_element_set_locked_state (src->wfdrtpbuffer, TRUE); + + if (!gst_bin_add (GST_BIN_CAST (src), src->wfdrtpbuffer)) { + GST_ERROR_OBJECT (src, "failed to add wfdrtpbuffer to wfdtizensrc"); + return FALSE; + } + } + + if (!gst_element_link_many (src->fecdec, src->session, src->requester, + src->wfdrtpbuffer, NULL)) { + GST_ERROR_OBJECT (src, "failed to link elements for wfdtizensrc"); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->fecdec)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdtizensrc", + GST_ELEMENT_NAME (src->fecdec)); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->session)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdtizensrc", + GST_ELEMENT_NAME (src->session)); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->requester)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdtizensrc", + GST_ELEMENT_NAME (src->requester)); + return FALSE; + } + + if (!gst_element_sync_state_with_parent (src->wfdrtpbuffer)) { + GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdtizensrc", + GST_ELEMENT_NAME (src->wfdrtpbuffer)); + return FALSE; + } + + /* set ghost pad */ + pad = gst_element_get_static_pad (src->wfdrtpbuffer, "src"); + if (G_UNLIKELY (pad == NULL)) { + GST_ERROR_OBJECT (src, + "failed to get src pad of wfdrtpbuffer for setting ghost pad of wfdtizensrc"); + return FALSE; + } + + if (!gst_wfd_base_src_set_target (GST_WFD_BASE_SRC (src), pad)) { + GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_wfd_tizen_src_configure_udp_sinks (GstWFDTizenSrc * src, + GstRTSPTransport * transport) +{ + GstPad *pad = NULL; + GSocket *socket = NULL; + gint rtp_port = -1, rtcp_port = -1, rtcp_fb_port = -1; + gboolean do_rtcp, do_rtcp_fb; + const gchar *destination = NULL; + gchar *uri = NULL; + GstPad *rtcp_fb_pad = NULL; + + /* get transport info */ + gst_wfd_base_src_get_transport_info (GST_WFD_BASE_SRC (src), transport, + &destination, &rtp_port, &rtcp_port); + rtcp_fb_port = RTCP_FB_PORT; + + /* it's possible that the server does not want us to send RTCP in which case + * the port is -1 */ + do_rtcp = (rtcp_port != -1 && src->session != NULL && src->do_rtcp); + do_rtcp_fb = (rtcp_fb_port != -1); + + /* we need a destination when we have RTCP RR and RTCP FB ports */ + if (destination == NULL && (do_rtcp_fb || do_rtcp)) + goto no_destination; + + if (do_rtcp) { + GstPad *rtcppad = NULL; + + GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination, + rtcp_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port); + src->udpsink[1] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (src->udpsink[1] == NULL) + goto no_sink_element; + + /* don't join multicast group, we will have the source socket do that */ + /* no sync or async state changes needed */ + g_object_set (G_OBJECT (src->udpsink[1]), "auto-multicast", FALSE, "loop", + FALSE, "sync", FALSE, "async", FALSE, NULL); + + if (src->udpsrc[1]) { + /* configure socket, we give it the same UDP socket as the udpsrc for RTCP + * because some servers check the port number of where it sends RTCP to identify + * the RTCP packets it receives */ + g_object_get (G_OBJECT (src->udpsrc[1]), "used-socket", &socket, NULL); + GST_DEBUG_OBJECT (src, "RTCP UDP src has sock %p", socket); + /* configure socket and make sure udpsink does not close it when shutting + * down, it belongs to udpsrc after all. */ + g_object_set (G_OBJECT (src->udpsink[1]), "socket", socket, + "close-socket", FALSE, NULL); + g_object_unref (socket); + } + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (src->udpsink[1], GST_ELEMENT_FLAG_SINK); + + /* we keep this playing always */ + gst_element_set_locked_state (src->udpsink[1], TRUE); + gst_element_set_state (src->udpsink[1], GST_STATE_PLAYING); + + gst_object_ref (src->udpsink[1]); + gst_bin_add (GST_BIN_CAST (src), src->udpsink[1]); + + rtcppad = gst_element_get_static_pad (src->udpsink[1], "sink"); + + /* get session RTCP pad */ + pad = gst_element_get_request_pad (src->session, "send_rtcp_src"); + + /* and link */ + if (pad && rtcppad) { + gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + gst_object_unref (rtcppad); + } + } + + if (do_rtcp_fb) { + GST_DEBUG_OBJECT (src, "configure RTCP FB sink for %s:%d", destination, + rtcp_fb_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_fb_port); + src->udpsink[2] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (src->udpsink[2] == NULL) + goto no_sink_element; + + /* don't join multicast group, we will have the source socket do that */ + /* no sync or async state changes needed */ + g_object_set (G_OBJECT (src->udpsink[2]), "auto-multicast", FALSE, "loop", + FALSE, "sync", FALSE, "async", FALSE, NULL); + + g_object_set (G_OBJECT (src->udpsink[2]), "bind-port", rtcp_fb_port, + "close-socket", FALSE, NULL); + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (src->udpsink[2], GST_ELEMENT_FLAG_SINK); + + /* we keep this playing always */ + gst_element_set_locked_state (src->udpsink[2], TRUE); + gst_element_set_state (src->udpsink[2], GST_STATE_PLAYING); + + gst_object_ref (src->udpsink[2]); + gst_bin_add (GST_BIN_CAST (src), src->udpsink[2]); + + /* get RTCP FB sink pad */ + rtcp_fb_pad = gst_element_get_static_pad (src->udpsink[2], "sink"); + + /* get requester RTCP pad */ + pad = gst_element_get_static_pad (src->requester, "rtcp_src"); + + /* and link */ + if (rtcp_fb_pad && pad) { + gst_pad_link (pad, rtcp_fb_pad); + gst_object_unref (pad); + gst_object_unref (rtcp_fb_pad); + } + } + + return TRUE; + + /* ERRORS */ +no_destination: + { + GST_DEBUG_OBJECT (src, "no destination address specified"); + return FALSE; + } +no_sink_element: + { + GST_DEBUG_OBJECT (src, "no UDP sink element found"); + return FALSE; + } +} + +static void +pad_blocked (GstPad * pad, gboolean blocked, GstWFDTizenSrc * src) +{ + GST_DEBUG_OBJECT (src, "pad %s:%s blocked, activating streams", + GST_DEBUG_PAD_NAME (pad)); + + if (src->udpsrc[0]) { + /* remove timeout, we are streaming now and timeouts will be handled by + * the session manager and jitter buffer */ + g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", (guint64) 0, NULL); + } + + /* activate the streams */ + gst_wfd_base_src_activate (GST_WFD_BASE_SRC (src)); + + /* unblock all pads */ + if (src->blockedpad && src->blockid != 0) { + GST_DEBUG_OBJECT (src, "unblocking blocked pad"); + gst_pad_remove_probe (src->blockedpad, src->blockid); + src->blockid = 0; + src->blockedpad = NULL; + } +} + +static gboolean +gst_wfd_tizen_src_configure_udp (GstWFDTizenSrc * src) +{ + GstPad *outpad; + + /* we manage the UDP elements now. For unicast, the UDP sources where + * allocated in the stream when we suggested a transport. */ + if (src->udpsrc[0]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[0], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[0]); + + GST_DEBUG_OBJECT (src, "setting up UDP source"); + + /* configure a timeout on the UDP port. When the timeout message is + * posted */ + g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", src->udp_timeout * 1000, + NULL); + + caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, + "clock-rate", G_TYPE_INT, 90000, NULL); + g_object_set (src->udpsrc[0], "caps", caps, NULL); + gst_caps_unref (caps); + + /* get output pad of the UDP source. */ + outpad = gst_element_get_static_pad (src->udpsrc[0], "src"); + + /* save it so we can unblock */ + src->blockedpad = outpad; + + /* configure pad block on the pad. As soon as there is dataflow on the + * UDP source, we know that UDP is not blocked by a firewall and we can + * configure all the streams to let the application autoplug decoders. */ + src->blockid = + gst_pad_add_probe (src->blockedpad, + GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | + GST_PAD_PROBE_TYPE_BUFFER_LIST, (GstPadProbeCallback) pad_blocked, src, + NULL); + + if (src->channelpad[0]) { + GST_DEBUG_OBJECT (src, "connecting UDP source 0 to session"); + /* configure for UDP delivery, we need to connect the UDP pads to + * the session plugin. */ + gst_pad_link_full (outpad, src->channelpad[0], + GST_PAD_LINK_CHECK_NOTHING); + /* we connected to pad-added signal to get pads from the manager */ + } else { + /* leave unlinked */ + } + } + + /* RTCP port */ + if (src->udpsrc[1]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[1], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[1]); + + caps = gst_caps_new_empty_simple ("application/x-rtcp"); + g_object_set (src->udpsrc[1], "caps", caps, NULL); + gst_caps_unref (caps); + + if (src->channelpad[1]) { + GstPad *pad; + + GST_DEBUG_OBJECT (src, "connecting UDP source 1 to session"); + + pad = gst_element_get_static_pad (src->udpsrc[1], "src"); + gst_pad_link_full (pad, src->channelpad[1], GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + } else { + /* leave unlinked */ + } + } + + /* Retransmitted RTP port */ + if (src->udpsrc[2]) { + GstCaps *caps; + + gst_element_set_locked_state (src->udpsrc[2], TRUE); + gst_bin_add (GST_BIN_CAST (src), src->udpsrc[2]); + + caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, + "clock-rate", G_TYPE_INT, 90000, NULL); + g_object_set (src->udpsrc[2], "caps", caps, NULL); + gst_caps_unref (caps); + + if (src->channelpad[2]) { + GstPad *pad; + + GST_DEBUG_OBJECT (src, "connecting UDP source 2 to requester"); + pad = gst_element_get_static_pad (src->udpsrc[2], "src"); + gst_pad_link_full (pad, src->channelpad[2], GST_PAD_LINK_CHECK_NOTHING); + gst_object_unref (pad); + } else { + /* leave unlinked */ + } + } + + return TRUE; +} + +static GstRTSPResult +gst_wfd_tizen_src_configure_transport (GstWFDBaseSrc * bsrc, + GstRTSPTransport * transport) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + const gchar *mime; + + g_return_val_if_fail (transport, GST_RTSP_EINVAL); + + GST_DEBUG_OBJECT (src, "configuring transport"); + + /* get the proper mime type for this manager now */ + if (gst_rtsp_transport_get_mime (transport->trans, &mime) < 0) + goto unknown_transport; + if (!mime) + goto unknown_transport; + + /* configure the final mime type */ + GST_DEBUG_OBJECT (src, "setting mime to %s", mime); + + if (!gst_wfd_tizen_src_configure_manager (src)) + goto no_manager; + + switch (transport->lower_transport) { + case GST_RTSP_LOWER_TRANS_TCP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + goto transport_failed; + case GST_RTSP_LOWER_TRANS_UDP: + if (!gst_wfd_tizen_src_configure_udp (src)) + goto transport_failed; + if (!gst_wfd_tizen_src_configure_udp_sinks (src, transport)) + goto transport_failed; + break; + default: + goto unknown_transport; + } + + return GST_RTSP_OK; + + /* ERRORS */ +unknown_transport: + { + GST_DEBUG_OBJECT (src, "unknown transport"); + return GST_RTSP_ERROR; + } +no_manager: + { + GST_DEBUG_OBJECT (src, "cannot configure manager"); + return GST_RTSP_ERROR; + } +transport_failed: + { + GST_DEBUG_OBJECT (src, "failed to configure transport"); + return GST_RTSP_ERROR; + } +} + +static gboolean +gst_wfd_tizen_src_push_event (GstWFDBaseSrc * bsrc, GstEvent * event) +{ + GstWFDTizenSrc *src = GST_WFD_TIZEN_SRC (bsrc); + gboolean res = TRUE; + + if (src->udpsrc[0] && GST_STATE (src->udpsrc[0]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res = gst_element_send_event (src->udpsrc[0], event); + } else if (src->channelpad[0]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[0])) + res = gst_pad_push_event (src->channelpad[0], event); + else + res = gst_pad_send_event (src->channelpad[0], event); + } + + if (src->udpsrc[1] && GST_STATE (src->udpsrc[1]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res &= gst_element_send_event (src->udpsrc[1], event); + } else if (src->channelpad[1]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[1])) + res &= gst_pad_push_event (src->channelpad[1], event); + else + res &= gst_pad_send_event (src->channelpad[1], event); + } + + if (src->udpsrc[2] && GST_STATE (src->udpsrc[2]) >= GST_STATE_PAUSED) { + gst_event_ref (event); + res &= gst_element_send_event (src->udpsrc[2], event); + } else if (src->channelpad[2]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (src->channelpad[2])) + res &= gst_pad_push_event (src->channelpad[2], event); + else + res &= gst_pad_send_event (src->channelpad[2], event); + } + + gst_event_unref (event); + + return res; +} diff --git a/wfdtizenmanager/gstwfdtizensrc.h b/wfdtizenmanager/gstwfdtizensrc.h new file mode 100755 index 0000000..cb9ab6c --- /dev/null +++ b/wfdtizenmanager/gstwfdtizensrc.h @@ -0,0 +1,108 @@ +/* + * wfdrtspsrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_WFD_TIZEN_SRC_H__ +#define __GST_WFD_TIZEN_SRC_H__ + +#include +#include "../wfdmanager/wfdbase/gstwfdbasesrc.h" +#include "gstwfdtizenmessage.h" + +G_BEGIN_DECLS + +#define GST_TYPE_WFD_TIZEN_SRC (gst_wfd_tizen_src_get_type()) +#define GST_WFD_TIZEN_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_TIZEN_SRC,GstWFDTizenSrc)) +#define GST_WFD_TIZEN_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_TIZEN_SRC,GstWFDTizenSrcClass)) +#define GST_WFD_TIZEN_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WFD_TIZEN_SRC, GstWFDTizenSrcClass)) +#define GST_IS_WFD_TIZEN_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_TIZEN_SRC)) +#define GST_IS_WFD_TIZEN_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_TIZEN_SRC)) +#define GST_WFD_TIZEN_SRC_CAST(obj) ((GstWFDTizenSrc *)(obj)); + +typedef struct _GstWFDTizenSrc GstWFDTizenSrc; +typedef struct _GstWFDTizenSrcClass GstWFDTizenSrcClass; + +#define RETRANSMITTED_RTP_PORT 19120 +#define RTCP_FB_PORT 19121 + +#define WFD_TIZEN_LATENCY_MODE (wfd_tizen_latency_mode_get_type()) +GType wfd_tizen_latency_mode_get_type (void); + +struct _GstWFDTizenSrc { + GstWFDBaseSrc parent; + + /* properties */ + gboolean do_rtcp; + guint latency; + gint udp_buffer_size; + guint64 udp_timeout; + gboolean do_request; + gboolean do_fec; + guint8 fec_max_k; + guint8 fec_max_p; + guint32 fec_symbol_length; + guint latency_mode; + + GstPad *channelpad[3]; + GstElement *udpsrc[3]; + GstElement *udpsink[3]; + GstElement *fecdec; + GstElement *session; + GstElement *wfdrtpbuffer; + GstElement *requester; + + GstPad *blockedpad; + gulong blockid; +}; + +struct _GstWFDTizenSrcClass { + GstWFDBaseSrcClass parent_class; +}; + +GType gst_wfd_tizen_src_get_type(void); + +G_END_DECLS + +#endif /* __GST_WFD_TIZEN_SRC_H__ */ -- 2.7.4 From c554d83efddfd94512db7fff9d0311924d603928 Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Tue, 15 Nov 2016 20:21:49 +0900 Subject: [PATCH 07/16] encodebin - Fix video recording resume failure Since GStreamer 1.0, GST_BUFFER_DTS is used with GST_BUFFER_PTS(GST_BUFFER_TIMESTAMP), but, GST_BUFFER_DTS is not updated in encodebin. It causes the failure on muxer when resume recording. [Version] 1.0.0-29 [Profile] Common [Issue Type] Bug fix [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-3.0-mobile_20161114.3] Change-Id: Ia58f53a7215162d739845d5368275c77595a67c4 Signed-off-by: Jeongmo Yang --- encodebin/src/gstencodebin.c | 10 +++++++--- packaging/gst-plugins-tizen.spec | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/encodebin/src/gstencodebin.c b/encodebin/src/gstencodebin.c index 77050f3..84a359d 100644 --- a/encodebin/src/gstencodebin.c +++ b/encodebin/src/gstencodebin.c @@ -2836,7 +2836,8 @@ gst_encode_bin_video_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *enc } //Adjusting timestamp of video source - GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + GST_BUFFER_DTS(gst_pad_probe_info_get_buffer(info)) = GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)); return GST_PAD_PROBE_OK; } @@ -2850,7 +2851,9 @@ gst_encode_bin_video_probe_hs(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin * return GST_PAD_PROBE_OK; } - GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) *= encodebin->multiple; + GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)) *= encodebin->multiple; + GST_BUFFER_DTS(gst_pad_probe_info_get_buffer(info)) = GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)); + return GST_PAD_PROBE_OK; } @@ -2864,7 +2867,8 @@ gst_encode_bin_audio_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *enc } //Adjusting timestamp of video source - GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + GST_BUFFER_DTS(gst_pad_probe_info_get_buffer(info)) = GST_BUFFER_PTS(gst_pad_probe_info_get_buffer(info)); return GST_PAD_PROBE_OK; } diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index dfa3ba5..8504c6d 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 28 +Release: 29 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ -- 2.7.4 From 885b9dff9d79ddf845917df595d804b5e55bdd35 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Thu, 17 Nov 2016 20:12:55 +0900 Subject: [PATCH 08/16] Modify function because of return type gstwfdbasesrc.c - modify 'g_return_if_fail' to 'g_return_val_if_fail' because return type of 'gst_wfd_base_src_get_streaminfo' function is 'GstRTSPResult'. Add free function of 'datatmp' & delete unreachable code gstwfdextsrc.c - modify memory leak of 'datatmp' variable. If program doesn't go inside of 'if' statement in line 1952, there is any free function of 'datatmp'. So i added it last of 'gst_wfd_ext_src_loop_tcp' function. - delete unreachable codes. When 'body' variable is not NULL, we can reach line 880. But after that there is if statement which can go when body is NULL. In my opinion, it is unreachable codes. So i deleted those. [Version] 1.0.0-30 [Profile] Common [Issue Type] Bug fix [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161101.3] Change-Id: Ifaab0440056acc2068873683b6f2f63e0faae482 Signed-off-by: Hyunsoo, Park --- packaging/gst-plugins-tizen.spec | 2 +- wfdextmanager/gstwfdextsrc.c | 6 ------ wfdmanager/wfdbase/gstwfdbasesrc.c | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 8504c6d..84fae83 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 29 +Release: 30 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdextmanager/gstwfdextsrc.c b/wfdextmanager/gstwfdextsrc.c index 6ed2fe9..f2ef9fa 100755 --- a/wfdextmanager/gstwfdextsrc.c +++ b/wfdextmanager/gstwfdextsrc.c @@ -879,12 +879,6 @@ gst_wfd_ext_src_handle_get_parameter (GstWFDBaseSrc * bsrc, if (msg_str != NULL) { g_string_append (body, (const gchar *) msg_str->str); - if (body == NULL) { - GST_ERROR_OBJECT (src, "g_string_append for uibc is failed "); - g_string_free (msg_str, TRUE); - msg_str = NULL; - goto error; - } g_string_free (msg_str, TRUE); msg_str = NULL; } diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c index e7eaa87..fd1ef59 100755 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -3631,7 +3631,7 @@ GstRTSPResult gst_wfd_base_src_get_streaminfo(GstWFDBaseSrc *src, GstStructure * { GstWFDBaseSrcPrivate *priv = src->priv; - g_return_if_fail (stream_info != NULL); + g_return_val_if_fail (stream_info != NULL, GST_RTSP_EINVAL); gst_structure_set (stream_info, "video_format", G_TYPE_STRING, "H265", -- 2.7.4 From 8ca10ed7779c049c4140aa2fc13ca67cbea2e760 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Wed, 23 Nov 2016 13:52:07 +0900 Subject: [PATCH 09/16] Add 'TCP/UDP Switching' feature Using this feature, User can choose transport layer protocol between TCP and UDP. [Version] 1.0.0-31 [Profile] Common [Issue Type] Add feature [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161111.1] Change-Id: I248acdc0fb826d8f00dc8265a3843ba160e66977 Signed-off-by: Hyunsoo, Park --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdbasesrc.c | 236 +++++++++++++++++++++-- wfdmanager/wfdbase/gstwfdbasesrc.h | 3 + wfdmanager/wfdbase/gstwfdsinkmessage.c | 225 +++++++++++++++++++++- wfdmanager/wfdbase/gstwfdsinkmessage.h | 69 ++++++- wfdmanager/wfdsrc/gstwfdsrc.c | 339 +++++++++++++++++++++++++++++++++ wfdmanager/wfdsrc/gstwfdsrc.h | 9 + 7 files changed, 854 insertions(+), 29 deletions(-) mode change 100755 => 100644 wfdmanager/wfdbase/gstwfdbasesrc.c mode change 100644 => 100755 wfdmanager/wfdbase/gstwfdsinkmessage.h mode change 100755 => 100644 wfdmanager/wfdsrc/gstwfdsrc.c mode change 100755 => 100644 wfdmanager/wfdsrc/gstwfdsrc.h diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 84fae83..3e18eee 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 30 +Release: 31 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c old mode 100755 new mode 100644 index fd1ef59..dbba724 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -231,6 +231,9 @@ struct _GstWFDBaseSrcPrivate guint audio_channels; guint audio_bitwidth; guint audio_frequency; + gint primary_tcpport; + guint buf_len; + GstRTSPLowerTrans protocol; }; /* object */ @@ -302,6 +305,9 @@ static void gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass); static void gst_wfd_base_src_init (GstWFDBaseSrc * src, gpointer g_class); static void gst_wfd_base_src_finalize (GObject * object); +static GstRTSPResult gst_wfd_base_src_switch_to_udp (GstWFDBaseSrc * src, GstRTSPMessage response); +static GstRTSPResult gst_wfd_base_src_switch_to_tcp (GstWFDBaseSrc * src, GstRTSPMessage response); + GType gst_wfd_base_src_get_type (void) { @@ -473,6 +479,8 @@ gst_wfd_base_src_class_init (GstWFDBaseSrcClass * klass) klass->request_resume = GST_DEBUG_FUNCPTR (gst_wfd_base_src_request_resume); klass->request_close = GST_DEBUG_FUNCPTR (gst_wfd_base_src_request_close); klass->set_standby = GST_DEBUG_FUNCPTR (gst_wfd_base_src_set_standby); + + klass->push_event = GST_DEBUG_FUNCPTR (gst_wfd_base_src_push_event); } static GstStructure * @@ -568,6 +576,8 @@ gst_wfd_base_src_init (GstWFDBaseSrc * src, gpointer g_class) src->priv->do_stop = FALSE; src->priv->state = GST_RTSP_STATE_INVALID; + src->priv->protocol = GST_RTSP_LOWER_TRANS_UDP; + GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_SOURCE); } @@ -1503,7 +1513,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) /* Note : wfd-3d-formats : * The wfd-3d-formats parameter specifies the support for stereoscopic video capabilities. */ - if(wfd_msg->video_3d_formats) { + if (wfd_msg->video_3d_formats) { /* TODO : Set preferred video_3d_formats */ wfd_res = GST_WFD_OK; } @@ -1511,7 +1521,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) /* Note : wfd-content-protection : * The wfd-content-protection parameter specifies whether the WFD sink supports the HDCP system 2.0/2.1 for content protection. */ - if(wfd_msg->content_protection) { + if (wfd_msg->content_protection) { gint hdcp_version = 0; gint hdcp_port_no = 0; @@ -1540,7 +1550,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * The WFD sink dongle without an integrated display or with an integrated display that is not being used to render streamed video * shall not set the edid filed of the wfd-display-edid paramter to "none" regardless of whether an external display devices is attached or not. */ - if(wfd_msg->display_edid) { + if (wfd_msg->display_edid) { /* TODO: Set preferred display_edid */ wfd_res = gst_wfd_message_set_display_EDID (wfd_msg, FALSE, @@ -1556,7 +1566,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * The wfd-coupled-sink parameter is used by a WFD sink to convey its coupled status * and if coupled to another WFD sink, the coupled WFD sink's MAC address */ - if(wfd_msg->coupled_sink) { + if (wfd_msg->coupled_sink) { /* To test with dummy coupled sink address */ wfd_res = gst_wfd_message_set_coupled_sink (wfd_msg, GST_WFD_SINK_COUPLED, @@ -1572,18 +1582,49 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * and by the a WFD source to indicate how audio, video or both audio and video payload will be encapsulated in the MPEG2-TS stream * transmitted from the WFD source to the WFD sink. */ - if(wfd_msg->client_rtp_ports) { + if (wfd_msg->client_rtp_ports) { /* Hardcoded as of now. This is to comply with dongle port settings. This should be derived from gst_wfd_base_src_alloc_udp_ports */ priv->primary_rtpport = 19000; - wfd_res = gst_wfd_message_set_prefered_RTP_ports (wfd_msg, + wfd_res = gst_wfd_message_set_preferred_RTP_ports (wfd_msg, GST_WFD_RTSP_TRANS_RTP, GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->primary_rtpport, 0); if (wfd_res != GST_WFD_OK) { - GST_ERROR ("gst_wfd_message_set_prefered_RTP_ports is failed"); + GST_ERROR ("gst_wfd_message_set_preferred_RTP_ports is failed"); + goto message_config_error; + } + } + + /* Note : wfd-client-tcp-ports : + * The wfd-coupled-sink parameter is used by a WFD sink to convey the TCP port(s) that the WFD sink is listening on + * and by the a WFD source to indicate how audio, video or both audio and video payload will be encapsulated in the MPEG2-TS stream + * transmitted from the WFD source to the WFD sink. + */ + if (wfd_msg->tcp_ports) { + /* Hardcoded as of now. This is to comply with dongle port settings. + This should be derived from gst_wfd_base_src_alloc_udp_ports */ + priv->primary_tcpport = 19006; + wfd_res = gst_wfd_message_set_preferred_TCP_ports (wfd_msg, + GST_WFD_RTSP_TRANS_RTP, + GST_WFD_RTSP_PROFILE_AVP, + GST_WFD_RTSP_LOWER_TRANS_TCP, + priv->primary_tcpport, + 0); + if (wfd_res != GST_WFD_OK) { + GST_ERROR ("gst_wfd_message_set_preferred_TCP_ports is failed"); + goto message_config_error; + } + } + + if (wfd_msg->buf_len) { + priv->buf_len = 512; + wfd_res = gst_wfd_message_set_buffer_length (wfd_msg, + priv->buf_len); + if (wfd_res != GST_WFD_OK) { + GST_ERROR ("gst_wfd_message_set_buffer_length is failed"); goto message_config_error; } } @@ -1593,7 +1634,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * If the WFD sink supports remote I2C read/write function, it shall set the value of this parameter to the TCP port number * to be used by the WFD source to exchange remote I2C read/write messaging transactions with the WFD sink. */ - if(wfd_msg->I2C) { + if (wfd_msg->I2C) { /* TODO */ wfd_res = GST_WFD_OK; } @@ -1604,7 +1645,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * The WFD sink dongle that is not connected to an external display and it is not acting as a WFD sink with embedded display * (to render streamed content) shall return a value of "none". Otherwise, the WFD sink shall choose a non-reserved value. */ - if(wfd_msg->connector_type) { + if (wfd_msg->connector_type) { /* TODO */ wfd_res = GST_WFD_OK; } @@ -1613,7 +1654,7 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) * The wfd-standby-resume-capability parameter describes support of both standby control using * a wfd-standby parameter and resume control using PLAY and using triggered-method setting PLAY. */ - if(wfd_msg->standby_resume_capability) { + if (wfd_msg->standby_resume_capability) { /* TODO */ wfd_res = GST_WFD_OK; } @@ -1771,21 +1812,97 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) GstWFDRTSPLowerTrans lowertrans = GST_WFD_RTSP_LOWER_TRANS_UNKNOWN; guint32 rtp_port0 =0, rtp_port1 =0; - wfd_res = gst_wfd_message_get_prefered_RTP_ports (wfd_msg, &trans, &profile, &lowertrans, &rtp_port0, &rtp_port1); + wfd_res = gst_wfd_message_get_preferred_RTP_ports (wfd_msg, &trans, &profile, &lowertrans, &rtp_port0, &rtp_port1); if(wfd_res != GST_WFD_OK) { goto message_config_error; } + priv->transport.trans = trans; + priv->transport.profile = profile; + priv->transport.lower_transport = lowertrans; + priv->transport.client_port.min = rtp_port0; + priv->transport.client_port.max = rtp_port0+1; + } + + if(wfd_msg->buf_len && wfd_msg->client_rtp_ports) { + gchar *rtsp_body = NULL; + guint rtsp_body_length = 0; + GString *rtsp_body_length_str = NULL; + GstWFDRTSPTransMode trans = GST_WFD_RTSP_TRANS_UNKNOWN; + GstWFDRTSPProfile profile = GST_WFD_RTSP_PROFILE_UNKNOWN; + GstWFDRTSPLowerTrans lowertrans = GST_WFD_RTSP_LOWER_TRANS_UNKNOWN; + guint32 rtp_port0 =0, rtp_port1 =0; + wfd_res = gst_wfd_message_get_preferred_RTP_ports (wfd_msg, &trans, &profile, &lowertrans, &rtp_port0, &rtp_port1); + if(wfd_res != GST_WFD_OK) { + goto message_config_error; + } priv->transport.trans = trans; priv->transport.profile = profile; priv->transport.lower_transport = lowertrans; priv->transport.client_port.min = rtp_port0; priv->transport.client_port.max = rtp_port0+1; + + rtsp_body = gst_wfd_message_as_text (wfd_msg); + if (rtsp_body == NULL) { + GST_ERROR ("gst_wfd_message_as_text is failed"); + goto message_config_error; + } + rtsp_body_length = strlen(rtsp_body); + rtsp_body_length_str = g_string_new (""); + g_string_append_printf (rtsp_body_length_str,"%d", rtsp_body_length); + + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (rtsp_body_length_str, FALSE)); + + res = gst_rtsp_message_set_body (&response, (guint8*)rtsp_body, rtsp_body_length); + + gst_wfd_base_src_switch_to_udp (src, response); + + goto done; + } + + if(wfd_msg->buf_len && wfd_msg->tcp_ports) { + gchar *rtsp_body = NULL; + guint rtsp_body_length = 0; + GString *rtsp_body_length_str = NULL; + GstWFDRTSPTransMode trans = GST_WFD_RTSP_TRANS_UNKNOWN; + GstWFDRTSPProfile profile = GST_WFD_RTSP_PROFILE_UNKNOWN; + GstWFDRTSPLowerTrans lowertrans = GST_WFD_RTSP_LOWER_TRANS_UNKNOWN; + guint32 rtp_port0 =0, rtp_port1 =0; + + wfd_res = gst_wfd_message_get_preferred_TCP_ports (wfd_msg, &trans, &profile, &lowertrans, &rtp_port0, &rtp_port1); + if(wfd_res != GST_WFD_OK) { + goto message_config_error; + } + priv->transport.trans = trans; + priv->transport.profile = profile; + priv->transport.lower_transport = lowertrans; + priv->transport.client_port.min = rtp_port0; + priv->transport.client_port.max = rtp_port0+1; + + wfd_res = gst_wfd_message_set_buffer_length (wfd_msg, + priv->buf_len); + + rtsp_body = gst_wfd_message_as_text (wfd_msg); + if (rtsp_body == NULL) { + GST_ERROR ("gst_wfd_message_as_text is failed"); + goto message_config_error; + } + rtsp_body_length = strlen(rtsp_body); + rtsp_body_length_str = g_string_new (""); + g_string_append_printf (rtsp_body_length_str,"%d", rtsp_body_length); + + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (rtsp_body_length_str, FALSE)); + + res = gst_rtsp_message_set_body (&response, (guint8*)rtsp_body, rtsp_body_length); + + gst_wfd_base_src_switch_to_tcp (src, response); + + goto done; } /* Note : wfd-preferred-display-mode : * The wfd-preferred-display-mode-supported field in a wfd-video-formats and/or in a wfd-3d-formats parameter in an RTSP M3 response message - * indicates whether a WFD sink supports the prefered display mod operation or not. + * indicates whether a WFD sink supports the preferred display mod operation or not. */ if(wfd_msg->preferred_display_mode) { } @@ -4067,9 +4184,9 @@ gst_wfd_base_src_get_wfd_audio_codecseter(GstWFDBaseSrc * src, GstWFDMessage * m guint32 audio_latency = 0; GstWFDResult wfd_res = GST_WFD_OK; - wfd_res = gst_wfd_message_get_prefered_audio_format (msg, &audio_format, &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); + wfd_res = gst_wfd_message_get_preferred_audio_format (msg, &audio_format, &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); if(wfd_res != GST_WFD_OK) { - GST_ERROR("Failed to get prefered audio format."); + GST_ERROR("Failed to get preferred audio format."); return GST_RTSP_ERROR; } @@ -4114,12 +4231,12 @@ gst_wfd_base_src_get_wfd_video_formatseter(GstWFDBaseSrc * src, GstWFDMessage * guint cvLatency = 0; GstWFDResult wfd_res = GST_WFD_OK; - wfd_res = gst_wfd_message_get_prefered_video_format (msg, &cvCodec, &cNative, &cNativeResolution, + wfd_res = gst_wfd_message_get_preferred_video_format (msg, &cvCodec, &cNative, &cNativeResolution, &cCEAResolution, &cVESAResolution, &cHHResolution, &cProfile, &cLevel, &cvLatency, &cMaxHeight, &cMaxWidth, &cmin_slice_size, &cslice_enc_params, &cframe_rate_control); if(wfd_res != GST_WFD_OK) { - GST_ERROR("Failed to get prefered video format."); + GST_ERROR("Failed to get preferred video format."); return GST_RTSP_ERROR; } @@ -4274,3 +4391,90 @@ _dump_rtsp_message (GstRTSPMessage * msg) GST_ERROR("------------------------------------------------------"); } /*rtsp dump code end*/ + +static GstRTSPResult +gst_wfd_base_src_switch_to_udp (GstWFDBaseSrc * src, GstRTSPMessage response) +{ + GstRTSPResult res = GST_RTSP_OK; + GstWFDBaseSrcClass *klass = NULL; + + if (src->priv->protocol == GST_RTSP_LOWER_TRANS_UDP) { + GST_ERROR ("Src transport is already UDP"); + return GST_RTSP_OK; + } + + GST_ERROR ("Switch to UDP"); + + gst_wfd_base_src_flush (src, TRUE); + + klass = GST_WFD_BASE_SRC_GET_CLASS (src); + if (klass->switch_udp) + res = klass->switch_udp(src, src->priv->transport.client_port.min, + src->priv->transport.client_port.max); + + gst_wfd_base_src_flush (src, FALSE); + + if(res != GST_RTSP_OK) { + GST_ERROR ("Failed to prepare switch to udp"); + return res; + } + + /* sending message after changing transport */ + res = gst_wfd_base_src_connection_send (src, &response, src->priv->ptcp_timeout); + if(res != GST_RTSP_OK) { + GST_ERROR ("Failed to send responce"); + return res; + } + + src->priv->protocol = GST_RTSP_LOWER_TRANS_UDP; + + GST_ERROR ("Transport change to UDP"); + return res; +} + +static GstRTSPResult +gst_wfd_base_src_switch_to_tcp (GstWFDBaseSrc * src, GstRTSPMessage response) +{ + GstRTSPResult res = GST_RTSP_OK; + GstWFDBaseSrcClass *klass = NULL; + + if (src->priv->protocol == GST_RTSP_LOWER_TRANS_TCP) { + GST_ERROR ("Src transport is already TCP"); + return GST_RTSP_OK; + } + + GST_ERROR ("Switch to TCP"); + + gst_wfd_base_src_flush (src, TRUE); + + klass = GST_WFD_BASE_SRC_GET_CLASS (src); + if (klass->prepare_tcp) + res = klass->prepare_tcp(src, src->priv->transport.client_port.min); + + if(res != GST_RTSP_OK) { + GST_ERROR ("Failed to prepare switch to tcp"); + return res; + } + + GST_ERROR ("Prepare Completed"); + + /* sending message after changing transport */ + res = gst_wfd_base_src_connection_send (src, &response, src->priv->ptcp_timeout); + if(res != GST_RTSP_OK) { + GST_ERROR ("Failed to send responce"); + return res; + } + + GST_ERROR ("response sent"); + + gst_wfd_base_src_flush (src, FALSE); + + if (klass->switch_tcp) + res = klass->switch_tcp(src); + + src->priv->protocol = GST_RTSP_LOWER_TRANS_TCP; + + GST_ERROR ("Transport change to TCP"); + + return res; +} diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.h b/wfdmanager/wfdbase/gstwfdbasesrc.h index 6024b7f..d6a3a85 100755 --- a/wfdmanager/wfdbase/gstwfdbasesrc.h +++ b/wfdmanager/wfdbase/gstwfdbasesrc.h @@ -132,6 +132,9 @@ struct _GstWFDBaseSrcClass { gboolean (*push_event) (GstWFDBaseSrc *src, GstEvent *event); void (*set_state) (GstWFDBaseSrc *src, GstState state); void (*cleanup) (GstWFDBaseSrc *src); + GstRTSPResult (*switch_udp) (GstWFDBaseSrc *src, gint rtpport, gint rtcpport); + GstRTSPResult (*prepare_tcp) (GstWFDBaseSrc *src, gint rtpport); + GstRTSPResult (*switch_tcp) (GstWFDBaseSrc *src); /* signals */ void (*update_media_info) (GstWFDBaseSrc *src, GstStructure * str); diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.c b/wfdmanager/wfdbase/gstwfdsinkmessage.c index ee910fb..2602328 100644 --- a/wfdmanager/wfdbase/gstwfdsinkmessage.c +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.c @@ -209,6 +209,23 @@ gst_wfd_message_uninit(GstWFDMessage *msg) FREE_STRING(msg->idr_request); } + if (msg->tcp_ports) { + FREE_STRING(msg->tcp_ports->profile); + FREE_STRING(msg->tcp_ports->mode); + FREE_STRING(msg->tcp_ports); + } + + if (msg->buf_len) { + FREE_STRING(msg->buf_len); + } + + if (msg->audio_status) { + FREE_STRING(msg->audio_status); + } + + if (msg->video_status) { + FREE_STRING(msg->video_status); + } return GST_WFD_OK; } @@ -509,6 +526,40 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) g_string_append_printf(lines, GST_STRING_WFD_CRLF); } + if (msg->tcp_ports) { + g_string_append_printf(lines, GST_STRING_WFD2_TCP_PORTS); + if (msg->tcp_ports->profile) { + g_string_append_printf(lines, GST_STRING_WFD_COLON); + g_string_append_printf(lines, " %s", msg->tcp_ports->profile); + g_string_append_printf(lines, " %d", msg->tcp_ports->rtp_port0); + g_string_append_printf(lines, " %d", msg->tcp_ports->rtp_port1); + g_string_append_printf(lines, " %s", msg->tcp_ports->mode); + } + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + + if (msg->buf_len) { + g_string_append_printf(lines, GST_STRING_WFD2_BUFFER_LEN); + g_string_append_printf(lines, GST_STRING_WFD_COLON); + g_string_append_printf(lines, " %d", msg->buf_len->buf_len); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + + if (msg->audio_status) { + g_string_append_printf(lines, GST_STRING_WFD2_AUDIO_STATUS); + g_string_append_printf(lines, GST_STRING_WFD_COLON); + g_string_append_printf(lines, " %d", msg->audio_status->aud_bufsize); + g_string_append_printf(lines, " %lld", msg->audio_status->aud_pts); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + + if (msg->video_status) { + g_string_append_printf(lines, GST_STRING_WFD2_VIDEO_STATUS); + g_string_append_printf(lines, GST_STRING_WFD_COLON); + g_string_append_printf(lines, " %d", msg->video_status->vid_bufsize); + g_string_append_printf(lines, " %lld", msg->video_status->vid_pts); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } /*g_string_append_printf (lines, "\0"); */ /*if(g_str_has_suffix (lines, "\r\n\0")) { @@ -597,6 +648,22 @@ gchar *gst_wfd_message_param_names_as_text(const GstWFDMessage *msg) g_string_append_printf(lines, GST_STRING_WFD_IDR_REQUEST); g_string_append_printf(lines, GST_STRING_WFD_CRLF); } + if (msg->tcp_ports) { + g_string_append_printf(lines, GST_STRING_WFD2_TCP_PORTS); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + if (msg->buf_len) { + g_string_append_printf(lines, GST_STRING_WFD2_BUFFER_LEN); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + if (msg->audio_status) { + g_string_append_printf(lines, GST_STRING_WFD2_AUDIO_STATUS); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } + if (msg->video_status) { + g_string_append_printf(lines, GST_STRING_WFD2_VIDEO_STATUS); + g_string_append_printf(lines, GST_STRING_WFD_CRLF); + } return g_string_free(lines, FALSE); } @@ -923,6 +990,24 @@ gst_wfd_parse_line(GstWFDMessage *msg, gchar *buffer) } else if (!g_strcmp0(type, GST_STRING_WFD_IDR_REQUEST)) { msg->idr_request = g_new0(GstWFDIdrRequest, 1); msg->idr_request->idr_request = TRUE; + } else if (!g_strcmp0(type, GST_STRING_WFD2_TCP_PORTS)) { + msg->tcp_ports = g_new0(GstWFDTCPPorts, 1); + if (strlen(v)) { + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_STRING(msg->tcp_ports->profile); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32_DIGIT(msg->tcp_ports->rtp_port0); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32_DIGIT(msg->tcp_ports->rtp_port1); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_STRING(msg->tcp_ports->mode); + } + } else if (!g_strcmp0(type, GST_STRING_WFD2_BUFFER_LEN)) { + msg->buf_len = g_new0(GstWFDBufferLen, 1); + if (strlen(v)) { + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32_DIGIT(msg->buf_len->buf_len); + } } return TRUE; @@ -1135,6 +1220,32 @@ gst_wfd_message_dump(const GstWFDMessage *msg) g_print(GST_STRING_WFD_IDR_REQUEST); } + if (msg->tcp_ports) { + g_print(" Client TCP Ports : "); + if (msg->tcp_ports->profile) { + g_print("%s", msg->tcp_ports->profile); + g_print(" %d", msg->tcp_ports->rtp_port0); + g_print(" %d", msg->tcp_ports->rtp_port1); + g_print(" %s", msg->tcp_ports->mode); + } + } + + if (msg->buf_len) { + g_print(" Current buffer length : "); + g_print(" %d", msg->buf_len->buf_len); + } + + if (msg->audio_status) { + g_print(" Current audio buffer status : "); + g_print(" bufsize %d", msg->audio_status->aud_bufsize); + g_print(" pts %lld", msg->audio_status->aud_pts); + } + + if (msg->video_status) { + g_print(" Current video buffer status : "); + g_print(" bufsize %d", msg->video_status->vid_bufsize); + g_print(" pts %lld", msg->video_status->vid_pts); + } g_print("==============================================="); return GST_WFD_OK; } @@ -1182,7 +1293,7 @@ GstWFDResult gst_wfd_message_set_supported_audio_format(GstWFDMessage *msg, GstW return GST_WFD_OK; } -GstWFDResult gst_wfd_message_set_prefered_audio_format(GstWFDMessage *msg, GstWFDAudioFormats aCodec, GstWFDAudioFreq aFreq, GstWFDAudioChannels aChanels, +GstWFDResult gst_wfd_message_set_preferred_audio_format(GstWFDMessage *msg, GstWFDAudioFormats aCodec, GstWFDAudioFreq aFreq, GstWFDAudioChannels aChanels, guint aBitwidth, guint32 aLatency) { @@ -1240,7 +1351,7 @@ GstWFDResult gst_wfd_message_get_supported_audio_format(GstWFDMessage *msg, guin return GST_WFD_OK; } -GstWFDResult gst_wfd_message_get_prefered_audio_format(GstWFDMessage *msg, GstWFDAudioFormats *aCodec, GstWFDAudioFreq *aFreq, GstWFDAudioChannels *aChanels, +GstWFDResult gst_wfd_message_get_preferred_audio_format(GstWFDMessage *msg, GstWFDAudioFormats *aCodec, GstWFDAudioFreq *aFreq, GstWFDAudioChannels *aChanels, guint *aBitwidth, guint32 *aLatency) { g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); @@ -1313,7 +1424,7 @@ GstWFDResult gst_wfd_message_set_supported_video_format(GstWFDMessage *msg, GstW return GST_WFD_OK; } -GstWFDResult gst_wfd_message_set_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, +GstWFDResult gst_wfd_message_set_preferred_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, GstWFDVideoNativeResolution vNative, guint64 vNativeResolution, guint64 vCEAResolution, guint64 vVESAResolution, guint64 vHHResolution, GstWFDVideoH264Profile vProfile, @@ -1387,7 +1498,7 @@ GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg, GstW return GST_WFD_OK; } -GstWFDResult gst_wfd_message_get_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, +GstWFDResult gst_wfd_message_get_preferred_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, GstWFDVideoNativeResolution *vNative, guint64 *vNativeResolution, guint64 *vCEAResolution, guint64 *vVESAResolution, guint64 *vHHResolution, GstWFDVideoH264Profile *vProfile, @@ -1586,7 +1697,7 @@ GstWFDResult gst_wfd_message_get_presentation_url(GstWFDMessage *msg, gchar **wf return GST_WFD_OK; } -GstWFDResult gst_wfd_message_set_prefered_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, +GstWFDResult gst_wfd_message_set_preferred_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1) { GString *lines; @@ -1631,7 +1742,7 @@ GstWFDResult gst_wfd_message_set_prefered_RTP_ports(GstWFDMessage *msg, GstWFDRT return GST_WFD_OK; } -GstWFDResult gst_wfd_message_get_prefered_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, +GstWFDResult gst_wfd_message_get_preferred_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1) { g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); @@ -1765,3 +1876,105 @@ GstWFDResult gst_wfd_message_set_idr_request(GstWFDMessage *msg) msg->idr_request->idr_request = TRUE; return GST_WFD_OK; } + +GstWFDResult gst_wfd_message_set_preferred_TCP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1) +{ + GString *lines; + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + + if (!msg->tcp_ports) + msg->tcp_ports = g_new0(GstWFDTCPPorts, 1); + + if (trans != GST_WFD_RTSP_TRANS_UNKNOWN) { + lines = g_string_new(""); + if (trans == GST_WFD_RTSP_TRANS_RTP) g_string_append_printf(lines, GST_STRING_WFD_RTP); + else if (trans == GST_WFD_RTSP_TRANS_RDT) g_string_append_printf(lines, GST_STRING_WFD_RDT); + + if (profile != GST_WFD_RTSP_PROFILE_UNKNOWN) g_string_append_printf(lines, GST_STRING_WFD_SLASH); + + if (profile == GST_WFD_RTSP_PROFILE_AVP) g_string_append_printf(lines, GST_STRING_WFD_AVP); + else if (profile == GST_WFD_RTSP_PROFILE_SAVP) g_string_append_printf(lines, GST_STRING_WFD_SAVP); + + if (lowertrans != GST_WFD_RTSP_LOWER_TRANS_UNKNOWN) g_string_append_printf(lines, GST_STRING_WFD_SLASH); + + if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP) { + g_string_append_printf(lines, GST_STRING_WFD_UDP); + g_string_append_printf(lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf(lines, GST_STRING_WFD_UNICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST) { + g_string_append_printf(lines, GST_STRING_WFD_UDP); + g_string_append_printf(lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf(lines, GST_STRING_WFD_MULTICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_TCP) { + g_string_append_printf(lines, GST_STRING_WFD_TCP); + g_string_append_printf(lines, GST_STRING_WFD_SEMI_COLON); + g_string_append_printf(lines, GST_STRING_WFD_UNICAST); + } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_HTTP) { + g_string_append_printf(lines, GST_STRING_WFD_TCP_HTTP); + } + + msg->tcp_ports->profile = g_string_free(lines, FALSE); + msg->tcp_ports->rtp_port0 = rtp_port0; + msg->tcp_ports->rtp_port1 = rtp_port1; + msg->tcp_ports->mode = g_strdup("mode=play"); + } + return GST_WFD_OK; +} + +GstWFDResult gst_wfd_message_get_preferred_TCP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, + GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1) +{ + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + g_return_val_if_fail(msg->tcp_ports != NULL, GST_WFD_EINVAL); + + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_RTP)) *trans = GST_WFD_RTSP_TRANS_RTP; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_RDT)) *trans = GST_WFD_RTSP_TRANS_RDT; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_AVP)) *profile = GST_WFD_RTSP_PROFILE_AVP; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_SAVP)) *profile = GST_WFD_RTSP_PROFILE_SAVP; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_UDP) && + g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_UNICAST)) *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_UDP) && + g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_MULTICAST)) *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_TCP) && + g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_UNICAST)) *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP; + if (g_strrstr(msg->tcp_ports->profile, GST_STRING_WFD_TCP_HTTP)) *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP; + + *rtp_port0 = msg->tcp_ports->rtp_port0; + *rtp_port1 = msg->tcp_ports->rtp_port1; + + return GST_WFD_OK; +} + +GstWFDResult gst_wfd_message_set_buffer_length(GstWFDMessage *msg, guint buf_len) +{ + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + if (!msg->buf_len) msg->buf_len = g_new0(GstWFDBufferLen, 1); + msg->buf_len->buf_len = buf_len; + return GST_WFD_OK; +} + +GstWFDResult gst_wfd_message_get_buffer_length(GstWFDMessage *msg, guint *buf_len) +{ + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + if (msg->buf_len) *buf_len = msg->buf_len->buf_len; + return GST_WFD_OK; +} + +GstWFDResult gst_wfd_message_set_audio_status(GstWFDMessage *msg, guint aud_bufsize, guint64 aud_pts) +{ + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + if (!msg->audio_status) msg->audio_status = g_new0(GstWFDAudioStatus, 1); + msg->audio_status->aud_bufsize = aud_bufsize; + msg->audio_status->aud_pts = aud_pts; + return GST_WFD_OK; +} + +GstWFDResult gst_wfd_message_set_video_status(GstWFDMessage *msg, guint vid_bufsize, guint64 vid_pts) +{ + g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); + if (!msg->video_status) msg->video_status = g_new0(GstWFDVideoStatus, 1); + msg->video_status->vid_bufsize = vid_bufsize; + msg->video_status->vid_pts = vid_pts; + return GST_WFD_OK; +} diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.h b/wfdmanager/wfdbase/gstwfdsinkmessage.h old mode 100644 new mode 100755 index 0761d2a..a2b92aa --- a/wfdmanager/wfdbase/gstwfdsinkmessage.h +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.h @@ -28,6 +28,15 @@ G_BEGIN_DECLS +#define GST_STRING_WFD2_AUDIO_CODECS "wfd2_audio_codecs" +#define GST_STRING_WFD2_VIDEO_FORMATS "wfd2_video_formats" +#define GST_STRING_WFD2_DIRECT_STREAMING_MODE "wfd2_direct_streaming_mode" + +#define GST_STRING_WFD2_TCP_PORTS "wfd2_tcp_ports" +#define GST_STRING_WFD2_BUFFER_LEN "wfd2_buffer_len" +#define GST_STRING_WFD2_AUDIO_STATUS "wfd2_audio_playback_status" +#define GST_STRING_WFD2_VIDEO_STATUS "wfd2_video_playback_status" + #define GST_STRING_WFD_AUDIO_CODECS "wfd_audio_codecs" #define GST_STRING_WFD_VIDEO_FORMATS "wfd_video_formats" #define GST_STRING_WFD_3D_VIDEO_FORMATS "wfd_3d_video_formats" @@ -48,6 +57,7 @@ G_BEGIN_DECLS #define GST_STRING_WFD_NONE "none" #define GST_STRING_WFD_ENABLE "enable" #define GST_STRING_WFD_DISABLE "disable" +#define GST_STRING_WFD_ACTIVE "active" #define GST_STRING_WFD_CRLF "\r\n" #define GST_STRING_WFD_SPACE " " #define GST_STRING_WFD_INPUT_CATEGORY_LIST "input_category_list" @@ -97,6 +107,9 @@ G_BEGIN_DECLS #define GST_STRING_WFD_SEMI_COLON ";" #define GST_STRING_WFD_SLASH "/" +#define GST_CHECK_VIDEO_FORMAT 0x7 +#define GST_SHIFT_VIDEO_FORMAT 3 + /** * GstWFDResult: * @GST_WFD_OK: A successful return value @@ -320,6 +333,10 @@ typedef struct { GstWFDAudioCodec *list; } GstWFDAudioCodeclist; +typedef struct { + guint count; + GstWFDAudioCodec *list; +} GstWFD2AudioCodeclist; typedef struct { guint64 CEA_Support; @@ -351,6 +368,11 @@ typedef struct { } GstWFDVideoCodeclist; typedef struct { + guint count; + GstWFDVideoCodec *list; +} GstWFD2VideoCodeclist; + +typedef struct { guint64 video_3d_capability; guint latency; guint min_slice_size; @@ -466,6 +488,26 @@ typedef struct { gboolean idr_request; } GstWFDIdrRequest; +typedef struct { + gchar *profile; + guint32 rtp_port0; + guint32 rtp_port1; + gchar *mode; +} GstWFDTCPPorts; + +typedef struct { + guint buf_len; +} GstWFDBufferLen; + +typedef struct { + guint aud_bufsize; + guint64 aud_pts; +} GstWFDAudioStatus; + +typedef struct { + guint vid_bufsize; + guint64 vid_pts; +} GstWFDVideoStatus; /***********************************************************/ typedef struct { @@ -487,6 +529,10 @@ typedef struct { GstWFDStandby *standby; GstWFDConnectorType *connector_type; GstWFDIdrRequest *idr_request; + GstWFDTCPPorts *tcp_ports; + GstWFDBufferLen *buf_len; + GstWFDAudioStatus *audio_status; + GstWFDVideoStatus *video_status; } GstWFDMessage; /* Session descriptions */ @@ -503,13 +549,13 @@ GstWFDResult gst_wfd_message_dump(const GstWFDMessage *msg); GstWFDResult gst_wfd_message_set_supported_audio_format(GstWFDMessage *msg, guint aCodec, guint aFreq, guint aChanels, guint aBitwidth, guint32 aLatency); -GstWFDResult gst_wfd_message_set_prefered_audio_format(GstWFDMessage *msg, +GstWFDResult gst_wfd_message_set_preferred_audio_format(GstWFDMessage *msg, GstWFDAudioFormats aCodec, GstWFDAudioFreq aFreq, GstWFDAudioChannels aChanels, guint aBitwidth, guint32 aLatency); GstWFDResult gst_wfd_message_get_supported_audio_format(GstWFDMessage *msg, guint *aCodec, guint *aFreq, guint *aChanels, guint *aBitwidth, guint32 *aLatency); -GstWFDResult gst_wfd_message_get_prefered_audio_format(GstWFDMessage *msg, +GstWFDResult gst_wfd_message_get_preferred_audio_format(GstWFDMessage *msg, GstWFDAudioFormats *aCodec, GstWFDAudioFreq *aFreq, GstWFDAudioChannels *aChanels, guint *aBitwidth, guint32 *aLatency); @@ -519,7 +565,7 @@ GstWFDResult gst_wfd_message_set_supported_video_format(GstWFDMessage *msg, GstW guint vProfile, guint vLevel, guint32 vLatency, guint32 vMaxHeight, guint32 vMaxWidth, guint32 min_slice_size, guint32 slice_enc_params, guint frame_rate_control, guint preferred_display_mode); -GstWFDResult gst_wfd_message_set_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, +GstWFDResult gst_wfd_message_set_preferred_video_format(GstWFDMessage *msg, GstWFDVideoCodecs vCodec, GstWFDVideoNativeResolution vNative, guint64 vNativeResolution, guint64 vCEAResolution, guint64 vVESAResolution, guint64 vHHResolution, GstWFDVideoH264Profile vProfile, @@ -530,7 +576,7 @@ GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg, GstW guint64 *vCEAResolution, guint64 *vVESAResolution, guint64 *vHHResolution, guint *vProfile, guint *vLevel, guint32 *vLatency, guint32 *vMaxHeight, guint32 *vMaxWidth, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); -GstWFDResult gst_wfd_message_get_prefered_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, +GstWFDResult gst_wfd_message_get_preferred_video_format(GstWFDMessage *msg, GstWFDVideoCodecs *vCodec, GstWFDVideoNativeResolution *vNative, guint64 *vNativeResolution, guint64 *vCEAResolution, guint64 *vVESAResolution, guint64 *vHHResolution, GstWFDVideoH264Profile *vProfile, @@ -555,9 +601,9 @@ GstWFDResult gst_wfd_message_get_trigger_type(GstWFDMessage *msg, GstWFDTrigger GstWFDResult gst_wfd_message_set_presentation_url(GstWFDMessage *msg, gchar *wfd_url0, gchar *wfd_url1); GstWFDResult gst_wfd_message_get_presentation_url(GstWFDMessage *msg, gchar **wfd_url0, gchar **wfd_url1); -GstWFDResult gst_wfd_message_set_prefered_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, +GstWFDResult gst_wfd_message_set_preferred_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1); -GstWFDResult gst_wfd_message_get_prefered_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, +GstWFDResult gst_wfd_message_get_preferred_RTP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1); GstWFDResult gst_wfd_message_set_audio_sink_type(GstWFDMessage *msg, GstWFDSinkType sinktype); @@ -582,6 +628,17 @@ GstWFDResult gst_wfd_message_get_connector_type(GstWFDMessage *msg, GstWFDConnec GstWFDResult gst_wfd_message_set_idr_request(GstWFDMessage *msg); +GstWFDResult gst_wfd_message_set_preferred_TCP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, + GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1); +GstWFDResult gst_wfd_message_get_preferred_TCP_ports(GstWFDMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, + GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1); + +GstWFDResult gst_wfd_message_set_buffer_length(GstWFDMessage *msg, guint buf_len); +GstWFDResult gst_wfd_message_get_buffer_length(GstWFDMessage *msg, guint *buf_len); + +GstWFDResult gst_wfd_message_set_audio_status(GstWFDMessage *msg, guint aud_bufsize, guint64 aud_pts); +GstWFDResult gst_wfd_message_set_video_status(GstWFDMessage *msg, guint vid_bufsize, guint64 vid_pts); + G_END_DECLS #endif /* __GST_WFD_SINK_MESSAGE_H__ */ diff --git a/wfdmanager/wfdsrc/gstwfdsrc.c b/wfdmanager/wfdsrc/gstwfdsrc.c old mode 100755 new mode 100644 index 33bbe9d..3b7624f --- a/wfdmanager/wfdsrc/gstwfdsrc.c +++ b/wfdmanager/wfdsrc/gstwfdsrc.c @@ -79,6 +79,14 @@ #include "config.h" #endif +#include +#include +#include +#include +#include +#include +#include + #include "gstwfdsrc.h" GST_DEBUG_CATEGORY_STATIC (wfdsrc_debug); @@ -120,6 +128,10 @@ static GstRTSPResult gst_wfd_src_prepare_transport (GstWFDBaseSrc *bsrc, static gboolean gst_wfd_src_push_event (GstWFDBaseSrc *bsrc, GstEvent * event); static void gst_wfd_src_set_state (GstWFDBaseSrc *src, GstState state); static void gst_wfd_src_cleanup (GstWFDBaseSrc *bsrc); +static GstRTSPResult gst_wfd_src_switch_udp (GstWFDBaseSrc *bsrc, + gint rtpport, gint rtcpport); +static GstRTSPResult gst_wfd_src_prepare_tcp (GstWFDBaseSrc *bsrc, gint rtpport); +static GstRTSPResult gst_wfd_src_switch_tcp (GstWFDBaseSrc *bsrc); //static guint gst_wfd_srcext_signals[LAST_SIGNAL] = { 0 }; @@ -177,6 +189,9 @@ gst_wfd_src_class_init (GstWFDSrcClass * klass) gstwfdbasesrc_class->push_event = GST_DEBUG_FUNCPTR (gst_wfd_src_push_event); gstwfdbasesrc_class->set_state = GST_DEBUG_FUNCPTR (gst_wfd_src_set_state); gstwfdbasesrc_class->cleanup = GST_DEBUG_FUNCPTR (gst_wfd_src_cleanup); + gstwfdbasesrc_class->switch_udp = GST_DEBUG_FUNCPTR (gst_wfd_src_switch_udp); + gstwfdbasesrc_class->prepare_tcp = GST_DEBUG_FUNCPTR (gst_wfd_src_prepare_tcp); + gstwfdbasesrc_class->switch_tcp = GST_DEBUG_FUNCPTR (gst_wfd_src_switch_tcp); } static void @@ -862,3 +877,327 @@ gst_wfd_src_push_event (GstWFDBaseSrc *bsrc, GstEvent * event) return res; } + + +static GstElement* +_create_udpsrc (GstWFDSrc *src, gint port) +{ + const gchar *host; + GstElement *udpsrc; + GstStateChangeReturn ret; + + host = "udp://0.0.0.0"; + + udpsrc = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); + if (udpsrc == NULL) + return NULL; + g_object_set (G_OBJECT (udpsrc), "port", port, "reuse", FALSE, NULL); + + ret = gst_element_set_state (udpsrc, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + gst_object_unref (udpsrc); + return NULL; + } + + /* we keep these elements, we configure all in configure_transport when the + * * server told us to really use the UDP ports. */ + gst_object_ref (udpsrc); + + /* they are ours now */ + gst_object_ref_sink (udpsrc); + gst_bin_add (GST_BIN_CAST (src), udpsrc); + return udpsrc; +} + +void +gst_wfd_src_free_tcp (GstWFDSrc *src) +{ + if (src->tcp_task) { + GST_ERROR ("Closing tcp loop"); + gst_task_stop (src->tcp_task); + if (src->tcp_connection) + gst_rtsp_connection_flush (src->tcp_connection, TRUE); + gst_task_join (src->tcp_task); + gst_object_unref (src->tcp_task); + g_rec_mutex_clear (&src->tcp_task_lock); + src->tcp_task = NULL; + if(src->tcp) { + g_socket_close (src->tcp, NULL); + src->tcp = NULL; + } + GST_ERROR ("TCP connection closed\n"); + } +} + +static GstRTSPResult +gst_wfd_src_switch_udp (GstWFDBaseSrc *bsrc, + gint rtpport, gint rtcpport) +{ + GstWFDSrc *src = GST_WFD_SRC (bsrc); + GstRTSPResult res = GST_RTSP_OK; + GstPad *pad; + + gst_wfd_src_free_tcp (src); + if (src->tcp_connection) { + GST_ERROR ("freeing connection..."); + gst_rtsp_connection_free (src->tcp_connection); + src->tcp_connection = NULL; + } + + /*Allocate udpsrc and link them.*/ + if ( (src->udpsrc[0] = _create_udpsrc (src, rtpport)) == NULL + || ((src->udpsrc[1] = _create_udpsrc (src, rtcpport)) == NULL)){ + return GST_RTSP_ERROR; + } + + pad = gst_element_get_static_pad (src->udpsrc[0], "src"); + if (gst_pad_link(pad,src->channelpad[0]) != GST_PAD_LINK_OK) { + GST_ERROR ("Can not link udpsrc%d to channel pad.\n", 0); + return GST_RTSP_ERROR; + } + pad = gst_element_get_static_pad (src->udpsrc[1], "src"); + if (gst_pad_link (pad,src->channelpad[1]) != GST_PAD_LINK_OK) { + GST_ERROR ("Can not link udpsrc%d to channel pad.\n", 1); + return GST_RTSP_ERROR; + } + + return res; +} + +static GstRTSPResult +gst_wfd_src_create_socket (GstWFDSrc *src, gint port) +{ + /* length of address structure */ + struct sockaddr_in my_addr; + /* client's address */ + gint sockoptval = 1; + int tcp_socket; + + /* create a TCP/IP socket */ + if ((tcp_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) { + GST_ERROR ("cannot create socket"); + return GST_RTSP_ERROR; + } + /* allow immediate reuse of the port */ + setsockopt (tcp_socket, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int)); + /* bind the socket to our source address */ + memset ((char*)&my_addr, 0, sizeof(my_addr)); + /* 0 out the structure */ + my_addr.sin_family = AF_INET; + /* address family */ + my_addr.sin_port = htons (port); + if (bind (tcp_socket, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) { + GST_ERROR ("cannot bind socket"); + close (tcp_socket); + return GST_RTSP_ERROR; + } + /* set the socket for listening (queue backlog of 5) */ + if (listen(tcp_socket, 5) < 0) { + close (tcp_socket); + GST_ERROR ("error while listening socket"); + return GST_RTSP_ERROR; + } + + src->tcp = g_socket_new_from_fd(tcp_socket, NULL); + + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_wfd_src_prepare_tcp (GstWFDBaseSrc *bsrc, gint rtpport) +{ + GstRTSPResult res = GST_RTSP_OK; + GstWFDSrc *src = GST_WFD_SRC (bsrc); + gint i; + GstPad *udp_pad; + + + for (i=0; i <2; i++) { + if (src->udpsrc[i]) { + udp_pad = gst_element_get_static_pad (src->udpsrc[i],"src"); + gst_pad_unlink (udp_pad, src->channelpad[i]); + gst_object_unref (udp_pad); + gst_element_set_state (src->udpsrc[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (src), src->udpsrc[i]); + gst_object_unref (src->udpsrc[i]); + src->udpsrc[i] = NULL; + } + } + + if (src->tcp_connection) { + GST_ERROR ("freeing connection..."); + gst_rtsp_connection_free (src->tcp_connection); + src->tcp_connection = NULL; + } + + res = gst_wfd_src_create_socket (src, rtpport); + if (res != GST_RTSP_OK) { + GST_ERROR ("fail to create tcp socket"); + return res; + } + + return res; +} + +static GstFlowReturn +gst_wfd_src_loop_tcp (GstWFDSrc *src) +{ + GstRTSPResult res; + GstPad *outpad = NULL; + GstFlowReturn ret = GST_FLOW_OK; + guint8 *sizedata, *datatmp; + gint message_size_length = 2, message_size; + GstBuffer *buf; + GstMapInfo map; + GTimeVal tv_timeout; + + if (!src->tcp_connection) + goto no_connection; + + /* get the next timeout interval */ + gst_rtsp_connection_next_timeout (src->tcp_connection, &tv_timeout); + if (tv_timeout.tv_sec == 0) { + gst_rtsp_connection_reset_timeout (src->tcp_connection); + gst_rtsp_connection_next_timeout (src->tcp_connection, &tv_timeout); + GST_ERROR ("doing receive with timeout %ld seconds, %ld usec", + tv_timeout.tv_sec, tv_timeout.tv_usec); + } + + /* Read 2 bytes message type in begining */ + sizedata = (guint8 *)malloc (message_size_length); + if((res = gst_rtsp_connection_read (src->tcp_connection,sizedata, message_size_length, &tv_timeout)) + !=GST_RTSP_OK){ + ret = GST_FLOW_ERROR; + switch (res) { + case GST_RTSP_EINTR: + { + GST_ERROR ("Got interrupted\n"); + if (src->tcp_connection) + gst_rtsp_connection_flush (src->tcp_connection, FALSE); + break; + } + default: + { + GST_ERROR ("Got error %d\n", res); + break; + } + } + g_free(sizedata); + return ret; + } + /*In rtp message over TCP the first 2 bytes are message size. + * * So firtstly read rtp message size.*/ + if((res = gst_rtsp_connection_read (src->tcp_connection,sizedata, message_size_length, &tv_timeout)) + !=GST_RTSP_OK){ + ret = GST_FLOW_ERROR; + switch (res) { + case GST_RTSP_EINTR: + { + GST_ERROR ("Got interrupted\n"); + if (src->tcp_connection) + gst_rtsp_connection_flush (src->tcp_connection, FALSE); + break; + } + default: + { + GST_ERROR ("Got error %d\n", res); + break; + } + } + g_free(sizedata); + return ret; + } + + message_size = ((guint)sizedata[0] << 8) | sizedata[1]; + datatmp = (guint8 *) malloc (message_size); + g_free(sizedata); + if((res = gst_rtsp_connection_read (src->tcp_connection,datatmp,message_size, &tv_timeout)) + !=GST_RTSP_OK){ + ret = GST_FLOW_ERROR; + switch (res) { + case GST_RTSP_EINTR: + { + GST_ERROR ("Got interrupted\n"); + if (src->tcp_connection) + gst_rtsp_connection_flush (src->tcp_connection, FALSE); + break; + } + default: + { + GST_ERROR ("Got error %d\n", res); + break; + } + } + g_free(datatmp); + return ret; + } + + /*first byte of data is type of payload + * * 200 is rtcp type then we need other pad*/ + if(datatmp[0] == 200) + outpad = src->channelpad[1]; + else + outpad = src->channelpad[0]; + + buf = gst_buffer_new_wrapped(datatmp, message_size); + gst_buffer_map(buf, &map, GST_MAP_READ); + + gst_buffer_unmap(buf, &map); + + if (src->discont) { + GstClockTime now; + GstClockTime base_time; + + now = gst_clock_get_time (GST_ELEMENT_CLOCK (src)); + base_time = GST_ELEMENT_CAST (src)->base_time; + + base_time = now - base_time; + /* mark first RTP buffer as discont */ + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + src->discont = FALSE; + GST_BUFFER_TIMESTAMP (buf) = base_time; + } + + if (GST_PAD_IS_SINK (outpad)) { + ret = gst_pad_chain (outpad, buf); + } + else { + ret = gst_pad_push (outpad, buf); + } + + return ret; + + /* ERRORS */ +no_connection: + { + GST_ERROR ("we are not connected"); + ret = GST_FLOW_ERROR; + + if (src->tcp_task) + gst_task_pause (src->tcp_task); + + return ret; + } +} + +static GstRTSPResult +gst_wfd_src_switch_tcp (GstWFDBaseSrc *bsrc) +{ + GstRTSPResult res = GST_RTSP_OK; + GstWFDSrc *src = GST_WFD_SRC (bsrc); + + if (GST_RTSP_OK != gst_rtsp_connection_accept (src->tcp, &src->tcp_connection, g_cancellable_new())) { + g_socket_close (src->tcp, NULL); + GST_ERROR ("Failed to accept connection"); + return GST_RTSP_ERROR; + } else { + g_socket_close (src->tcp, NULL); + src->discont = TRUE; + src->tcp_task = gst_task_new ((GstTaskFunction) gst_wfd_src_loop_tcp, src, NULL); + g_rec_mutex_init (&src->tcp_task_lock); + gst_task_set_lock (src->tcp_task, &src->tcp_task_lock); + gst_task_start (src->tcp_task); + } + + return res; +} diff --git a/wfdmanager/wfdsrc/gstwfdsrc.h b/wfdmanager/wfdsrc/gstwfdsrc.h old mode 100755 new mode 100644 index 6d7d278..9418d0d --- a/wfdmanager/wfdsrc/gstwfdsrc.h +++ b/wfdmanager/wfdsrc/gstwfdsrc.h @@ -86,6 +86,15 @@ struct _GstWFDSrc { GstPad *blockedpad; gulong blockid; + /*For tcp*/ + GstRTSPConnection *tcp_connection; + gboolean discont; + GRecMutex tcp_task_lock; + GstTask *tcp_task; + GRecMutex tcp_status_task_lock; + GstTask *tcp_status_report_task; + int tcp_socket; + GSocket *tcp; }; struct _GstWFDSrcClass { -- 2.7.4 From 8391a2415b391919e0cfef6c2faf967d214a4a84 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Wed, 30 Nov 2016 16:55:33 +0900 Subject: [PATCH 10/16] Modify spell 'prefered' to 'preferred' [Version] 1.0.0-32 [Profile] Common [Issue Type] Modify mispelling api name [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161111.1] Change-Id: I5a7256ec75e75196dddcfdd394cc9ba8c982e1e0 Signed-off-by: Hyunsoo, Park --- packaging/gst-plugins-tizen.spec | 2 +- wfdextmanager/gstwfdextmessage.c | 4 ++-- wfdextmanager/gstwfdextmessage.h | 4 ++-- wfdextmanager/gstwfdextsrc.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 3e18eee..656c4a8 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 31 +Release: 32 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdextmanager/gstwfdextmessage.c b/wfdextmanager/gstwfdextmessage.c index 80702a3..27cd571 100755 --- a/wfdextmanager/gstwfdextmessage.c +++ b/wfdextmanager/gstwfdextmessage.c @@ -1068,7 +1068,7 @@ gst_wfd_ext_message_init_wfd2_audio_codecs (GstWFDExtMessage * msg) } GstWFDResult -gst_wfd_ext_message_get_prefered_video_format (GstWFDExtMessage * msg, +gst_wfd_ext_message_get_preferred_video_format (GstWFDExtMessage * msg, GstWFD2VideoCodecEnum * vCodec, GstWFD2DisplayNativeResolutionEnum * vNative, guint64 * vNativeResolution, guint64 * vCEAResolution, guint64 * vVESAResolution, @@ -1115,7 +1115,7 @@ gst_wfd_ext_message_get_prefered_video_format (GstWFDExtMessage * msg, } GstWFDResult -gst_wfd_ext_message_get_prefered_audio_format (GstWFDExtMessage * msg, +gst_wfd_ext_message_get_preferred_audio_format (GstWFDExtMessage * msg, GstWFD2AudioFormatEnum * aCodec, GstWFD2AudioFreq * aFreq, GstWFD2AudioChannels * aChanels, guint * aBitwidth, guint32 * aLatency) { diff --git a/wfdextmanager/gstwfdextmessage.h b/wfdextmanager/gstwfdextmessage.h index be21c2b..a4204fd 100755 --- a/wfdextmanager/gstwfdextmessage.h +++ b/wfdextmanager/gstwfdextmessage.h @@ -341,13 +341,13 @@ const char *gst_wfd_ext_peek_wfd2_audio_format_string(const GstWFD2AudioFormatEn GstWFDResult gst_wfd_ext_message_init_wfd2_video_formats(GstWFDExtMessage *msg); GstWFDResult gst_wfd_ext_message_init_wfd2_audio_codecs(GstWFDExtMessage *msg); -GstWFDResult gst_wfd_ext_message_get_prefered_video_format(GstWFDExtMessage *msg, GstWFD2VideoCodecEnum *vCodec, +GstWFDResult gst_wfd_ext_message_get_preferred_video_format(GstWFDExtMessage *msg, GstWFD2VideoCodecEnum *vCodec, GstWFD2DisplayNativeResolutionEnum *vNative, guint64 *vNativeResolution, guint64 *vCEAResolution, guint64 *vVESAResolution, guint64 *vHHResolution, GstWFD2VideoH265ProfileEnum *vProfile, GstWFD2VideoH265LevelEnum *vLevel, guint32 *vLatency, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); -GstWFDResult gst_wfd_ext_message_get_prefered_audio_format(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum *aCodec, GstWFD2AudioFreq *aFreq, GstWFD2AudioChannels *aChanels, +GstWFDResult gst_wfd_ext_message_get_preferred_audio_format(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum *aCodec, GstWFD2AudioFreq *aFreq, GstWFD2AudioChannels *aChanels, guint *aBitwidth, guint32 *aLatency); diff --git a/wfdextmanager/gstwfdextsrc.c b/wfdextmanager/gstwfdextsrc.c index f2ef9fa..5a1deab 100755 --- a/wfdextmanager/gstwfdextsrc.c +++ b/wfdextmanager/gstwfdextsrc.c @@ -418,10 +418,10 @@ gst_wfd_ext_src_get_audio_parameter (GstWFDBaseSrc * src, GstWFDResult wfd_res = GST_WFD_OK; wfd_res = - gst_wfd_ext_message_get_prefered_audio_format (msg, &audio_format, + gst_wfd_ext_message_get_preferred_audio_format (msg, &audio_format, &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); if (wfd_res != GST_WFD_OK) { - GST_ERROR_OBJECT (src, "Failed to get prefered audio format."); + GST_ERROR_OBJECT (src, "Failed to get preferred audio format."); return GST_RTSP_ERROR; } @@ -458,12 +458,12 @@ gst_wfd_ext_src_get_video_parameter (GstWFDBaseSrc * src, GstWFDResult wfd_res = GST_WFD_OK; wfd_res = - gst_wfd_ext_message_get_prefered_video_format (msg, &cvCodec, &cNative, + gst_wfd_ext_message_get_preferred_video_format (msg, &cvCodec, &cNative, &cNativeResolution, &cCEAResolution, &cVESAResolution, &cHHResolution, &cProfile, &cLevel, &cvLatency, &cmin_slice_size, &cslice_enc_params, &cframe_rate_control); if (wfd_res != GST_WFD_OK) { - GST_ERROR ("Failed to get prefered video format."); + GST_ERROR ("Failed to get preferred video format."); return GST_RTSP_ERROR; } -- 2.7.4 From c531fa84252ae23917840ab7c0551273801a6023 Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Mon, 19 Dec 2016 14:51:28 +0900 Subject: [PATCH 11/16] [encodebin] Remove unused function [Version] 1.0.0-33 [Profile] Common [Issue Type] Clean up [Dependency module] N/A Change-Id: I710775ffa7a60cb629b1d8312027cc0dbe6f5dbb Signed-off-by: Jeongmo Yang --- encodebin/src/gstencodebin.c | 215 +-------------------------------------- packaging/gst-plugins-tizen.spec | 2 +- 2 files changed, 2 insertions(+), 215 deletions(-) diff --git a/encodebin/src/gstencodebin.c b/encodebin/src/gstencodebin.c index 84a359d..57e79d2 100644 --- a/encodebin/src/gstencodebin.c +++ b/encodebin/src/gstencodebin.c @@ -258,12 +258,6 @@ static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element, G static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad); static gint pad_compare_name (GstPad * pad1, const gchar * name); static gboolean gst_encode_bin_add_element_by_name (GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name); -#if 0 //disable unused function -static gboolean gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean profile); -static void gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * newelement); -static gboolean gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name); -static gboolean gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinElement type, GstElement * element); -#endif //disable unused function static gboolean gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element); static gboolean gst_encode_bin_link_elements (GstEncodeBin *encodebin); static gboolean gst_encode_bin_unlink_elements (GstEncodeBin *encodebin); @@ -1461,213 +1455,6 @@ element_make_fail: return FALSE; } -#if 0 //disable unused function -static gboolean -gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean newprofile) -{ - - gst_encode_bin_remove_element(encodebin, encodebin->video_encode); - gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); - gst_encode_bin_remove_element(encodebin, encodebin->image_encode); - gst_encode_bin_remove_element(encodebin, encodebin->mux); - - switch (newprofile) { - case GST_ENCODE_BIN_PROFILE_AV : - encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); - encodebin->video_encode = gst_element_factory_make (encodebin->venc_name,"video_encode"); - encodebin->mux = gst_element_factory_make (encodebin->mux_name,"mux"); - - gst_bin_add_many (GST_BIN (encodebin), - encodebin->audio_encode, - encodebin->video_encode, - encodebin->mux, - NULL); - break; - case GST_ENCODE_BIN_PROFILE_AUDIO : - encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); - encodebin->mux = gst_element_factory_make (encodebin->mux_name,"mux"); - - gst_bin_add_many (GST_BIN (encodebin), - encodebin->audio_encode, - encodebin->mux, - NULL); - break; - case GST_ENCODE_BIN_PROFILE_IMAGE : - encodebin->image_encode = gst_element_factory_make (encodebin->ienc_name,"image_encode"); - - gst_bin_add_many (GST_BIN (encodebin), - encodebin->image_encode, - NULL); - break; - default: - GST_WARNING_OBJECT(encodebin, "Invalid profile number = %d", encodebin->profile); - return FALSE; - break; - } - return TRUE; - -} - -static void -gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * newelement) -{ - if(newelement == NULL) { - GST_ERROR_OBJECT(encodebin, "some elements are null\n"); - return; - } - switch(type) { - case PROP_VIDEO_ENC: - gst_encode_bin_remove_element(encodebin, encodebin->video_encode); - encodebin->video_encode = newelement; - gst_object_ref (encodebin->video_encode); - gst_object_sink (GST_OBJECT_CAST (encodebin->video_encode)); // take ownership ?? - gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); - break; - case PROP_AUDIO_ENC: - gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); - encodebin->audio_encode = newelement; - gst_object_ref (encodebin->audio_encode); - gst_object_sink (GST_OBJECT_CAST (encodebin->audio_encode)); - gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); - break; - case PROP_IMAGE_ENC: - gst_encode_bin_remove_element(encodebin, encodebin->image_encode); - encodebin->image_encode = newelement; - gst_object_ref (encodebin->image_encode); - gst_object_sink (GST_OBJECT_CAST (encodebin->image_encode)); - gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); - break; - case PROP_MUX: - gst_encode_bin_remove_element(encodebin, encodebin->mux); - encodebin->mux = newelement; - gst_object_ref (encodebin->mux); - gst_object_sink (GST_OBJECT_CAST (encodebin->mux)); - gst_bin_add(GST_BIN(encodebin), encodebin->mux); - break; - default: - GST_WARNING_OBJECT(encodebin, "Invalid type = %d", type); - return; - break; - } -} - -static gboolean -gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name) -{ - GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; - - switch(type) { - case ENCODEBIN_ELEMENT_VENC: - if(encodebin->video_encode == NULL) { - encodebin->video_encode = gst_element_factory_make (name, "video_encode"); - gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); - } else { - sink1 = gst_element_get_static_pad(encodebin->video_encode, "sink"); - src = gst_element_get_static_pad(encodebin->video_encode, "src"); - if(sink1 != NULL) { - peersink1 = gst_pad_get_peer(sink1); - if(peersink1 != NULL) { - if(!gst_pad_unlink(peersink1, sink1)) { - goto unlink_fail; - } - } - } - - if(src !=NULL) { - peersrc = gst_pad_get_peer(src); - if(peersrc != NULL) { - if(!gst_pad_unlink(src, peersrc)) { - goto unlink_fail; - } - } - } - - if(gst_encode_bin_remove_element(encodebin, encodebin->video_encode)) { - if(encodebin->video_encode = gst_element_factory_make (name, "video_encode") != NULL) { - gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); - if(peersink1 != NULL) { - if(!gst_pad_link(peersink1, gst_element_get_pad(encodebin->video_encode, "sink"))) { - goto link_fail; - } - } - - if(peersrc != NULL) { - if(!gst_pad_link(gst_element_get_pad(encodebin->video_encode, "src"), peersrc)) { - goto link_fail; - } - } - } else { - GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] make fail\n", type); - return FALSE; - } - } else { - GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] remove fail\n", type); - return FALSE; - } - } - break; - case ENCODEBIN_ELEMENT_AENC: - break; - case ENCODEBIN_ELEMENT_IENC: - break; - case ENCODEBIN_ELEMENT_MUX: - break; - default : - GST_WARNING_OBJECT(encodebin, "Invalid element type = %d", type); - break; - } - gst_object_unref(sink1); - gst_object_unref(sink2); - gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); - return TRUE; - -unlink_fail: - gst_object_unref(sink1); - gst_object_unref(sink2); - gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); - GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] unlink fail\n", type); - return FALSE; - - -link_fail: - gst_object_unref(sink1); - gst_object_unref(sink2); - gst_object_unref(src); - gst_object_unref(peersink1); - gst_object_unref(peersink2); - gst_object_unref(peersrc); - GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] link fail\n", type); - return FALSE; -} - -static gboolean -gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinElement type, GstElement * element) -{ - GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; - - switch(type) - case ENCODEBIN_ELEMENT_VENC: - if(encodebin->video_encode == NULL) { - encodebin->video_encode = element - } - break; - case ENCODEBIN_ELEMENT_AENC: - break; - case ENCODEBIN_ELEMENT_IENC: - break; - case ENCODEBIN_ELEMENT_MUX: - break; - default : - GST_WARNING_OBJECT (encodebin,"Invalid element type = %d", type); - break; -} -#endif //disable unused function static gboolean gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element) @@ -1699,7 +1486,7 @@ gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element) } return TRUE; - } +} static gboolean gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 656c4a8..b060aee 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 32 +Release: 33 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ -- 2.7.4 From b20d0f3092a30564f5d654333906e0d6d4408763 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Mon, 19 Dec 2016 16:01:44 +0900 Subject: [PATCH 12/16] Add gst_object_unref in case of pad assigned by gst_element_get_static_pad/gst_element_get_static_pad [Version] 1.0.0 [Profile] Common [Issue Type] Bug fix [Dependency module] N/A [Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-3.0-mobile_20161219.2] Signed-off-by: SeokHoon Lee Change-Id: I9cb13eaac3968bbbc12ce355e66045b735050d6b --- wfdextmanager/gstwfdextsrc.c | 10 ++++++++-- wfdmanager/wfdsrc/gstwfdsrc.c | 10 +++++++++- wfdtizenmanager/gstwfdtizensrc.c | 11 +++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) mode change 100755 => 100644 wfdextmanager/gstwfdextsrc.c mode change 100755 => 100644 wfdtizenmanager/gstwfdtizensrc.c diff --git a/wfdextmanager/gstwfdextsrc.c b/wfdextmanager/gstwfdextsrc.c old mode 100755 new mode 100644 index 5a1deab..8ce88cc --- a/wfdextmanager/gstwfdextsrc.c +++ b/wfdextmanager/gstwfdextsrc.c @@ -1342,9 +1342,11 @@ gst_wfd_ext_src_configure_manager (GstWFDExtSrc * src) if (!gst_wfd_base_src_set_target (GST_WFD_BASE_SRC (src), pad)) { GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); + gst_object_unref(pad); return FALSE; } + gst_object_unref(pad); return TRUE; } @@ -1422,9 +1424,11 @@ gst_wfd_ext_src_configure_udp_sinks (GstWFDExtSrc * src, /* and link */ if (pad && rtcppad) { gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); + } + if (pad) gst_object_unref (pad); + if (rtcppad) gst_object_unref (rtcppad); - } } if (do_rtcp_fb) { @@ -1464,9 +1468,11 @@ gst_wfd_ext_src_configure_udp_sinks (GstWFDExtSrc * src, /* and link */ if (rtcp_fb_pad && pad) { gst_pad_link (pad, rtcp_fb_pad); + } + if (pad) gst_object_unref (pad); + if (rtcp_fb_pad) gst_object_unref (rtcp_fb_pad); - } } return TRUE; diff --git a/wfdmanager/wfdsrc/gstwfdsrc.c b/wfdmanager/wfdsrc/gstwfdsrc.c index 3b7624f..b89c75f 100644 --- a/wfdmanager/wfdsrc/gstwfdsrc.c +++ b/wfdmanager/wfdsrc/gstwfdsrc.c @@ -588,9 +588,11 @@ gst_wfd_src_configure_manager (GstWFDSrc *src) if (!gst_wfd_base_src_set_target(GST_WFD_BASE_SRC(src), pad)) { GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); + gst_object_unref (pad); return FALSE; } + gst_object_unref (pad); return TRUE; } @@ -664,9 +666,11 @@ gst_wfd_src_configure_udp_sinks (GstWFDSrc *src, GstRTSPTransport * transport) /* and link */ if (pad && rtcppad) { gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); + } + if (pad) gst_object_unref (pad); + if (rtcppad) gst_object_unref (rtcppad); - } } return TRUE; @@ -953,14 +957,18 @@ gst_wfd_src_switch_udp (GstWFDBaseSrc *bsrc, pad = gst_element_get_static_pad (src->udpsrc[0], "src"); if (gst_pad_link(pad,src->channelpad[0]) != GST_PAD_LINK_OK) { GST_ERROR ("Can not link udpsrc%d to channel pad.\n", 0); + gst_object_unref (pad); return GST_RTSP_ERROR; } + gst_object_unref (pad); pad = gst_element_get_static_pad (src->udpsrc[1], "src"); if (gst_pad_link (pad,src->channelpad[1]) != GST_PAD_LINK_OK) { GST_ERROR ("Can not link udpsrc%d to channel pad.\n", 1); + gst_object_unref (pad); return GST_RTSP_ERROR; } + gst_object_unref (pad); return res; } diff --git a/wfdtizenmanager/gstwfdtizensrc.c b/wfdtizenmanager/gstwfdtizensrc.c old mode 100755 new mode 100644 index 5984599..0f62bc1 --- a/wfdtizenmanager/gstwfdtizensrc.c +++ b/wfdtizenmanager/gstwfdtizensrc.c @@ -991,6 +991,7 @@ gst_wfd_tizen_src_configure_manager (GstWFDTizenSrc * src) GST_ERROR_OBJECT (src, "could not create rtp sink pad"); return FALSE; } + gst_object_unref (sinkpad); src->channelpad[1] = gst_element_get_request_pad (src->session, "recv_rtcp_sink"); @@ -1103,9 +1104,11 @@ gst_wfd_tizen_src_configure_manager (GstWFDTizenSrc * src) if (!gst_wfd_base_src_set_target (GST_WFD_BASE_SRC (src), pad)) { GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); + gst_object_unref (pad); return FALSE; } + gst_object_unref (pad); return TRUE; } @@ -1183,9 +1186,11 @@ gst_wfd_tizen_src_configure_udp_sinks (GstWFDTizenSrc * src, /* and link */ if (pad && rtcppad) { gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); + } + if (pad) gst_object_unref (pad); + if (rtcppad) gst_object_unref (rtcppad); - } } if (do_rtcp_fb) { @@ -1225,9 +1230,11 @@ gst_wfd_tizen_src_configure_udp_sinks (GstWFDTizenSrc * src, /* and link */ if (rtcp_fb_pad && pad) { gst_pad_link (pad, rtcp_fb_pad); + } + if (pad) gst_object_unref (pad); + if (rtcp_fb_pad) gst_object_unref (rtcp_fb_pad); - } } return TRUE; -- 2.7.4 From 8be7d22d68f45b34c1a71fe4fed0e7809eadb323 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 27 Dec 2016 09:51:05 +0900 Subject: [PATCH 13/16] Add g_object_unref add g_object_unre for assigned item by gst_element_get_clock Signed-off-by: SeokHoon Lee Change-Id: I9c43760d93959c77807e188d232f303813f9c9f3 --- packaging/gst-plugins-tizen.spec | 2 +- waylandsrc/src/gstwaylandsrc.c | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index b060aee..0ad2e15 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 33 +Release: 34 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/waylandsrc/src/gstwaylandsrc.c b/waylandsrc/src/gstwaylandsrc.c index 0d5bed3..be6ee11 100644 --- a/waylandsrc/src/gstwaylandsrc.c +++ b/waylandsrc/src/gstwaylandsrc.c @@ -256,7 +256,7 @@ mirror_handle_dequeued (void *data, struct output_buffer *out_buffer; GstWaylandSrc *src = data; GstBuffer *gst_buffer; - GstClock *clock; + GstClock *clock = NULL; GstClockTime base_time, next_capture_ts; gint64 next_frame_no; #ifdef TIZEN_PROFILE_LITE @@ -269,6 +269,11 @@ mirror_handle_dequeued (void *data, if (out_buffer->wl_buffer != buffer) continue; + if(NULL != clock) { + g_object_unref(clock); + clock = NULL; + } + clock = gst_element_get_clock (GST_ELEMENT (src)); if (!clock) { GST_WARNING_OBJECT (src, "Failed to get clock"); @@ -348,7 +353,7 @@ mirror_handle_dequeued (void *data, mm_video_buf = (MMVideoBuffer *) malloc (sizeof (MMVideoBuffer)); if (mm_video_buf == NULL) { GST_ERROR_OBJECT (src, "failed to alloc MMVideoBuffer"); - return; + goto FUNC_END; } memset (mm_video_buf, 0x00, sizeof (MMVideoBuffer)); @@ -394,7 +399,7 @@ mirror_handle_dequeued (void *data, mm_video_buf->handle.paddr[0] = (void *)phy_addr; GST_INFO_OBJECT(src, "mm_vbuffer->paddr : %p", mm_video_buf->handle.paddr[0]); } - mm_video_buf->data[0] = (tbm_bo_map(mm_video_buf->handle.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE)).ptr; + mm_video_buf->data[0] = (tbm_bo_map(mm_video_buf->handle.bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE)).ptr; tbm_bo_unmap (mm_video_buf->handle.bo[0]); #endif @@ -461,6 +466,13 @@ mirror_handle_dequeued (void *data, break; } +FUNC_END: + + if(NULL != clock) { + g_object_unref(clock); + clock = NULL; + } + return; } -- 2.7.4 From be90eced07d37ab9015fea126588997ad18771d4 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 27 Dec 2016 17:28:12 +0900 Subject: [PATCH 14/16] Remove unused plugins Signed-off-by: SeokHoon Lee Change-Id: I84df2292350b4eb025886bf60708d37d7002e822 --- Makefile.am | 8 - configure.ac | 13 - packaging/gst-plugins-tizen.spec | 3 +- wfdextmanager/Makefile.am | 15 - wfdextmanager/gstwfdextmanager.c | 71 -- wfdextmanager/gstwfdextmessage.c | 1235 --------------------- wfdextmanager/gstwfdextmessage.h | 359 ------ wfdextmanager/gstwfdextsrc.c | 2124 ------------------------------------ wfdextmanager/gstwfdextsrc.h | 113 -- wfdextmanager/gstwfdrtprequester.c | 977 ----------------- wfdextmanager/gstwfdrtprequester.h | 102 -- 11 files changed, 1 insertion(+), 5019 deletions(-) delete mode 100755 wfdextmanager/Makefile.am delete mode 100644 wfdextmanager/gstwfdextmanager.c delete mode 100755 wfdextmanager/gstwfdextmessage.c delete mode 100755 wfdextmanager/gstwfdextmessage.h delete mode 100644 wfdextmanager/gstwfdextsrc.c delete mode 100755 wfdextmanager/gstwfdextsrc.h delete mode 100755 wfdextmanager/gstwfdrtprequester.c delete mode 100755 wfdextmanager/gstwfdrtprequester.h diff --git a/Makefile.am b/Makefile.am index e9ad191..2c5cb4f 100755 --- a/Makefile.am +++ b/Makefile.am @@ -49,10 +49,6 @@ if GST_TIZEN_USE_TIZENIPC SUBDIRS += tizenipc endif -if GST_TIZEN_USE_WFDEXTMANAGER -SUBDIRS += wfdextmanager -endif - if GST_TIZEN_USE_WFDTIZENMANAGER SUBDIRS += wfdtizenmanager endif @@ -96,10 +92,6 @@ if GST_TIZEN_USE_DRMDECRYPTOR DIST_SUBDIRS += drmdecryptor endif -if GST_TIZEN_USE_WFDEXTMANAGER -DIST_SUBDIRS += wfdextmanager -endif - if GST_TIZEN_USE_WFDTIZENMANAGER DIST_SUBDIRS += wfdtizenmanager endif diff --git a/configure.ac b/configure.ac index 91b9509..65136f2 100755 --- a/configure.ac +++ b/configure.ac @@ -334,18 +334,6 @@ AC_ARG_ENABLE(tizenipc, AC_HELP_STRING([--enable-tizenipc], [using tizenipc]), [GST_TIZEN_USE_TIZENIPC=yes]) AM_CONDITIONAL(GST_TIZEN_USE_TIZENIPC, test "x$GST_TIZEN_USE_TIZENIPC" = "xyes") -dnl use ext-wfdextmanager -------------------------------------------------------------------------- -AC_ARG_ENABLE(ext-wfdextmanager, AC_HELP_STRING([--enable-ext-wfdextmanager], [using wfdextmanager]), -[ - case "${enableval}" in - yes) GST_TIZEN_USE_WFDEXTMANAGER=yes ;; - no) GST_TIZEN_USE_WFDEXTMANAGER=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-wfdextmanager) ;; - esac - ], - [GST_TIZEN_USE_WFDEXTMANAGER=yes]) -AM_CONDITIONAL(GST_TIZEN_USE_WFDEXTMANAGER, test "x$GST_TIZEN_USE_WFDEXTMANAGER" = "xyes") - dnl use ext-wfdtizenmanager -------------------------------------------------------------------------- AC_ARG_ENABLE(ext-wfdtizenmanager, AC_HELP_STRING([--enable-ext-wfdtizenmanager], [using wfdtizenmanager]), [ @@ -408,7 +396,6 @@ drmdecryptor/src/Makefile tizenipc/Makefile tizenipc/src/Makefile wfdtizenmanager/Makefile -wfdextmanager/Makefile alfec/Makefile rtpresender/Makefile rtpresender/src/Makefile diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 0ad2e15..33a07c7 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 34 +Release: 35 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ @@ -61,7 +61,6 @@ export CFLAGS="$CFLAGS -DTIZEN_PROFILE_LITE" ./autogen.sh --disable-static %configure \ --disable-drmdecryptor\ - --enable-ext-wfdextmanager\ --enable-ext-wfdtizenmanager\ --enable-ext-alfec\ --enable-ext-rtpresender\ diff --git a/wfdextmanager/Makefile.am b/wfdextmanager/Makefile.am deleted file mode 100755 index 8b7a223..0000000 --- a/wfdextmanager/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -plugin_LTLIBRARIES = libgstwfdextmanager.la - -libgstwfdextmanager_la_SOURCES = gstwfdextmanager.c \ - gstwfdextsrc.c gstwfdrtprequester.c gstwfdextmessage.c - -libgstwfdextmanager_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) - -libgstwfdextmanager_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ - $(top_builddir)/wfdmanager/wfdbase/libgstwfdbase.la - -libgstwfdextmanager_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstwfdextmanager_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstwfdextsrc.h gstwfdrtprequester.h gstwfdextmessage.h diff --git a/wfdextmanager/gstwfdextmanager.c b/wfdextmanager/gstwfdextmanager.c deleted file mode 100644 index 472616c..0000000 --- a/wfdextmanager/gstwfdextmanager.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -* wfdextmanager -* -* Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the "Software"), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -* DEALINGS IN THE SOFTWARE. -* -* Alternatively, the contents of this file may be used under the -* GNU Lesser General Public License Version 2.1 (the "LGPL"), in -* which case the following provisions apply instead of the ones -* mentioned above: -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Library General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Library General Public License for more details. -* -* You should have received a copy of the GNU Library General Public -* License along with this library; if not, write to the -* Free Software Foundation, Inc., 59 Temple Place - Suite 330, -* Boston, MA 02111-1307, USA. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstwfdextsrc.h" -#include "gstwfdrtprequester.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "wfdextsrc", GST_RANK_NONE, - GST_TYPE_WFD_EXT_SRC)) - return FALSE; - if (!gst_element_register (plugin, "wfdrtprequester", GST_RANK_NONE, - GST_TYPE_WFD_RTP_REQUESTER)) - return FALSE; - - return TRUE; -} - - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - wfdextmanager, - "Wi-Fi Display management extension plugin library", - plugin_init, - VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com") diff --git a/wfdextmanager/gstwfdextmessage.c b/wfdextmanager/gstwfdextmessage.c deleted file mode 100755 index 27cd571..0000000 --- a/wfdextmanager/gstwfdextmessage.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * wfdextmessage - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#include /* for G_OS_WIN32 */ -#include "gstwfdextmessage.h" - -/* FIXME, is currently allocated on the stack */ -#define MAX_LINE_LEN (1024 * 16) - -#define FREE_STRING(field) if (field != NULL) g_free(field); (field) = NULL; -#define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup(val); - -static GstWFDExtMessage *gst_wfd_ext_message_boxed_copy (GstWFDExtMessage * - orig); -static void gst_wfd_ext_message_boxed_free (GstWFDExtMessage * msg); -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE -static GString *_gst_wfd_ext_convert_wfd2_video_formats_to_gstring (const - GstWFDExtMessage * msg); -static GString *_gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (const - GstWFDExtMessage * msg); - -GString * -_gst_wfd_ext_convert_wfd2_video_formats_to_gstring (const GstWFDExtMessage * - msg) -{ - GstWFD2VideoCodec *codec_list = NULL; - GString *str = NULL; - - if (msg->wfd2_video_formats == NULL || - msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) { - return NULL; - } - - str = g_string_new (""); - - codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; - - g_string_append_printf (str, - GST_STRING_EXT_WFD2_VIDEO_FORMATS GST_STRING_WFD_COLON); - g_string_append_printf (str, " %02x", - msg->wfd2_video_formats->sink_video_cap.native); - - while (codec_list) { - g_string_append_printf (str, " %02x %02x %04x", - codec_list->codec, codec_list->profile, codec_list->level); - - g_string_append_printf (str, " %012llx %012llx %012llx %02x %04x %04x %02x", - codec_list->misc_params.CEA_Support, - codec_list->misc_params.VESA_Support, - codec_list->misc_params.HH_Support, - codec_list->misc_params.latency, - codec_list->misc_params.min_slice_size, - codec_list->misc_params.slice_enc_params, - codec_list->misc_params.frame_rate_control_support); - - if (codec_list->next) { - g_string_append_printf (str, GST_STRING_WFD_COMMA); - } - codec_list = codec_list->next; - } - - g_string_append_printf (str, " %02x", - msg->wfd2_video_formats->sink_video_cap.non_transcoding_support); - - if (msg->wfd2_video_formats->portrait_mode == TRUE) { - g_string_append_printf (str, " %s", GST_STRING_EXT_WFD2_PORTRAIT_ENABLED); - } - - g_string_append_printf (str, GST_STRING_WFD_CRLF); - - return str; - -} - -const char * -gst_wfd_ext_peek_wfd2_audio_format_string (const GstWFD2AudioFormatEnum - audio_format) -{ - if (audio_format == GST_WFD2_AUDIO_FORMAT_LPCM) { - return GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM; - } else if (audio_format == GST_WFD2_AUDIO_FORMAT_AAC) { - return GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC; - } else if (audio_format == GST_WFD2_AUDIO_FORMAT_AC3) { - return GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3; - } else { - return NULL; - } -} - -GstWFD2AudioFormatEnum -gst_wfd_ext_get_wfd2_audio_format (gchar * str) -{ - if (!g_strcmp0 ((const char *) str, GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM)) { - return GST_WFD2_AUDIO_FORMAT_LPCM; - } else if (!g_strcmp0 ((const char *) str, - GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC)) { - return GST_WFD2_AUDIO_FORMAT_AAC; - } else if (!g_strcmp0 ((const char *) str, - GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3)) { - return GST_WFD2_AUDIO_FORMAT_AC3; - } else { - return GST_WFD2_AUDIO_FORMAT_UNKNOWN; - } -} - -GString * -_gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (const GstWFDExtMessage * msg) -{ - GstWFD2SinkAudio *sink_audio_list = NULL; - GString *str = NULL; - - if (msg->wfd2_audio_codecs == NULL || - msg->wfd2_audio_codecs->sink_audio_list == NULL) { - return NULL; - } - - str = - g_string_new (GST_STRING_EXT_WFD2_AUDIO_CODECS GST_STRING_WFD_COLON - GST_STRING_WFD_SPACE); - - sink_audio_list = msg->wfd2_audio_codecs->sink_audio_list; - - while (sink_audio_list) { - - g_string_append_printf (str, "%s %08x %02x", - gst_wfd_ext_peek_wfd2_audio_format_string (sink_audio_list-> - audio_format), sink_audio_list->mode, sink_audio_list->latency); - - if (sink_audio_list->next) { - g_string_append_printf (str, GST_STRING_WFD_COMMA GST_STRING_WFD_SPACE); - } - sink_audio_list = sink_audio_list->next; - } - - g_string_append_printf (str, GST_STRING_WFD_CRLF); - - return str; - -} -#endif - -G_DEFINE_BOXED_TYPE (GstWFDExtMessage, gst_wfd_ext_message, - gst_wfd_ext_message_boxed_copy, gst_wfd_ext_message_boxed_free); - -static GstWFDExtMessage * -gst_wfd_ext_message_boxed_copy (GstWFDExtMessage * orig) -{ - GstWFDExtMessage *copy; - - if (gst_wfd_ext_message_copy (orig, ©) == GST_WFD_OK) - return copy; - - return NULL; -} - -static void -gst_wfd_ext_message_boxed_free (GstWFDExtMessage * msg) -{ - gst_wfd_ext_message_free (msg); -} - -/** -* gst_wfd_ext_message_new: -* @msg: pointer to new #GstWFDExtMessage -* -* Allocate a new GstWFDExtMessage and store the result in @msg. -* -* Returns: a #GstWFDExtMessage. -*/ -GstWFDResult -gst_wfd_ext_message_new (GstWFDExtMessage ** msg) -{ - GstWFDExtMessage *newmsg; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - newmsg = g_new0 (GstWFDExtMessage, 1); - - *msg = newmsg; - - return gst_wfd_ext_message_init (newmsg); -} - -/** -* gst_wfd_ext_message_init: -* @msg: a #GstWFDExtMessage -* -* Initialize @msg so that its contents are as if it was freshly allocated -* with gst_wfd_ext_message_new(). This function is mostly used to initialize a message -* allocated on the stack. gst_wfd_ext_message_uninit() undoes this operation. -* -* When this function is invoked on newly allocated data(with malloc or on the -* stack), its contents should be set to 0 before calling this function. -* -* Returns: a #GstWFDExtMessage. -*/ -GstWFDResult -gst_wfd_ext_message_init (GstWFDExtMessage * msg) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - return GST_WFD_OK; -} - -/** -* gst_wfd_ext_message_uninit: -* @msg: a #GstWFDExtMessage -* -* Free all resources allocated in @msg. @msg should not be used anymore after -* this function. This function should be used when @msg was allocated on the -* stack and initialized with gst_wfd_ext_message_init(). -* -*/ -void -gst_wfd_ext_message_uninit (GstWFDExtMessage * msg) -{ - g_return_if_fail (msg != NULL); - - if (msg->client_rtp_ports) { - FREE_STRING (msg->client_rtp_ports->profile); - FREE_STRING (msg->client_rtp_ports->mode); - FREE_STRING (msg->client_rtp_ports); - } - - if (msg->max_buffer_length) { - FREE_STRING (msg->max_buffer_length); - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (msg->wfd2_video_formats) { - GstWFD2VideoCodec *codec_list = NULL; - GstWFD2VideoCodec *temp = NULL; - codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; - while (codec_list) { - temp = codec_list; - codec_list = codec_list->next; - FREE_STRING (temp); - } - FREE_STRING (msg->wfd2_video_formats); - } - - if (msg->wfd2_audio_codecs) { - GstWFD2SinkAudio *codec_list = NULL; - GstWFD2SinkAudio *temp = NULL; - codec_list = msg->wfd2_audio_codecs->sink_audio_list; - while (codec_list) { - temp = codec_list; - codec_list = codec_list->next; - FREE_STRING (temp); - } - FREE_STRING (msg->wfd2_audio_codecs); - } -#endif -} - -/** -* gst_wfd_ext_message_free: -* @msg: a #GstWFDExtMessage -* -* Free all resources allocated by @msg. @msg should not be used anymore after -* this function. This function should be used when @msg was dynamically -* allocated with gst_wfd_ext_message_new(). -* -*/ -void -gst_wfd_ext_message_free (GstWFDExtMessage * msg) -{ - g_return_if_fail (msg != NULL); - - gst_wfd_ext_message_uninit (msg); - g_free (msg); -} - -/** - * gst_wfd_ext_message_copy: - * @msg: a #GstWFDExtMessage - * @copy: (out) (transfer full): pointer to new #GstWFDExtMessage - * - * Allocate a new copy of @msg and store the result in @copy. The value in - * @copy should be release with gst_wfd_ext_message_free function. - * - * Returns: a #GstWFDResult - * - * Since: 1.6 - */ -GstWFDResult -gst_wfd_ext_message_copy (const GstWFDExtMessage * msg, - GstWFDExtMessage ** copy) -{ - GstWFDResult ret; - GstWFDExtMessage *cp; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - ret = gst_wfd_ext_message_new (copy); - if (ret != GST_WFD_OK) - return ret; - - cp = *copy; - - /* TODO-WFD */ - if (msg->client_rtp_ports) { - cp->client_rtp_ports = g_malloc (sizeof (GstWFDClientRtpPorts)); - if (cp->client_rtp_ports) { - cp->client_rtp_ports->profile = g_strdup (msg->client_rtp_ports->profile); - cp->client_rtp_ports->rtp_port0 = msg->client_rtp_ports->rtp_port0; - cp->client_rtp_ports->rtp_port1 = msg->client_rtp_ports->rtp_port1; - cp->client_rtp_ports->mode = g_strdup (msg->client_rtp_ports->mode); - } - } - if (msg->max_buffer_length) { - cp->max_buffer_length->length = msg->max_buffer_length->length; - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (msg->wfd2_video_formats) { - cp->wfd2_video_formats = g_malloc0 (sizeof (GstWFD2VideoFormats)); - memcpy (cp->wfd2_video_formats, msg->wfd2_video_formats, - sizeof (GstWFD2VideoFormats)); - - if (cp->wfd2_video_formats) { - if (msg->wfd2_video_formats->sink_video_cap.video_codec_list) { - GstWFD2VideoCodec *copy = NULL; - GstWFD2VideoCodec *temp = NULL; - cp->wfd2_video_formats->sink_video_cap.video_codec_list = - g_malloc0 (sizeof (GstWFD2VideoCodec)); - memcpy (cp->wfd2_video_formats->sink_video_cap.video_codec_list, - msg->wfd2_video_formats->sink_video_cap.video_codec_list, - sizeof (GstWFD2VideoCodec)); - - copy = cp->wfd2_video_formats->sink_video_cap.video_codec_list; - temp = msg->wfd2_video_formats->sink_video_cap.video_codec_list->next; - while (temp != NULL) { - copy->next = g_malloc0 (sizeof (GstWFD2VideoCodec)); - memcpy (copy->next, temp, sizeof (GstWFD2VideoCodec)); - copy = copy->next; - temp = temp->next; - } - } - } - } - - if (msg->wfd2_audio_codecs) { - cp->wfd2_audio_codecs = g_malloc0 (sizeof (GstWFD2SinkAudioCap)); - memcpy (cp->wfd2_audio_codecs, msg->wfd2_audio_codecs, - sizeof (GstWFD2SinkAudioCap)); - - if (cp->wfd2_audio_codecs) { - if (msg->wfd2_audio_codecs->sink_audio_list) { - GstWFD2SinkAudio *copy = NULL; - GstWFD2SinkAudio *temp = NULL; - cp->wfd2_audio_codecs->sink_audio_list = - g_malloc0 (sizeof (GstWFD2SinkAudio)); - memcpy (cp->wfd2_audio_codecs->sink_audio_list, - msg->wfd2_audio_codecs->sink_audio_list, sizeof (GstWFD2SinkAudio)); - - copy = cp->wfd2_audio_codecs->sink_audio_list; - temp = msg->wfd2_audio_codecs->sink_audio_list->next; - while (temp != NULL) { - copy->next = g_malloc0 (sizeof (GstWFD2SinkAudio)); - memcpy (copy->next, temp, sizeof (GstWFD2SinkAudio)); - copy = copy->next; - temp = temp->next; - } - } - } - } -#endif - - return GST_WFD_OK; -} - -/** -* gst_wfd_ext_message_as_text: -* @msg: a #GstWFDExtMessage -* -* Convert the contents of @msg to a text string. -* -* Returns: A dynamically allocated string representing the WFD description. -*/ -gchar * -gst_wfd_ext_message_as_text (const GstWFDExtMessage * msg) -{ - /* change all vars so they match rfc? */ - GString *lines; - g_return_val_if_fail (msg != NULL, NULL); - - lines = g_string_new (""); - - if (msg->client_rtp_ports) { - g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS); - if (msg->client_rtp_ports->profile) { - g_string_append_printf (lines, GST_STRING_WFD_COLON); - g_string_append_printf (lines, " %s", msg->client_rtp_ports->profile); - g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port0); - g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port1); - g_string_append_printf (lines, " %s", msg->client_rtp_ports->mode); - } - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } - if (msg->max_buffer_length) { - g_string_append_printf (lines, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH); - g_string_append_printf (lines, GST_STRING_WFD_COLON); - g_string_append_printf (lines, " %d", msg->max_buffer_length->length); - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - { - GString *str_result = - _gst_wfd_ext_convert_wfd2_video_formats_to_gstring (msg); - if (str_result != NULL) { - g_string_append_printf (lines, "%s", str_result->str); - g_string_free (str_result, TRUE); - str_result = NULL; - } - - str_result = _gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring (msg); - if (str_result != NULL) { - g_string_append_printf (lines, "%s", str_result->str); - g_string_free (str_result, TRUE); - } - } -#endif - return g_string_free (lines, FALSE); -} - -gchar * -gst_wfd_ext_message_parameter_names_as_text (const GstWFDExtMessage * msg) -{ - /* change all vars so they match rfc? */ - GString *lines; - - g_return_val_if_fail (msg != NULL, NULL); - - lines = g_string_new (""); - - if (msg->client_rtp_ports) { - g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS); - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } - if (msg->max_buffer_length) { - g_string_append_printf (lines, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH); - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (msg->wfd2_video_formats) { - g_string_append_printf (lines, GST_STRING_EXT_WFD2_VIDEO_FORMATS); - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } - if (msg->wfd2_audio_codecs) { - g_string_append_printf (lines, GST_STRING_EXT_WFD2_AUDIO_CODECS); - g_string_append_printf (lines, GST_STRING_WFD_CRLF); - } -#endif - return g_string_free (lines, FALSE); -} - -static void -read_string_space_ended (gchar * dest, guint size, gchar * src) -{ - guint idx = 0; - - while (!g_ascii_isspace (*src) && *src != '\0') { - if (idx < size - 1) - dest[idx++] = *src; - src++; - } - - if (size > 0) - dest[idx] = '\0'; -} - -#if 0 -static void -read_string_char_ended (gchar * dest, guint size, gchar del, gchar * src) -{ - guint idx = 0; - - while (*src != del && *src != '\0') { - if (idx < size - 1) - dest[idx++] = *src; - src++; - } - - if (size > 0) - dest[idx] = '\0'; -} -#endif - -static void -read_string_type_and_value (gchar * type, gchar * value, guint tsize, - guint vsize, gchar del, gchar * src) -{ - guint idx; - - idx = 0; - while (*src != del && *src != '\0') { - if (idx < tsize - 1) - type[idx++] = *src; - src++; - } - - if (tsize > 0) - type[idx] = '\0'; - - src++; - idx = 0; - while (*src != '\0') { - if (idx < vsize - 1) - value[idx++] = *src; - src++; - } - if (vsize > 0) - value[idx] = '\0'; -} - -static gboolean -gst_wfd_ext_message_parse_line (GstWFDExtMessage * msg, gchar * buffer) -{ - gchar type[8192] = { 0 }; - gchar value[8192] = { 0 }; - gchar temp[8192] = { 0 }; - gchar *p = buffer; - gchar *v = value; - -#define SKIP_SPACE(q) if (*q && g_ascii_isspace(*q)) q++; -#define SKIP_EQUAL(q) if (*q && *q == '=') q++; -#define SKIP_COMMA(q) if (*q && g_ascii_ispunct(*q)) q++; -#define READ_STRING(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); REPLACE_STRING(field, temp); -#if 0 -#define READ_CHAR_END_STRING(field, del) read_string_char_ended(temp, sizeof(temp), del, v); v += strlen(temp); REPLACE_STRING(field, temp); -#endif -#define READ_UINT32(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); field = strtoul(temp, NULL, 16); -#define READ_UINT32_DIGIT(field) read_string_space_ended(temp, sizeof(temp), v); v += strlen(temp); field = strtoul(temp, NULL, 10); - - /*g_print("gst_wfd_ext_config_parse_line input: %s\n", buffer); */ - read_string_type_and_value (type, value, sizeof (type), sizeof (value), ':', - p); - /*g_print("gst_wfd_ext_config_parse_line type:%s value:%s\n", type, value); */ - if (!g_strcmp0 (type, GST_STRING_WFD_CLIENT_RTP_PORTS)) { - msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1); - if (strlen (v)) { - SKIP_SPACE (v); - READ_STRING (msg->client_rtp_ports->profile); - SKIP_SPACE (v); - READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port0); - SKIP_SPACE (v); - READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port1); - SKIP_SPACE (v); - READ_STRING (msg->client_rtp_ports->mode); - } - } - if (!g_strcmp0 (type, GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH)) { - msg->max_buffer_length = g_new0 (GstWFDExtMaxBufferLength, 1); - if (strlen (v)) { - SKIP_SPACE (v); - READ_UINT32_DIGIT (msg->max_buffer_length->length); - } - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (!g_strcmp0 (type, GST_STRING_EXT_WFD2_VIDEO_FORMATS)) { - - GstWFD2VideoCodec *codec_list = NULL; - msg->wfd2_video_formats = g_new0 (GstWFD2VideoFormats, 1); - - if (strstr (v, GST_STRING_WFD_NONE) == NULL) { - SKIP_SPACE (v); - READ_UINT32 (msg->wfd2_video_formats->sink_video_cap.native); - - if (strlen (v)) { - char *str_result = NULL; - msg->wfd2_video_formats->sink_video_cap.video_codec_list = - g_new0 (GstWFD2VideoCodec, 1); - codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; - - while (strlen (v)) { - - SKIP_SPACE (v); - READ_UINT32 (codec_list->codec); - SKIP_SPACE (v); - READ_UINT32 (codec_list->profile); - SKIP_SPACE (v); - READ_UINT32 (codec_list->level); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.CEA_Support); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.VESA_Support); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.HH_Support); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.latency); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.min_slice_size); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.slice_enc_params); - SKIP_SPACE (v); - READ_UINT32 (codec_list->misc_params.frame_rate_control_support); - SKIP_SPACE (v); - - str_result = strstr (v, GST_STRING_WFD_COMMA); - if (str_result != NULL) { - v = str_result; - codec_list->next = g_new0 (GstWFD2VideoCodec, 1); - codec_list = codec_list->next; - - SKIP_COMMA (v); - } else { - break; - } - } - - READ_UINT32 (msg->wfd2_video_formats->sink_video_cap. - non_transcoding_support); - - if (strstr (v, GST_STRING_EXT_WFD2_PORTRAIT_ENABLED)) { - msg->wfd2_video_formats->portrait_mode = TRUE; - } - } - } - } - if (!g_strcmp0 (type, GST_STRING_EXT_WFD2_AUDIO_CODECS)) { - - GstWFD2SinkAudio *codec_list = NULL; - gchar *audio_format_str = NULL; - msg->wfd2_audio_codecs = g_new0 (GstWFD2SinkAudioCap, 1); - - if (strstr (v, GST_STRING_WFD_NONE) == NULL) { - - if (strlen (v)) { - char *str_result = NULL; - msg->wfd2_audio_codecs->sink_audio_list = g_new0 (GstWFD2SinkAudio, 1); - codec_list = msg->wfd2_audio_codecs->sink_audio_list; - - while (strlen (v)) { - - SKIP_SPACE (v); - READ_STRING (audio_format_str); - if (audio_format_str != NULL) { - codec_list->audio_format = - gst_wfd_ext_get_wfd2_audio_format (audio_format_str); - if (codec_list->audio_format == GST_WFD2_AUDIO_FORMAT_UNKNOWN) { - g_print ("Invaild audio format [%s] in wfd2_audio_codecs", - audio_format_str); - } - FREE_STRING (audio_format_str); - } else { - g_print ("There is no audio format in wfd2_audio_codecs"); - break; - } - SKIP_SPACE (v); - READ_UINT32 (codec_list->mode); - SKIP_SPACE (v); - READ_UINT32 (codec_list->latency); - - str_result = strstr (v, GST_STRING_WFD_COMMA); - if (str_result != NULL) { - v = str_result; - codec_list->next = g_new0 (GstWFD2SinkAudio, 1); - codec_list = codec_list->next; - - SKIP_COMMA (v); - } else { - break; - } - } - } - } - } -#endif - return TRUE; -} - -/** -* gst_wfd_ext_message_parse_buffer: -* @data: the start of the buffer -* @size: the size of the buffer -* @msg: the result #GstWFDExtMessage -* -* Parse the contents of @size bytes pointed to by @data and store the result in -* @msg. -* -* Returns: #GST_WFD_OK on success. -*/ -GstWFDResult -gst_wfd_ext_message_parse_buffer (const guint8 * data, guint size, - GstWFDExtMessage * msg) -{ - const gchar *p; - gchar buffer[MAX_LINE_LEN] = { 0 }; - guint idx = 0; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (data != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (size != 0, GST_WFD_EINVAL); - - p = (const gchar *) data; - while (TRUE) { - if (*p == '\0') - break; - - idx = 0; - while (*p != '\n' && *p != '\r' && *p != '\0') { - if (idx < sizeof (buffer) - 1) - buffer[idx++] = *p; - p++; - } - buffer[idx] = '\0'; - - gst_wfd_ext_message_parse_line (msg, buffer); - - if (*p == '\0') - break; - p += 2; - } - - return GST_WFD_OK; -} - -/** -* gst_wfd_ext_message_fdump: -* @msg: a #GstWFDExtMessage -* -* Dump the parsed contents of @msg to stdout. -* -* Returns: a #GstWFDExtMessage. -*/ -GstWFDResult -gst_wfd_ext_message_dump (const GstWFDExtMessage * msg) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - g_print ("===========WFD Message dump========="); - - if (msg->client_rtp_ports) { - g_print (" Client RTP Ports : "); - if (msg->client_rtp_ports->profile) { - g_print ("%s", msg->client_rtp_ports->profile); - g_print (" %d", msg->client_rtp_ports->rtp_port0); - g_print (" %d", msg->client_rtp_ports->rtp_port1); - g_print (" %s", msg->client_rtp_ports->mode); - } - } - - if (msg->max_buffer_length) { - g_print (" Max Buffer Length: "); - g_print ("%d", msg->max_buffer_length->length); - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (msg->wfd2_video_formats) { - GString *str = NULL; - str = - _gst_wfd_ext_convert_wfd2_video_formats_to_gstring ((const - GstWFDExtMessage *) msg->wfd2_video_formats); - if (str != NULL) { - g_print ("%s", str->str); - g_string_free (str, TRUE); - } - } - if (msg->wfd2_audio_codecs) { - GString *str = NULL; - str = - _gst_wfd_ext_convert_wfd2_audio_codecs_to_gstring ((const - GstWFDExtMessage *) msg->wfd2_audio_codecs); - if (str != NULL) { - g_print ("%s", str->str); - g_string_free (str, TRUE); - } - } -#endif - - g_print ("==================================="); - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_set_client_RTP_ports (GstWFDExtMessage * msg, - GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, - GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1) -{ - GString *lines; - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (!msg->client_rtp_ports) - msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1); - - if (trans != GST_WFD_RTSP_TRANS_UNKNOWN) { - lines = g_string_new (""); - if (trans == GST_WFD_RTSP_TRANS_RTP) - g_string_append_printf (lines, GST_STRING_WFD_RTP); - else if (trans == GST_WFD_RTSP_TRANS_RDT) - g_string_append_printf (lines, GST_STRING_WFD_RDT); - - if (profile != GST_WFD_RTSP_PROFILE_UNKNOWN) - g_string_append_printf (lines, GST_STRING_WFD_SLASH); - - if (profile == GST_WFD_RTSP_PROFILE_AVP) - g_string_append_printf (lines, GST_STRING_WFD_AVP); - else if (profile == GST_WFD_RTSP_PROFILE_SAVP) - g_string_append_printf (lines, GST_STRING_WFD_SAVP); - - if (lowertrans != GST_WFD_RTSP_LOWER_TRANS_UNKNOWN) - g_string_append_printf (lines, GST_STRING_WFD_SLASH); - - if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP) { - g_string_append_printf (lines, GST_STRING_WFD_UDP); - g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); - g_string_append_printf (lines, GST_STRING_WFD_UNICAST); - } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST) { - g_string_append_printf (lines, GST_STRING_WFD_UDP); - g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); - g_string_append_printf (lines, GST_STRING_WFD_MULTICAST); - } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_TCP) { - g_string_append_printf (lines, GST_STRING_WFD_TCP); - g_string_append_printf (lines, GST_STRING_WFD_SEMI_COLON); - g_string_append_printf (lines, GST_STRING_WFD_UNICAST); - } else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_HTTP) { - g_string_append_printf (lines, GST_STRING_WFD_TCP_HTTP); - } - - msg->client_rtp_ports->profile = g_string_free (lines, FALSE); - msg->client_rtp_ports->rtp_port0 = rtp_port0; - msg->client_rtp_ports->rtp_port1 = rtp_port1; - msg->client_rtp_ports->mode = g_strdup ("mode=play"); - } - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_get_client_RTP_ports (GstWFDExtMessage * msg, - GstWFDRTSPTransMode * trans, GstWFDRTSPProfile * profile, - GstWFDRTSPLowerTrans * lowertrans, guint32 * rtp_port0, guint32 * rtp_port1) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (msg->client_rtp_ports != NULL, GST_WFD_EINVAL); - - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_RTP)) - *trans = GST_WFD_RTSP_TRANS_RTP; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_RDT)) - *trans = GST_WFD_RTSP_TRANS_RDT; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_AVP)) - *profile = GST_WFD_RTSP_PROFILE_AVP; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_SAVP)) - *profile = GST_WFD_RTSP_PROFILE_SAVP; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UDP) - && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UNICAST)) - *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UDP) - && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_MULTICAST)) - *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_TCP) - && g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_UNICAST)) - *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP; - if (g_strrstr (msg->client_rtp_ports->profile, GST_STRING_WFD_TCP_HTTP)) - *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP; - - *rtp_port0 = msg->client_rtp_ports->rtp_port0; - *rtp_port1 = msg->client_rtp_ports->rtp_port1; - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_set_max_buffer_length (GstWFDExtMessage * msg, guint length) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (!msg->max_buffer_length) - msg->max_buffer_length = g_new0 (GstWFDExtMaxBufferLength, 1); - - msg->max_buffer_length->length = length; - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_get_max_buffer_length (GstWFDExtMessage * msg, - guint * length) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (msg->max_buffer_length != NULL, GST_WFD_EINVAL); - - *length = msg->max_buffer_length->length; - - return GST_WFD_OK; -} - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE -GstWFDResult -gst_wfd_ext_add_wfd2_video_format (GstWFDExtMessage * msg, guint native, - GstWFD2VideoCodecEnum codec, - guint profile, guint level, - guint64 CEA_resolution, guint64 VESA_resolution, guint64 HH_resolution, - guint latency, guint min_slice_size, guint slice_enc_params, - guint frame_rate_control_support, guint non_transcoding_support, - guint portrait_mode) -{ - GstWFD2VideoCodec *video_codec = NULL; - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_video_formats == NULL) - msg->wfd2_video_formats = g_new0 (GstWFD2VideoFormats, 1); - - msg->wfd2_video_formats->portrait_mode = portrait_mode; - msg->wfd2_video_formats->sink_video_cap.native = native; - msg->wfd2_video_formats->sink_video_cap.non_transcoding_support = - non_transcoding_support; - msg->wfd2_video_formats->sink_video_cap.video_codec_list = NULL; - - if (msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) { - msg->wfd2_video_formats->sink_video_cap.video_codec_list = - g_new0 (GstWFD2VideoCodec, 1); - video_codec = msg->wfd2_video_formats->sink_video_cap.video_codec_list; - - } else { - GstWFD2VideoCodec *list = - msg->wfd2_video_formats->sink_video_cap.video_codec_list; - while (list->next) { - list = list->next; - } - list->next = g_new0 (GstWFD2VideoCodec, 1); - video_codec = list->next; - } - - video_codec->codec = codec; - video_codec->level = level; - video_codec->profile = profile; - video_codec->misc_params.CEA_Support = CEA_resolution; - video_codec->misc_params.VESA_Support = VESA_resolution; - video_codec->misc_params.HH_Support = HH_resolution; - video_codec->misc_params.frame_rate_control_support = - frame_rate_control_support; - video_codec->misc_params.latency = latency; - video_codec->misc_params.min_slice_size = min_slice_size; - video_codec->misc_params.slice_enc_params = slice_enc_params; - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_get_wfd2_video_formats (GstWFDExtMessage * msg, - GstWFD2VideoFormats * video_formats) -{ - GstWFDResult res = GST_WFD_OK; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_video_formats == NULL - || msg->wfd2_video_formats->sink_video_cap.video_codec_list == NULL) - res = GST_WFD_EINVAL; - - video_formats = msg->wfd2_video_formats; - - return res; -} - -GstWFDResult -gst_wfd_ext_add_wfd2_audio_codec (GstWFDExtMessage * msg, - GstWFD2AudioFormatEnum audio_format, guint mode, guint latency) -{ - GstWFD2SinkAudio *sink_audio = NULL; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_audio_codecs == NULL) - msg->wfd2_audio_codecs = g_new0 (GstWFD2SinkAudioCap, 1); - - if (msg->wfd2_audio_codecs->sink_audio_list == NULL) { - msg->wfd2_audio_codecs->sink_audio_list = g_new0 (GstWFD2SinkAudio, 1); - sink_audio = msg->wfd2_audio_codecs->sink_audio_list; - } else { - sink_audio = msg->wfd2_audio_codecs->sink_audio_list; - while (sink_audio->next) { - sink_audio = sink_audio->next; - } - sink_audio->next = g_new0 (GstWFD2SinkAudio, 1); - sink_audio = sink_audio->next; - } - - sink_audio->audio_format = audio_format; - sink_audio->mode = mode; - sink_audio->latency = latency; - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_get_wfd2_audio_codecs (GstWFDExtMessage * msg, - GstWFD2SinkAudioCap * audio_codecs) -{ - GstWFDResult res = GST_WFD_OK; - - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_audio_codecs == NULL - || msg->wfd2_audio_codecs->sink_audio_list == NULL) - res = GST_WFD_EINVAL; - - audio_codecs = msg->wfd2_audio_codecs; - return res; -} - -GstWFDResult -gst_wfd_ext_message_init_wfd2_video_formats (GstWFDExtMessage * msg) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_video_formats) { - GstWFD2VideoCodec *codec_list = NULL; - GstWFD2VideoCodec *temp = NULL; - codec_list = msg->wfd2_video_formats->sink_video_cap.video_codec_list; - while (codec_list) { - temp = codec_list; - codec_list = codec_list->next; - FREE_STRING (temp); - } - FREE_STRING (msg->wfd2_video_formats); - } - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_init_wfd2_audio_codecs (GstWFDExtMessage * msg) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_audio_codecs) { - GstWFD2SinkAudio *codec_list = NULL; - GstWFD2SinkAudio *temp = NULL; - codec_list = msg->wfd2_audio_codecs->sink_audio_list; - while (codec_list) { - temp = codec_list; - codec_list = codec_list->next; - FREE_STRING (temp); - } - FREE_STRING (msg->wfd2_audio_codecs); - } - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_get_preferred_video_format (GstWFDExtMessage * msg, - GstWFD2VideoCodecEnum * vCodec, - GstWFD2DisplayNativeResolutionEnum * vNative, guint64 * vNativeResolution, - guint64 * vCEAResolution, guint64 * vVESAResolution, - guint64 * vHHResolution, GstWFD2VideoH265ProfileEnum * vProfile, - GstWFD2VideoH265LevelEnum * vLevel, guint32 * vLatency, - guint32 * min_slice_size, guint32 * slice_enc_params, - guint * frame_rate_control) -{ - guint nativeindex = 0; - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (msg->wfd2_video_formats != NULL, GST_WFD_EINVAL); - g_return_val_if_fail (msg->wfd2_video_formats->sink_video_cap. - video_codec_list != NULL, GST_WFD_EINVAL); - - *vCodec = msg->wfd2_video_formats->sink_video_cap.video_codec_list->codec; - *vNative = msg->wfd2_video_formats->sink_video_cap.native & 0x7; - nativeindex = msg->wfd2_video_formats->sink_video_cap.native >> 3; - *vNativeResolution = (guint64) 1 << nativeindex; - *vProfile = msg->wfd2_video_formats->sink_video_cap.video_codec_list->profile; - *vLevel = msg->wfd2_video_formats->sink_video_cap.video_codec_list->level; - *vCEAResolution = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - CEA_Support; - *vVESAResolution = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - VESA_Support; - *vHHResolution = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - HH_Support; - *vLatency = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - latency; - *min_slice_size = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - min_slice_size; - *slice_enc_params = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - slice_enc_params; - *frame_rate_control = - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - frame_rate_control_support; - - return GST_WFD_OK; -} - -GstWFDResult -gst_wfd_ext_message_get_preferred_audio_format (GstWFDExtMessage * msg, - GstWFD2AudioFormatEnum * aCodec, GstWFD2AudioFreq * aFreq, - GstWFD2AudioChannels * aChanels, guint * aBitwidth, guint32 * aLatency) -{ - g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL); - - if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == - GST_WFD2_AUDIO_FORMAT_LPCM) { - *aCodec = GST_WFD2_AUDIO_FORMAT_LPCM; - - switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { - case GST_WFD2_LPCM_441KH_16B_2C: - *aFreq = 44100; - *aChanels = 2; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_48KH_16B_2C: - *aFreq = 48000; - *aChanels = 2; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_48KH_16B_6C: - *aFreq = 48000; - *aChanels = 6; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_48KH_16B_8C: - *aFreq = 48000; - *aChanels = 8; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_48KH_24B_2C: - *aFreq = 48000; - *aChanels = 2; - *aBitwidth = 24; - break; - case GST_WFD2_LPCM_96KH_16B_2C: - *aFreq = 96000; - *aChanels = 2; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_96KH_24B_2C: - *aFreq = 96000; - *aChanels = 2; - *aBitwidth = 24; - break; - case GST_WFD2_LPCM_96KH_24B_6C: - *aFreq = 96000; - *aChanels = 6; - *aBitwidth = 24; - break; - case GST_WFD2_LPCM_96KH_24B_8C: - *aFreq = 96000; - *aChanels = 8; - *aBitwidth = 24; - break; - default: - break; - } - } else if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == - GST_WFD2_AUDIO_FORMAT_AAC) { - *aCodec = GST_WFD2_AUDIO_FORMAT_AAC; - - switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { - case GST_WFD2_AAC_48KH_16B_2C: - *aFreq = 48000; - *aChanels = 2; - *aBitwidth = 16; - break; - case GST_WFD2_AAC_48KH_16B_4C: - *aFreq = 48000; - *aChanels = 4; - *aBitwidth = 16; - break; - case GST_WFD2_LPCM_48KH_16B_6C: - *aFreq = 48000; - *aChanels = 6; - *aBitwidth = 16; - break; - case GST_WFD2_AAC_48KH_16B_8C: - *aFreq = 48000; - *aChanels = 8; - *aBitwidth = 16; - break; - default: - break; - } - - } else if (msg->wfd2_audio_codecs->sink_audio_list->audio_format == - GST_WFD2_AUDIO_FORMAT_AC3) { - *aCodec = GST_WFD2_AUDIO_FORMAT_AC3; - - switch (msg->wfd2_audio_codecs->sink_audio_list->mode) { - case GST_WFD2_AC3_48KH_16B_2C: - *aFreq = 48000; - *aChanels = 2; - *aBitwidth = 16; - break; - case GST_WFD2_AC3_48KH_16B_4C: - *aFreq = 48000; - *aChanels = 4; - *aBitwidth = 16; - break; - case GST_WFD2_AC3_48KH_16B_6C: - *aFreq = 48000; - *aChanels = 6; - *aBitwidth = 16; - break; - default: - break; - } - - } - *aLatency = msg->wfd2_audio_codecs->sink_audio_list->latency; - return GST_WFD_OK; -} - -#endif diff --git a/wfdextmanager/gstwfdextmessage.h b/wfdextmanager/gstwfdextmessage.h deleted file mode 100755 index a4204fd..0000000 --- a/wfdextmanager/gstwfdextmessage.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * wfdextmessage - * - * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi , ByungWook Jang - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _GST_WFD_EXT_MESSAGE_H__ -#define _GST_WFD_EXT_MESSAGE_H__ - -#include -#include -#include "../wfdmanager/wfdbase/gstwfdsinkmessage.h" - -G_BEGIN_DECLS; - -#define GST_TYPE_WFD_SINK_MESSAGE (gst_wfd_ext_message_get_type()) -#define GST_WFD_EXT_MESSAGE_CAST(object) ((GstWFDExtMessage *)(object)) -#define GST_WFD_EXT_MESSAGE(object) (GST_WFD_EXT_MESSAGE_CAST(object)) - -#define ENABLE_WFD2_EXTENDED_CODEC_FEATURE -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE -#define GST_WFD2_CEA_NONE 0 -#define GST_WFD2_CEA_640x480P60 (1 << 0) -#define GST_WFD2_CEA_720x480P60 (1 << 1) -#define GST_WFD2_CEA_720x480I60 (1 << 2) -#define GST_WFD2_CEA_720x576P50 (1 << 3) -#define GST_WFD2_CEA_720x576I50 (1 << 4) -#define GST_WFD2_CEA_1280x720P30 (1 << 5) -#define GST_WFD2_CEA_1280x720P60 (1 << 6) -#define GST_WFD2_CEA_1920x1080P30 (1 << 7) -#define GST_WFD2_CEA_1920x1080P60 (1 << 8) -#define GST_WFD2_CEA_1920x1080I60 (1 << 9) -#define GST_WFD2_CEA_1280x720P25 (1 << 10) -#define GST_WFD2_CEA_1280x720P50 (1 << 11) -#define GST_WFD2_CEA_1920x1080P25 (1 << 12) -#define GST_WFD2_CEA_1920x1080P50 (1 << 13) -#define GST_WFD2_CEA_1920x1080I50 (1 << 14) -#define GST_WFD2_CEA_1280x720P24 (1 << 15) -#define GST_WFD2_CEA_1920x1080P24 (1 << 16) -#define GST_WFD2_CEA_3840x2160P24 (1 << 17) -#define GST_WFD2_CEA_3840x2160P25 (1 << 18) -#define GST_WFD2_CEA_3840x2160P30 (1 << 19) -#define GST_WFD2_CEA_3840x2160P50 (1 << 20) -#define GST_WFD2_CEA_3840x2160P60 (1 << 21) -#define GST_WFD2_CEA_4096x2160P24 (1 << 22) -#define GST_WFD2_CEA_4096x2160P25 (1 << 23) -#define GST_WFD2_CEA_4096x2160P30 (1 << 24) -#define GST_WFD2_CEA_4096x2160P50 (1 << 25) -#define GST_WFD2_CEA_4096x2160P60 (1 << 26) - -#define GST_WFD2_VESA_NONE 0 -#define GST_WFD2_VESA_800x600P30 (1 << 0) -#define GST_WFD2_VESA_800x600P60 (1 << 1) -#define GST_WFD2_VESA_1024x768P30 (1 << 2) -#define GST_WFD2_VESA_1024x768P60 (1 << 3) -#define GST_WFD2_VESA_1152x864P30 (1 << 4) -#define GST_WFD2_VESA_1152x864P60 (1 << 5) -#define GST_WFD2_VESA_1280x768P30 (1 << 6) -#define GST_WFD2_VESA_1280x768P60 (1 << 7) -#define GST_WFD2_VESA_1280x800P30 (1 << 8) -#define GST_WFD2_VESA_1280x800P60 (1 << 9) -#define GST_WFD2_VESA_1360x768P30 (1 << 10) -#define GST_WFD2_VESA_1360x768P60 (1 << 11) -#define GST_WFD2_VESA_1366x768P30 (1 << 12) -#define GST_WFD2_VESA_1366x768P60 (1 << 13) -#define GST_WFD2_VESA_1280x1024P30 (1 << 14) -#define GST_WFD2_VESA_1280x1024P60 (1 << 15) -#define GST_WFD2_VESA_1400x1050P30 (1 << 16) -#define GST_WFD2_VESA_1400x1050P60 (1 << 17) -#define GST_WFD2_VESA_1440x900P30 (1 << 18) -#define GST_WFD2_VESA_1440x900P60 (1 << 19) -#define GST_WFD2_VESA_1600x900P30 (1 << 20) -#define GST_WFD2_VESA_1600x900P60 (1 << 21) -#define GST_WFD2_VESA_1600x1200P30 (1 << 22) -#define GST_WFD2_VESA_1600x1200P60 (1 << 23) -#define GST_WFD2_VESA_1680x1024P30 (1 << 24) -#define GST_WFD2_VESA_1680x1024P60 (1 << 25) -#define GST_WFD2_VESA_1680x1050P30 (1 << 26) -#define GST_WFD2_VESA_1680x1050P60 (1 << 27) -#define GST_WFD2_VESA_1920x1200P30 (1 << 28) -#define GST_WFD2_VESA_1920x1200P60 (1 << 29) -#define GST_WFD2_VESA_2560x1440P30 (1 << 30) -#define GST_WFD2_VESA_2560x1440P60 (1 << 31) -#define GST_WFD2_VESA_2560x1600P30 (1ULL << 32) -#define GST_WFD2_VESA_2560x1600P60 (1ULL << 33) - -#define GST_WFD2_HH_NONE 0 -#define GST_WFD2_HH_800x480P30 (1 << 0) -#define GST_WFD2_HH_800x480P60 (1 << 1) -#define GST_WFD2_HH_854x480P30 (1 << 2) -#define GST_WFD2_HH_854x480P60 (1 << 3) -#define GST_WFD2_HH_864x480P30 (1 << 4) -#define GST_WFD2_HH_864x480P60 (1 << 5) -#define GST_WFD2_HH_640x360P30 (1 << 6) -#define GST_WFD2_HH_640x360P60 (1 << 7) -#define GST_WFD2_HH_960x540P30 (1 << 8) -#define GST_WFD2_HH_960x540P60 (1 << 9) -#define GST_WFD2_HH_848x480P30 (1 << 10) -#define GST_WFD2_HH_848x480P60 (1 << 11) - -typedef enum { - GST_WFD2_VIDEO_CODEC_NONE = 0, - GST_WFD2_VIDEO_CODEC_H264 = (1 << 0), - GST_WFD2_VIDEO_CODEC_H265 = (1 << 1) -} GstWFD2VideoCodecEnum; - -typedef enum { - GST_WFD2_DISPALY_NATIVE_CEA = 0, - GST_WFD2_DISPALY_NATIVE_VESA = 1, - GST_WFD2_DISPALY_NATIVE_HH = 2 -} GstWFD2DisplayNativeResolutionEnum; - -typedef enum { - GST_WFD2_H264_UNKNOWN_PROFILE = 0, - GST_WFD2_H264_CBP = (1 << 0), /* Constrained Baseline Profile */ - GST_WFD2_H264_CHP = (1 << 1), /* Constrained High Profile */ - GST_WFD2_H264_CHP2 = (1 << 2), /* Constrained High Profile2 */ - GST_WFD2_H264_BP = (1 << 3), /* Baseline Profile */ - GST_WFD2_H264_MP = (1 << 4), /* Main Profile */ - GST_WFD2_H264_HP = (1 << 5) /* High Profile */ -} GstWFD2VideoH264ProfileEnum; - -typedef enum { - GST_WFD2_H265_UNKNOWN_PROFILE = 0, - GST_WFD2_H265_MAIN_PROFILE = (1 << 0), - GST_WFD2_H265_MAIN_10_PROFILE = (1 << 1), - GST_WFD2_H265_MAIN_444_PROFILE = (1 << 2), - GST_WFD2_H265_MAIN_STILL_PICTURE_PROFILE = (1 << 3), - GST_WFD2_H265_SCREEN_CONTENT_CODING_PROFILE = (1 << 4), - GST_WFD2_H265_MAIN_444_10_PROFILE = (1 << 5) -} GstWFD2VideoH265ProfileEnum; - -typedef enum { - GST_WFD2_H264_LEVEL_UNKNOWN = 0, - GST_WFD2_H264_LEVEL_3_1 = (1 << 0), - GST_WFD2_H264_LEVEL_3_2 = (1 << 1), - GST_WFD2_H264_LEVEL_4 = (1 << 2), - GST_WFD2_H264_LEVEL_4_1 = (1 << 3), - GST_WFD2_H264_LEVEL_4_2 = (1 << 4), - GST_WFD2_H264_LEVEL_5 = (1 << 5), - GST_WFD2_H264_LEVEL_5_1 = (1 << 6), - GST_WFD2_H264_LEVEL_5_2 = (1 << 7) -} GstWFD2VideoH264LevelEnum; - -typedef enum { - GST_WFD2_H265_LEVEL_UNKNOWN = 0, - GST_WFD2_H265_LEVEL_3_1 = (1 << 1), - GST_WFD2_H265_LEVEL_4 = (1 << 2), - GST_WFD2_H265_LEVEL_4_1 = (1 << 3), - GST_WFD2_H265_LEVEL_5 = (1 << 4), - GST_WFD2_H265_LEVEL_5_1 = (1 << 5) -} GstWFD2VideoH265LevelEnum; - -typedef enum { - GST_WFD2_AUX_STREAM_UNKNOWN = 0, - GST_WFD2_AUX_STREAM_PNG = (1 << 0), - GST_WFD2_AUX_STREAM_JPEG = (1 << 1), - GST_WFD2_AUX_STREAM_H264_CBP = (1 << 2) -} GstWFD2AuxStreamCodecEnum; - -typedef enum { - GST_WFD2_AUDIO_FORMAT_UNKNOWN = 0, - GST_WFD2_AUDIO_FORMAT_LPCM = (1 << 0), - GST_WFD2_AUDIO_FORMAT_AAC = (1 << 1), - GST_WFD2_AUDIO_FORMAT_AC3 = (1 << 2) -} GstWFD2AudioFormatEnum; - -typedef enum { - GST_WFD2_LPCM_UNKNOWN_MODE = 0, - GST_WFD2_LPCM_441KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ - GST_WFD2_LPCM_48KH_16B_2C = (1 << 1), - GST_WFD2_LPCM_48KH_16B_6C = (1 << 2), - GST_WFD2_LPCM_48KH_16B_8C = (1 << 3), - GST_WFD2_LPCM_48KH_24B_2C = (1 << 4), - GST_WFD2_LPCM_96KH_16B_2C = (1 << 5), - GST_WFD2_LPCM_96KH_24B_2C = (1 << 6), - GST_WFD2_LPCM_96KH_24B_6C = (1 << 7), - GST_WFD2_LPCM_96KH_24B_8C = (1 << 8) -} GstWFD2LpcmModeEnum; - -typedef enum { - GST_WFD2_AAC_UNKNOWN_MODE = 0, - GST_WFD2_AAC_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ - GST_WFD2_AAC_48KH_16B_4C = (1 << 1), - GST_WFD2_AAC_48KH_16B_6C = (1 << 2), - GST_WFD2_AAC_48KH_16B_8C = (1 << 3) -} GstWFD2AacModeEnum; - -typedef enum { - GST_WFD2_AC3_UNKNOWN_MODE = 0, - GST_WFD2_AC3_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ - GST_WFD2_AC3_48KH_16B_4C = (1 << 1), - GST_WFD2_AC3_48KH_16B_6C = (1 << 2) -} GstWFD2AC3ModeEnum; - -typedef enum { - GST_WFD2_RCA_LPCM_UNKNOWN_MODE = 0, - GST_WFD2_RCA_LPCM_48KH_16B_2C = (1 << 0), /* Samplirng Frequency(kHz), Bit-width(bits), Channels */ -} GstWFD2RcaLpcmModeEnum; - -typedef enum { - GST_WFD2_FREQ_UNKNOWN = 0, - GST_WFD2_FREQ_44100 = (1 << 0), - GST_WFD2_FREQ_48000 = (1 << 1), - GST_WFD2_FREQ_96000 = (1 << 2) -} GstWFD2AudioFreq; - -typedef enum { - GST_WFD2_CHANNEL_UNKNOWN = 0, - GST_WFD2_CHANNEL_2 = (1 << 0), - GST_WFD2_CHANNEL_4 = (1 << 1), - GST_WFD2_CHANNEL_6 = (1 << 2), - GST_WFD2_CHANNEL_8 = (1 << 3) -} GstWFD2AudioChannels; - -typedef enum { - GST_WFD2_EXTENDED_CAPABILITY_NONE = 0, - GST_WFD2_EXTENDED_CAPABILITY_UIBC = (1 << 0), - GST_WFD2_EXTENDED_CAPABILITY_I2C = (1 << 1), - GST_WFD2_EXTENDED_CAPABILITY_PREFERRED_DISPLAY_MODE = (1 << 2), - GST_WFD2_EXTENDED_CAPABILITY_STANBY_RESUME_CONTROL = (1 << 3), - GST_WFD2_EXTENDED_CAPABILITY_TDLS = (1 << 4), - GST_WFD2_EXTENDED_CAPABILITY_TDLS_BSSID = (1 << 5), - GST_WFD2_EXTENDED_CAPABILITY_RCA_BIDIRECTIONAL_VOICE = (1 << 6), - GST_WFD2_EXTENDED_CAPABILITY_RCA_VOICE_COMMAND = (1 << 7) -} GstWFD2ExtendedCapabilitiesEnum; - -typedef struct _GstWFD2SinkAudio{ - GstWFD2AudioFormatEnum audio_format; - guint mode; - guint latency; - struct _GstWFD2SinkAudio *next; -} GstWFD2SinkAudio; - -typedef struct { - GstWFD2SinkAudio *sink_audio_list; -} GstWFD2SinkAudioCap; - -typedef struct { - guint64 CEA_Support; - guint64 VESA_Support; - guint64 HH_Support; - guint latency; - guint min_slice_size; - guint slice_enc_params; - guint frame_rate_control_support; -} GstWFD2VideoMiscParams; - -typedef struct _GstWFD2VideoCodec { - GstWFD2VideoCodecEnum codec; - guint profile; - guint level; - GstWFD2VideoMiscParams misc_params; - struct _GstWFD2VideoCodec *next; -} GstWFD2VideoCodec; - -typedef struct { - guint native; - GstWFD2VideoCodec *video_codec_list; - guint non_transcoding_support; -} GstWFD2SinkVideoCap; - -typedef struct { - GstWFD2SinkVideoCap sink_video_cap; - gboolean portrait_mode; -} GstWFD2VideoFormats; - -#define GST_STRING_EXT_WFD2_VIDEO_FORMATS "wfd2_video_formats" -#define GST_STRING_EXT_WFD2_AUDIO_CODECS "wfd2_audio_codecs" -#define GST_STRING_EXT_WFD2_PORTRAIT_ENABLED "enabled" -#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_LPCM "LPCM" -#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_AAC "AAC" -#define GST_STRING_EXT_WFD2_AUDIO_FORMAT_AC3 "AC3" - -#endif - -#define GST_STRING_WFD_EXT_MAX_BUFFER_LENGTH "wfd_vnd_sec_max_buffer_length" - -typedef struct { - guint32 length; -} GstWFDExtMaxBufferLength; - -typedef struct { - GstWFDClientRtpPorts *client_rtp_ports; - GstWFDExtMaxBufferLength *max_buffer_length; -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - GstWFD2VideoFormats *wfd2_video_formats; - GstWFD2SinkAudioCap *wfd2_audio_codecs; - -#endif -} GstWFDExtMessage; - -GType gst_wfd_ext_message_get_type (void); - -/* Session descriptions */ -GstWFDResult gst_wfd_ext_message_new(GstWFDExtMessage **msg); -GstWFDResult gst_wfd_ext_message_init(GstWFDExtMessage *msg); -void gst_wfd_ext_message_uninit(GstWFDExtMessage *msg); -void gst_wfd_ext_message_free(GstWFDExtMessage *msg); -GstWFDResult gst_wfd_ext_message_copy (const GstWFDExtMessage *msg, GstWFDExtMessage **copy); -GstWFDResult gst_wfd_ext_message_parse_buffer(const guint8 *data, guint size, GstWFDExtMessage *msg); -gchar *gst_wfd_ext_message_as_text(const GstWFDExtMessage *msg); -gchar *gst_wfd_ext_parameter_names_as_text(const GstWFDExtMessage *msg); -GstWFDResult gst_wfd_ext_message_dump(const GstWFDExtMessage *msg); - -GstWFDResult gst_wfd_ext_message_set_max_buffer_length(GstWFDExtMessage *msg, guint length); -GstWFDResult gst_wfd_ext_message_get_max_buffer_length(GstWFDExtMessage *msg, guint *length); -GstWFDResult gst_wfd_ext_message_set_client_RTP_ports(GstWFDExtMessage *msg, GstWFDRTSPTransMode trans, GstWFDRTSPProfile profile, - GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1); -GstWFDResult gst_wfd_ext_message_get_client_RTP_ports(GstWFDExtMessage *msg, GstWFDRTSPTransMode *trans, GstWFDRTSPProfile *profile, - GstWFDRTSPLowerTrans *lowertrans, guint32 *rtp_port0, guint32 *rtp_port1); - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE -GstWFDResult gst_wfd_ext_add_wfd2_video_format(GstWFDExtMessage *msg, guint native, - GstWFD2VideoCodecEnum codec, - guint profile, guint level, - guint64 CEA_resolution, guint64 VESA_resolution, guint64 HH_resolution, - guint latency, guint min_slice_size, guint slice_enc_params, guint frame_rate_control_support, - guint non_transcoding_support, guint portrait_mode); -GstWFDResult gst_wfd_ext_get_wfd2_video_formats (GstWFDExtMessage *msg, GstWFD2VideoFormats *video_formats); - -GstWFDResult gst_wfd_ext_add_wfd2_audio_codec(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum audio_format, guint mode, guint latency); -GstWFDResult gst_wfd_ext_get_wfd2_audio_codecs (GstWFDExtMessage *msg, GstWFD2SinkAudioCap *audio_codecs); -GstWFD2AudioFormatEnum gst_wfd_ext_get_wfd2_audio_format(gchar *str); -const char *gst_wfd_ext_peek_wfd2_audio_format_string(const GstWFD2AudioFormatEnum audio_format); -GstWFDResult gst_wfd_ext_message_init_wfd2_video_formats(GstWFDExtMessage *msg); -GstWFDResult gst_wfd_ext_message_init_wfd2_audio_codecs(GstWFDExtMessage *msg); - -GstWFDResult gst_wfd_ext_message_get_preferred_video_format(GstWFDExtMessage *msg, GstWFD2VideoCodecEnum *vCodec, - GstWFD2DisplayNativeResolutionEnum *vNative, guint64 *vNativeResolution, - guint64 *vCEAResolution, guint64 *vVESAResolution, - guint64 *vHHResolution, GstWFD2VideoH265ProfileEnum *vProfile, - GstWFD2VideoH265LevelEnum *vLevel, guint32 *vLatency, guint32 *min_slice_size, guint32 *slice_enc_params, guint *frame_rate_control); - -GstWFDResult gst_wfd_ext_message_get_preferred_audio_format(GstWFDExtMessage *msg, GstWFD2AudioFormatEnum *aCodec, GstWFD2AudioFreq *aFreq, GstWFD2AudioChannels *aChanels, - guint *aBitwidth, guint32 *aLatency); - - -#endif - -G_END_DECLS - -#endif /* _GST_WFD_EXT_MESSAGE_H__ */ - diff --git a/wfdextmanager/gstwfdextsrc.c b/wfdextmanager/gstwfdextsrc.c deleted file mode 100644 index 8ce88cc..0000000 --- a/wfdextmanager/gstwfdextsrc.c +++ /dev/null @@ -1,2124 +0,0 @@ -/* - * wfdextsrc - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** -* SECTION:element-wfdextsrc -* -* Makes a connection to an RTSP server and read the data. -* Device recognition is through wifi direct. -* wfdextsrc strictly follows Wifi display specification. -* -* RTSP supports transport over TCP or UDP in unicast or multicast mode. By -* default wfdextsrc will negotiate a connection in the following order: -* UDP unicast/UDP multicast/TCP. The order cannot be changed but the allowed -* protocols can be controlled with the #GstWFDExtSrc:protocols property. -* -* wfdextsrc currently understands WFD capability negotiation messages -* -* wfdextsrc will internally instantiate an RTP session manager element -* that will handle the RTCP messages to and from the server, jitter removal, -* packet reordering along with providing a clock for the pipeline. -* This feature is implemented using the gstrtpbin element. -* -* wfdextsrc acts like a live source and will therefore only generate data in the -* PLAYING state. -* -* -* Example launch line -* |[ -* gst-launch wfdextsrc location=rtsp://some.server/url ! fakesink -* ]| Establish a connection to an RTSP server and send the raw RTP packets to a -* fakesink. -* -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "gstwfdextsrc.h" - -GST_DEBUG_CATEGORY_STATIC (wfdextsrc_debug); -#define GST_CAT_DEFAULT (wfdextsrc_debug) - -/* signals and args */ -/* -enum { - LAST_SIGNAL -}; -static guint gst_wfdextsrc_signals[LAST_SIGNAL]; -*/ -enum -{ - PROP_0, - PROP_DO_RTCP, - PROP_LATENCY, - PROP_UDP_BUFFER_SIZE, - PROP_UDP_TIMEOUT, - PROP_DO_REQUEST, -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - PROP_AUDIO_R2_PARAM, - PROP_VIDEO_R2_PARAM, -#endif - PROP_LAST -}; - -#define DEFAULT_DO_RTCP TRUE -#define DEFAULT_LATENCY_MS 2000 -#define DEFAULT_UDP_BUFFER_SIZE 0x80000 -#define DEFAULT_UDP_TIMEOUT 10000000 -#define DEFAULT_DO_REQUEST FALSE - -/* object */ -static void gst_wfd_ext_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_wfd_ext_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_wfd_ext_src_finalize (GObject * object); - -/* wfdbasesrc */ -static GstRTSPResult gst_wfd_ext_src_handle_set_parameter (GstWFDBaseSrc * bsrc, - GstRTSPMessage * request, GstRTSPMessage * response); -static GstRTSPResult gst_wfd_ext_src_handle_get_parameter (GstWFDBaseSrc * bsrc, - GstRTSPMessage * request, GstRTSPMessage * response); -static GstRTSPResult gst_wfd_ext_src_configure_transport (GstWFDBaseSrc * bsrc, - GstRTSPTransport * transport); -static GstRTSPResult gst_wfd_ext_src_prepare_transport (GstWFDBaseSrc * bsrc, - gint rtpport, gint rtcpport); -static gboolean gst_wfd_ext_src_push_event (GstWFDBaseSrc * bsrc, - GstEvent * event); -static void gst_wfd_ext_src_set_state (GstWFDBaseSrc * src, GstState state); -static void gst_wfd_ext_src_cleanup (GstWFDBaseSrc * bsrc); - -static GstRTSPResult gst_wfd_ext_src_switch_transport (GstWFDExtSrc * src, - GstWFDRTSPLowerTrans lowertrans, guint32 port0, guint32 port1); -static void gst_wfd_ext_src_free_tcp (GstWFDExtSrc * src); - -/* static guint gst_wfd_ext_srcext_signals[LAST_SIGNAL] = { 0 }; */ - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT(wfdextsrc_debug, "wfdextsrc", 0, "Wi-Fi Display Sink Extension source"); - -#define gst_wfd_ext_src_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstWFDExtSrc, gst_wfd_ext_src, GST_TYPE_WFD_BASE_SRC, - _do_init); - -static void -gst_wfd_ext_src_class_init (GstWFDExtSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstWFDBaseSrcClass *gstwfdbasesrc_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstwfdbasesrc_class = (GstWFDBaseSrcClass *) klass; - - gobject_class->set_property = gst_wfd_ext_src_set_property; - gobject_class->get_property = gst_wfd_ext_src_get_property; - gobject_class->finalize = gst_wfd_ext_src_finalize; - - g_object_class_install_property (gobject_class, PROP_DO_RTCP, - g_param_spec_boolean ("do-rtcp", "Do RTCP", - "Send RTCP packets, disable for old incompatible server.", - DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_LATENCY, - g_param_spec_uint ("latency", "Buffer latency in ms", - "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_UDP_BUFFER_SIZE, - g_param_spec_int ("udp-buffer-size", "UDP Buffer Size", - "Size of the kernel UDP receive buffer in bytes, 0=default", - 0, G_MAXINT, DEFAULT_UDP_BUFFER_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_UDP_TIMEOUT, - g_param_spec_uint64 ("timeout", "Timeout", - "Fail after timeout microseconds on UDP connections (0 = disabled)", - 0, G_MAXUINT64, DEFAULT_UDP_TIMEOUT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_DO_REQUEST, - g_param_spec_boolean ("do-request", "Enable RTP Retransmission Request", - "Send RTCP FB packets and handel retransmitted RTP packets.", - DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - g_object_class_install_property (gobject_class, PROP_AUDIO_R2_PARAM, - g_param_spec_boxed ("audio-r2-param", "audio r2 parameters", - "A GstStructure mapped for wfd audio parameters, " - "See all attributes in WFD specification(wfd-audio-codecs)." - "\n audio_codec: LPCM:0x01, AAC:0x02, AC3:0x04" - "\n audio_latency: an integer" - "\n audio_channels: 2:0x01, 4:0x02, 6:0x04 8:0x08" - "\n audio_sampling_frequency: 44.1khz:1, 48khz:2\n", - GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_VIDEO_R2_PARAM, - g_param_spec_boxed ("video-r2-param", "video r2 parameters", - "A GstStructure mapped for wfd video parameters, " - "See all attributes in WFD specification(wfd2-video-formats).\n", - GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); -#endif - - gst_element_class_set_static_metadata (gstelement_class, - "Wi-Fi Display Sink source element", "Source/Network", - "Negotiate the capability and receive the RTP packets from the Wi-Fi Display source", - "YeJin Cho "); - - gstwfdbasesrc_class->handle_set_parameter = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_handle_set_parameter); - gstwfdbasesrc_class->handle_get_parameter = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_handle_get_parameter); - gstwfdbasesrc_class->configure_transport = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_configure_transport); - gstwfdbasesrc_class->prepare_transport = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_prepare_transport); - gstwfdbasesrc_class->push_event = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_push_event); - gstwfdbasesrc_class->set_state = - GST_DEBUG_FUNCPTR (gst_wfd_ext_src_set_state); - gstwfdbasesrc_class->cleanup = GST_DEBUG_FUNCPTR (gst_wfd_ext_src_cleanup); -} - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - -static GstStructure * -gst_wfd_ext_set_default_audio_r2_param () -{ - GstStructure *param = NULL; - param = gst_structure_new ("audio_param", - "audio_codec", G_TYPE_UINT, 0x3, - "audio_lpcm_mode", G_TYPE_UINT, 0x1, - "audio_aac_mode", G_TYPE_UINT, 0x1, - "audio_ac3_mode", G_TYPE_UINT, 0x1, NULL); - - return param; -} - -static GstStructure * -gst_wfd_ext_set_default_video_r2_param () -{ - GstStructure *param = NULL; - param = gst_structure_new ("video_param", - "video_codec", G_TYPE_UINT, 0x1, - "video_native_resolution", G_TYPE_UINT, 0x20, - "video_cea_support", G_TYPE_UINT, 0x194ab, - "video_vesa_support", G_TYPE_UINT, 0x15555555, - "video_hh_support", G_TYPE_UINT, 0x555, - "video_profile", G_TYPE_UINT, 0x1, - "video_level", G_TYPE_UINT, 0x2, - "video_latency", G_TYPE_UINT, 0x0, - "video_vertical_resolution", G_TYPE_INT, 1200, - "video_horizontal_resolution", G_TYPE_INT, 1920, - "video_minimum_slicing", G_TYPE_INT, 0, - "video_slice_enc_param", G_TYPE_INT, 200, - "video_framerate_control_support", G_TYPE_INT, 11, - "video_non_transcoding_support", G_TYPE_INT, 0, NULL); - - return param; -} -#endif - -static void -gst_wfd_ext_src_init (GstWFDExtSrc * src) -{ - gint i; - - src->do_rtcp = DEFAULT_DO_RTCP; - src->latency = DEFAULT_LATENCY_MS; - src->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; - src->udp_timeout = DEFAULT_UDP_TIMEOUT; - src->do_request = DEFAULT_DO_REQUEST; - - src->session = NULL; - src->requester = NULL; - src->wfdrtpbuffer = NULL; - for (i = 0; i < 3; i++) { - src->channelpad[i] = NULL; - src->udpsrc[i] = NULL; - src->udpsink[i] = NULL; - } - src->blockid = 0; - src->blockedpad = NULL; - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - src->audio_r2_param = gst_wfd_ext_set_default_audio_r2_param (); - src->video_r2_param = gst_wfd_ext_set_default_video_r2_param (); -#endif - -} - -static void -gst_wfd_ext_src_finalize (GObject * object) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if (src->audio_r2_param) - gst_structure_free (src->audio_r2_param); - src->audio_r2_param = NULL; - if (src->video_r2_param) - gst_structure_free (src->video_r2_param); - src->video_r2_param = NULL; -#endif - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_wfd_ext_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); - - switch (prop_id) { - case PROP_DO_RTCP: - src->do_rtcp = g_value_get_boolean (value); - break; - case PROP_LATENCY: - src->latency = g_value_get_uint (value); - break; - case PROP_UDP_BUFFER_SIZE: - src->udp_buffer_size = g_value_get_int (value); - break; - case PROP_UDP_TIMEOUT: - src->udp_timeout = g_value_get_uint64 (value); - break; - case PROP_DO_REQUEST: - src->do_request = g_value_get_boolean (value); - break; -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - case PROP_AUDIO_R2_PARAM: - { - const GstStructure *s = gst_value_get_structure (value); - if (src->audio_r2_param) - gst_structure_free (src->audio_r2_param); - if (s) - src->audio_r2_param = gst_structure_copy (s); - else - src->audio_r2_param = NULL; - break; - } - case PROP_VIDEO_R2_PARAM: - { - const GstStructure *s = gst_value_get_structure (value); - if (src->video_r2_param) - gst_structure_free (src->video_r2_param); - if (s) - src->video_r2_param = gst_structure_copy (s); - else - src->video_r2_param = NULL; - break; - } -#endif - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_wfd_ext_src_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (object); - - switch (prop_id) { - case PROP_DO_RTCP: - g_value_set_boolean (value, src->do_rtcp); - break; - case PROP_LATENCY: - g_value_set_uint (value, src->latency); - break; - case PROP_UDP_BUFFER_SIZE: - g_value_set_int (value, src->udp_buffer_size); - break; - case PROP_UDP_TIMEOUT: - g_value_set_uint64 (value, src->udp_timeout); - break; - case PROP_DO_REQUEST: - g_value_set_boolean (value, src->do_request); - break; -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - case PROP_AUDIO_R2_PARAM: - gst_value_set_structure (value, src->audio_r2_param); - break; - case PROP_VIDEO_R2_PARAM: - gst_value_set_structure (value, src->video_r2_param); - break; -#endif - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE -static GstRTSPResult -gst_wfd_ext_src_get_audio_parameter (GstWFDBaseSrc * src, - GstWFDExtMessage * msg) -{ - guint audio_format = 0; - guint audio_channels = 0; - guint audio_frequency = 0; - guint audio_bitwidth = 0; - guint32 audio_latency = 0; - GstWFDResult wfd_res = GST_WFD_OK; - - wfd_res = - gst_wfd_ext_message_get_preferred_audio_format (msg, &audio_format, - &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); - if (wfd_res != GST_WFD_OK) { - GST_ERROR_OBJECT (src, "Failed to get preferred audio format."); - return GST_RTSP_ERROR; - } - - GST_ERROR_OBJECT (src, "channel:%d, audio_frequency:%d", audio_channels, - audio_frequency); - - GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); - gst_structure_set (stream_info, - "audio_format", G_TYPE_STRING, - gst_wfd_ext_peek_wfd2_audio_format_string (audio_format), - "audio_channels", G_TYPE_UINT, audio_channels, "audio_rate", G_TYPE_UINT, - audio_frequency, "audio_bitwidth", G_TYPE_UINT, audio_bitwidth, NULL); - gst_wfd_base_src_set_streaminfo (GST_WFD_BASE_SRC (src), stream_info); - - return GST_RTSP_OK; -} - -static GstRTSPResult -gst_wfd_ext_src_get_video_parameter (GstWFDBaseSrc * src, - GstWFDExtMessage * msg) -{ - GstWFD2VideoCodecEnum cvCodec = GST_WFD2_VIDEO_CODEC_NONE; - GstWFD2DisplayNativeResolutionEnum cNative = GST_WFD2_DISPALY_NATIVE_CEA; - guint64 cNativeResolution = 0; - guint64 cCEAResolution = GST_WFD_CEA_UNKNOWN; - guint64 cVESAResolution = GST_WFD_VESA_UNKNOWN; - guint64 cHHResolution = GST_WFD_HH_UNKNOWN; - GstWFD2VideoH265ProfileEnum cProfile = GST_WFD2_H265_UNKNOWN_PROFILE; - GstWFD2VideoH265LevelEnum cLevel = GST_WFD2_H265_LEVEL_UNKNOWN; - guint32 cmin_slice_size = 0; - guint32 cslice_enc_params = 0; - guint cframe_rate_control = 0; - guint cvLatency = 0; - GstWFDResult wfd_res = GST_WFD_OK; - - wfd_res = - gst_wfd_ext_message_get_preferred_video_format (msg, &cvCodec, &cNative, - &cNativeResolution, &cCEAResolution, &cVESAResolution, &cHHResolution, - &cProfile, &cLevel, &cvLatency, &cmin_slice_size, &cslice_enc_params, - &cframe_rate_control); - if (wfd_res != GST_WFD_OK) { - GST_ERROR ("Failed to get preferred video format."); - return GST_RTSP_ERROR; - } - - if (cCEAResolution != GST_WFD_CEA_UNKNOWN) { - gst_wfd_base_src_get_cea_resolution_and_set_to_src (src, cCEAResolution); - } else if (cVESAResolution != GST_WFD_VESA_UNKNOWN) { - gst_wfd_base_src_get_vesa_resolution_and_set_to_src (src, cVESAResolution); - } else if (cHHResolution != GST_WFD_HH_UNKNOWN) { - gst_wfd_base_src_get_hh_resolution_and_set_to_src (src, cHHResolution); - } - - return GST_RTSP_OK; -} -#endif - -static GstRTSPResult -gst_wfd_ext_src_handle_set_parameter (GstWFDBaseSrc * bsrc, - GstRTSPMessage * request, GstRTSPMessage * response) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - GstRTSPResult res = GST_RTSP_OK; - GstWFDResult wfd_res = GST_WFD_OK; - GstWFDExtMessage *msg = NULL; - GstRTSPMethod method; - GstRTSPVersion version; - const gchar *uri; - guint8 *data = NULL; - guint size = 0; - gchar *msg_str = NULL; - gboolean add_reponse = FALSE; - - GString *body = NULL; - GString *body_length = NULL; - - g_return_val_if_fail (request, GST_RTSP_EINVAL); - g_return_val_if_fail (response, GST_RTSP_EINVAL); - - res = gst_rtsp_message_parse_request (request, &method, &uri, &version); - if (res < 0) - goto error; - - if (G_UNLIKELY (method != GST_RTSP_SET_PARAMETER)) - goto error; - - res = gst_rtsp_message_get_body (request, &data, &size); - if (res < 0) - goto error; - - wfd_res = gst_wfd_ext_message_new (&msg); - if (wfd_res != GST_WFD_OK) - goto error; - - wfd_res = gst_wfd_ext_message_parse_buffer (data, size, msg); - if (wfd_res != GST_WFD_OK) - goto error; - - if (msg->max_buffer_length) { - GstWFDRTSPTransMode trans = GST_WFD_RTSP_TRANS_UNKNOWN; - GstWFDRTSPProfile profile = GST_WFD_RTSP_PROFILE_UNKNOWN; - GstWFDRTSPLowerTrans lowertrans = GST_WFD_RTSP_LOWER_TRANS_UNKNOWN; - guint32 rtp_port0 = 0, rtp_port1 = 0; - guint32 length = 0; - - wfd_res = gst_wfd_ext_message_get_max_buffer_length (msg, &length); - if (wfd_res != GST_WFD_OK) - goto error; - - GST_DEBUG_OBJECT (src, "max_buffer_length : %d", length); - - if (msg->client_rtp_ports) { - wfd_res = - gst_wfd_ext_message_get_client_RTP_ports (msg, &trans, &profile, - &lowertrans, &rtp_port0, &rtp_port1); - if (wfd_res != GST_WFD_OK) - goto error; - - GST_DEBUG_OBJECT (src, "rtp_port0 : %d", rtp_port0); - GST_DEBUG_OBJECT (src, "rtp_port1 : %d", rtp_port1); - } - - res = - gst_wfd_ext_src_switch_transport (src, lowertrans, rtp_port0, - rtp_port1); - if (res != GST_RTSP_OK) - goto error; - - add_reponse = TRUE; - } -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - if ((msg->wfd2_video_formats - && msg->wfd2_video_formats->sink_video_cap.video_codec_list) - || (msg->wfd2_audio_codecs && msg->wfd2_audio_codecs->sink_audio_list)) { - - GstStructure *stream_info = gst_structure_new ("WFDStreamInfo", NULL, NULL); - - if (msg->wfd2_video_formats - && msg->wfd2_video_formats->sink_video_cap.video_codec_list) { - - GST_ERROR_OBJECT (src, "wfd2_video_formats : native[%02x] codec[%02x]" - " profile[%02x] level[%0x4] CEA[%012llx] VESA[%012llx] HH[%012llx]" - " latency[%02x] min_slice_size[%04x] slice_enc_params[%04x] frame_rate_control_support[%02x]" - " non_transcoding_support[%02x] portrait_mode[%d]", - msg->wfd2_video_formats->sink_video_cap.native, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->codec, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->profile, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->level, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - CEA_Support, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - VESA_Support, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - HH_Support, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - latency, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - min_slice_size, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - slice_enc_params, - msg->wfd2_video_formats->sink_video_cap.video_codec_list->misc_params. - frame_rate_control_support, - msg->wfd2_video_formats->sink_video_cap.non_transcoding_support, - msg->wfd2_video_formats->portrait_mode); - - gst_wfd_ext_src_get_video_parameter (GST_WFD_BASE_SRC (src), msg); - - } - - if (msg->wfd2_audio_codecs && msg->wfd2_audio_codecs->sink_audio_list) { - - const char *codec = NULL; - codec = - gst_wfd_ext_peek_wfd2_audio_format_string (msg->wfd2_audio_codecs-> - sink_audio_list->audio_format); - if (codec == NULL) - codec = "INVALID AUDIO CODEC"; - - GST_ERROR_OBJECT (src, "wfd2_audio_codecs: %s %08x %02x", - codec, - msg->wfd2_audio_codecs->sink_audio_list->mode, - msg->wfd2_audio_codecs->sink_audio_list->latency); - - gst_wfd_ext_src_get_audio_parameter (GST_WFD_BASE_SRC (src), msg); - - } - - gst_wfd_base_src_get_streaminfo (GST_WFD_BASE_SRC (src), stream_info); - - GST_DEBUG_OBJECT (src, "Send signal update-media-info"); - g_signal_emit_by_name (src, "update-media-info", stream_info); - } -#endif - - if (!add_reponse) - goto done; - - msg_str = gst_wfd_ext_message_as_text (msg); - if (msg_str == NULL) - goto error; - - data = NULL; - res = gst_rtsp_message_steal_body (response, &data, &size); - if (res != GST_RTSP_OK) - goto error; - - body = g_string_new_len ((const gchar *) data, size); - g_string_append (body, (const gchar *) msg_str); - if (body == NULL) { - GST_ERROR ("gst_wfd_ext_message_as_text is failed"); - goto error; - } - - body_length = g_string_new (""); - g_string_append_printf (body_length, "%d", body->len); - GST_DEBUG_OBJECT (src, "body_length : %s", body_length->str); - - gst_rtsp_message_remove_header (response, GST_RTSP_HDR_CONTENT_LENGTH, -1); - gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONTENT_LENGTH, - (const gchar *) body_length->str); - - GST_DEBUG_OBJECT (src, "body : %s", body->str); - - res = - gst_rtsp_message_set_body (response, (const guint8 *) body->str, - body->len); - if (res < 0) - goto error; - - g_string_free (body, TRUE); - g_string_free (body_length, TRUE); - -done: - if (msg_str) - g_free (msg_str); - if (msg) - gst_wfd_ext_message_free (msg); - - return res; - -/* ERRORS */ -error: - { - g_string_free (body_length, TRUE); - g_string_free (body, TRUE); - - if (msg_str) - g_free (msg_str); - if (msg) - gst_wfd_ext_message_free (msg); - - GST_ERROR_OBJECT (src, "Could not handle message"); - return res; - } -} - -static GstRTSPResult -gst_wfd_ext_src_handle_get_parameter (GstWFDBaseSrc * bsrc, - GstRTSPMessage * request, GstRTSPMessage * response) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - GstRTSPResult res = GST_RTSP_OK; - GstRTSPMethod method; - GstRTSPVersion version; - const gchar *uri; - guint8 *data = NULL; - guint size = 0; - GString *body = NULL; - GString *body_length = NULL; - GString *msg_str = NULL; - - g_return_val_if_fail (request, GST_RTSP_EINVAL); - g_return_val_if_fail (response, GST_RTSP_EINVAL); - - GST_DEBUG_OBJECT (src, ""); - - res = gst_rtsp_message_parse_request (request, &method, &uri, &version); - if (res < 0) - goto error; - - if (G_UNLIKELY (method != GST_RTSP_GET_PARAMETER)) - goto error; - - res = gst_rtsp_message_get_body (request, &data, &size); - if (res < 0) - goto error; - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - { - GstWFDExtMessage *parse_msg = NULL; - GstWFDExtMessage *msg = NULL; - GstWFDResult wfd_res = GST_WFD_OK; - gchar *ext_codec_str = NULL; - guint video_native = GST_WFD2_DISPALY_NATIVE_CEA; - guint video_codec = 0; - guint video_native_resolution = 0; - guint video_cea_support = 0; - guint video_vesa_support = 0; - guint video_hh_support = 0; - guint video_profile = 0; - guint video_level = 0; - guint video_latency = 0; - gint video_vertical_resolution = 0; - gint video_horizontal_resolution = 0; - gint video_minimum_slicing = 0; - gint video_slice_enc_param = 0; - gint video_framerate_control_support = 0; - gint video_non_transcoding_support = 0; - guint video_portrait_mode = 0; - - wfd_res = gst_wfd_ext_message_new (&parse_msg); - if (wfd_res != GST_WFD_OK) - goto error; - - wfd_res = gst_wfd_ext_message_parse_buffer (data, size, parse_msg); - if (wfd_res != GST_WFD_OK) { - gst_wfd_ext_message_free (parse_msg); - goto error; - } - - if (parse_msg->wfd2_video_formats) { - - wfd_res = gst_wfd_ext_message_new (&msg); - if (wfd_res != GST_WFD_OK) { - gst_wfd_ext_message_free (parse_msg); - goto error; - } - - if (src->video_r2_param != NULL) { - GstStructure *video_param = src->video_r2_param; - - if (gst_structure_has_field (video_param, "video_codec")) - gst_structure_get_uint (video_param, "video_codec", &video_codec); - if (gst_structure_has_field (video_param, "video_native_resolution")) - gst_structure_get_uint (video_param, "video_native_resolution", - &video_native_resolution); - if (gst_structure_has_field (video_param, "video_cea_support")) - gst_structure_get_uint (video_param, "video_cea_support", - &video_cea_support); - if (gst_structure_has_field (video_param, "video_vesa_support")) - gst_structure_get_uint (video_param, "video_vesa_support", - &video_vesa_support); - if (gst_structure_has_field (video_param, "video_hh_support")) - gst_structure_get_uint (video_param, "video_hh_support", - &video_hh_support); - if (gst_structure_has_field (video_param, "video_profile")) - gst_structure_get_uint (video_param, "video_profile", &video_profile); - if (gst_structure_has_field (video_param, "video_level")) - gst_structure_get_uint (video_param, "video_level", &video_level); - if (gst_structure_has_field (video_param, "video_latency")) - gst_structure_get_uint (video_param, "video_latency", &video_latency); - if (gst_structure_has_field (video_param, "video_vertical_resolution")) - gst_structure_get_int (video_param, "video_vertical_resolution", - &video_vertical_resolution); - if (gst_structure_has_field (video_param, - "video_horizontal_resolution")) - gst_structure_get_int (video_param, "video_horizontal_resolution", - &video_horizontal_resolution); - if (gst_structure_has_field (video_param, "video_minimum_slicing")) - gst_structure_get_int (video_param, "video_minimum_slicing", - &video_minimum_slicing); - if (gst_structure_has_field (video_param, "video_slice_enc_param")) - gst_structure_get_int (video_param, "video_slice_enc_param", - &video_slice_enc_param); - if (gst_structure_has_field (video_param, - "video_framerate_control_support")) - gst_structure_get_int (video_param, "video_framerate_control_support", - &video_framerate_control_support); - if (gst_structure_has_field (video_param, - "video_non_transcoding_support")) - gst_structure_get_int (video_param, "video_non_transcoding_support", - &video_non_transcoding_support); - - } - - wfd_res = gst_wfd_ext_add_wfd2_video_format (msg, video_native, - video_codec, - video_profile, video_level, - video_cea_support, video_vesa_support, video_hh_support, - video_latency, video_minimum_slicing, video_slice_enc_param, - video_framerate_control_support, video_non_transcoding_support, - video_portrait_mode); - - if (wfd_res != GST_WFD_OK) { - gst_wfd_ext_message_free (parse_msg); - gst_wfd_ext_message_free (msg); - goto error; - } - } - - if (parse_msg->wfd2_audio_codecs) { - - guint audio_codec = 0; - guint audio_lpcm_mode = 0; - guint audio_aac_mode = 0; - guint audio_ac3_mode = 0; - - if (msg == NULL) { - wfd_res = gst_wfd_ext_message_new (&msg); - if (wfd_res != GST_WFD_OK) { - gst_wfd_ext_message_free (parse_msg); - goto error; - } - } - - if (src->audio_r2_param != NULL) { - GstStructure *audio_param = src->audio_r2_param; - - if (gst_structure_has_field (audio_param, "audio_codec")) - gst_structure_get_uint (audio_param, "audio_codec", &audio_codec); - if (gst_structure_has_field (audio_param, "audio_lpcm_mode")) - gst_structure_get_uint (audio_param, "audio_lpcm_mode", - &audio_lpcm_mode); - if (gst_structure_has_field (audio_param, "audio_aac_mode")) - gst_structure_get_uint (audio_param, "audio_aac_mode", - &audio_aac_mode); - if (gst_structure_has_field (audio_param, "audio_ac3_mode")) - gst_structure_get_uint (audio_param, "audio_ac3_mode", - &audio_ac3_mode); - } - - if (audio_codec & GST_WFD2_AUDIO_FORMAT_LPCM) - gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_LPCM, - audio_lpcm_mode, 0); - if (audio_codec & GST_WFD2_AUDIO_FORMAT_AAC) - gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_AAC, - audio_aac_mode, 0); - if (audio_codec & GST_WFD2_AUDIO_FORMAT_AC3) - gst_wfd_ext_add_wfd2_audio_codec (msg, GST_WFD2_AUDIO_FORMAT_AC3, - audio_ac3_mode, 0); - } - - ext_codec_str = gst_wfd_ext_message_as_text (msg); - if (ext_codec_str != NULL) { - if (msg_str == NULL) - msg_str = g_string_new (""); - g_string_append_printf (msg_str, "%s", ext_codec_str); - g_free (ext_codec_str); - ext_codec_str = NULL; - } - gst_wfd_ext_message_free (msg); - gst_wfd_ext_message_free (parse_msg); - } -#endif - data = NULL; - res = gst_rtsp_message_steal_body (response, &data, &size); - if (res != GST_RTSP_OK) - goto error; - - body = g_string_new_len ((const gchar *) data, size); - if (body == NULL) { - GST_ERROR ("g_string_new is failed"); - goto error; - } - - if (msg_str != NULL) { - g_string_append (body, (const gchar *) msg_str->str); - g_string_free (msg_str, TRUE); - msg_str = NULL; - } - body_length = g_string_new (""); - g_string_append_printf (body_length, "%d", body->len); - GST_DEBUG_OBJECT (src, "body_length : %s", body_length->str); - - gst_rtsp_message_remove_header (response, GST_RTSP_HDR_CONTENT_LENGTH, -1); - gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONTENT_LENGTH, - (const gchar *) body_length->str); - - GST_DEBUG_OBJECT (src, "body : %s", body->str); - - res = - gst_rtsp_message_set_body (response, (const guint8 *) body->str, - body->len); - if (res < 0) - goto error; - - g_string_free (body, TRUE); - g_string_free (body_length, TRUE); - - return res; - -/* ERRORS */ -error: - { - g_string_free (body_length, TRUE); - g_string_free (body, TRUE); - g_string_free (msg_str, TRUE); - - GST_ERROR_OBJECT (src, "Could not handle message"); - return res; - } -} - -static void -gst_wfd_ext_src_set_state (GstWFDBaseSrc * bsrc, GstState state) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - gint i; - - GST_DEBUG_OBJECT (src, "try to set %s state", - gst_element_state_get_name (state)); - - for (i = 0; i < 3; i++) { - if (src->udpsrc[i]) - gst_element_set_state (src->udpsrc[i], state); - if (src->udpsink[i]) - gst_element_set_state (src->udpsink[i], state); - } - - if (src->session) - gst_element_set_state (src->session, state); - - if (src->requester) - gst_element_set_state (src->requester, state); - - if (src->wfdrtpbuffer) - gst_element_set_state (src->wfdrtpbuffer, state); -} - -static void -gst_wfd_ext_src_cleanup (GstWFDBaseSrc * bsrc) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - gint i; - - GST_DEBUG_OBJECT (src, "cleanup"); - - gst_wfd_ext_src_free_tcp (src); - - for (i = 0; i < 3; i++) { - if (src->channelpad[i]) { - gst_object_unref (src->channelpad[i]); - src->channelpad[i] = NULL; - } - if (src->udpsrc[i]) { - gst_element_set_state (src->udpsrc[i], GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (src), src->udpsrc[i]); - gst_object_unref (src->udpsrc[i]); - src->udpsrc[i] = NULL; - } - if (src->udpsink[i]) { - gst_element_set_state (src->udpsink[i], GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (src), src->udpsink[i]); - gst_object_unref (src->udpsink[i]); - src->udpsrc[i] = NULL; - } - } - if (src->session) { - gst_element_set_state (src->session, GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (src), src->session); - gst_object_unref (src->session); - src->session = NULL; - } - if (src->requester) { - gst_element_set_state (src->requester, GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (src), src->requester); - gst_object_unref (src->requester); - src->requester = NULL; - } - if (src->wfdrtpbuffer) { - gst_element_set_state (src->wfdrtpbuffer, GST_STATE_NULL); - gst_bin_remove (GST_BIN_CAST (src), src->wfdrtpbuffer); - gst_object_unref (src->wfdrtpbuffer); - src->wfdrtpbuffer = NULL; - } -} - -static GstRTSPResult -gst_wfd_ext_src_prepare_transport (GstWFDBaseSrc * bsrc, gint rtpport, - gint rtcpport) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - GstStateChangeReturn ret; - GstElement *udpsrc0, *udpsrc1, *udpsrc2; - gint tmp_rtp, tmp_rtcp, tmp_rtcp_fb; - const gchar *host; - - udpsrc0 = NULL; - udpsrc1 = NULL; - udpsrc2 = NULL; - - if (bsrc->is_ipv6) - host = "udp://[::0]"; - else - host = "udp://0.0.0.0"; - - /* try to allocate 2 UDP ports */ - udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc0 == NULL) - goto no_udp_protocol; - g_object_set (G_OBJECT (udpsrc0), "port", rtpport, "reuse", TRUE, NULL); - - if (src->udp_buffer_size != 0) - g_object_set (G_OBJECT (udpsrc0), "buffer-size", src->udp_buffer_size, - NULL); - - GST_DEBUG_OBJECT (src, "starting RTP on port %d", rtpport); - ret = gst_element_set_state (udpsrc0, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTP port %d", rtpport); - goto no_ports; - } - - g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); - GST_DEBUG_OBJECT (src, "got RTP port %d", tmp_rtp); - - /* check if port is even */ - if ((tmp_rtp & 0x01) != 0) { - GST_DEBUG_OBJECT (src, "RTP port not even"); - /* port not even, free RTP udpsrc */ - goto no_ports; - } - - /* allocate port+1 for RTCP now */ - udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc1 == NULL) - goto no_udp_protocol; - - /* set port */ - g_object_set (G_OBJECT (udpsrc1), "port", rtcpport, "reuse", TRUE, NULL); - - GST_DEBUG_OBJECT (src, "starting RTCP on port %d", rtcpport); - ret = gst_element_set_state (udpsrc1, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (src, "Unable to make udpsrc from RTCP port %d", rtcpport); - goto no_ports; - } - - /* allocate port #19120 for retransmitted RTP now */ - udpsrc2 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL); - if (udpsrc2 == NULL) - goto no_udp_protocol; - - /* set port */ - g_object_set (G_OBJECT (udpsrc2), "port", RETRANSMITTED_RTP_PORT, "reuse", - TRUE, NULL); - - if (src->udp_buffer_size != 0) - g_object_set (G_OBJECT (udpsrc2), "buffer-size", src->udp_buffer_size, - NULL); - - GST_DEBUG_OBJECT (src, "starting Retransmitted RTP on port %d", - RETRANSMITTED_RTP_PORT); - ret = gst_element_set_state (udpsrc2, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (src, - "Unable to make udpsrc from Retransmitted RTP port %d", - RETRANSMITTED_RTP_PORT); - goto no_ports; - } - - /* all fine, do port check */ - g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); - g_object_get (G_OBJECT (udpsrc1), "port", &tmp_rtcp, NULL); - g_object_get (G_OBJECT (udpsrc2), "port", &tmp_rtcp_fb, NULL); - - /* this should not happen... */ - if (rtpport != tmp_rtp || rtcpport != tmp_rtcp - || tmp_rtcp_fb != RETRANSMITTED_RTP_PORT) - goto port_error; - - /* we keep these elements, we configure all in configure_transport when the - * server told us to really use the UDP ports. */ - src->udpsrc[0] = gst_object_ref_sink (udpsrc0); - src->udpsrc[1] = gst_object_ref_sink (udpsrc1); - src->udpsrc[2] = gst_object_ref_sink (udpsrc2); - gst_element_set_locked_state (src->udpsrc[0], TRUE); - gst_element_set_locked_state (src->udpsrc[1], TRUE); - gst_element_set_locked_state (src->udpsrc[2], TRUE); - - return GST_RTSP_OK; - - /* ERRORS */ -no_udp_protocol: - { - GST_DEBUG_OBJECT (src, "could not get UDP source"); - goto cleanup; - } -no_ports: - { - GST_DEBUG_OBJECT (src, "could not allocate UDP port pair"); - goto cleanup; - } -port_error: - { - GST_DEBUG_OBJECT (src, - "ports don't match rtp: %d<->%d, rtcp: %d<->%d, retransmitted rtp: %d<->%d", - tmp_rtp, rtpport, tmp_rtcp, rtcpport, tmp_rtcp_fb, - RETRANSMITTED_RTP_PORT); - goto cleanup; - } -cleanup: - { - if (udpsrc0) { - gst_element_set_state (udpsrc0, GST_STATE_NULL); - gst_object_unref (udpsrc0); - } - if (udpsrc1) { - gst_element_set_state (udpsrc1, GST_STATE_NULL); - gst_object_unref (udpsrc1); - } - if (udpsrc2) { - gst_element_set_state (udpsrc2, GST_STATE_NULL); - gst_object_unref (udpsrc2); - } - return GST_RTSP_ERROR; - } -} - -static void -request_idr_by_requester (GstElement * requester, GstWFDExtSrc * src) -{ - GstEvent *event = NULL; - - GST_DEBUG_OBJECT (src, "try to request idr"); - - /* Send IDR request */ - event = - gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, - gst_structure_new ("GstWFDIDRRequest", NULL, NULL)); - - if (!gst_pad_send_event (GST_WFD_BASE_SRC_CAST (src)->srcpad, event)) - GST_WARNING_OBJECT (src, "failed to send event for idr reuest"); -} - -static void -on_bye_ssrc (GObject * session, guint32 ssrc, GstWFDExtSrc * src) -{ - GST_DEBUG_OBJECT (src, "source in session received BYE"); - - //gst_wfdextsrc_do_stream_eos (src, manager); -} - -static void -on_new_ssrc (GObject * session, guint32 ssrc, GstWFDExtSrc * src) -{ - GST_DEBUG_OBJECT (src, "source in session received NEW"); -} - -static void -on_timeout (GObject * session, guint32 ssrc, GstWFDExtSrc * src) -{ - GST_DEBUG_OBJECT (src, "source in session timed out"); - - //gst_wfdextsrc_do_stream_eos (src, manager); -} - -static void -on_ssrc_active (GObject * session, guint32 ssrc, GstWFDExtSrc * src) -{ - GST_DEBUG_OBJECT (src, "source in session is active"); -} - -static GstCaps * -request_pt_map_for_wfdrtpbuffer (GstElement * wfdrtpbuffer, guint pt, - GstWFDExtSrc * src) -{ - GstCaps *caps; - - GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); - - GST_WFD_BASE_STATE_LOCK (src); - caps = GST_WFD_BASE_SRC_CAST (src)->caps; - if (caps) - gst_caps_ref (caps); - GST_WFD_BASE_STATE_UNLOCK (src); - - return caps; -} - -static GstCaps * -request_pt_map_for_session (GstElement * session, guint pt, GstWFDExtSrc * src) -{ - GstCaps *caps; - - GST_DEBUG_OBJECT (src, "getting pt map for pt %d", pt); - - GST_WFD_BASE_STATE_LOCK (src); - caps = GST_WFD_BASE_SRC_CAST (src)->caps; - if (caps) - gst_caps_ref (caps); - GST_WFD_BASE_STATE_UNLOCK (src); - - return caps; -} - -static gboolean -gst_wfd_ext_src_configure_manager (GstWFDExtSrc * src) -{ - GstPad *pad = NULL; - - /* construct wfdextsrc */ - src->session = gst_element_factory_make ("rtpsession", "wfdextsrc_session"); - if (G_UNLIKELY (src->session == NULL)) { - GST_ERROR_OBJECT (src, "could not create gstrtpsession element"); - return FALSE; - } else { - g_signal_connect (src->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, - src); - g_signal_connect (src->session, "on-bye-timeout", (GCallback) on_timeout, - src); - g_signal_connect (src->session, "on-timeout", (GCallback) on_timeout, src); - g_signal_connect (src->session, "on-ssrc-active", - (GCallback) on_ssrc_active, src); - g_signal_connect (src->session, "on-new-ssrc", (GCallback) on_new_ssrc, - src); - g_signal_connect (src->session, "request-pt-map", - (GCallback) request_pt_map_for_session, src); - - g_object_set (G_OBJECT (src->session), "rtcp-min-interval", - (guint64) 1000000000, NULL); - - src->channelpad[0] = - gst_element_get_request_pad (src->session, "recv_rtp_sink"); - if (G_UNLIKELY (src->channelpad[0] == NULL)) { - GST_ERROR_OBJECT (src, "could not create rtp channel pad"); - return FALSE; - } - - src->channelpad[1] = - gst_element_get_request_pad (src->session, "recv_rtcp_sink"); - if (G_UNLIKELY (src->channelpad[1] == NULL)) { - GST_ERROR_OBJECT (src, "could not create rtcp channel pad"); - return FALSE; - } - - /* we manage session element */ - gst_element_set_locked_state (src->session, TRUE); - - if (!gst_bin_add (GST_BIN_CAST (src), src->session)) { - GST_ERROR_OBJECT (src, "failed to add rtpsession to wfdextsrc"); - return FALSE; - } - } - - src->requester = - gst_element_factory_make ("wfdrtprequester", "wfdextsrc_requester"); - if (G_UNLIKELY (src->requester == NULL)) { - GST_ERROR_OBJECT (src, "could not create wfdrtprequester element"); - return FALSE; - } else { - g_signal_connect (src->requester, "request-idr", - (GCallback) request_idr_by_requester, src); - - g_object_set (src->requester, "do-request", src->do_request, NULL); - - GST_DEBUG_OBJECT (src, - "getting retransmitted RTP sink pad of gstrtprequester"); - src->channelpad[2] = - gst_element_get_request_pad (src->requester, "retransmitted_rtp_sink"); - if (!src->channelpad[2]) { - GST_DEBUG_OBJECT (src, - "fail to get retransmitted RTP sink pad of gstrtprequester"); - return FALSE; - } - - /* we manage requester element */ - gst_element_set_locked_state (src->requester, TRUE); - - if (!gst_bin_add (GST_BIN_CAST (src), src->requester)) { - GST_ERROR_OBJECT (src, "failed to add wfdrtprequester to wfdextsrc"); - return FALSE; - } - } - - src->wfdrtpbuffer = - gst_element_factory_make ("wfdrtpbuffer", "wfdextsrc_wfdrtpbuffer"); - if (G_UNLIKELY (src->wfdrtpbuffer == NULL)) { - GST_ERROR_OBJECT (src, "could not create wfdrtpbuffer element"); - return FALSE; - } else { - /* configure latency and packet lost */ - g_object_set (src->wfdrtpbuffer, "latency", src->latency, NULL); - - g_signal_connect (src->wfdrtpbuffer, "request-pt-map", - (GCallback) request_pt_map_for_wfdrtpbuffer, src); - - /* we manage wfdrtpbuffer element */ - gst_element_set_locked_state (src->wfdrtpbuffer, TRUE); - - if (!gst_bin_add (GST_BIN_CAST (src), src->wfdrtpbuffer)) { - GST_ERROR_OBJECT (src, "failed to add wfdrtpbuffer to wfdextsrc"); - return FALSE; - } - } - - if (!gst_element_link_many (src->session, src->requester, src->wfdrtpbuffer, - NULL)) { - GST_ERROR_OBJECT (src, "failed to link elements for wfdextsrc"); - return FALSE; - } - - if (!gst_element_sync_state_with_parent (src->session)) { - GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", - GST_ELEMENT_NAME (src->session)); - return FALSE; - } - - if (!gst_element_sync_state_with_parent (src->requester)) { - GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", - GST_ELEMENT_NAME (src->requester)); - return FALSE; - } - - if (!gst_element_sync_state_with_parent (src->wfdrtpbuffer)) { - GST_ERROR_OBJECT (src, "failed for %s to sync state with wfdextsrc", - GST_ELEMENT_NAME (src->wfdrtpbuffer)); - return FALSE; - } - - /* set ghost pad */ - pad = gst_element_get_static_pad (src->wfdrtpbuffer, "src"); - if (G_UNLIKELY (pad == NULL)) { - GST_ERROR_OBJECT (src, - "failed to get src pad of wfdrtpbuffer for setting ghost pad of wfdextsrc"); - return FALSE; - } - - if (!gst_wfd_base_src_set_target (GST_WFD_BASE_SRC (src), pad)) { - GST_ERROR_OBJECT (src, "failed to set target pad of ghost pad"); - gst_object_unref(pad); - return FALSE; - } - - gst_object_unref(pad); - return TRUE; -} - -static gboolean -gst_wfd_ext_src_configure_udp_sinks (GstWFDExtSrc * src, - GstRTSPTransport * transport) -{ - GstPad *pad = NULL; - GSocket *socket = NULL; - gint rtp_port = -1, rtcp_port = -1, rtcp_fb_port = -1; - gboolean do_rtcp, do_rtcp_fb; - const gchar *destination = NULL; - gchar *uri = NULL; - GstPad *rtcp_fb_pad = NULL; - - /* get transport info */ - gst_wfd_base_src_get_transport_info (GST_WFD_BASE_SRC (src), transport, - &destination, &rtp_port, &rtcp_port); - rtcp_fb_port = RTCP_FB_PORT; - - /* it's possible that the server does not want us to send RTCP in which case - * the port is -1 */ - do_rtcp = (rtcp_port != -1 && src->session != NULL && src->do_rtcp); - do_rtcp_fb = (rtcp_fb_port != -1); - - /* we need a destination when we have RTCP RR and RTCP FB ports */ - if (destination == NULL && (do_rtcp_fb || do_rtcp)) - goto no_destination; - - if (do_rtcp) { - GstPad *rtcppad = NULL; - - GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination, - rtcp_port); - - uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port); - src->udpsink[1] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); - g_free (uri); - if (src->udpsink[1] == NULL) - goto no_sink_element; - - /* don't join multicast group, we will have the source socket do that */ - /* no sync or async state changes needed */ - g_object_set (G_OBJECT (src->udpsink[1]), "auto-multicast", FALSE, "loop", - FALSE, "sync", FALSE, "async", FALSE, NULL); - - if (src->udpsrc[1]) { - /* configure socket, we give it the same UDP socket as the udpsrc for RTCP - * because some servers check the port number of where it sends RTCP to identify - * the RTCP packets it receives */ - g_object_get (G_OBJECT (src->udpsrc[1]), "used-socket", &socket, NULL); - GST_DEBUG_OBJECT (src, "RTCP UDP src has sock %p", socket); - /* configure socket and make sure udpsink does not close it when shutting - * down, it belongs to udpsrc after all. */ - g_object_set (G_OBJECT (src->udpsink[1]), "socket", socket, - "close-socket", FALSE, NULL); - g_object_unref (socket); - } - - /* we don't want to consider this a sink */ - GST_OBJECT_FLAG_UNSET (src->udpsink[1], GST_ELEMENT_FLAG_SINK); - - /* we keep this playing always */ - gst_element_set_locked_state (src->udpsink[1], TRUE); - gst_element_set_state (src->udpsink[1], GST_STATE_PLAYING); - - gst_object_ref (src->udpsink[1]); - gst_bin_add (GST_BIN_CAST (src), src->udpsink[1]); - - rtcppad = gst_element_get_static_pad (src->udpsink[1], "sink"); - - /* get session RTCP pad */ - pad = gst_element_get_request_pad (src->session, "send_rtcp_src"); - - /* and link */ - if (pad && rtcppad) { - gst_pad_link_full (pad, rtcppad, GST_PAD_LINK_CHECK_NOTHING); - } - if (pad) - gst_object_unref (pad); - if (rtcppad) - gst_object_unref (rtcppad); - } - - if (do_rtcp_fb) { - GST_DEBUG_OBJECT (src, "configure RTCP FB sink for %s:%d", destination, - rtcp_fb_port); - - uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_fb_port); - src->udpsink[2] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); - g_free (uri); - if (src->udpsink[2] == NULL) - goto no_sink_element; - - /* don't join multicast group, we will have the source socket do that */ - /* no sync or async state changes needed */ - g_object_set (G_OBJECT (src->udpsink[2]), "auto-multicast", FALSE, - "loop", FALSE, "sync", FALSE, "async", FALSE, NULL); - - g_object_set (G_OBJECT (src->udpsink[2]), "bind-port", rtcp_fb_port, - "close-socket", FALSE, NULL); - - /* we don't want to consider this a sink */ - GST_OBJECT_FLAG_UNSET (src->udpsink[2], GST_ELEMENT_FLAG_SINK); - - /* we keep this playing always */ - gst_element_set_locked_state (src->udpsink[2], TRUE); - gst_element_set_state (src->udpsink[2], GST_STATE_PLAYING); - - gst_object_ref (src->udpsink[2]); - gst_bin_add (GST_BIN_CAST (src), src->udpsink[2]); - - /* get RTCP FB sink pad */ - rtcp_fb_pad = gst_element_get_static_pad (src->udpsink[2], "sink"); - - /* get requester RTCP pad */ - pad = gst_element_get_static_pad (src->requester, "rtcp_src"); - - /* and link */ - if (rtcp_fb_pad && pad) { - gst_pad_link (pad, rtcp_fb_pad); - } - if (pad) - gst_object_unref (pad); - if (rtcp_fb_pad) - gst_object_unref (rtcp_fb_pad); - } - - return TRUE; - - /* ERRORS */ -no_destination: - { - GST_DEBUG_OBJECT (src, "no destination address specified"); - return FALSE; - } -no_sink_element: - { - GST_DEBUG_OBJECT (src, "no UDP sink element found"); - return FALSE; - } -} - -static void -pad_blocked (GstPad * pad, gboolean blocked, GstWFDExtSrc * src) -{ - GST_DEBUG_OBJECT (src, "pad %s:%s blocked, activating streams", - GST_DEBUG_PAD_NAME (pad)); - - if (src->udpsrc[0]) { - /* remove timeout, we are streaming now and timeouts will be handled by - * the session manager and jitter buffer */ - g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", (guint64) 0, NULL); - } - - /* activate the streams */ - gst_wfd_base_src_activate (GST_WFD_BASE_SRC (src)); - - /* unblock all pads */ - if (src->blockedpad && src->blockid != 0) { - GST_DEBUG_OBJECT (src, "unblocking blocked pad"); - gst_pad_remove_probe (src->blockedpad, src->blockid); - src->blockid = 0; - src->blockedpad = NULL; - } -} - -static gboolean -gst_wfd_ext_src_configure_udp (GstWFDExtSrc * src) -{ - GstPad *outpad; - - /* we manage the UDP elements now. For unicast, the UDP sources where - * allocated in the stream when we suggested a transport. */ - if (src->udpsrc[0]) { - GstCaps *caps; - - gst_element_set_locked_state (src->udpsrc[0], TRUE); - gst_bin_add (GST_BIN_CAST (src), src->udpsrc[0]); - - GST_DEBUG_OBJECT (src, "setting up UDP source"); - - /* configure a timeout on the UDP port. When the timeout message is - * posted */ - g_object_set (G_OBJECT (src->udpsrc[0]), "timeout", - src->udp_timeout * 1000, NULL); - - caps = gst_caps_new_simple ("application/x-rtp", - "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, - "clock-rate", G_TYPE_INT, 90000, NULL); - g_object_set (src->udpsrc[0], "caps", caps, NULL); - gst_caps_unref (caps); - - /* get output pad of the UDP source. */ - outpad = gst_element_get_static_pad (src->udpsrc[0], "src"); - - /* save it so we can unblock */ - src->blockedpad = outpad; - - /* configure pad block on the pad. As soon as there is dataflow on the - * UDP source, we know that UDP is not blocked by a firewall and we can - * configure all the streams to let the application autoplug decoders. */ - src->blockid = - gst_pad_add_probe (src->blockedpad, - GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER | - GST_PAD_PROBE_TYPE_BUFFER_LIST, (GstPadProbeCallback) pad_blocked, src, - NULL); - - if (src->channelpad[0]) { - GST_DEBUG_OBJECT (src, "connecting UDP source 0 to session"); - /* configure for UDP delivery, we need to connect the UDP pads to - * the session plugin. */ - gst_pad_link_full (outpad, src->channelpad[0], - GST_PAD_LINK_CHECK_NOTHING); - /* we connected to pad-added signal to get pads from the manager */ - } else { - /* leave unlinked */ - } - } - - /* RTCP port */ - if (src->udpsrc[1]) { - GstCaps *caps; - - gst_element_set_locked_state (src->udpsrc[1], TRUE); - gst_bin_add (GST_BIN_CAST (src), src->udpsrc[1]); - - caps = gst_caps_new_empty_simple ("application/x-rtcp"); - g_object_set (src->udpsrc[1], "caps", caps, NULL); - gst_caps_unref (caps); - - if (src->channelpad[1]) { - GstPad *pad; - - GST_DEBUG_OBJECT (src, "connecting UDP source 1 to session"); - - pad = gst_element_get_static_pad (src->udpsrc[1], "src"); - gst_pad_link_full (pad, src->channelpad[1], GST_PAD_LINK_CHECK_NOTHING); - gst_object_unref (pad); - } else { - /* leave unlinked */ - } - } - - /* Retransmitted RTP port */ - if (src->udpsrc[2]) { - GstCaps *caps; - - gst_element_set_locked_state (src->udpsrc[2], TRUE); - gst_bin_add (GST_BIN_CAST (src), src->udpsrc[2]); - - caps = gst_caps_new_simple ("application/x-rtp", - "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, - "clock-rate", G_TYPE_INT, 90000, NULL); - g_object_set (src->udpsrc[2], "caps", caps, NULL); - gst_caps_unref (caps); - - if (src->channelpad[2]) { - GstPad *pad; - - GST_DEBUG_OBJECT (src, "connecting UDP source 2 to requester"); - pad = gst_element_get_static_pad (src->udpsrc[2], "src"); - gst_pad_link_full (pad, src->channelpad[2], GST_PAD_LINK_CHECK_NOTHING); - gst_object_unref (pad); - } else { - /* leave unlinked */ - } - } - - return TRUE; -} - -static GstRTSPResult -gst_wfd_ext_src_configure_transport (GstWFDBaseSrc * bsrc, - GstRTSPTransport * transport) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - const gchar *mime; - - g_return_val_if_fail (transport, GST_RTSP_EINVAL); - - GST_DEBUG_OBJECT (src, "configuring transport"); - - /* get the proper mime type for this manager now */ - if (gst_rtsp_transport_get_mime (transport->trans, &mime) < 0) - goto unknown_transport; - if (!mime) - goto unknown_transport; - - /* configure the final mime type */ - GST_DEBUG_OBJECT (src, "setting mime to %s", mime); - - if (!gst_wfd_ext_src_configure_manager (src)) - goto no_manager; - - switch (transport->lower_transport) { - case GST_RTSP_LOWER_TRANS_TCP: - case GST_RTSP_LOWER_TRANS_UDP_MCAST: - goto transport_failed; - case GST_RTSP_LOWER_TRANS_UDP: - if (!gst_wfd_ext_src_configure_udp (src)) - goto transport_failed; - if (!gst_wfd_ext_src_configure_udp_sinks (src, transport)) - goto transport_failed; - break; - default: - goto unknown_transport; - } - - return GST_RTSP_OK; - - /* ERRORS */ -unknown_transport: - { - GST_DEBUG_OBJECT (src, "unknown transport"); - return GST_RTSP_ERROR; - } -no_manager: - { - GST_DEBUG_OBJECT (src, "cannot configure manager"); - return GST_RTSP_ERROR; - } -transport_failed: - { - GST_DEBUG_OBJECT (src, "failed to configure transport"); - return GST_RTSP_ERROR; - } -} - -static gboolean -gst_wfd_ext_src_push_event (GstWFDBaseSrc * bsrc, GstEvent * event) -{ - GstWFDExtSrc *src = GST_WFD_EXT_SRC (bsrc); - gboolean res = TRUE; - - if (src->udpsrc[0] && GST_STATE (src->udpsrc[0]) >= GST_STATE_PAUSED) { - gst_event_ref (event); - res = gst_element_send_event (src->udpsrc[0], event); - } else if (src->channelpad[0]) { - gst_event_ref (event); - if (GST_PAD_IS_SRC (src->channelpad[0])) - res = gst_pad_push_event (src->channelpad[0], event); - else - res = gst_pad_send_event (src->channelpad[0], event); - } - - if (src->udpsrc[1] && GST_STATE (src->udpsrc[1]) >= GST_STATE_PAUSED) { - gst_event_ref (event); - res &= gst_element_send_event (src->udpsrc[1], event); - } else if (src->channelpad[1]) { - gst_event_ref (event); - if (GST_PAD_IS_SRC (src->channelpad[1])) - res &= gst_pad_push_event (src->channelpad[1], event); - else - res &= gst_pad_send_event (src->channelpad[1], event); - } - - if (src->udpsrc[2] && GST_STATE (src->udpsrc[2]) >= GST_STATE_PAUSED) { - gst_event_ref (event); - res &= gst_element_send_event (src->udpsrc[2], event); - } else if (src->channelpad[2]) { - gst_event_ref (event); - if (GST_PAD_IS_SRC (src->channelpad[2])) - res &= gst_pad_push_event (src->channelpad[2], event); - else - res &= gst_pad_send_event (src->channelpad[2], event); - } - - gst_event_unref (event); - - return res; -} - -static gboolean -gst_wfd_ext_src_change_udpsrc_uri (GstWFDExtSrc * src, GstElement * udpsrc, - gint port) -{ - GstStateChangeReturn ret; - gint org_port; - - g_object_get (G_OBJECT (udpsrc), "port", &org_port, NULL); - if (port == org_port) - goto done; - - ret = gst_element_set_state (udpsrc, GST_STATE_NULL); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (src, "Unable to stop udpsrc"); - goto error; - } - - g_object_set (G_OBJECT (udpsrc), "port", port, NULL); - - GST_DEBUG_OBJECT (src, "starting udpsrc with port %d", port); - ret = gst_element_set_state (udpsrc, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR_OBJECT (src, "Unable to run udpsrc port %d", port); - goto error; - } - - g_object_get (G_OBJECT (udpsrc), "port", &org_port, NULL); - if (port != org_port) - goto error; - -done: - return TRUE; - - /* ERRORS */ -error: - { - GST_DEBUG_OBJECT (src, "error"); - return FALSE; - } -} - -static void -gst_wfd_ext_src_free_tcp (GstWFDExtSrc * src) -{ - if (src->tcp_task) { - GST_DEBUG_OBJECT (src, "Closing tcp loop"); - if (src->tcp_conn) - gst_rtsp_connection_flush (src->tcp_conn, TRUE); - - gst_task_stop (src->tcp_task); - - g_rec_mutex_lock (&(src->tcp_task_lock)); - g_rec_mutex_unlock (&(src->tcp_task_lock)); - - gst_task_join (src->tcp_task); - gst_object_unref (src->tcp_task); - g_rec_mutex_clear (&(src->tcp_task_lock)); - src->tcp_task = NULL; - if (src->tcp_socket) { - g_object_unref (src->tcp_socket); - src->tcp_socket = NULL; - } - if (src->tcp_conn) { - GST_DEBUG_OBJECT (src, "freeing connection..."); - gst_rtsp_connection_free (src->tcp_conn); - src->tcp_conn = NULL; - } - - GST_DEBUG_OBJECT (src, "Tcp connection closed"); - } -} - -static GstRTSPResult -gst_wfd_ext_src_switch_to_udp (GstWFDExtSrc * src, guint32 port0, guint32 port1) -{ - gint i; - GstEvent *event; - - /* flush stop and send custon event */ - for (i = 0; i < 3; i++) { - if (src->udpsrc[i]) - gst_element_set_state (src->udpsrc[i], GST_STATE_READY); - if (src->udpsink[i]) - gst_element_set_state (src->udpsink[i], GST_STATE_READY); - } - if (src->session) - gst_element_set_state (src->session, GST_STATE_PAUSED); - if (src->requester) - gst_element_set_state (src->requester, GST_STATE_PAUSED); - if (src->wfdrtpbuffer) - gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PAUSED); - - gst_wfd_ext_src_free_tcp (src); - - /*change udpsrc port */ - if (gst_wfd_ext_src_change_udpsrc_uri (src, src->udpsrc[0], port0) == FALSE) - return GST_RTSP_ERROR; - - /*change udpsrc port */ - if (gst_wfd_ext_src_change_udpsrc_uri (src, src->udpsrc[1], - port0 + 1) == FALSE) - return GST_RTSP_ERROR; - - if (src->requester) - g_object_set (src->requester, "do-request", src->do_request, NULL); - - /* send custon event */ - event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, - gst_structure_new ("GstWFDEvent", "reset", G_TYPE_BOOLEAN, TRUE, NULL)); - gst_wfd_ext_src_push_event (GST_WFD_BASE_SRC_CAST (src), event); - - for (i = 0; i < 3; i++) { - if (src->udpsrc[i]) - gst_element_set_state (src->udpsrc[i], GST_STATE_PLAYING); - if (src->udpsink[i]) - gst_element_set_state (src->udpsink[i], GST_STATE_PLAYING); - } - - if (src->session) - gst_element_set_state (src->session, GST_STATE_PLAYING); - if (src->requester) - gst_element_set_state (src->requester, GST_STATE_PLAYING); - if (src->wfdrtpbuffer) - gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PLAYING); - - GST_DEBUG_OBJECT (src, "Transport change to UDP"); - - return GST_RTSP_OK; -} - -static void -do_timestamp (GstWFDExtSrc * src, GstBuffer * buffer) -{ - GstClockTime base_time; - GstClock *clock; - GstClockTime now = GST_CLOCK_TIME_NONE, dts, pts; - - GST_OBJECT_LOCK (src); - - /* get clock, if no clock, we can't do timestamps */ - if ((clock = GST_ELEMENT_CLOCK (src)) == NULL) - goto no_clock; - else - gst_object_ref (clock); - - base_time = GST_ELEMENT_CAST (src)->base_time; - - GST_OBJECT_UNLOCK (src); - - now = gst_clock_get_time (clock); - pts = dts = now - base_time; - - GST_BUFFER_PTS (buffer) = pts; - GST_BUFFER_DTS (buffer) = dts; - - return; - - /* special cases */ -no_clock: - { - GST_OBJECT_UNLOCK (src); - GST_DEBUG_OBJECT (src, "we have no clock"); - - return; - } -} - -static void -gst_wfd_ext_src_loop_tcp (GstWFDExtSrc * src) -{ - GstRTSPResult res; - GstPad *outpad = NULL; - GstFlowReturn ret = GST_FLOW_OK; - guint8 *sizedata, *datatmp; - gint message_size; - GstBuffer *buf; - GTimeVal tv_timeout; - GstEvent *event; - gint i; - - res = gst_rtsp_connection_accept (src->tcp_socket, &src->tcp_conn, NULL); - if (res < GST_RTSP_OK) - goto error; - - for (i = 0; i < 3; i++) { - if (src->udpsrc[i]) - gst_element_set_state (src->udpsrc[i], GST_STATE_READY); - if (src->udpsink[i]) - gst_element_set_state (src->udpsink[i], GST_STATE_READY); - } - if (src->session) - gst_element_set_state (src->session, GST_STATE_PLAYING); - if (src->requester) - gst_element_set_state (src->requester, GST_STATE_PLAYING); - if (src->wfdrtpbuffer) - gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PLAYING); - - /* send custon event */ - event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, - gst_structure_new ("GstWFDEvent", "reset", G_TYPE_BOOLEAN, TRUE, NULL)); - gst_wfd_ext_src_push_event (GST_WFD_BASE_SRC_CAST (src), event); - - while (TRUE) { - /* get the next timeout interval */ - gst_rtsp_connection_next_timeout (src->tcp_conn, &tv_timeout); - if (tv_timeout.tv_sec == 0) { - gst_rtsp_connection_reset_timeout (src->tcp_conn); - gst_rtsp_connection_next_timeout (src->tcp_conn, &tv_timeout); - GST_DEBUG ("doing receive with timeout %ld seconds, %ld usec", - tv_timeout.tv_sec, tv_timeout.tv_usec); - } - - /*In rtp message over TCP the first 2 bytes are message size. - * So firtstly read rtp message size.*/ - sizedata = (guint8 *) g_malloc (2); - res = gst_rtsp_connection_read (src->tcp_conn, sizedata, 2, &tv_timeout); - if (res < GST_RTSP_OK) { - ret = GST_FLOW_ERROR; - switch (res) { - case GST_RTSP_EINTR: - gst_rtsp_connection_flush (src->tcp_conn, FALSE); - break; - default: - break; - } - g_free (sizedata); - goto error; - } - message_size = ((guint) sizedata[0] << 8) | sizedata[1]; - datatmp = (guint8 *) g_malloc (message_size); - g_free (sizedata); - - res = - gst_rtsp_connection_read (src->tcp_conn, datatmp, message_size, - &tv_timeout); - if (res < GST_RTSP_OK) { - ret = GST_FLOW_ERROR; - switch (res) { - case GST_RTSP_EINTR: - GST_ERROR_OBJECT (src, "interrupted"); - gst_rtsp_connection_flush (src->tcp_conn, FALSE); - break; - default: - break; - } - g_free (datatmp); - goto error; - } - - /*first byte of data is type of payload - * 200 is rtcp type then we need other pad*/ - if (datatmp[0] == 200) - outpad = src->channelpad[1]; - else - outpad = src->channelpad[0]; - - buf = gst_buffer_new (); - gst_buffer_append_memory (buf, gst_memory_new_wrapped (0, datatmp, - message_size, 0, message_size, datatmp, g_free)); - - /* timestamp the buffers */ - do_timestamp (src, buf); - - /* If needed send a new segment, don't forget we are live and buffer are - * timestamped with running time */ - if (src->discont) { - GstSegment segment; - - gst_segment_init (&segment, GST_FORMAT_TIME); - gst_segment_set_running_time (&segment, GST_FORMAT_TIME, - (guint64) GST_BUFFER_DTS (buf)); - if (GST_PAD_IS_SINK (outpad)) - gst_pad_send_event (outpad, gst_event_new_segment (&segment)); - else - gst_pad_push_event (outpad, gst_event_new_segment (&segment)); - - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - src->discont = FALSE; - } - - if (GST_PAD_IS_SINK (outpad)) - ret = gst_pad_chain (outpad, buf); - else - ret = gst_pad_push (outpad, buf); - - if (ret < GST_FLOW_OK) - break; - } - g_assert_not_reached (); - - return; - - /* ERRORS */ -error: - { - GST_ERROR_OBJECT (src, "got error"); - goto pause; - } -pause: - { - if (src->tcp_task) - gst_task_pause (src->tcp_task); - } -} - -static GstRTSPResult -gst_wfd_ext_src_switch_to_tcp (GstWFDExtSrc * src, guint32 port) -{ - GSocket *socket = NULL; - GError *err = NULL; - GSocketAddress *sockaddr = NULL; - GInetAddress *anyaddr; - gint i; - - /* flush start */ - for (i = 0; i < 3; i++) { - if (src->udpsrc[i]) - gst_element_set_state (src->udpsrc[i], GST_STATE_READY); - if (src->udpsink[i]) - gst_element_set_state (src->udpsink[i], GST_STATE_READY); - } - - if (src->session) - gst_element_set_state (src->session, GST_STATE_PAUSED); - if (src->requester) - gst_element_set_state (src->requester, GST_STATE_PAUSED); - if (src->wfdrtpbuffer) - gst_element_set_state (src->wfdrtpbuffer, GST_STATE_PAUSED); - - if (src->requester) - g_object_set (src->requester, "do-request", FALSE, NULL); - - anyaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); - sockaddr = g_inet_socket_address_new (anyaddr, port); - - /* Open tcp socket */ - socket = - g_socket_new (g_socket_address_get_family (sockaddr), - G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); - if (socket == NULL) - goto error; - - if (!g_socket_bind (socket, sockaddr, TRUE, &err)) - goto bind_error; - g_object_unref (anyaddr); - g_object_unref (sockaddr); - - //g_socket_set_keepalive (socket, TRUE); - //g_socket_set_listen_backlog (socket, 5); - if (!g_socket_listen (socket, &err)) - goto error; - - src->discont = TRUE; - src->tcp_socket = socket; - src->tcp_task = - gst_task_new ((GstTaskFunction) gst_wfd_ext_src_loop_tcp, src, NULL); - if (src->tcp_task == NULL) - goto error; - g_rec_mutex_init (&(src->tcp_task_lock)); - gst_task_set_lock (src->tcp_task, &(src->tcp_task_lock)); - - gst_task_start (src->tcp_task); - - GST_DEBUG_OBJECT (src, "Transport change to TCP"); - - return GST_RTSP_OK; - -/* ERRORS */ -bind_error: - { - GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("bind failed: %s", - err->message)); - g_object_unref (socket); - g_object_unref (anyaddr); - g_object_unref (sockaddr); - return GST_RTSP_ERROR; - } -error: - { - return GST_RTSP_ERROR; - } -} - -static GstRTSPResult -gst_wfd_ext_src_switch_transport (GstWFDExtSrc * src, - GstWFDRTSPLowerTrans lowertrans, guint32 port0, guint32 port1) -{ - GstRTSPResult res = GST_RTSP_OK; - - switch (lowertrans) { - case GST_WFD_RTSP_LOWER_TRANS_TCP: - res = gst_wfd_ext_src_switch_to_tcp (src, port0); - break; - case GST_WFD_RTSP_LOWER_TRANS_UDP: - res = gst_wfd_ext_src_switch_to_udp (src, port0, port1); - break; - default: - break; - } - - return res; -} diff --git a/wfdextmanager/gstwfdextsrc.h b/wfdextmanager/gstwfdextsrc.h deleted file mode 100755 index b1e3f22..0000000 --- a/wfdextmanager/gstwfdextsrc.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * wfdrtspsrc - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_WFD_EXT_SRC_H__ -#define __GST_WFD_EXT_SRC_H__ - -#include -#include "../wfdmanager/wfdbase/gstwfdbasesrc.h" -#include "gstwfdextmessage.h" - -G_BEGIN_DECLS - -#define GST_TYPE_WFD_EXT_SRC (gst_wfd_ext_src_get_type()) -#define GST_WFD_EXT_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_EXT_SRC,GstWFDExtSrc)) -#define GST_WFD_EXT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_EXT_SRC,GstWFDExtSrcClass)) -#define GST_WFD_EXT_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WFD_EXT_SRC, GstWFDExtSrcClass)) -#define GST_IS_WFD_EXT_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_EXT_SRC)) -#define GST_IS_WFD_EXT_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_EXT_SRC)) -#define GST_WFD_EXT_SRC_CAST(obj) ((GstWFDExtSrc *)(obj)) - -typedef struct _GstWFDExtSrc GstWFDExtSrc; -typedef struct _GstWFDExtSrcClass GstWFDExtSrcClass; - -#define RETRANSMITTED_RTP_PORT 19120 -#define RTCP_FB_PORT 19121 - -struct _GstWFDExtSrc { - GstWFDBaseSrc parent; - - /* properties */ - gboolean do_rtcp; - guint latency; - gint udp_buffer_size; - guint64 udp_timeout; - gboolean do_request; - - GstPad *channelpad[3]; - GstElement *udpsrc[3]; - GstElement *udpsink[3]; - GstElement *session; - GstElement *wfdrtpbuffer; - GstElement *requester; - - GstPad *blockedpad; - gulong blockid; - - /*For tcp*/ - GstClockTime base_time; - gboolean discont; - GRecMutex tcp_task_lock; - GstTask *tcp_task; - GSocket *tcp_socket; - GstRTSPConnection *tcp_conn; - -#ifdef ENABLE_WFD2_EXTENDED_CODEC_FEATURE - GstStructure *audio_r2_param; - GstStructure *video_r2_param; -#endif -}; - -struct _GstWFDExtSrcClass { - GstWFDBaseSrcClass parent_class; - -}; - -GType gst_wfd_ext_src_get_type(void); - -G_END_DECLS - -#endif /* __GST_WFD_EXT_SRC_H__ */ diff --git a/wfdextmanager/gstwfdrtprequester.c b/wfdextmanager/gstwfdrtprequester.c deleted file mode 100755 index 58386cf..0000000 --- a/wfdextmanager/gstwfdrtprequester.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * wfdrtprequester - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "gstwfdrtprequester.h" - -GST_DEBUG_CATEGORY_STATIC (wfdrtprequester_debug); -#define GST_CAT_DEFAULT (wfdrtprequester_debug) - -/* signals and args */ -enum -{ - SIGNAL_REQUEST_IDR, - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_DO_REQUEST, - PROP_SSRC, - PROP_PT, - PROP_TIMEOUT -}; - -#define DEFAULT_DO_REQUEST TRUE -#define DEFAULT_SSRC 0x0000 -#define DEFAULT_PT 33 //MP2t-ES payload type -#define DEFAULT_TIMEOUT_MS 0 - - /* sink pads */ -static GstStaticPadTemplate rtp_sink_template = -GST_STATIC_PAD_TEMPLATE ("rtp_sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-rtp") - ); - -static GstStaticPadTemplate retransmitted_rtp_sink_template = -GST_STATIC_PAD_TEMPLATE ("retransmitted_rtp_sink", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS ("application/x-rtp") - ); - -/* src pads */ -static GstStaticPadTemplate rtp_src_template = -GST_STATIC_PAD_TEMPLATE ("rtp_src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-rtp") - ); - -static GstStaticPadTemplate rtcp_src_template = -GST_STATIC_PAD_TEMPLATE ("rtcp_src", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS ("application/x-rtcp") - ); - - -#define GST_WFD_RTP_REQUESTER_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_WFD_RTP_REQUESTER, GstWFDRTPRequesterPrivate)) - -#define GST_WFD_RTP_REQUESTER_LOCK(requester) g_mutex_lock (&(requester)->priv->lock) -#define GST_WFD_RTP_REQUESTER_UNLOCK(requester) g_mutex_unlock (&(requester)->priv->lock) - -struct _GstWFDRTPRequesterPrivate -{ - GMutex lock; - - gboolean flushing; - - /* the next expected seqnum we receive */ - guint64 next_in_seqnum; -}; - -/* - * The maximum number of missing packets we tollerate. These are packets with a - * sequence number bigger than the last seen packet. - */ -#define REQUESTER_MAX_DROPOUT 17 -/* - * The maximum number of misordered packets we tollerate. These are packets with - * a sequence number smaller than the last seen packet. - */ -#define REQUESTER_MAX_MISORDER 16 - -#define REQUESTER_MTU_SIZE 1400 /* bytes */ - -#define gst_wfd_rtp_requester_parent_class parent_class - -/* GObject vmethods */ -static void gst_wfd_rtp_requester_finalize (GObject * object); -static void gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_wfd_rtp_requester_sink_event (GstPad * pad, - GstObject * parent, GstEvent * event); -static gboolean gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, - GstEvent * event); -static gboolean gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * - pad, GstObject * parent, GstEvent * event); -static gboolean gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, - GstObject * parent, GstEvent * event); - -/* GstElement vmethods */ -static GstFlowReturn gst_wfd_rtp_requester_chain (GstPad * pad, - GstObject * parent, GstBuffer * buf); -static GstPad *gst_wfd_rtp_requester_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name, const GstCaps * caps); -static void gst_wfd_rtp_requester_release_pad (GstElement * element, - GstPad * pad); - -static GstFlowReturn gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * - pad, GstObject * parent, GstBuffer * buf); - -static void gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester); -static void gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester); - -static guint gst_wfd_rtp_requester_signals[LAST_SIGNAL] = { 0 }; - -/* GObject vmethod implementations */ -static void -_do_init (GType wfdrtprequester_type) -{ - GST_DEBUG_CATEGORY_INIT (wfdrtprequester_debug, "wfdrtprequester", 0, - "WFD RTP Requester"); -} - -G_DEFINE_TYPE_WITH_CODE (GstWFDRTPRequester, gst_wfd_rtp_requester, - GST_TYPE_ELEMENT, _do_init ((g_define_type_id))); - -/* initialize the plugin's class */ -static void -gst_wfd_rtp_requester_class_init (GstWFDRTPRequesterClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - g_type_class_add_private (klass, sizeof (GstWFDRTPRequesterPrivate)); - - gobject_class->finalize = gst_wfd_rtp_requester_finalize; - gobject_class->set_property = gst_wfd_rtp_requester_set_property; - gobject_class->get_property = gst_wfd_rtp_requester_get_property; - - g_object_class_install_property (gobject_class, PROP_DO_REQUEST, - g_param_spec_boolean ("do-request", "Do request", - "Request RTP retransmission", - DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_SSRC, - g_param_spec_uint ("ssrc", "SSRC", - "The SSRC of the RTP packets", 0, G_MAXUINT32, - DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_PT, - g_param_spec_uint ("pt", "payload type", - "The payload type of the RTP packets", 0, 0x80, DEFAULT_PT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstWFDRTPRequester::timeout: - * - * The maximum timeout of the requester. Packets should be retransmitted - * at most this time. Unless, the request-timeout signal will be emit. - */ - g_object_class_install_property (gobject_class, PROP_TIMEOUT, - g_param_spec_uint ("timeout", "Retransmssion timeout in ms", - "Timeout in ms for retransmission", 0, G_MAXUINT, DEFAULT_TIMEOUT_MS, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstWFDRTPRequester::request-timeout: - * @req: a #GstWFDRTPRequester - * - * Notify of timeout which is requesting rtp retransmission. - */ - gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_IDR] = - g_signal_new ("request-idr", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstWFDRTPRequesterClass, request_idr), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - - gst_element_class_set_details_simple (gstelement_class, - "Wi-Fi Display RTP Request Retransmission Element", - "Filter/Network/RTP", - "Receive RTP packet and request RTP retransmission", - "Yejin Cho "); - - gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_request_new_pad); - gstelement_class->release_pad = - GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_release_pad); - - /* sink pads */ - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&rtp_sink_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&retransmitted_rtp_sink_template)); - /* src pads */ - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&rtp_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&rtcp_src_template)); -} - -static void -gst_wfd_rtp_requester_init (GstWFDRTPRequester * requester) -{ - requester->priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); - g_mutex_init (&requester->priv->lock); - requester->priv->flushing = FALSE; - requester->priv->next_in_seqnum = GST_CLOCK_TIME_NONE; - - requester->rtp_sink = - gst_pad_new_from_static_template (&rtp_sink_template, "rtp_sink"); - gst_pad_set_event_function (requester->rtp_sink, - GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_sink_event)); - gst_pad_set_chain_function (requester->rtp_sink, - GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_chain)); - gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_sink); - - requester->rtp_src = - gst_pad_new_from_static_template (&rtp_src_template, "rtp_src"); - gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_src); - - requester->do_request = DEFAULT_DO_REQUEST; - requester->ssrc = DEFAULT_SSRC; - requester->pt = DEFAULT_PT; - requester->timeout_ms = DEFAULT_TIMEOUT_MS; - requester->timeout_ns = requester->timeout_ms * GST_MSECOND; -} - -static void -gst_wfd_rtp_requester_finalize (GObject * object) -{ - GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER_CAST (object); - - requester = GST_WFD_RTP_REQUESTER (object); - - g_mutex_clear (&requester->priv->lock); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); - - switch (prop_id) { - case PROP_DO_REQUEST: - requester->do_request = g_value_get_boolean (value); - break; - case PROP_SSRC: - requester->ssrc = g_value_get_uint (value); - break; - case PROP_PT: - requester->pt = g_value_get_uint (value); - break; - case PROP_TIMEOUT: - requester->timeout_ms = g_value_get_uint (value); - requester->timeout_ns = requester->timeout_ms * GST_MSECOND; - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); - - switch (prop_id) { - case PROP_DO_REQUEST: - g_value_set_boolean (value, requester->do_request); - break; - case PROP_SSRC: - g_value_set_uint (value, requester->ssrc); - break; - case PROP_PT: - g_value_set_uint (value, requester->pt); - break; - case PROP_TIMEOUT: - g_value_set_uint (value, requester->timeout_ms); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, GstEvent * event) -{ - GstWFDRTPRequester *requester; - gboolean res = TRUE; - GstCaps *caps; - - requester = GST_WFD_RTP_REQUESTER_CAST (gst_pad_get_parent (pad)); - gst_event_parse_caps (event, &caps); - - gst_object_unref (requester); - - return res; -} - -/* GstElement vmethod implementations */ - -/* this function handles sink events */ -static gboolean -gst_wfd_rtp_requester_sink_event (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - gboolean ret = FALSE; - GstWFDRTPRequester *requester = NULL; - - requester = GST_WFD_RTP_REQUESTER (parent); - - GST_DEBUG_OBJECT (requester, "requester got event %s", - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CUSTOM_DOWNSTREAM:{ - const GstStructure *structure; - - structure = gst_event_get_structure (event); - if (gst_structure_has_name (structure, "GstWFDEvent")) { - gboolean reset = FALSE; - gst_structure_get_boolean (structure, "reset", &reset); - if (reset) { - GST_WFD_RTP_REQUESTER_LOCK (requester); - requester->priv->next_in_seqnum = GST_CLOCK_TIME_NONE; - requester->ssrc = 0; - requester->pt = 0; - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - } - } - ret = gst_pad_event_default (pad, parent, event); - break; - } - case GST_EVENT_FLUSH_START: - gst_wfd_rtp_requester_flush_start (requester); - ret = gst_pad_push_event (requester->rtp_src, event); - break; - case GST_EVENT_FLUSH_STOP: - ret = gst_pad_push_event (requester->rtp_src, event); - gst_wfd_rtp_requester_flush_stop (requester); - break; - case GST_EVENT_CAPS: - gst_wfd_rtp_requester_sink_newcaps (pad, event); - ret = gst_pad_push_event (requester->rtp_src, event); - break; - default: - ret = gst_pad_event_default (pad, parent, event); - break; - } - - return ret; -} - -static void -gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester) -{ - GstWFDRTPRequesterPrivate *priv; - - priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); - - GST_WFD_RTP_REQUESTER_LOCK (requester); - - /* mark ourselves as flushing */ - priv->flushing = TRUE; - GST_DEBUG_OBJECT (requester, "flush start.."); - - GST_WFD_RTP_REQUESTER_UNLOCK (requester); -} - -static void -gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester) -{ - GstWFDRTPRequesterPrivate *priv; - - priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); - - GST_WFD_RTP_REQUESTER_LOCK (requester); - - GST_DEBUG_OBJECT (requester, "flush stop..."); - /* Mark as non flushing */ - priv->flushing = FALSE; - - priv->next_in_seqnum = GST_CLOCK_TIME_NONE; - - requester->ssrc = 0; - requester->pt = 0; - - GST_WFD_RTP_REQUESTER_UNLOCK (requester); -} - -static gboolean -gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * pad, - GstObject * parent, GstEvent * event) -{ - gboolean ret; - GstWFDRTPRequester *requester; - - requester = GST_WFD_RTP_REQUESTER_CAST (parent); - - GST_DEBUG_OBJECT (requester, "requester got event %s", - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - default: - ret = gst_pad_event_default (pad, parent, event); - break; - } - - return ret; -} - -static gboolean -gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, GstObject * parent, - GstEvent * event) -{ - GstWFDRTPRequester *requester; - gboolean ret; - - requester = GST_WFD_RTP_REQUESTER_CAST (parent); - - GST_DEBUG_OBJECT (requester, "requester got event %s", - GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - default: - ret = gst_pad_event_default (pad, parent, event); - break; - } - - return ret; -} - -void -wfd_rtp_requester_perform_request (GstWFDRTPRequester * requester, - guint16 expected_seqnum, guint16 received_seqnum) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstRTCPPacket rtcp_fb_packet; - GstBuffer *rtcp_fb_buf; - GstRTCPBuffer rtcp_buf = { NULL }; - guint8 *fci_data; - guint16 pid, blp; - guint rtcp_packet_cnt = 0; - gint gap; - gint i; - - /* can't continue without gap */ - gap = received_seqnum - expected_seqnum; - if (G_UNLIKELY (gap < 1)) - goto no_gap; - - pid = expected_seqnum; - -again: - /* create buffer for rtcp fb packets */ - rtcp_fb_buf = gst_rtcp_buffer_new (REQUESTER_MTU_SIZE); - if (!G_UNLIKELY (rtcp_fb_buf)) - goto fail_buf; - if (!gst_rtcp_buffer_map (rtcp_fb_buf, GST_MAP_READWRITE, &rtcp_buf)) - goto fail_buf; - - /* create rtcp fb packet */ - do { - if (!gst_rtcp_buffer_add_packet (&rtcp_buf, GST_RTCP_TYPE_RTPFB, - &rtcp_fb_packet)) { - if (rtcp_packet_cnt > 0) - goto send_packets; - else { - gst_rtcp_buffer_unmap (&rtcp_buf); - goto fail_packet; - } - } - - /* set rtcp fb header : wfd use RTCPFB with Generick NACK */ - gst_rtcp_packet_fb_set_type (&rtcp_fb_packet, GST_RTCP_RTPFB_TYPE_NACK); - gst_rtcp_packet_fb_set_sender_ssrc (&rtcp_fb_packet, 0); - gst_rtcp_packet_fb_set_media_ssrc (&rtcp_fb_packet, 0); - - /* set rtcp fb fci(feedback control information) : 32bits */ - if (!gst_rtcp_packet_fb_set_fci_length (&rtcp_fb_packet, 1)) { - GST_DEBUG_OBJECT (requester, - "failed to set FCI length to RTCP FB packet"); - gst_rtcp_packet_remove (&rtcp_fb_packet); - return; - } - - fci_data = gst_rtcp_packet_fb_get_fci ((&rtcp_fb_packet)); - - /* set pid */ - GST_WRITE_UINT16_BE (fci_data, pid); - pid += 0x0011; - gap--; - - /* set blp */ - blp = 0x0000; - for (i = 0; i < 16 && gap > 0; i++) { - blp += (0x0001 << i); - gap--; - } - GST_WRITE_UINT16_BE (fci_data + 2, blp); - - rtcp_packet_cnt++; - - GST_DEBUG_OBJECT (requester, "%d RTCP FB packet : pid : %x, blp : %x", - rtcp_packet_cnt, pid - 0x0011, blp); - } while (gap > 0); - -send_packets: - /* end rtcp fb buffer */ - gst_rtcp_buffer_unmap (&rtcp_buf); - - ret = gst_pad_push (requester->rtcp_src, rtcp_fb_buf); - if (ret != GST_FLOW_OK) - GST_WARNING_OBJECT (requester, "fail to pad push RTCP FB buffer"); - - if (gap > 0) - goto again; - - return; - - /* ERRORS */ -no_gap: - { - GST_DEBUG_OBJECT (requester, - "there is no gap, don't need to make the RTSP FB packet"); - return; - } -fail_buf: - { - GST_DEBUG_OBJECT (requester, "fail to make RTSP FB buffer"); - return; - } -fail_packet: - { - GST_DEBUG_OBJECT (requester, "fail to make RTSP FB packet"); - return; - } -} - -/* chain function - * this function does the actual processing - */ -static GstFlowReturn -gst_wfd_rtp_requester_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) -{ - GstWFDRTPRequester *requester; - GstWFDRTPRequesterPrivate *priv; - guint16 seqnum; - guint8 pt; - guint32 ssrc; - GstFlowReturn ret = GST_FLOW_OK; - GstRTPBuffer rtp_buf = GST_RTP_BUFFER_INIT; - - requester = GST_WFD_RTP_REQUESTER_CAST (parent); - priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); - - GST_WFD_RTP_REQUESTER_LOCK (requester); - - if (priv->flushing) - goto drop_buffer; - - if (G_UNLIKELY (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp_buf))) - goto invalid_buffer; - - ssrc = gst_rtp_buffer_get_ssrc (&rtp_buf); - pt = gst_rtp_buffer_get_payload_type (&rtp_buf); - seqnum = gst_rtp_buffer_get_seq (&rtp_buf); - gst_rtp_buffer_unmap (&rtp_buf); - - /* check ssrc */ - if (G_LIKELY (!requester->ssrc)) { - GST_DEBUG_OBJECT (requester, "set ssrc as %x using first rtp packet", ssrc); - requester->ssrc = ssrc; - } else if (G_LIKELY (requester->ssrc != ssrc)) { - /* goto invalid_ssrc; */ - GST_ERROR_OBJECT (requester, "ssrc is changed from %x to %x", - requester->ssrc, ssrc); - requester->ssrc = ssrc; - } - - /* check pt : pt should always 33 for MP2T-ES */ - if (G_LIKELY (requester->pt != pt)) { - if (G_LIKELY (!requester->pt)) - requester->pt = pt; - else - goto invalid_pt; - } - - /* now check against our expected seqnum */ - if (G_LIKELY (priv->next_in_seqnum != GST_CLOCK_TIME_NONE)) { - gint gap; - - gap = gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, seqnum); - if (G_UNLIKELY (gap != 0)) { - GST_ERROR_OBJECT (requester, "expected #%d, got #%d, gap of %d", - (guint16) priv->next_in_seqnum, seqnum, gap); - - if (requester->do_request) { - if (G_UNLIKELY (gap < 0)) { - if (G_UNLIKELY (gap < -150)) { - GST_WARNING_OBJECT (requester, - "#%d is too late, just unref the buffer for prevent of resetting jitterbuffer", - seqnum); - gst_buffer_unref (buf); - goto finished; - } else { - GST_DEBUG_OBJECT (requester, "#%d is late, but try to push", - seqnum); - goto skip; - } - } else if (G_UNLIKELY (gap > REQUESTER_MAX_DROPOUT)) { - GST_DEBUG_OBJECT (requester, - "too many dropped packets %d, need to request IDR", gap); - g_signal_emit (requester, - gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_IDR], 0); - } else { - GST_DEBUG_OBJECT (requester, "tolerable gap"); - wfd_rtp_requester_perform_request (requester, priv->next_in_seqnum, - seqnum); - } - } - } - } else { - GST_DEBUG_OBJECT (requester, - "got the first buffer, need to set buffer timestamp 0"); - GST_BUFFER_TIMESTAMP (buf) = 0; - } - - priv->next_in_seqnum = (seqnum + 1) & 0xffff; - -skip: - /* just push out the incoming buffer without touching it */ - ret = gst_pad_push (requester->rtp_src, buf); - if (ret != GST_FLOW_OK) - GST_ERROR_OBJECT (requester, "failed to pad push..reason %s", - gst_flow_get_name (ret)); - -finished: - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - - return ret; - - /* ERRORS */ -drop_buffer: - { - GST_ERROR_OBJECT (requester, - "requeseter is flushing, drop incomming buffers.."); - gst_buffer_unref (buf); - ret = GST_FLOW_OK; - goto finished; - } -invalid_buffer: - { - /* this is not fatal but should be filtered earlier */ - GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), - ("Received invalid RTP payload, dropping")); - gst_buffer_unref (buf); - ret = GST_FLOW_OK; - goto finished; - } -#if 0 -invalid_ssrc: - { - /* this is not fatal but should be filtered earlier */ - GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), - ("ssrc of this rtp packet is differtent from before. dropping")); - gst_buffer_unref (buf); - ret = GST_FLOW_OK; - goto finished; - } -#endif -invalid_pt: - { - /* this is not fatal but should be filtered earlier */ - GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), - ("pt of this rtp packet is differtent from before. dropping")); - gst_buffer_unref (buf); - ret = GST_FLOW_OK; - goto finished; - } -} - -GstBuffer * -wfd_requester_handle_retransmitted_rtp (GstWFDRTPRequester * requester, - GstBuffer * inbuf) -{ - GstBuffer *outbuf = NULL; - GstMapInfo inbuf_mapinfo = GST_MAP_INFO_INIT; - GstRTPBuffer rtp_inbuf = GST_RTP_BUFFER_INIT; - GstMapInfo outbuf_mapinfo = GST_MAP_INFO_INIT; - GstRTPBuffer rtp_outbuf = GST_RTP_BUFFER_INIT; - guint16 seqnum; - guint8 *buf_data; - guint buf_size; - guint8 *payload; - guint payload_len, header_len; - - if (!gst_rtp_buffer_map (inbuf, GST_MAP_READ, &rtp_inbuf)) { - GST_WARNING_OBJECT (requester, - "failed to map for the retransmitted rtp buffer"); - return NULL; - } - - payload = gst_rtp_buffer_get_payload (&rtp_inbuf); - payload_len = gst_rtp_buffer_get_payload_len (&rtp_inbuf); - header_len = gst_rtp_buffer_get_header_len (&rtp_inbuf); - gst_rtp_buffer_unmap (&rtp_inbuf); - - gst_buffer_map (inbuf, &inbuf_mapinfo, GST_MAP_READ); - buf_data = inbuf_mapinfo.data; - buf_size = inbuf_mapinfo.size; - - outbuf = gst_buffer_new_and_alloc (buf_size - 2); - if (!outbuf) { - GST_WARNING_OBJECT (requester, "failed to alloc for rtp buffer"); - gst_buffer_unmap (inbuf, &inbuf_mapinfo); - return NULL; - } - - gst_buffer_map (outbuf, &outbuf_mapinfo, GST_MAP_READWRITE); - /* copy rtp header */ - memcpy (outbuf_mapinfo.data, buf_data, header_len); - /* copy rtp payload */ - memcpy (outbuf_mapinfo.data + header_len, payload + 2, payload_len - 2); - - /* set seqnum to original */ - if (!gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp_outbuf)) { - GST_WARNING_OBJECT (requester, "failed to map rtp result buffer"); - gst_buffer_unmap (inbuf, &inbuf_mapinfo); - gst_buffer_unmap (outbuf, &outbuf_mapinfo); - return NULL; - } - seqnum = GST_READ_UINT16_BE (payload); - gst_rtp_buffer_set_seq (&rtp_outbuf, seqnum); - gst_rtp_buffer_unmap (&rtp_outbuf); - - GST_DEBUG_OBJECT (requester, "restored rtp packet #%d", seqnum); - - gst_buffer_unmap (inbuf, &inbuf_mapinfo); - gst_buffer_unmap (outbuf, &outbuf_mapinfo); - - return outbuf; -} - -static GstFlowReturn -gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * pad, GstObject * parent, - GstBuffer * buf) -{ - GstWFDRTPRequester *requester; - GstWFDRTPRequesterPrivate *priv; - GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *outbuf; - gint gap = 0; - gint seqnum = 0; - GstRTPBuffer rtp_buf = GST_RTP_BUFFER_INIT; - - requester = GST_WFD_RTP_REQUESTER_CAST (parent); - priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE (requester); - - if (!requester->do_request) - goto skip_buffer; - - outbuf = wfd_requester_handle_retransmitted_rtp (requester, buf); - if (!outbuf) { - GST_ERROR_OBJECT (requester, - "failed to handle retransmitted rtp packet..."); - return GST_FLOW_OK; - } - - /* check sequence of retransmitted rtp packet. */ - if (G_UNLIKELY (priv->next_in_seqnum == GST_CLOCK_TIME_NONE)) - goto skip_buffer; - - if (G_UNLIKELY (!gst_rtp_buffer_map (outbuf, GST_MAP_READ, &rtp_buf))) - goto skip_buffer; - - seqnum = gst_rtp_buffer_get_seq (&rtp_buf); - gst_rtp_buffer_unmap (&rtp_buf); - - gap = gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, seqnum); - if (G_UNLIKELY (gap > 0)) { - GST_ERROR_OBJECT (requester, "#%d is invalid sequence number, gap of %d", - seqnum, gap); - goto skip_buffer; - } - - ret = gst_wfd_rtp_requester_chain (requester->rtp_sink, parent, outbuf); - if (ret != GST_FLOW_OK) - GST_ERROR_OBJECT (requester, "failed to push retransmitted rtp packet..."); - -finished: - gst_buffer_unref (buf); - - /* just return OK */ - return GST_FLOW_OK; - - /* ERRORS */ -skip_buffer: - { - GST_DEBUG_OBJECT (requester, - "requeseter is set to not handle retransmission, dropping"); - goto finished; - } -} - -static GstPad * -gst_wfd_rtp_requester_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name, const GstCaps * caps) -{ - GstWFDRTPRequester *requester; - GstElementClass *klass; - - requester = GST_WFD_RTP_REQUESTER (element); - klass = GST_ELEMENT_GET_CLASS (element); - - GST_WFD_RTP_REQUESTER_LOCK (requester); - - if (templ != gst_element_class_get_pad_template (klass, name)) - goto wrong_template; - - if (requester->retransmitted_rtp_sink != NULL) - goto exists; - - GST_LOG_OBJECT (requester, "Creating new pad for retreansmitted RTP packets"); - - requester->retransmitted_rtp_sink = - gst_pad_new_from_static_template (&retransmitted_rtp_sink_template, - "retransmitted_rtp_sink"); - gst_pad_set_chain_function (requester->retransmitted_rtp_sink, - gst_wfd_rtp_requester_chain_retransmitted_rtp); - gst_pad_set_event_function (requester->retransmitted_rtp_sink, - (GstPadEventFunction) gst_wfd_rtp_requester_sink_event_retransmitted_rtp); - gst_pad_use_fixed_caps (requester->retransmitted_rtp_sink); - gst_pad_set_active (requester->retransmitted_rtp_sink, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (requester), - requester->retransmitted_rtp_sink); - - GST_DEBUG_OBJECT (requester, "creating RTCP src pad for RTCP FB packets"); - requester->rtcp_src = - gst_pad_new_from_static_template (&rtcp_src_template, "rtcp_src"); - gst_pad_set_event_function (requester->rtcp_src, - (GstPadEventFunction) gst_wfd_rtp_requester_src_event_rtcp); - gst_pad_use_fixed_caps (requester->rtcp_src); - gst_pad_set_active (requester->rtcp_src, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (requester), requester->rtcp_src); - - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - - return requester->retransmitted_rtp_sink; - -/* ERRORS */ -wrong_template: - { - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - g_warning ("wfdrtprequester: this is not our template"); - return NULL; - } -exists: - { - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - g_warning ("wfdrtprequester: pad already requested"); - return NULL; - } -} - -static void -gst_wfd_rtp_requester_release_pad (GstElement * element, GstPad * pad) -{ - GstWFDRTPRequester *requester; - - g_return_if_fail (GST_IS_WFD_RTP_REQUESTER (element)); - g_return_if_fail (GST_IS_PAD (pad)); - - requester = GST_WFD_RTP_REQUESTER (element); - - GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - - GST_WFD_RTP_REQUESTER_LOCK (requester); - - if (requester->retransmitted_rtp_sink == pad) { - /* deactivate from source to sink */ - gst_pad_set_active (requester->rtcp_src, FALSE); - gst_pad_set_active (requester->retransmitted_rtp_sink, FALSE); - - /* remove pads */ - GST_DEBUG_OBJECT (requester, "removing retransmitted RTP sink pad"); - gst_element_remove_pad (GST_ELEMENT_CAST (requester), - requester->retransmitted_rtp_sink); - requester->retransmitted_rtp_sink = NULL; - - GST_DEBUG_OBJECT (requester, "removing RTCP src pad"); - gst_element_remove_pad (GST_ELEMENT_CAST (requester), requester->rtcp_src); - requester->rtcp_src = NULL; - } else - goto wrong_pad; - - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - - return; - - /* ERRORS */ -wrong_pad: - { - GST_WFD_RTP_REQUESTER_UNLOCK (requester); - g_warning ("wfdrtprequester: asked to release an unknown pad"); - return; - } -} diff --git a/wfdextmanager/gstwfdrtprequester.h b/wfdextmanager/gstwfdrtprequester.h deleted file mode 100755 index 46f31be..0000000 --- a/wfdextmanager/gstwfdrtprequester.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * wfdrtprequester - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: JongHyuk Choi - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Alternatively, the contents of this file may be used under the - * GNU Lesser General Public License Version 2.1 (the "LGPL"), in - * which case the following provisions apply instead of the ones - * mentioned above: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - -#ifndef __GST_WFD_RTP_REQUESTER_H__ -#define __GST_WFD_RTP_REQUESTER_H__ - -#include - -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_WFD_RTP_REQUESTER \ - (gst_wfd_rtp_requester_get_type()) -#define GST_WFD_RTP_REQUESTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequester)) -#define GST_WFD_RTP_REQUESTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequesterClass)) -#define GST_IS_WFD_RTP_REQUESTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_RTP_REQUESTER)) -#define GST_IS_WFD_RTP_REQUESTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_RTP_REQUESTER)) -#define GST_WFD_RTP_REQUESTER_CAST(obj) ((GstWFDRTPRequester *)(obj)) - -typedef struct _GstWFDRTPRequester GstWFDRTPRequester; -typedef struct _GstWFDRTPRequesterClass GstWFDRTPRequesterClass; -typedef struct _GstWFDRTPRequesterPrivate GstWFDRTPRequesterPrivate; - -struct _GstWFDRTPRequester -{ - GstElement element; - - GstPad *rtp_sink, *rtp_src; - GstPad *rtcp_src, *retransmitted_rtp_sink; - - /* properties */ - gboolean do_request; - guint32 ssrc; - guint8 pt; - guint timeout_ms; - guint64 timeout_ns; - - GstWFDRTPRequesterPrivate *priv; -}; - -struct _GstWFDRTPRequesterClass -{ - GstElementClass parent_class; - - /* signals */ - void (*request_idr) (GstWFDRTPRequester *requester); -}; - -GType gst_wfd_rtp_requester_get_type (void); - -G_END_DECLS - -#endif /* __GST_WFD_RTP_REQUESTER_H__ */ - -- 2.7.4 From 8c69b7a72391b0c4da6538ead236ee7d7c38aadb Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 3 Jan 2017 13:13:08 +0900 Subject: [PATCH 15/16] Add gst_caps_unref for assigned caps Signed-off-by: SeokHoon Lee Change-Id: Ib2cf898af9492d7507685c3477d796131c9b22b6 --- alfec/gst_source_deblocking_algorithm.c | 1 + alfec/gstalfecencoder.c | 1 + packaging/gst-plugins-tizen.spec | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) mode change 100755 => 100644 alfec/gst_source_deblocking_algorithm.c mode change 100755 => 100644 alfec/gstalfecencoder.c diff --git a/alfec/gst_source_deblocking_algorithm.c b/alfec/gst_source_deblocking_algorithm.c old mode 100755 new mode 100644 index 2973a2a..f98a3d9 --- a/alfec/gst_source_deblocking_algorithm.c +++ b/alfec/gst_source_deblocking_algorithm.c @@ -184,6 +184,7 @@ fill_empty_packets (GstSourceDeblockingAlgorithm *self) GstCaps *caps = gst_caps_new_empty_simple ("fec"); gst_buffer_pool_config_set_params (conf, caps, self->priv->t_max, 1, self->priv->k_max); gst_buffer_pool_set_config (self->priv->pool, conf); + gst_caps_unref (caps); if (!gst_buffer_pool_set_active (self->priv->pool, TRUE)) { GST_ERROR_OBJECT (self, "activation failed"); diff --git a/alfec/gstalfecencoder.c b/alfec/gstalfecencoder.c old mode 100755 new mode 100644 index 78330d0..d0865a2 --- a/alfec/gstalfecencoder.c +++ b/alfec/gstalfecencoder.c @@ -483,6 +483,7 @@ gst_al_fec_encoder_create_parity_block (GstALFECEncoder *enc, const guint8 *p) GstCaps *caps = gst_caps_new_empty_simple ("fec"); gst_buffer_pool_config_set_params (conf, caps, enc->symbol_length + DEFAULT_HEADER_SIZE, 1, 2 * enc->max_p); gst_buffer_pool_set_config (enc->pool, conf); + gst_caps_unref (caps); if (!gst_buffer_pool_set_active (enc->pool, TRUE)) { GST_ERROR_OBJECT (enc, "activation failed"); diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 33a07c7..a1bee34 100755 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 35 +Release: 36 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ -- 2.7.4 From 80d9924a96bc7b7ad5cae54128a53bb1c5a5c66c Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 7 Feb 2017 16:08:23 +0900 Subject: [PATCH 16/16] Change wfd message wfd-video-formats have none parameter for audio only sink Signed-off-by: SeokHoon Lee Change-Id: I9c4f4198a21c6ab7c02a8d2714a06f5bde0a2353 --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdsinkmessage.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) mode change 100755 => 100644 packaging/gst-plugins-tizen.spec diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec old mode 100755 new mode 100644 index a1bee34..ffc4798 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -5,7 +5,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 36 +Release: 37 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.c b/wfdmanager/wfdbase/gstwfdsinkmessage.c index 2602328..550358f 100644 --- a/wfdmanager/wfdbase/gstwfdsinkmessage.c +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.c @@ -288,8 +288,8 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) /* list of video codecs */ if (msg->video_formats) { g_string_append_printf(lines, GST_STRING_WFD_VIDEO_FORMATS); + g_string_append_printf(lines, GST_STRING_WFD_COLON); if (msg->video_formats->list) { - g_string_append_printf(lines, GST_STRING_WFD_COLON); g_string_append_printf(lines, " %02x", msg->video_formats->list->native); g_string_append_printf(lines, " %02x", msg->video_formats->list->preferred_display_mode_supported); g_string_append_printf(lines, " %02x", msg->video_formats->list->H264_codec.profile); @@ -316,6 +316,9 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) g_string_append_printf(lines, GST_STRING_WFD_SPACE); g_string_append_printf(lines, GST_STRING_WFD_NONE); } + } else { + g_string_append_printf(lines, GST_STRING_WFD_SPACE); + g_string_append_printf(lines, GST_STRING_WFD_NONE); } g_string_append_printf(lines, GST_STRING_WFD_CRLF); } -- 2.7.4