From bb653e371d0f7ddaaf4f9ae6bc457228e20d4d03 Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Fri, 28 Oct 2016 15:58:43 +0900 Subject: [PATCH 01/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 02/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 03/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 04/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 05/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 06/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 07/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 08/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 09/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 10/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 11/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 From 4154b173ec1fd50d1c00c2628452f7be2f3ba076 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Mon, 13 Feb 2017 15:02:56 +0900 Subject: [PATCH 12/16] fix memoryleak and unerflow Signed-off-by: SeokHoon Lee Change-Id: Id3d760189f8bb32cf28f326eb07cd045016efcd0 --- wfdmanager/wfdbase/gstwfdsinkmessage.c | 4 +++- wfdtsdemux/wfdtsdemux.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) mode change 100755 => 100644 wfdtsdemux/wfdtsdemux.c diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.c b/wfdmanager/wfdbase/gstwfdsinkmessage.c index 550358f..83a3026 100644 --- a/wfdmanager/wfdbase/gstwfdsinkmessage.c +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.c @@ -1398,12 +1398,14 @@ GstWFDResult gst_wfd_message_set_supported_video_format(GstWFDMessage *msg, GstW if (vCodec != GST_WFD_VIDEO_UNKNOWN) { msg->video_formats->list = g_new0(GstWFDVideoCodec, 1); + + temp >>= 1; while (temp) { nativeindex++; temp >>= 1; } - msg->video_formats->list->native = nativeindex - 1; + msg->video_formats->list->native = nativeindex; msg->video_formats->list->native <<= 3; if (vNative == GST_WFD_VIDEO_VESA_RESOLUTION) diff --git a/wfdtsdemux/wfdtsdemux.c b/wfdtsdemux/wfdtsdemux.c old mode 100755 new mode 100644 index f9a6a4b..50ff7d3 --- a/wfdtsdemux/wfdtsdemux.c +++ b/wfdtsdemux/wfdtsdemux.c @@ -1160,6 +1160,10 @@ create_pad_for_stream (WFDTSBase * base, WFDTSBaseStream * bstream, /* hack for itv hd (sid 10510, video pid 3401 */ if (program->program_number == 10510 && bstream->pid == 3401) { template = gst_static_pad_template_get (&video_template); + if (name) + g_free (name); + if (caps) + gst_caps_unref (caps); name = g_strdup_printf ("video_%04x", bstream->pid); caps = gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING, "byte-stream", -- 2.7.4 From 96a4e62e0944954704236b8114f1655a03dd27ed Mon Sep 17 00:00:00 2001 From: "Hyunsoo, Park" Date: Tue, 21 Feb 2017 20:25:20 +0900 Subject: [PATCH 13/16] Change wfd message for video only mirroring Using this patch, 'wfd-audio-formats' parameter have none parameter for video only sink. Basically, screen mirroring provides video & audio simultaneously. This patch will make screen mirroring to provide Video only. -When Video only mirroring mode goes, it makes 'wfd_audio_codecs' messages to 'none'. If 'sink session mode' in 'mmfw_wfd_sink.ini' is set '2', screen mirroring runs without audio(that is, video only mirroring) Change-Id: Ib71d7b1b9faacc2b98b9f6e3ae20c9bebac4d350 Signed-off-by: Hyunsoo, Park --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdbasesrc.c | 12 +-- wfdmanager/wfdbase/gstwfdsinkmessage.c | 130 ++++++++++++++++++--------------- 3 files changed, 80 insertions(+), 64 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index ffc4798..d9e66e0 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: 37 +Release: 38 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c index dbba724..1342ee6 100644 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -1750,9 +1750,9 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) 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_wfd_audio_codecseter(src, wfd_msg); - if(res != GST_RTSP_OK) { + if (wfd_msg->audio_codecs && wfd_msg->audio_codecs->count > 0) { + res = gst_wfd_base_src_get_wfd_audio_codecseter (src, wfd_msg); + if (res != GST_RTSP_OK) { goto message_config_error; } @@ -1764,9 +1764,9 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) NULL); } - if(wfd_msg->video_formats) { - res = gst_wfd_base_src_get_wfd_video_formatseter(src, wfd_msg); - if(res != GST_RTSP_OK) { + if (wfd_msg->video_formats && wfd_msg->video_formats->count > 0) { + res = gst_wfd_base_src_get_wfd_video_formatseter (src, wfd_msg); + if (res != GST_RTSP_OK) { goto message_config_error; } diff --git a/wfdmanager/wfdbase/gstwfdsinkmessage.c b/wfdmanager/wfdbase/gstwfdsinkmessage.c index 83a3026..333eada 100644 --- a/wfdmanager/wfdbase/gstwfdsinkmessage.c +++ b/wfdmanager/wfdbase/gstwfdsinkmessage.c @@ -272,8 +272,8 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) if (msg->audio_codecs) { guint i = 0; g_string_append_printf(lines, GST_STRING_WFD_AUDIO_CODECS); + g_string_append_printf(lines, GST_STRING_WFD_COLON); if (msg->audio_codecs->list) { - g_string_append_printf(lines, GST_STRING_WFD_COLON); for (; i < msg->audio_codecs->count; i++) { g_string_append_printf(lines, " %s", msg->audio_codecs->list[i].audio_format); g_string_append_printf(lines, " %08x", msg->audio_codecs->list[i].modes); @@ -281,6 +281,9 @@ gst_wfd_message_as_text(const GstWFDMessage *msg) if ((i + 1) < msg->audio_codecs->count) g_string_append_printf(lines, GST_STRING_WFD_COMMA); } + } 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); } @@ -730,55 +733,66 @@ gst_wfd_parse_line(GstWFDMessage *msg, gchar *buffer) /*g_print("gst_wfd_parse_line input: %s\n", buffer); */ read_string_type_and_value(type, value, sizeof(type), sizeof(value), ':', p); /*g_print("gst_wfd_parse_line type:%s value:%s\n", type, value); */ + if (!g_strcmp0(type, GST_STRING_WFD_AUDIO_CODECS)) { msg->audio_codecs = g_new0(GstWFDAudioCodeclist, 1); if (strlen(v)) { - guint i = 0; - msg->audio_codecs->count = strlen(v) / 16; - msg->audio_codecs->list = g_new0(GstWFDAudioCodec, msg->audio_codecs->count); - for (; i < msg->audio_codecs->count; i++) { - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_STRING(msg->audio_codecs->list[i].audio_format); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->audio_codecs->list[i].modes); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->audio_codecs->list[i].latency); - GST_WFD_SKIP_COMMA(v); + if (!strcmp(v, GST_STRING_WFD_NONE)) { + msg->audio_codecs->list = NULL; + msg->audio_codecs->count = 0; + } else { + guint i = 0; + msg->audio_codecs->count = strlen(v) / 16; + msg->audio_codecs->list = g_new0(GstWFDAudioCodec, msg->audio_codecs->count); + for (; i < msg->audio_codecs->count; i++) { + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_STRING(msg->audio_codecs->list[i].audio_format); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->audio_codecs->list[i].modes); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->audio_codecs->list[i].latency); + GST_WFD_SKIP_COMMA(v); + } } } } else if (!g_strcmp0(type, GST_STRING_WFD_VIDEO_FORMATS)) { msg->video_formats = g_new0(GstWFDVideoCodeclist, 1); if (strlen(v)) { - msg->video_formats->count = 1; - msg->video_formats->list = g_new0(GstWFDVideoCodec, 1); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->native); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->preferred_display_mode_supported); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.profile); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.level); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.CEA_Support); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.VESA_Support); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.HH_Support); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.latency); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.min_slice_size); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.slice_enc_params); - GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.frame_rate_control_support); - GST_WFD_SKIP_SPACE(v); - if (msg->video_formats->list->preferred_display_mode_supported == GST_WFD_PREFERRED_DISPLAY_MODE_SUPPORTED) { - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.max_hres); + if (!strcmp(v, GST_STRING_WFD_NONE)) { + msg->video_formats->count = 0 ; + msg->video_formats->list = NULL; + } else { + msg->video_formats->count = 1; + msg->video_formats->list = g_new0(GstWFDVideoCodec, 1); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->native); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->preferred_display_mode_supported); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.profile); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.level); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.CEA_Support); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.VESA_Support); GST_WFD_SKIP_SPACE(v); - GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.max_vres); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.HH_Support); GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.latency); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.min_slice_size); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.slice_enc_params); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.misc_params.frame_rate_control_support); + GST_WFD_SKIP_SPACE(v); + if (msg->video_formats->list->preferred_display_mode_supported == GST_WFD_PREFERRED_DISPLAY_MODE_SUPPORTED) { + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.max_hres); + GST_WFD_SKIP_SPACE(v); + GST_WFD_READ_UINT32(msg->video_formats->list->H264_codec.max_vres); + GST_WFD_SKIP_SPACE(v); + } } } } else if (!g_strcmp0(type, GST_STRING_WFD_3D_VIDEO_FORMATS)) { @@ -1304,21 +1318,25 @@ GstWFDResult gst_wfd_message_set_preferred_audio_format(GstWFDMessage *msg, GstW if (!msg->audio_codecs) msg->audio_codecs = g_new0(GstWFDAudioCodeclist, 1); - - msg->audio_codecs->list = g_new0(GstWFDAudioCodec, 1); - msg->audio_codecs->count = 1; - if (aCodec == GST_WFD_AUDIO_LPCM) { - msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_LPCM); - msg->audio_codecs->list->modes = aFreq; - msg->audio_codecs->list->latency = aLatency; - } else if (aCodec == GST_WFD_AUDIO_AAC) { - msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_AAC); - msg->audio_codecs->list->modes = aChanels; - msg->audio_codecs->list->latency = aLatency; - } else if (aCodec == GST_WFD_AUDIO_AC3) { - msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_AC3); - msg->audio_codecs->list->modes = aChanels; - msg->audio_codecs->list->latency = aLatency; + if (aCodec != GST_WFD_AUDIO_UNKNOWN) { + msg->audio_codecs->list = g_new0(GstWFDAudioCodec, 1); + msg->audio_codecs->count = 1; + if (aCodec == GST_WFD_AUDIO_LPCM) { + msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_LPCM); + msg->audio_codecs->list->modes = aFreq; + msg->audio_codecs->list->latency = aLatency; + } else if (aCodec == GST_WFD_AUDIO_AAC) { + msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_AAC); + msg->audio_codecs->list->modes = aChanels; + msg->audio_codecs->list->latency = aLatency; + } else if (aCodec == GST_WFD_AUDIO_AC3) { + msg->audio_codecs->list->audio_format = g_strdup(GST_STRING_WFD_AC3); + msg->audio_codecs->list->modes = aChanels; + msg->audio_codecs->list->latency = aLatency; + } + } else { + msg->audio_codecs->list = NULL; + msg->audio_codecs->count = 0; } return GST_WFD_OK; } @@ -1329,7 +1347,6 @@ GstWFDResult gst_wfd_message_get_supported_audio_format(GstWFDMessage *msg, guin guint i = 0; g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); g_return_val_if_fail(msg->audio_codecs != NULL, GST_WFD_EINVAL); - for (; i < msg->audio_codecs->count; i++) { if (!g_strcmp0(msg->audio_codecs->list[i].audio_format, GST_STRING_WFD_LPCM)) { *aCodec |= GST_WFD_AUDIO_LPCM; @@ -1358,7 +1375,6 @@ GstWFDResult gst_wfd_message_get_preferred_audio_format(GstWFDMessage *msg, GstW guint *aBitwidth, guint32 *aLatency) { g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL); - if (!g_strcmp0(msg->audio_codecs->list->audio_format, GST_STRING_WFD_LPCM)) { *aCodec = GST_WFD_AUDIO_LPCM; *aFreq = msg->audio_codecs->list->modes; -- 2.7.4 From f8d142e594be5d2c2788bcebf5a91c54cf72293c Mon Sep 17 00:00:00 2001 From: "hk57.kim" Date: Wed, 8 Feb 2017 14:28:47 +0900 Subject: [PATCH 14/16] [4.0] Remove Target_Name Dependency - This is for Tizen 4.0 - We are going to unify repositories as well as build projects. - When you SR this, you need to create JIRA-TRE issue of: : add gst-plugins-tizen-extension-TM1 for TM1 (mobile) (It's add, not replace.) Change-Id: I98b7a5d14e875a36879744a9473dbb3b7a2dd38f Signed-off-by: hk57.kim --- packaging/gst-plugins-tizen.spec | 103 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index d9e66e0..e735114 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -1,3 +1,7 @@ +# Do not create provides fro extension-tm1 because the main package +# should anchor any reverse-dependencies +%global __provides_exclude_from ^(.*\\.tm1)$ + %bcond_with wayland %bcond_with x %define gst_branch 1.0 @@ -39,14 +43,25 @@ BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(tizen-extension-client) BuildRequires: pkgconfig(gstreamer-wayland-1.0) %endif -%if "%{tizen_target_name}" == "TM1" + +%description +GStreamer tizen plugins (common) + +%ifarch %{arm} +# This is for backward-compatibility. This does not deteriorate 4.0 Configurability +# if mobile || "undefined" +%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common" +%package extension-TM1 +Summary: Extension for mobile TM1 +Requires: %{name} = %{version}-%{release} #!BuildIgnore: kernel-headers BuildConflicts: linux-glibc-devel BuildRequires: kernel-headers-tizen-dev -%endif -%description -GStreamer tizen plugins (common) +%description extension-TM1 +GStreamer tizen plugins Extension for mobile TM1 +%endif +%endif %prep %setup -q @@ -54,10 +69,36 @@ GStreamer tizen plugins (common) %build export CFLAGS+=" -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " -%if "%{tizen_target_name}" == "TM1" -export CFLAGS="$CFLAGS -DTIZEN_PROFILE_LITE" +export CFLAGS_DEFAULT="$CFLAGS" + +%ifarch %{arm} +# This is for backward-compatibility. This does not deteriorate 4.0 Configurability +# if mobile || "undefined" +%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common" +# extension-TM1 +export CFLAGS="$CFLAGS_DEFAULT -DTIZEN_PROFILE_LITE" + +./autogen.sh --disable-static +%configure \ + --disable-drmdecryptor\ + --enable-ext-wfdtizenmanager\ + --enable-ext-alfec\ + --enable-ext-rtpresender\ + --disable-static + +make %{?jobs:-j%jobs} + +mkdir -p tm1 + +%make_install +cp -a %{buildroot}%{_libdir}/gstreamer-%{gst_branch}/*.so tm1/ +cp -a %{buildroot}%{_libdir}/libgstwfdbase.so* tm1/ +%endif %endif +# common +export CFLAGS="$CFLAGS_DEFAULT" + ./autogen.sh --disable-static %configure \ --disable-drmdecryptor\ @@ -74,9 +115,59 @@ rm -rf %{buildroot} mkdir -p %{buildroot}/%{_datadir}/license cp -rf %{_builddir}/%{name}-%{version}/COPYING %{buildroot}%{_datadir}/license/%{name} +%ifarch %{arm} +# This is for backward-compatibility. This does not deteriorate 4.0 Configurability +# if mobile || "undefined" +%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common" +# extension-TM1 +pushd tm1 +for FILE in libgstwfdbase.so*; do mv "$FILE" "%{buildroot}%{_libdir}/$FILE.tm1"; done +for FILE in *.so; do mv "$FILE" "%{buildroot}%{_libdir}/gstreamer-%{gst_branch}/$FILE.tm1"; done +popd + +%post extension-TM1 +pushd %{_libdir} +for FILE in libgstwfdbase.so*.tm1; do mv "$FILE" "${FILE%.tm1}"; done +popd +pushd %{_libdir}/gstreamer-%{gst_branch} +for FILE in *.so.tm1; do mv "$FILE" "${FILE%.tm1}"; done +popd +/sbin/ldconfig + +%preun extension-TM1 +case "$1" in + 0) + # This is an un-installation. + pushd %{_libdir} + for FILE in libgstwfdbase.so*; do mv "$FILE" "${FILE%.tm1}"; done + popd + pushd %{_libdir}/gstreamer-%{gst_branch} + for FILE in *.so; do mv "$FILE" "${FILE%.tm1}"; done + popd + /sbin/ldconfig + ;; + 1) + # This is an upgrade. + # Do nothing. + : + ;; +esac + +%files extension-TM1 +%manifest gst-plugins-tizen1.0.manifest +%{_libdir}/gstreamer-%{gst_branch}/*.so.tm1 +%{_libdir}/libgstwfdbase.so*.tm1 +%endif +%endif + %files %manifest gst-plugins-tizen1.0.manifest %defattr(-,root,root,-) %{_libdir}/gstreamer-%{gst_branch}/*.so %{_libdir}/libgstwfdbase.so* +%ifarch %{arm} +%exclude %{_libdir}/gstreamer-%{gst_branch}/*.so.tm1 +%exclude %{_libdir}/libgstwfdbase.so*.tm1 +%endif + %{_datadir}/license/%{name} -- 2.7.4 From b835abd4dbb3da801a5e8430748887e0d24402ac Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Wed, 22 Mar 2017 19:58:07 +0900 Subject: [PATCH 15/16] spec: Use %license macro to copy license - fix SVACE issue by Reviewer AEGIS Change-Id: If8102bce9ca0de9ce422ad66292ec6c180188588 --- packaging/gst-plugins-tizen.spec | 5 ++--- waylandsrc/src/gstwaylandsrc.c | 1 + wfdtizenmanager/gstwfdtizensrc.c | 3 +++ wfdtsdemux/wfdtsdemux.c | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index e735114..779e0ac 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -112,8 +112,6 @@ make %{?jobs:-j%jobs} %install rm -rf %{buildroot} %make_install -mkdir -p %{buildroot}/%{_datadir}/license -cp -rf %{_builddir}/%{name}-%{version}/COPYING %{buildroot}%{_datadir}/license/%{name} %ifarch %{arm} # This is for backward-compatibility. This does not deteriorate 4.0 Configurability @@ -155,6 +153,7 @@ esac %files extension-TM1 %manifest gst-plugins-tizen1.0.manifest +%license COPYING %{_libdir}/gstreamer-%{gst_branch}/*.so.tm1 %{_libdir}/libgstwfdbase.so*.tm1 %endif @@ -162,6 +161,7 @@ esac %files %manifest gst-plugins-tizen1.0.manifest +%license COPYING %defattr(-,root,root,-) %{_libdir}/gstreamer-%{gst_branch}/*.so %{_libdir}/libgstwfdbase.so* @@ -170,4 +170,3 @@ esac %exclude %{_libdir}/libgstwfdbase.so*.tm1 %endif -%{_datadir}/license/%{name} diff --git a/waylandsrc/src/gstwaylandsrc.c b/waylandsrc/src/gstwaylandsrc.c index be6ee11..5c16396 100644 --- a/waylandsrc/src/gstwaylandsrc.c +++ b/waylandsrc/src/gstwaylandsrc.c @@ -548,6 +548,7 @@ shm_buffer_create (struct wl_shm *shm, gsize width, gsize height) pool = make_shm_pool (shm, block_size, &data); if (!pool) { + g_free (out_buffer); return NULL; } diff --git a/wfdtizenmanager/gstwfdtizensrc.c b/wfdtizenmanager/gstwfdtizensrc.c index 0f62bc1..f20289d 100644 --- a/wfdtizenmanager/gstwfdtizensrc.c +++ b/wfdtizenmanager/gstwfdtizensrc.c @@ -502,6 +502,9 @@ gst_wfd_tizen_src_handle_set_parameter (GstWFDBaseSrc * bsrc, /* ERRORS */ error: { + if (msg) + gst_wfd_tizen_message_free (msg); + GST_ERROR_OBJECT (src, "Could not handle message"); return res; } diff --git a/wfdtsdemux/wfdtsdemux.c b/wfdtsdemux/wfdtsdemux.c index 50ff7d3..bb8d3fd 100644 --- a/wfdtsdemux/wfdtsdemux.c +++ b/wfdtsdemux/wfdtsdemux.c @@ -1419,6 +1419,8 @@ activate_pad_for_stream (GstWFDTSDemux * tsdemux, WFDTSDemuxStream * stream) if (((WFDTSBaseStream *) stream)->stream_type == ST_PS_WFD_AUDIO_LPCM) { GstCaps *caps = NULL; gchar *format = g_strdup_printf ("S%dBE", stream->lpcm_data.width); + if (!format) + return; caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, format, @@ -1429,6 +1431,7 @@ activate_pad_for_stream (GstWFDTSDemux * tsdemux, WFDTSDemuxStream * stream) if (caps) gst_caps_unref (caps); + g_free (format); } #endif -- 2.7.4 From e138ff409919938219962bd2291e113bac808ada Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Wed, 29 Mar 2017 09:49:36 +0900 Subject: [PATCH 16/16] Fix memory leak - msg free in error case - url0,url1 free after use Signed-off-by: SeokHoon Lee Change-Id: I9bfd4f481abd6b24ccc3df5f9990dd79bbf4d6cb --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdbasesrc.c | 3 +++ wfdtizenmanager/gstwfdtizensrc.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 779e0ac..b5d0e49 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 38 +Release: 39 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c index 1342ee6..2c090a6 100644 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -1798,7 +1798,10 @@ gst_wfd_base_src_handle_request (GstWFDBaseSrc * src, GstRTSPMessage * request) g_free (priv->conninfo.location); priv->conninfo.location = g_strdup (url0); + g_free (url0); + /* url1 is ignored as of now */ + g_free (url1); } /* Note : wfd-client-rtp-ports : diff --git a/wfdtizenmanager/gstwfdtizensrc.c b/wfdtizenmanager/gstwfdtizensrc.c index f20289d..db6647a 100644 --- a/wfdtizenmanager/gstwfdtizensrc.c +++ b/wfdtizenmanager/gstwfdtizensrc.c @@ -624,6 +624,8 @@ gst_wfd_tizen_src_handle_get_parameter (GstWFDBaseSrc * bsrc, /* ERRORS */ error: { + if (msg) + gst_wfd_tizen_message_free (msg); GST_ERROR_OBJECT (src, "Could not handle message"); return res; } -- 2.7.4