mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
realmedia: remove RealServer RTSP extension, RDT handling and PNM source
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6091>
This commit is contained in:
parent
1ef7e9be73
commit
68d62a8433
19 changed files with 6 additions and 5533 deletions
|
@ -13890,9 +13890,6 @@
|
|||
"GstOverlayComposition!src",
|
||||
"GstOverlayComposition::caps-changed",
|
||||
"GstOverlayComposition::draw",
|
||||
"GstPNMSrc",
|
||||
"GstPNMSrc!src",
|
||||
"GstPNMSrc:location",
|
||||
"GstPad",
|
||||
"GstPad.ABI._gst_reserved",
|
||||
"GstPad.ABI.abi.eventfullfunc",
|
||||
|
@ -14612,21 +14609,6 @@
|
|||
"GstQueueLeaky::downstream",
|
||||
"GstQueueLeaky::no",
|
||||
"GstQueueLeaky::upstream",
|
||||
"GstRDTDepay",
|
||||
"GstRDTDepay!sink",
|
||||
"GstRDTDepay!src",
|
||||
"GstRDTManager",
|
||||
"GstRDTManager!recv_rtcp_sink_%u",
|
||||
"GstRDTManager!recv_rtp_sink_%u",
|
||||
"GstRDTManager!recv_rtp_src_%u_%u_%u",
|
||||
"GstRDTManager!rtcp_src_%u",
|
||||
"GstRDTManager::clear-pt-map",
|
||||
"GstRDTManager::on-bye-ssrc",
|
||||
"GstRDTManager::on-bye-timeout",
|
||||
"GstRDTManager::on-npt-stop",
|
||||
"GstRDTManager::on-timeout",
|
||||
"GstRDTManager::request-pt-map",
|
||||
"GstRDTManager:latency",
|
||||
"GstRGB2Bayer",
|
||||
"GstRGB2Bayer!sink",
|
||||
"GstRGB2Bayer!src",
|
||||
|
@ -15234,7 +15216,6 @@
|
|||
"GstRTSPRange.max",
|
||||
"GstRTSPRange.min",
|
||||
"GstRTSPRangeUnit",
|
||||
"GstRTSPReal",
|
||||
"GstRTSPResult",
|
||||
"GstRTSPSendFunc",
|
||||
"GstRTSPSendListFunc",
|
||||
|
@ -36698,7 +36679,6 @@
|
|||
"element-pngparse",
|
||||
"element-pnmdec",
|
||||
"element-pnmenc",
|
||||
"element-pnmsrc",
|
||||
"element-progressreport",
|
||||
"element-proxysink",
|
||||
"element-proxysrc",
|
||||
|
@ -36718,8 +36698,6 @@
|
|||
"element-radioactv",
|
||||
"element-rawaudioparse",
|
||||
"element-rawvideoparse",
|
||||
"element-rdtdepay",
|
||||
"element-rdtmanager",
|
||||
"element-removesilence",
|
||||
"element-retinex",
|
||||
"element-revtv",
|
||||
|
@ -36860,7 +36838,6 @@
|
|||
"element-rtpvrawpay",
|
||||
"element-rtpxqtdepay",
|
||||
"element-rtspclientsink",
|
||||
"element-rtspreal",
|
||||
"element-rtspsrc",
|
||||
"element-rtspwms",
|
||||
"element-sbcdec",
|
||||
|
@ -66572,8 +66549,6 @@
|
|||
"pnmdec",
|
||||
"pnmenc",
|
||||
"pnmenc:ascii",
|
||||
"pnmsrc",
|
||||
"pnmsrc:location",
|
||||
"progressreport",
|
||||
"progressreport:do-query",
|
||||
"progressreport:format",
|
||||
|
@ -66834,15 +66809,6 @@
|
|||
"rawvideoparse:plane-strides",
|
||||
"rawvideoparse:top-field-first",
|
||||
"rawvideoparse:width",
|
||||
"rdtdepay",
|
||||
"rdtmanager",
|
||||
"rdtmanager::clear-pt-map",
|
||||
"rdtmanager::on-bye-ssrc",
|
||||
"rdtmanager::on-bye-timeout",
|
||||
"rdtmanager::on-npt-stop",
|
||||
"rdtmanager::on-timeout",
|
||||
"rdtmanager::request-pt-map",
|
||||
"rdtmanager:latency",
|
||||
"removesilence",
|
||||
"removesilence:hysteresis",
|
||||
"removesilence:minimum-silence-buffers",
|
||||
|
@ -67462,7 +67428,6 @@
|
|||
"rtspclientsink:user-agent",
|
||||
"rtspclientsink:user-id",
|
||||
"rtspclientsink:user-pw",
|
||||
"rtspreal",
|
||||
"rtspsrc",
|
||||
"rtspsrc::accept-certificate",
|
||||
"rtspsrc::before-send",
|
||||
|
|
|
@ -99,6 +99,10 @@ static const GstRTSPTransMap transports[] = {
|
|||
{"srtpf", GST_RTSP_TRANS_RTP, GST_RTSP_PROFILE_SAVPF,
|
||||
GST_RTSP_LOWER_TRANS_UDP_MCAST, "application/x-srtp",
|
||||
{"rtpbin", "rtpdec"}},
|
||||
/* FIXME: these two are no longer supported (the rdtmanager element and
|
||||
* related code has been removed from the realmedia plugin), but let's keep
|
||||
* this around for now so it can still be added back via plugins if needed.
|
||||
* FIXME 2.0: remove */
|
||||
{"x-real-rdt", GST_RTSP_TRANS_RDT, GST_RTSP_PROFILE_AVP,
|
||||
GST_RTSP_LOWER_TRANS_UNKNOWN, "application/x-rdt",
|
||||
{"rdtmanager", NULL}},
|
||||
|
|
|
@ -507,46 +507,6 @@
|
|||
"realmedia": {
|
||||
"description": "RealMedia support plugins",
|
||||
"elements": {
|
||||
"pnmsrc": {
|
||||
"author": "Wim Taymans <wim.taymans@gmail.com>",
|
||||
"description": "Receive data over the network via PNM",
|
||||
"hierarchy": [
|
||||
"GstPNMSrc",
|
||||
"GstPushSrc",
|
||||
"GstBaseSrc",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"interfaces": [
|
||||
"GstURIHandler"
|
||||
],
|
||||
"klass": "Source/Network",
|
||||
"long-name": "PNM packet receiver",
|
||||
"pad-templates": {
|
||||
"src": {
|
||||
"caps": "application/vnd.rn-realmedia:\n",
|
||||
"direction": "src",
|
||||
"presence": "always"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"location": {
|
||||
"blurb": "Location of the PNM url to read",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "NULL",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gchararray",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "marginal"
|
||||
},
|
||||
"rademux": {
|
||||
"author": "Tim-Philipp Müller <tim centricular net>",
|
||||
"description": "Demultiplex a RealAudio file",
|
||||
|
@ -558,7 +518,6 @@
|
|||
"GObject"
|
||||
],
|
||||
"klass": "Codec/Demuxer",
|
||||
"long-name": "RealAudio Demuxer",
|
||||
"pad-templates": {
|
||||
"sink": {
|
||||
"caps": "application/x-pn-realaudio:\n",
|
||||
|
@ -571,163 +530,7 @@
|
|||
"presence": "sometimes"
|
||||
}
|
||||
},
|
||||
"rank": "secondary",
|
||||
"signals": {}
|
||||
},
|
||||
"rdtdepay": {
|
||||
"author": "Lutz Mueller <lutz at topfrose dot de>, Wim Taymans <wim@fluendo.com>",
|
||||
"description": "Extracts RealMedia from RDT packets",
|
||||
"hierarchy": [
|
||||
"GstRDTDepay",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"klass": "Codec/Depayloader/Network",
|
||||
"long-name": "RDT packet parser",
|
||||
"pad-templates": {
|
||||
"sink": {
|
||||
"caps": "application/x-rdt:\n media: application\n clock-rate: [ 1, 2147483647 ]\n encoding-name: X-REAL-RDT\n",
|
||||
"direction": "sink",
|
||||
"presence": "always"
|
||||
},
|
||||
"src": {
|
||||
"caps": "application/vnd.rn-realmedia:\n",
|
||||
"direction": "src",
|
||||
"presence": "always"
|
||||
}
|
||||
},
|
||||
"rank": "marginal"
|
||||
},
|
||||
"rdtmanager": {
|
||||
"author": "Wim Taymans <wim.taymans@gmail.com>",
|
||||
"description": "Accepts raw RTP and RTCP packets and sends them forward",
|
||||
"hierarchy": [
|
||||
"GstRDTManager",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"klass": "Codec/Parser/Network",
|
||||
"long-name": "RTP Decoder",
|
||||
"pad-templates": {
|
||||
"recv_rtcp_sink_%%u": {
|
||||
"caps": "application/x-rtcp:\n",
|
||||
"direction": "sink",
|
||||
"presence": "request"
|
||||
},
|
||||
"recv_rtp_sink_%%u": {
|
||||
"caps": "application/x-rdt:\n",
|
||||
"direction": "sink",
|
||||
"presence": "request"
|
||||
},
|
||||
"recv_rtp_src_%%u_%%u_%%u": {
|
||||
"caps": "application/x-rdt:\n",
|
||||
"direction": "src",
|
||||
"presence": "sometimes"
|
||||
},
|
||||
"rtcp_src_%%u": {
|
||||
"caps": "application/x-rtcp:\n",
|
||||
"direction": "src",
|
||||
"presence": "request"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"latency": {
|
||||
"blurb": "Amount of ms to buffer",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "200",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "none",
|
||||
"signals": {
|
||||
"clear-pt-map": {
|
||||
"args": [],
|
||||
"return-type": "void",
|
||||
"when": "last"
|
||||
},
|
||||
"on-bye-ssrc": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "guint"
|
||||
},
|
||||
{
|
||||
"name": "arg1",
|
||||
"type": "guint"
|
||||
}
|
||||
],
|
||||
"return-type": "void",
|
||||
"when": "last"
|
||||
},
|
||||
"on-bye-timeout": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "guint"
|
||||
},
|
||||
{
|
||||
"name": "arg1",
|
||||
"type": "guint"
|
||||
}
|
||||
],
|
||||
"return-type": "void",
|
||||
"when": "last"
|
||||
},
|
||||
"on-npt-stop": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "guint"
|
||||
},
|
||||
{
|
||||
"name": "arg1",
|
||||
"type": "guint"
|
||||
}
|
||||
],
|
||||
"return-type": "void",
|
||||
"when": "last"
|
||||
},
|
||||
"on-timeout": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "guint"
|
||||
},
|
||||
{
|
||||
"name": "arg1",
|
||||
"type": "guint"
|
||||
}
|
||||
],
|
||||
"return-type": "void",
|
||||
"when": "last"
|
||||
},
|
||||
"request-pt-map": {
|
||||
"args": [
|
||||
{
|
||||
"name": "arg0",
|
||||
"type": "guint"
|
||||
},
|
||||
{
|
||||
"name": "arg1",
|
||||
"type": "guint"
|
||||
}
|
||||
],
|
||||
"return-type": "GstCaps",
|
||||
"when": "last"
|
||||
}
|
||||
}
|
||||
"rank": "secondary"
|
||||
},
|
||||
"rmdemux": {
|
||||
"author": "David Schleef <ds@schleef.org>",
|
||||
|
@ -740,7 +543,6 @@
|
|||
"GObject"
|
||||
],
|
||||
"klass": "Codec/Demuxer",
|
||||
"long-name": "RealMedia Demuxer",
|
||||
"pad-templates": {
|
||||
"audio_%%u": {
|
||||
"caps": "ANY",
|
||||
|
@ -758,25 +560,7 @@
|
|||
"presence": "sometimes"
|
||||
}
|
||||
},
|
||||
"rank": "primary",
|
||||
"signals": {}
|
||||
},
|
||||
"rtspreal": {
|
||||
"author": "Wim Taymans <wim.taymans@gmail.com>",
|
||||
"description": "Extends RTSP so that it can handle RealMedia setup",
|
||||
"hierarchy": [
|
||||
"GstRTSPReal",
|
||||
"GstElement",
|
||||
"GstObject",
|
||||
"GInitiallyUnowned",
|
||||
"GObject"
|
||||
],
|
||||
"interfaces": [
|
||||
"GstRTSPExtension"
|
||||
],
|
||||
"klass": "Network/Extension/Protocol",
|
||||
"long-name": "RealMedia RTSP Extension",
|
||||
"rank": "marginal"
|
||||
"rank": "primary"
|
||||
}
|
||||
},
|
||||
"filename": "gstrealmedia",
|
||||
|
|
|
@ -1,712 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asmrules.h"
|
||||
|
||||
#define MAX_RULE_LENGTH 2048
|
||||
|
||||
/* define to enable some more debug */
|
||||
#undef DEBUG
|
||||
|
||||
static GstASMNode *
|
||||
gst_asm_node_new (void)
|
||||
{
|
||||
GstASMNode *node;
|
||||
|
||||
node = g_new0 (GstASMNode, 1);
|
||||
node->type = GST_ASM_NODE_UNKNOWN;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_node_free (GstASMNode * node)
|
||||
{
|
||||
if (node->left)
|
||||
gst_asm_node_free (node->left);
|
||||
if (node->right)
|
||||
gst_asm_node_free (node->right);
|
||||
if (node->type == GST_ASM_NODE_VARIABLE && node->data.varname)
|
||||
g_free (node->data.varname);
|
||||
g_free (node);
|
||||
}
|
||||
|
||||
static gfloat
|
||||
gst_asm_operator_eval (GstASMOp optype, gfloat left, gfloat right)
|
||||
{
|
||||
gfloat result = 0.0;
|
||||
|
||||
switch (optype) {
|
||||
case GST_ASM_OP_GREATER:
|
||||
result = (gfloat) (left > right);
|
||||
break;
|
||||
case GST_ASM_OP_LESS:
|
||||
result = (gfloat) (left < right);
|
||||
break;
|
||||
case GST_ASM_OP_GREATEREQUAL:
|
||||
result = (gfloat) (left >= right);
|
||||
break;
|
||||
case GST_ASM_OP_LESSEQUAL:
|
||||
result = (gfloat) (left <= right);
|
||||
break;
|
||||
case GST_ASM_OP_EQUAL:
|
||||
result = (gfloat) (left == right);
|
||||
break;
|
||||
case GST_ASM_OP_NOTEQUAL:
|
||||
result = (gfloat) (left != right);
|
||||
break;
|
||||
case GST_ASM_OP_AND:
|
||||
result = (gfloat) (left && right);
|
||||
break;
|
||||
case GST_ASM_OP_OR:
|
||||
result = (gfloat) (left || right);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
gst_asm_node_evaluate (GstASMNode * node, GHashTable * vars)
|
||||
{
|
||||
gfloat result = 0.0;
|
||||
|
||||
if (node == NULL)
|
||||
return 0.0;
|
||||
|
||||
switch (node->type) {
|
||||
case GST_ASM_NODE_VARIABLE:
|
||||
{
|
||||
gchar *val;
|
||||
|
||||
val = g_hash_table_lookup (vars, node->data.varname);
|
||||
if (val)
|
||||
result = (gfloat) atof (val);
|
||||
break;
|
||||
}
|
||||
case GST_ASM_NODE_INTEGER:
|
||||
result = (gfloat) node->data.intval;
|
||||
break;
|
||||
case GST_ASM_NODE_FLOAT:
|
||||
result = node->data.floatval;
|
||||
break;
|
||||
case GST_ASM_NODE_OPERATOR:
|
||||
{
|
||||
gfloat left, right;
|
||||
|
||||
left = gst_asm_node_evaluate (node->left, vars);
|
||||
right = gst_asm_node_evaluate (node->right, vars);
|
||||
|
||||
result = gst_asm_operator_eval (node->data.optype, left, right);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define IS_SPACE(p) (((p) == ' ') || ((p) == '\n') || \
|
||||
((p) == '\r') || ((p) == '\t'))
|
||||
#define IS_RULE_DELIM(p) (((p) == ',') || ((p) == ';') || ((p) == ')'))
|
||||
#define IS_OPERATOR(p) (((p) == '>') || ((p) == '<') || \
|
||||
((p) == '=') || ((p) == '!') || \
|
||||
((p) == '&') || ((p) == '|'))
|
||||
#define IS_NUMBER(p) ((((p) >= '0') && ((p) <= '9')) || ((p) == '.'))
|
||||
#define IS_CHAR(p) (!IS_OPERATOR(ch) && !IS_RULE_DELIM(ch) && (ch != '\0'))
|
||||
|
||||
#define IS_OP_TOKEN(t) (((t) == GST_ASM_TOKEN_AND) || ((t) == GST_ASM_TOKEN_OR))
|
||||
#define IS_COND_TOKEN(t) (((t) == GST_ASM_TOKEN_LESS) || ((t) == GST_ASM_TOKEN_LESSEQUAL) || \
|
||||
((t) == GST_ASM_TOKEN_GREATER) || ((t) == GST_ASM_TOKEN_GREATEREQUAL) || \
|
||||
((t) == GST_ASM_TOKEN_EQUAL) || ((t) == GST_ASM_TOKEN_NOTEQUAL))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *buffer;
|
||||
gint pos;
|
||||
gchar ch;
|
||||
|
||||
GstASMToken token;
|
||||
gchar val[MAX_RULE_LENGTH];
|
||||
} GstASMScan;
|
||||
|
||||
#define NEXT_CHAR(scan) ((scan)->ch = (scan)->buffer[(scan)->pos++])
|
||||
#define THIS_CHAR(scan) ((scan)->ch)
|
||||
|
||||
static GstASMScan *
|
||||
gst_asm_scan_new (const gchar * buffer)
|
||||
{
|
||||
GstASMScan *scan;
|
||||
|
||||
scan = g_new0 (GstASMScan, 1);
|
||||
scan->buffer = buffer;
|
||||
NEXT_CHAR (scan);
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_free (GstASMScan * scan)
|
||||
{
|
||||
g_free (scan);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_string (GstASMScan * scan, gchar delim)
|
||||
{
|
||||
gchar ch;
|
||||
gint i = 0;
|
||||
|
||||
ch = THIS_CHAR (scan);
|
||||
while ((ch != delim) && (ch != '\0')) {
|
||||
if (i < MAX_RULE_LENGTH - 1)
|
||||
scan->val[i++] = ch;
|
||||
ch = NEXT_CHAR (scan);
|
||||
if (ch == '\\')
|
||||
ch = NEXT_CHAR (scan);
|
||||
}
|
||||
scan->val[i] = '\0';
|
||||
|
||||
if (ch == delim)
|
||||
NEXT_CHAR (scan);
|
||||
|
||||
scan->token = GST_ASM_TOKEN_STRING;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_number (GstASMScan * scan)
|
||||
{
|
||||
gchar ch;
|
||||
gint i = 0;
|
||||
gboolean have_float = FALSE;
|
||||
|
||||
ch = THIS_CHAR (scan);
|
||||
/* real strips all spaces that are not inside quotes for numbers */
|
||||
while ((IS_NUMBER (ch) || IS_SPACE (ch))) {
|
||||
if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
|
||||
scan->val[i++] = ch;
|
||||
if (ch == '.')
|
||||
have_float = TRUE;
|
||||
ch = NEXT_CHAR (scan);
|
||||
}
|
||||
scan->val[i] = '\0';
|
||||
|
||||
if (have_float)
|
||||
scan->token = GST_ASM_TOKEN_FLOAT;
|
||||
else
|
||||
scan->token = GST_ASM_TOKEN_INT;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_identifier (GstASMScan * scan)
|
||||
{
|
||||
gchar ch;
|
||||
gint i = 0;
|
||||
|
||||
ch = THIS_CHAR (scan);
|
||||
/* real strips all spaces that are not inside quotes for identifiers */
|
||||
while ((IS_CHAR (ch) || IS_SPACE (ch))) {
|
||||
if (i < (MAX_RULE_LENGTH - 1) && !IS_SPACE (ch))
|
||||
scan->val[i++] = ch;
|
||||
ch = NEXT_CHAR (scan);
|
||||
}
|
||||
scan->val[i] = '\0';
|
||||
|
||||
scan->token = GST_ASM_TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_print_token (GstASMScan * scan)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
switch (scan->token) {
|
||||
case GST_ASM_TOKEN_NONE:
|
||||
g_print ("none\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_EOF:
|
||||
g_print ("EOF\n");
|
||||
break;
|
||||
|
||||
case GST_ASM_TOKEN_INT:
|
||||
g_print ("INT %d\n", atoi (scan->val));
|
||||
break;
|
||||
case GST_ASM_TOKEN_FLOAT:
|
||||
g_print ("FLOAT %f\n", atof (scan->val));
|
||||
break;
|
||||
case GST_ASM_TOKEN_IDENTIFIER:
|
||||
g_print ("ID %s\n", scan->val);
|
||||
break;
|
||||
case GST_ASM_TOKEN_STRING:
|
||||
g_print ("STRING %s\n", scan->val);
|
||||
break;
|
||||
|
||||
case GST_ASM_TOKEN_HASH:
|
||||
g_print ("HASH\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_SEMICOLON:
|
||||
g_print ("SEMICOLON\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_COMMA:
|
||||
g_print ("COMMA\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_EQUAL:
|
||||
g_print ("==\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_NOTEQUAL:
|
||||
g_print ("!=\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_AND:
|
||||
g_print ("&&\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_OR:
|
||||
g_print ("||\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_LESS:
|
||||
g_print ("<\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_LESSEQUAL:
|
||||
g_print ("<=\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_GREATER:
|
||||
g_print (">\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_GREATEREQUAL:
|
||||
g_print (">=\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_DOLLAR:
|
||||
g_print ("$\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_LPAREN:
|
||||
g_print ("(\n");
|
||||
break;
|
||||
case GST_ASM_TOKEN_RPAREN:
|
||||
g_print (")\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static GstASMToken
|
||||
gst_asm_scan_next_token (GstASMScan * scan)
|
||||
{
|
||||
gchar ch;
|
||||
|
||||
ch = THIS_CHAR (scan);
|
||||
|
||||
/* skip spaces */
|
||||
while (IS_SPACE (ch))
|
||||
ch = NEXT_CHAR (scan);
|
||||
|
||||
/* remove \ which is common in front of " */
|
||||
while (ch == '\\')
|
||||
ch = NEXT_CHAR (scan);
|
||||
|
||||
switch (ch) {
|
||||
case '#':
|
||||
scan->token = GST_ASM_TOKEN_HASH;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case ';':
|
||||
scan->token = GST_ASM_TOKEN_SEMICOLON;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case ',':
|
||||
scan->token = GST_ASM_TOKEN_COMMA;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '=':
|
||||
scan->token = GST_ASM_TOKEN_EQUAL;
|
||||
if (NEXT_CHAR (scan) == '=')
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '!':
|
||||
if (NEXT_CHAR (scan) == '=') {
|
||||
scan->token = GST_ASM_TOKEN_NOTEQUAL;
|
||||
NEXT_CHAR (scan);
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
scan->token = GST_ASM_TOKEN_AND;
|
||||
if (NEXT_CHAR (scan) == '&')
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '|':
|
||||
scan->token = GST_ASM_TOKEN_OR;
|
||||
if (NEXT_CHAR (scan) == '|')
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '<':
|
||||
scan->token = GST_ASM_TOKEN_LESS;
|
||||
if (NEXT_CHAR (scan) == '=') {
|
||||
scan->token = GST_ASM_TOKEN_LESSEQUAL;
|
||||
NEXT_CHAR (scan);
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
scan->token = GST_ASM_TOKEN_GREATER;
|
||||
if (NEXT_CHAR (scan) == '=') {
|
||||
scan->token = GST_ASM_TOKEN_GREATEREQUAL;
|
||||
NEXT_CHAR (scan);
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
scan->token = GST_ASM_TOKEN_DOLLAR;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '(':
|
||||
scan->token = GST_ASM_TOKEN_LPAREN;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case ')':
|
||||
scan->token = GST_ASM_TOKEN_RPAREN;
|
||||
NEXT_CHAR (scan);
|
||||
break;
|
||||
case '"':
|
||||
NEXT_CHAR (scan);
|
||||
gst_asm_scan_string (scan, '"');
|
||||
break;
|
||||
case '\'':
|
||||
NEXT_CHAR (scan);
|
||||
gst_asm_scan_string (scan, '\'');
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
gst_asm_scan_number (scan);
|
||||
break;
|
||||
case '\0':
|
||||
scan->token = GST_ASM_TOKEN_EOF;
|
||||
break;
|
||||
default:
|
||||
gst_asm_scan_identifier (scan);
|
||||
break;
|
||||
}
|
||||
gst_asm_scan_print_token (scan);
|
||||
return scan->token;
|
||||
}
|
||||
|
||||
static GstASMRule *
|
||||
gst_asm_rule_new (void)
|
||||
{
|
||||
GstASMRule *rule;
|
||||
|
||||
rule = g_new (GstASMRule, 1);
|
||||
rule->root = NULL;
|
||||
rule->props = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_rule_free (GstASMRule * rule)
|
||||
{
|
||||
g_hash_table_destroy (rule->props);
|
||||
if (rule->root)
|
||||
gst_asm_node_free (rule->root);
|
||||
g_free (rule);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_rule_add_property (GstASMRule * rule, gchar * key, gchar * val)
|
||||
{
|
||||
g_hash_table_insert (rule->props, key, val);
|
||||
}
|
||||
|
||||
static GstASMNode *gst_asm_scan_parse_condition (GstASMScan * scan);
|
||||
|
||||
static GstASMNode *
|
||||
gst_asm_scan_parse_operand (GstASMScan * scan)
|
||||
{
|
||||
GstASMNode *node;
|
||||
|
||||
switch (scan->token) {
|
||||
case GST_ASM_TOKEN_DOLLAR:
|
||||
gst_asm_scan_next_token (scan);
|
||||
|
||||
if (scan->token != GST_ASM_TOKEN_IDENTIFIER)
|
||||
g_warning ("identifier expected");
|
||||
|
||||
node = gst_asm_node_new ();
|
||||
node->type = GST_ASM_NODE_VARIABLE;
|
||||
node->data.varname = g_strdup (scan->val);
|
||||
break;
|
||||
case GST_ASM_TOKEN_INT:
|
||||
node = gst_asm_node_new ();
|
||||
node->type = GST_ASM_NODE_INTEGER;
|
||||
node->data.intval = (gfloat) atof (scan->val);
|
||||
break;
|
||||
case GST_ASM_TOKEN_FLOAT:
|
||||
node = gst_asm_node_new ();
|
||||
node->type = GST_ASM_NODE_FLOAT;
|
||||
node->data.floatval = atoi (scan->val);
|
||||
break;
|
||||
case GST_ASM_TOKEN_LPAREN:
|
||||
gst_asm_scan_next_token (scan);
|
||||
node = gst_asm_scan_parse_condition (scan);
|
||||
if (scan->token != GST_ASM_TOKEN_RPAREN)
|
||||
g_warning (") expected");
|
||||
break;
|
||||
default:
|
||||
g_warning ("$ <number> or ) expected");
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
gst_asm_scan_next_token (scan);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GstASMNode *
|
||||
gst_asm_scan_parse_expression (GstASMScan * scan)
|
||||
{
|
||||
GstASMNode *node, *left;
|
||||
|
||||
node = gst_asm_scan_parse_operand (scan);
|
||||
|
||||
while (IS_COND_TOKEN (scan->token)) {
|
||||
left = node;
|
||||
|
||||
node = gst_asm_node_new ();
|
||||
node->type = GST_ASM_NODE_OPERATOR;
|
||||
node->data.optype = (GstASMOp) scan->token;
|
||||
|
||||
gst_asm_scan_next_token (scan);
|
||||
|
||||
node->right = gst_asm_scan_parse_operand (scan);
|
||||
node->left = left;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static GstASMNode *
|
||||
gst_asm_scan_parse_condition (GstASMScan * scan)
|
||||
{
|
||||
GstASMNode *node, *left;
|
||||
|
||||
node = gst_asm_scan_parse_expression (scan);
|
||||
|
||||
while (IS_OP_TOKEN (scan->token)) {
|
||||
left = node;
|
||||
|
||||
node = gst_asm_node_new ();
|
||||
node->type = GST_ASM_NODE_OPERATOR;
|
||||
node->data.optype = (GstASMOp) scan->token;
|
||||
|
||||
gst_asm_scan_next_token (scan);
|
||||
|
||||
node->right = gst_asm_scan_parse_expression (scan);
|
||||
node->left = left;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asm_scan_parse_property (GstASMRule * rule, GstASMScan * scan)
|
||||
{
|
||||
gchar *key, *val;
|
||||
|
||||
if (scan->token != GST_ASM_TOKEN_IDENTIFIER) {
|
||||
g_warning ("identifier expected");
|
||||
return;
|
||||
}
|
||||
key = g_strdup (scan->val);
|
||||
|
||||
gst_asm_scan_next_token (scan);
|
||||
if (scan->token != GST_ASM_TOKEN_EQUAL) {
|
||||
g_warning ("= expected");
|
||||
g_free (key);
|
||||
return;
|
||||
}
|
||||
gst_asm_scan_next_token (scan);
|
||||
val = g_strdup (scan->val);
|
||||
|
||||
gst_asm_rule_add_property (rule, key, val);
|
||||
gst_asm_scan_next_token (scan);
|
||||
}
|
||||
|
||||
static GstASMRule *
|
||||
gst_asm_scan_parse_rule (GstASMScan * scan)
|
||||
{
|
||||
GstASMRule *rule;
|
||||
|
||||
rule = gst_asm_rule_new ();
|
||||
|
||||
if (scan->token == GST_ASM_TOKEN_HASH) {
|
||||
gst_asm_scan_next_token (scan);
|
||||
rule->root = gst_asm_scan_parse_condition (scan);
|
||||
if (scan->token == GST_ASM_TOKEN_COMMA)
|
||||
gst_asm_scan_next_token (scan);
|
||||
}
|
||||
|
||||
if (scan->token != GST_ASM_TOKEN_SEMICOLON) {
|
||||
gst_asm_scan_parse_property (rule, scan);
|
||||
while (scan->token == GST_ASM_TOKEN_COMMA) {
|
||||
gst_asm_scan_next_token (scan);
|
||||
gst_asm_scan_parse_property (rule, scan);
|
||||
}
|
||||
gst_asm_scan_next_token (scan);
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asm_rule_evaluate (GstASMRule * rule, GHashTable * vars)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (rule->root) {
|
||||
res = (gboolean) gst_asm_node_evaluate (rule->root, vars);
|
||||
} else
|
||||
res = TRUE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GstASMRuleBook *
|
||||
gst_asm_rule_book_new (const gchar * rulebook)
|
||||
{
|
||||
GstASMRuleBook *book;
|
||||
GstASMRule *rule = NULL;
|
||||
GstASMScan *scan;
|
||||
GstASMToken token;
|
||||
|
||||
book = g_new0 (GstASMRuleBook, 1);
|
||||
book->rulebook = rulebook;
|
||||
|
||||
scan = gst_asm_scan_new (book->rulebook);
|
||||
gst_asm_scan_next_token (scan);
|
||||
|
||||
do {
|
||||
rule = gst_asm_scan_parse_rule (scan);
|
||||
if (rule) {
|
||||
book->rules = g_list_append (book->rules, rule);
|
||||
book->n_rules++;
|
||||
}
|
||||
token = scan->token;
|
||||
} while (token != GST_ASM_TOKEN_EOF);
|
||||
|
||||
gst_asm_scan_free (scan);
|
||||
|
||||
return book;
|
||||
}
|
||||
|
||||
void
|
||||
gst_asm_rule_book_free (GstASMRuleBook * book)
|
||||
{
|
||||
GList *walk;
|
||||
|
||||
for (walk = book->rules; walk; walk = g_list_next (walk)) {
|
||||
GstASMRule *rule = (GstASMRule *) walk->data;
|
||||
|
||||
gst_asm_rule_free (rule);
|
||||
}
|
||||
g_list_free (book->rules);
|
||||
g_free (book);
|
||||
}
|
||||
|
||||
gint
|
||||
gst_asm_rule_book_match (GstASMRuleBook * book, GHashTable * vars,
|
||||
gint * rulematches)
|
||||
{
|
||||
GList *walk;
|
||||
gint i, n = 0;
|
||||
|
||||
for (walk = book->rules, i = 0; walk; walk = g_list_next (walk), i++) {
|
||||
GstASMRule *rule = (GstASMRule *) walk->data;
|
||||
|
||||
if (gst_asm_rule_evaluate (rule, vars)) {
|
||||
rulematches[n++] = i;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
gint
|
||||
main (gint argc, gchar * argv[])
|
||||
{
|
||||
GstASMRuleBook *book;
|
||||
gint rulematch[MAX_RULEMATCHES];
|
||||
GHashTable *vars;
|
||||
gint i, n;
|
||||
|
||||
static const gchar rules1[] =
|
||||
"#($Bandwidth < 67959),TimestampDelivery=T,DropByN=T,"
|
||||
"priority=9;#($Bandwidth >= 67959) && ($Bandwidth < 167959),"
|
||||
"AverageBandwidth=67959,Priority=9;#($Bandwidth >= 67959) && ($Bandwidth"
|
||||
" < 167959),AverageBandwidth=0,Priority=5,OnDepend=\\\"1\\\";#($Bandwidth >= 167959)"
|
||||
" && ($Bandwidth < 267959),AverageBandwidth=167959,Priority=9;#($Bandwidth >= 167959)"
|
||||
" && ($Bandwidth < 267959),AverageBandwidth=0,Priority=5,OnDepend=\\\"3\\\";"
|
||||
"#($Bandwidth >= 267959),AverageBandwidth=267959,Priority=9;#($Bandwidth >= 267959)"
|
||||
",AverageBandwidth=0,Priority=5,OnDepend=\\\"5\\\";";
|
||||
static const gchar rules2[] =
|
||||
"AverageBandwidth=32041,Priority=5;AverageBandwidth=0,"
|
||||
"Priority=5,OnDepend=\\\"0\\\", OffDepend=\\\"0\\\";";
|
||||
static const gchar rules3[] =
|
||||
"#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=27500,priority=9,PNMKeyframeRule=T;#(($Bandwidth >= 27500) && ($OldPNMPlayer)),AverageBandwidth=0,priority=5,PNMNonKeyframeRule=T;#(($Bandwidth < 27500) && ($OldPNMPlayer)),TimestampDelivery=T,DropByN=T,priority=9,PNMThinningRule=T;#($Bandwidth < 13899),TimestampDelivery=T,DropByN=T,priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=13899,Priority=9;#($Bandwidth >= 13899) && ($Bandwidth < 19000),AverageBandwidth=0,Priority=5,OnDepend=\\\"4\\\";#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=19000,Priority=9;#($Bandwidth >= 19000) && ($Bandwidth < 27500),AverageBandwidth=0,Priority=5,OnDepend=\\\"6\\\";#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=27500,Priority=9;#($Bandwidth >= 27500) && ($Bandwidth < 132958),AverageBandwidth=0,Priority=5,OnDepend=\\\"8\\\";#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=132958,Priority=9;#($Bandwidth >= 132958) && ($Bandwidth < 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"10\\\";#($Bandwidth >= 187958),AverageBandwidth=187958,Priority=9;#($Bandwidth >= 187958),AverageBandwidth=0,Priority=5,OnDepend=\\\"12\\\";";
|
||||
|
||||
vars = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (vars, (gchar *) "Bandwidth", (gchar *) "300000");
|
||||
|
||||
book = gst_asm_rule_book_new (rules1);
|
||||
n = gst_asm_rule_book_match (book, vars, rulematch);
|
||||
gst_asm_rule_book_free (book);
|
||||
|
||||
g_print ("%d rules matched\n", n);
|
||||
for (i = 0; i < n; i++) {
|
||||
g_print ("rule %d matched\n", rulematch[i]);
|
||||
}
|
||||
|
||||
book = gst_asm_rule_book_new (rules2);
|
||||
n = gst_asm_rule_book_match (book, vars, rulematch);
|
||||
gst_asm_rule_book_free (book);
|
||||
|
||||
g_print ("%d rules matched\n", n);
|
||||
for (i = 0; i < n; i++) {
|
||||
g_print ("rule %d matched\n", rulematch[i]);
|
||||
}
|
||||
|
||||
book = gst_asm_rule_book_new (rules3);
|
||||
n = gst_asm_rule_book_match (book, vars, rulematch);
|
||||
gst_asm_rule_book_free (book);
|
||||
|
||||
|
||||
g_print ("%d rules matched\n", n);
|
||||
for (i = 0; i < n; i++) {
|
||||
g_print ("rule %d matched\n", rulematch[i]);
|
||||
}
|
||||
|
||||
g_hash_table_destroy (vars);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,115 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_ASM_RULES_H__
|
||||
#define __GST_ASM_RULES_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define MAX_RULEMATCHES 16
|
||||
|
||||
typedef struct _GstASMNode GstASMNode;
|
||||
typedef struct _GstASMRule GstASMRule;
|
||||
typedef struct _GstASMRuleBook GstASMRuleBook;
|
||||
|
||||
typedef enum {
|
||||
GST_ASM_TOKEN_NONE,
|
||||
GST_ASM_TOKEN_EOF,
|
||||
|
||||
GST_ASM_TOKEN_INT,
|
||||
GST_ASM_TOKEN_FLOAT,
|
||||
GST_ASM_TOKEN_IDENTIFIER,
|
||||
GST_ASM_TOKEN_STRING,
|
||||
|
||||
GST_ASM_TOKEN_HASH,
|
||||
GST_ASM_TOKEN_SEMICOLON,
|
||||
GST_ASM_TOKEN_COMMA,
|
||||
GST_ASM_TOKEN_DOLLAR,
|
||||
|
||||
GST_ASM_TOKEN_LPAREN,
|
||||
GST_ASM_TOKEN_RPAREN,
|
||||
|
||||
GST_ASM_TOKEN_GREATER,
|
||||
GST_ASM_TOKEN_LESS,
|
||||
GST_ASM_TOKEN_GREATEREQUAL,
|
||||
GST_ASM_TOKEN_LESSEQUAL,
|
||||
GST_ASM_TOKEN_EQUAL,
|
||||
GST_ASM_TOKEN_NOTEQUAL,
|
||||
|
||||
GST_ASM_TOKEN_AND,
|
||||
GST_ASM_TOKEN_OR
|
||||
} GstASMToken;
|
||||
|
||||
typedef enum {
|
||||
GST_ASM_NODE_UNKNOWN,
|
||||
GST_ASM_NODE_VARIABLE,
|
||||
GST_ASM_NODE_INTEGER,
|
||||
GST_ASM_NODE_FLOAT,
|
||||
GST_ASM_NODE_OPERATOR
|
||||
} GstASMNodeType;
|
||||
|
||||
typedef enum {
|
||||
GST_ASM_OP_GREATER = GST_ASM_TOKEN_GREATER,
|
||||
GST_ASM_OP_LESS = GST_ASM_TOKEN_LESS,
|
||||
GST_ASM_OP_GREATEREQUAL = GST_ASM_TOKEN_GREATEREQUAL,
|
||||
GST_ASM_OP_LESSEQUAL = GST_ASM_TOKEN_LESSEQUAL,
|
||||
GST_ASM_OP_EQUAL = GST_ASM_TOKEN_EQUAL,
|
||||
GST_ASM_OP_NOTEQUAL = GST_ASM_TOKEN_NOTEQUAL,
|
||||
|
||||
GST_ASM_OP_AND = GST_ASM_TOKEN_AND,
|
||||
GST_ASM_OP_OR = GST_ASM_TOKEN_OR
|
||||
} GstASMOp;
|
||||
|
||||
struct _GstASMNode {
|
||||
GstASMNodeType type;
|
||||
|
||||
union {
|
||||
gchar *varname;
|
||||
gint intval;
|
||||
gfloat floatval;
|
||||
GstASMOp optype;
|
||||
} data;
|
||||
|
||||
GstASMNode *left;
|
||||
GstASMNode *right;
|
||||
};
|
||||
|
||||
struct _GstASMRule {
|
||||
GstASMNode *root;
|
||||
GHashTable *props;
|
||||
};
|
||||
|
||||
struct _GstASMRuleBook {
|
||||
const gchar *rulebook;
|
||||
|
||||
guint n_rules;
|
||||
GList *rules;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
GstASMRuleBook* gst_asm_rule_book_new (const gchar *rulebook);
|
||||
void gst_asm_rule_book_free (GstASMRuleBook *book);
|
||||
|
||||
gint gst_asm_rule_book_match (GstASMRuleBook *book, GHashTable *vars,
|
||||
gint *rulematches);
|
||||
|
||||
#endif /* __GST_ASM_RULES_H__ */
|
|
@ -1,477 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "gstrdtbuffer.h"
|
||||
|
||||
gboolean
|
||||
gst_rdt_buffer_validate_data (guint8 * data, guint len)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_rdt_buffer_validate (GstBuffer * buffer)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint
|
||||
gst_rdt_buffer_get_packet_count (GstBuffer * buffer)
|
||||
{
|
||||
GstRDTPacket packet;
|
||||
guint count;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
|
||||
|
||||
count = 0;
|
||||
if (gst_rdt_buffer_get_first_packet (buffer, &packet)) {
|
||||
do {
|
||||
count++;
|
||||
} while (gst_rdt_packet_move_to_next (&packet));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
read_packet_header (GstRDTPacket * packet)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint8 *data;
|
||||
gsize size;
|
||||
guint offset;
|
||||
guint length;
|
||||
guint length_offset;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, FALSE);
|
||||
g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
data = map.data;
|
||||
size = map.size;
|
||||
|
||||
offset = packet->offset;
|
||||
|
||||
/* check if we are at the end of the buffer, we add 3 because we also want to
|
||||
* ensure we can read the type, which is always at offset 1 and 2 bytes long. */
|
||||
if (offset + 3 > size)
|
||||
goto packet_end;
|
||||
|
||||
/* read type */
|
||||
packet->type = GST_READ_UINT16_BE (&data[offset + 1]);
|
||||
|
||||
length = -1;
|
||||
length_offset = -1;
|
||||
|
||||
/* figure out the length of the packet, this depends on the type */
|
||||
if (GST_RDT_IS_DATA_TYPE (packet->type)) {
|
||||
if (data[offset] & 0x80)
|
||||
/* length is present */
|
||||
length_offset = 3;
|
||||
} else {
|
||||
switch (packet->type) {
|
||||
case GST_RDT_TYPE_ASMACTION:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 5;
|
||||
break;
|
||||
case GST_RDT_TYPE_BWREPORT:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_ACK:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_RTTREQ:
|
||||
length = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_RTTRESP:
|
||||
length = 11;
|
||||
break;
|
||||
case GST_RDT_TYPE_CONGESTION:
|
||||
length = 11;
|
||||
break;
|
||||
case GST_RDT_TYPE_STREAMEND:
|
||||
length = 9;
|
||||
/* total_reliable */
|
||||
if (data[offset] & 0x80)
|
||||
length += 2;
|
||||
/* stream_id_expansion */
|
||||
if ((data[offset] & 0x7c) == 0x7c)
|
||||
length += 2;
|
||||
/* ext_flag, FIXME, get string length */
|
||||
if ((data[offset] & 0x1) == 0x1)
|
||||
length += 7;
|
||||
break;
|
||||
case GST_RDT_TYPE_REPORT:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_LATENCY:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_INFOREQ:
|
||||
length = 3;
|
||||
/* request_time_ms */
|
||||
if (data[offset] & 0x2)
|
||||
length += 2;
|
||||
break;
|
||||
case GST_RDT_TYPE_INFORESP:
|
||||
length = 3;
|
||||
/* has_rtt_info */
|
||||
if (data[offset] & 0x4) {
|
||||
length += 4;
|
||||
/* is_delayed */
|
||||
if (data[offset] & 0x2) {
|
||||
length += 4;
|
||||
}
|
||||
}
|
||||
if (data[offset] & 0x1) {
|
||||
/* buffer_info_count, FIXME read and skip */
|
||||
length += 2;
|
||||
}
|
||||
break;
|
||||
case GST_RDT_TYPE_AUTOBW:
|
||||
if (data[offset] & 0x80)
|
||||
length_offset = 3;
|
||||
break;
|
||||
case GST_RDT_TYPE_INVALID:
|
||||
default:
|
||||
goto unknown_packet;
|
||||
}
|
||||
}
|
||||
|
||||
if (length != -1) {
|
||||
/* we have a fixed length */
|
||||
packet->length = length;
|
||||
} else if (length_offset != -1) {
|
||||
/* we can read the length from an offset */
|
||||
packet->length = GST_READ_UINT16_BE (&data[length_offset]);
|
||||
} else {
|
||||
/* length is remainder of packet */
|
||||
packet->length = size - offset;
|
||||
}
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
|
||||
/* the length should be smaller than the remaining size */
|
||||
if (packet->length + offset > size)
|
||||
goto invalid_length;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
packet_end:
|
||||
{
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
return FALSE;
|
||||
}
|
||||
unknown_packet:
|
||||
{
|
||||
packet->type = GST_RDT_TYPE_INVALID;
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
return FALSE;
|
||||
}
|
||||
invalid_length:
|
||||
{
|
||||
packet->type = GST_RDT_TYPE_INVALID;
|
||||
packet->length = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_rdt_buffer_get_first_packet (GstBuffer * buffer, GstRDTPacket * packet)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
||||
g_return_val_if_fail (packet != NULL, FALSE);
|
||||
|
||||
/* init to 0 */
|
||||
packet->buffer = buffer;
|
||||
packet->offset = 0;
|
||||
packet->type = GST_RDT_TYPE_INVALID;
|
||||
memset (&packet->map, 0, sizeof (GstMapInfo));
|
||||
|
||||
if (!read_packet_header (packet))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_rdt_packet_move_to_next (GstRDTPacket * packet)
|
||||
{
|
||||
g_return_val_if_fail (packet != NULL, FALSE);
|
||||
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, FALSE);
|
||||
g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
|
||||
|
||||
/* if we have an invalid packet, it must be the last,
|
||||
* return FALSE */
|
||||
if (packet->type == GST_RDT_TYPE_INVALID)
|
||||
goto end;
|
||||
|
||||
/* move to next packet */
|
||||
packet->offset += packet->length;
|
||||
|
||||
/* try to read new header */
|
||||
if (!read_packet_header (packet))
|
||||
goto end;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
end:
|
||||
{
|
||||
packet->type = GST_RDT_TYPE_INVALID;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GstRDTType
|
||||
gst_rdt_packet_get_type (GstRDTPacket * packet)
|
||||
{
|
||||
g_return_val_if_fail (packet != NULL, GST_RDT_TYPE_INVALID);
|
||||
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID,
|
||||
GST_RDT_TYPE_INVALID);
|
||||
|
||||
return packet->type;
|
||||
}
|
||||
|
||||
guint16
|
||||
gst_rdt_packet_get_length (GstRDTPacket * packet)
|
||||
{
|
||||
g_return_val_if_fail (packet != NULL, 0);
|
||||
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, 0);
|
||||
|
||||
return packet->length;
|
||||
}
|
||||
|
||||
GstBuffer *
|
||||
gst_rdt_packet_to_buffer (GstRDTPacket * packet)
|
||||
{
|
||||
GstBuffer *result;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, NULL);
|
||||
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, NULL);
|
||||
|
||||
result =
|
||||
gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
|
||||
packet->offset, packet->length);
|
||||
/* timestamp applies to all packets in this buffer */
|
||||
GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (packet->buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gint
|
||||
gst_rdt_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
|
||||
{
|
||||
return (gint16) (seqnum2 - seqnum1);
|
||||
}
|
||||
|
||||
guint16
|
||||
gst_rdt_packet_data_get_seq (GstRDTPacket * packet)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint header;
|
||||
guint16 result;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, FALSE);
|
||||
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
|
||||
/* skip header bits */
|
||||
header = packet->offset + 1;
|
||||
|
||||
/* read seq_no */
|
||||
result = GST_READ_UINT16_BE (&map.data[header]);
|
||||
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
guint8 *
|
||||
gst_rdt_packet_data_map (GstRDTPacket * packet, guint * size)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint header;
|
||||
gboolean length_included_flag;
|
||||
gboolean need_reliable_flag;
|
||||
guint8 stream_id;
|
||||
guint8 asm_rule_number;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, NULL);
|
||||
g_return_val_if_fail (packet->map.data == NULL, NULL);
|
||||
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), NULL);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
|
||||
header = packet->offset;
|
||||
|
||||
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
||||
need_reliable_flag = (map.data[header] & 0x40) == 0x40;
|
||||
stream_id = (map.data[header] & 0x3e) >> 1;
|
||||
|
||||
/* skip seq_no and header bits */
|
||||
header += 3;
|
||||
|
||||
if (length_included_flag) {
|
||||
/* skip length */
|
||||
header += 2;
|
||||
}
|
||||
asm_rule_number = (map.data[header] & 0x3f);
|
||||
|
||||
/* skip timestamp and asm_rule_number */
|
||||
header += 5;
|
||||
|
||||
if (stream_id == 0x1f) {
|
||||
/* skip stream_id_expansion */
|
||||
header += 2;
|
||||
}
|
||||
if (need_reliable_flag) {
|
||||
/* skip total_reliable */
|
||||
header += 2;
|
||||
}
|
||||
if (asm_rule_number == 63) {
|
||||
/* skip asm_rule_number_expansion */
|
||||
header += 2;
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = packet->length - (header - packet->offset);
|
||||
|
||||
packet->map = map;
|
||||
|
||||
return &map.data[header];
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_rdt_packet_data_unmap (GstRDTPacket * packet)
|
||||
{
|
||||
g_return_val_if_fail (packet != NULL, FALSE);
|
||||
g_return_val_if_fail (packet->map.data != NULL, FALSE);
|
||||
|
||||
gst_buffer_unmap (packet->buffer, &packet->map);
|
||||
packet->map.data = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint16
|
||||
gst_rdt_packet_data_get_stream_id (GstRDTPacket * packet)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint16 result;
|
||||
guint header;
|
||||
gboolean length_included_flag;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, 0);
|
||||
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
|
||||
header = packet->offset;
|
||||
|
||||
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
||||
result = (map.data[header] & 0x3e) >> 1;
|
||||
if (result == 31) {
|
||||
/* skip seq_no and header bits */
|
||||
header += 3;
|
||||
|
||||
if (length_included_flag) {
|
||||
/* skip length */
|
||||
header += 2;
|
||||
}
|
||||
/* skip asm_rule_number and timestamp */
|
||||
header += 5;
|
||||
|
||||
/* stream_id_expansion */
|
||||
result = GST_READ_UINT16_BE (&map.data[header]);
|
||||
}
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
guint32
|
||||
gst_rdt_packet_data_get_timestamp (GstRDTPacket * packet)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint header;
|
||||
gboolean length_included_flag;
|
||||
guint32 result;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, 0);
|
||||
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
|
||||
header = packet->offset;
|
||||
|
||||
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
||||
|
||||
/* skip seq_no and header bits */
|
||||
header += 3;
|
||||
|
||||
if (length_included_flag) {
|
||||
/* skip length */
|
||||
header += 2;
|
||||
}
|
||||
/* skip asm_rule_number */
|
||||
header += 1;
|
||||
|
||||
/* get timestamp */
|
||||
result = GST_READ_UINT32_BE (&map.data[header]);
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
guint8
|
||||
gst_rdt_packet_data_get_flags (GstRDTPacket * packet)
|
||||
{
|
||||
GstMapInfo map;
|
||||
guint8 result;
|
||||
guint header;
|
||||
gboolean length_included_flag;
|
||||
|
||||
g_return_val_if_fail (packet != NULL, 0);
|
||||
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
||||
|
||||
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
||||
|
||||
header = packet->offset;
|
||||
|
||||
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
||||
|
||||
/* skip seq_no and header bits */
|
||||
header += 3;
|
||||
|
||||
if (length_included_flag) {
|
||||
/* skip length */
|
||||
header += 2;
|
||||
}
|
||||
/* get flags */
|
||||
result = map.data[header];
|
||||
gst_buffer_unmap (packet->buffer, &map);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* gstrdtbuffer.h: various helper functions to manipulate buffers
|
||||
* with RDT payload.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RDTBUFFER_H__
|
||||
#define __GST_RDTBUFFER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
/**
|
||||
* GstRDTType:
|
||||
* @GST_RDT_TYPE_INVALID:
|
||||
* @GST_RDT_TYPE_ASMACTION:
|
||||
* @GST_RDT_TYPE_ACK:
|
||||
* @GST_RDT_TYPE_RTTREQ:
|
||||
* @GST_RDT_TYPE_RTTRESP:
|
||||
* @GST_RDT_TYPE_CONGESTION:
|
||||
* @GST_RDT_TYPE_STREAMEND:
|
||||
* @GST_RDT_TYPE_LATENCY:
|
||||
* @GST_RDT_TYPE_INFOREQ:
|
||||
* @GST_RDT_TYPE_INFORESP:
|
||||
* @GST_RDT_TYPE_AUTOBW:
|
||||
*
|
||||
* Different RDT packet types.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_RDT_TYPE_INVALID = 0xffff,
|
||||
GST_RDT_TYPE_ASMACTION = 0xff00,
|
||||
GST_RDT_TYPE_BWREPORT = 0xff01,
|
||||
GST_RDT_TYPE_ACK = 0xff02,
|
||||
GST_RDT_TYPE_RTTREQ = 0xff03,
|
||||
GST_RDT_TYPE_RTTRESP = 0xff04,
|
||||
GST_RDT_TYPE_CONGESTION = 0xff05,
|
||||
GST_RDT_TYPE_STREAMEND = 0xff06,
|
||||
GST_RDT_TYPE_REPORT = 0xff07,
|
||||
GST_RDT_TYPE_LATENCY = 0xff08,
|
||||
GST_RDT_TYPE_INFOREQ = 0xff09,
|
||||
GST_RDT_TYPE_INFORESP = 0xff0a,
|
||||
GST_RDT_TYPE_AUTOBW = 0xff0b
|
||||
} GstRDTType;
|
||||
|
||||
/**
|
||||
* GST_RDT_IS_DATA_TYPE:
|
||||
* @t: the #GstRDTType to check
|
||||
*
|
||||
* Check if @t is a data packet type.
|
||||
*/
|
||||
#define GST_RDT_IS_DATA_TYPE(t) ((t) < 0xff00)
|
||||
|
||||
typedef struct _GstRDTPacket GstRDTPacket;
|
||||
|
||||
/**
|
||||
* GstRDTPacket:
|
||||
* @buffer: pointer to RDT buffer
|
||||
* @offset: offset of packet in buffer data
|
||||
*
|
||||
* Data structure that points to a packet at @offset in @buffer.
|
||||
* The size of the structure is made public to allow stack allocations.
|
||||
*/
|
||||
struct _GstRDTPacket
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
guint offset;
|
||||
|
||||
/*< private >*/
|
||||
GstRDTType type; /* type of current packet */
|
||||
guint16 length; /* length of current packet in bytes */
|
||||
GstMapInfo map; /* last mapped data */
|
||||
};
|
||||
|
||||
/* validate buffers */
|
||||
gboolean gst_rdt_buffer_validate_data (guint8 *data, guint len);
|
||||
gboolean gst_rdt_buffer_validate (GstBuffer *buffer);
|
||||
|
||||
/* retrieving packets */
|
||||
guint gst_rdt_buffer_get_packet_count (GstBuffer *buffer);
|
||||
gboolean gst_rdt_buffer_get_first_packet (GstBuffer *buffer, GstRDTPacket *packet);
|
||||
gboolean gst_rdt_packet_move_to_next (GstRDTPacket *packet);
|
||||
|
||||
/* working with packets */
|
||||
GstRDTType gst_rdt_packet_get_type (GstRDTPacket *packet);
|
||||
guint16 gst_rdt_packet_get_length (GstRDTPacket *packet);
|
||||
GstBuffer* gst_rdt_packet_to_buffer (GstRDTPacket *packet);
|
||||
|
||||
|
||||
/* data packets */
|
||||
guint16 gst_rdt_packet_data_get_seq (GstRDTPacket *packet);
|
||||
guint8 * gst_rdt_packet_data_map (GstRDTPacket *packet, guint *size);
|
||||
gboolean gst_rdt_packet_data_unmap (GstRDTPacket *packet);
|
||||
guint16 gst_rdt_packet_data_get_stream_id (GstRDTPacket *packet);
|
||||
guint32 gst_rdt_packet_data_get_timestamp (GstRDTPacket *packet);
|
||||
|
||||
guint8 gst_rdt_packet_data_get_flags (GstRDTPacket * packet);
|
||||
|
||||
/* utils */
|
||||
gint gst_rdt_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RDTBUFFER_H__ */
|
||||
|
|
@ -2,14 +2,6 @@ real_sources = [
|
|||
'rademux.c',
|
||||
'rmdemux.c',
|
||||
'rmutils.c',
|
||||
'rdtdepay.c',
|
||||
'rdtmanager.c',
|
||||
'rtspreal.c',
|
||||
'realhash.c',
|
||||
'asmrules.c',
|
||||
'rdtjitterbuffer.c',
|
||||
'gstrdtbuffer.c',
|
||||
'pnmsrc.c',
|
||||
'realmedia.c'
|
||||
]
|
||||
|
||||
|
|
|
@ -1,496 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2006> Lutz Mueller <lutz at topfrose dot de>
|
||||
* <2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gstrdtbuffer.h"
|
||||
#include "rdtdepay.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rdtdepay_debug);
|
||||
#define GST_CAT_DEFAULT rdtdepay_debug
|
||||
|
||||
/* RDTDepay signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
static GstStaticPadTemplate gst_rdt_depay_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("application/vnd.rn-realmedia")
|
||||
);
|
||||
|
||||
static GstStaticPadTemplate gst_rdt_depay_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("application/x-rdt, "
|
||||
"media = (string) \"application\", "
|
||||
"clock-rate = (int) [1, MAX ], "
|
||||
"encoding-name = (string) \"X-REAL-RDT\""
|
||||
/* All optional parameters
|
||||
*
|
||||
* "config="
|
||||
*/
|
||||
)
|
||||
);
|
||||
|
||||
#define gst_rdt_depay_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstRDTDepay, gst_rdt_depay, GST_TYPE_ELEMENT);
|
||||
GST_ELEMENT_REGISTER_DEFINE (rdtdepay, "rdtdepay",
|
||||
GST_RANK_MARGINAL, GST_TYPE_RDT_DEPAY);
|
||||
|
||||
static void gst_rdt_depay_finalize (GObject * object);
|
||||
|
||||
static GstStateChangeReturn gst_rdt_depay_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
|
||||
static gboolean gst_rdt_depay_sink_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
static GstFlowReturn gst_rdt_depay_chain (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buf);
|
||||
|
||||
static void
|
||||
gst_rdt_depay_class_init (GstRDTDepayClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
gobject_class->finalize = gst_rdt_depay_finalize;
|
||||
|
||||
gstelement_class->change_state = gst_rdt_depay_change_state;
|
||||
|
||||
gst_element_class_add_static_pad_template (gstelement_class,
|
||||
&gst_rdt_depay_src_template);
|
||||
gst_element_class_add_static_pad_template (gstelement_class,
|
||||
&gst_rdt_depay_sink_template);
|
||||
|
||||
gst_element_class_set_static_metadata (gstelement_class, "RDT packet parser",
|
||||
"Codec/Depayloader/Network",
|
||||
"Extracts RealMedia from RDT packets",
|
||||
"Lutz Mueller <lutz at topfrose dot de>, "
|
||||
"Wim Taymans <wim@fluendo.com>");
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rdtdepay_debug, "rdtdepay",
|
||||
0, "Depayloader for RDT RealMedia packets");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rdt_depay_init (GstRDTDepay * rdtdepay)
|
||||
{
|
||||
rdtdepay->sinkpad =
|
||||
gst_pad_new_from_static_template (&gst_rdt_depay_sink_template, "sink");
|
||||
gst_pad_set_chain_function (rdtdepay->sinkpad, gst_rdt_depay_chain);
|
||||
gst_pad_set_event_function (rdtdepay->sinkpad, gst_rdt_depay_sink_event);
|
||||
gst_element_add_pad (GST_ELEMENT_CAST (rdtdepay), rdtdepay->sinkpad);
|
||||
|
||||
rdtdepay->srcpad =
|
||||
gst_pad_new_from_static_template (&gst_rdt_depay_src_template, "src");
|
||||
gst_element_add_pad (GST_ELEMENT_CAST (rdtdepay), rdtdepay->srcpad);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rdt_depay_finalize (GObject * object)
|
||||
{
|
||||
GstRDTDepay *rdtdepay;
|
||||
|
||||
rdtdepay = GST_RDT_DEPAY (object);
|
||||
|
||||
if (rdtdepay->header)
|
||||
gst_buffer_unref (rdtdepay->header);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rdt_depay_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstStructure *structure;
|
||||
GstRDTDepay *rdtdepay;
|
||||
GstCaps *srccaps;
|
||||
gint clock_rate = 1000; /* default */
|
||||
const GValue *value;
|
||||
GstBuffer *header;
|
||||
|
||||
rdtdepay = GST_RDT_DEPAY (GST_PAD_PARENT (pad));
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (gst_structure_has_field (structure, "clock-rate"))
|
||||
gst_structure_get_int (structure, "clock-rate", &clock_rate);
|
||||
|
||||
/* config contains the RealMedia header as a buffer. */
|
||||
value = gst_structure_get_value (structure, "config");
|
||||
if (!value)
|
||||
goto no_header;
|
||||
|
||||
header = gst_value_get_buffer (value);
|
||||
if (!header)
|
||||
goto no_header;
|
||||
|
||||
/* get other values for newsegment */
|
||||
value = gst_structure_get_value (structure, "npt-start");
|
||||
if (value && G_VALUE_HOLDS_UINT64 (value))
|
||||
rdtdepay->npt_start = g_value_get_uint64 (value);
|
||||
else
|
||||
rdtdepay->npt_start = 0;
|
||||
GST_DEBUG_OBJECT (rdtdepay, "NPT start %" G_GUINT64_FORMAT,
|
||||
rdtdepay->npt_start);
|
||||
|
||||
value = gst_structure_get_value (structure, "npt-stop");
|
||||
if (value && G_VALUE_HOLDS_UINT64 (value))
|
||||
rdtdepay->npt_stop = g_value_get_uint64 (value);
|
||||
else
|
||||
rdtdepay->npt_stop = -1;
|
||||
|
||||
GST_DEBUG_OBJECT (rdtdepay, "NPT stop %" G_GUINT64_FORMAT,
|
||||
rdtdepay->npt_stop);
|
||||
|
||||
value = gst_structure_get_value (structure, "play-speed");
|
||||
if (value && G_VALUE_HOLDS_DOUBLE (value))
|
||||
rdtdepay->play_speed = g_value_get_double (value);
|
||||
else
|
||||
rdtdepay->play_speed = 1.0;
|
||||
|
||||
value = gst_structure_get_value (structure, "play-scale");
|
||||
if (value && G_VALUE_HOLDS_DOUBLE (value))
|
||||
rdtdepay->play_scale = g_value_get_double (value);
|
||||
else
|
||||
rdtdepay->play_scale = 1.0;
|
||||
|
||||
/* caps seem good, configure element */
|
||||
rdtdepay->clock_rate = clock_rate;
|
||||
|
||||
/* set caps on pad and on header */
|
||||
srccaps = gst_caps_new_empty_simple ("application/vnd.rn-realmedia");
|
||||
gst_pad_set_caps (rdtdepay->srcpad, srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
|
||||
if (rdtdepay->header)
|
||||
gst_buffer_unref (rdtdepay->header);
|
||||
rdtdepay->header = gst_buffer_ref (header);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
no_header:
|
||||
{
|
||||
GST_ERROR_OBJECT (rdtdepay, "no header found in caps, no 'config' field");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rdt_depay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
GstRDTDepay *depay;
|
||||
gboolean res = TRUE;
|
||||
|
||||
depay = GST_RDT_DEPAY (parent);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
gst_event_parse_caps (event, &caps);
|
||||
res = gst_rdt_depay_setcaps (pad, caps);
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_FLUSH_STOP:
|
||||
res = gst_pad_push_event (depay->srcpad, event);
|
||||
|
||||
gst_segment_init (&depay->segment, GST_FORMAT_UNDEFINED);
|
||||
depay->need_newsegment = TRUE;
|
||||
depay->next_seqnum = -1;
|
||||
break;
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
gst_event_copy_segment (event, &depay->segment);
|
||||
/* don't pass the event downstream, we generate our own segment
|
||||
* including the NTP time and other things we receive in caps */
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* pass other events forward */
|
||||
res = gst_pad_push_event (depay->srcpad, event);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstEvent *
|
||||
create_segment_event (GstRDTDepay * depay, gboolean update,
|
||||
GstClockTime position)
|
||||
{
|
||||
GstSegment segment;
|
||||
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
segment.rate = depay->play_speed;
|
||||
segment.applied_rate = depay->play_scale;
|
||||
segment.start = position;
|
||||
|
||||
if (depay->npt_stop != -1)
|
||||
segment.stop = depay->npt_stop - depay->npt_start;
|
||||
else
|
||||
segment.stop = -1;
|
||||
|
||||
segment.time = position + depay->npt_start;
|
||||
|
||||
return gst_event_new_segment (&segment);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rdt_depay_push (GstRDTDepay * rdtdepay, GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
||||
if (rdtdepay->need_newsegment) {
|
||||
GstEvent *event;
|
||||
|
||||
event = create_segment_event (rdtdepay, FALSE, 0);
|
||||
gst_pad_push_event (rdtdepay->srcpad, event);
|
||||
|
||||
rdtdepay->need_newsegment = FALSE;
|
||||
}
|
||||
|
||||
if (rdtdepay->discont) {
|
||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||
rdtdepay->discont = FALSE;
|
||||
}
|
||||
ret = gst_pad_push (rdtdepay->srcpad, buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime,
|
||||
GstRDTPacket * packet)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
GstBuffer *outbuf;
|
||||
GstMapInfo outmap;
|
||||
guint8 *data, *outdata;
|
||||
guint size;
|
||||
guint16 stream_id;
|
||||
guint32 timestamp;
|
||||
gint gap;
|
||||
guint16 seqnum;
|
||||
guint8 flags;
|
||||
guint16 outflags;
|
||||
|
||||
/* get pointers to the packet data */
|
||||
data = gst_rdt_packet_data_map (packet, &size);
|
||||
|
||||
outbuf = gst_buffer_new_and_alloc (12 + size);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = outtime;
|
||||
|
||||
GST_DEBUG_OBJECT (rdtdepay, "have size %u", size);
|
||||
|
||||
/* copy over some things */
|
||||
stream_id = gst_rdt_packet_data_get_stream_id (packet);
|
||||
timestamp = gst_rdt_packet_data_get_timestamp (packet);
|
||||
flags = gst_rdt_packet_data_get_flags (packet);
|
||||
|
||||
seqnum = gst_rdt_packet_data_get_seq (packet);
|
||||
|
||||
GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d, flags %d",
|
||||
stream_id, timestamp, seqnum, flags);
|
||||
|
||||
if (rdtdepay->next_seqnum != -1) {
|
||||
gap = gst_rdt_buffer_compare_seqnum (seqnum, rdtdepay->next_seqnum);
|
||||
|
||||
/* if we have no gap, all is fine */
|
||||
if (G_UNLIKELY (gap != 0)) {
|
||||
GST_LOG_OBJECT (rdtdepay, "got packet %u, expected %u, gap %d", seqnum,
|
||||
rdtdepay->next_seqnum, gap);
|
||||
if (gap < 0) {
|
||||
/* seqnum > next_seqnum, we are missing some packets, this is always a
|
||||
* DISCONT. */
|
||||
GST_LOG_OBJECT (rdtdepay, "%d missing packets", gap);
|
||||
rdtdepay->discont = TRUE;
|
||||
} else {
|
||||
/* seqnum < next_seqnum, we have seen this packet before or the sender
|
||||
* could be restarted. If the packet is not too old, we throw it away as
|
||||
* a duplicate, otherwise we mark discont and continue. 100 misordered
|
||||
* packets is a good threshold. See also RFC 4737. */
|
||||
if (gap < 100)
|
||||
goto dropping;
|
||||
|
||||
GST_LOG_OBJECT (rdtdepay,
|
||||
"%d > 100, packet too old, sender likely restarted", gap);
|
||||
rdtdepay->discont = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
rdtdepay->next_seqnum = (seqnum + 1);
|
||||
if (rdtdepay->next_seqnum == 0xff00)
|
||||
rdtdepay->next_seqnum = 0;
|
||||
|
||||
if ((flags & 1) == 0)
|
||||
outflags = 2;
|
||||
else
|
||||
outflags = 0;
|
||||
|
||||
gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
|
||||
outdata = outmap.data;
|
||||
GST_WRITE_UINT16_BE (outdata + 0, 0); /* version */
|
||||
GST_WRITE_UINT16_BE (outdata + 2, size + 12); /* length */
|
||||
GST_WRITE_UINT16_BE (outdata + 4, stream_id); /* stream */
|
||||
GST_WRITE_UINT32_BE (outdata + 6, timestamp); /* timestamp */
|
||||
GST_WRITE_UINT16_BE (outdata + 10, outflags); /* flags */
|
||||
memcpy (outdata + 12, data, size);
|
||||
gst_buffer_unmap (outbuf, &outmap);
|
||||
gst_buffer_resize (outbuf, 0, 12 + size);
|
||||
|
||||
gst_rdt_packet_data_unmap (packet);
|
||||
|
||||
GST_DEBUG_OBJECT (rdtdepay, "Pushing packet, outtime %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (outtime));
|
||||
|
||||
ret = gst_rdt_depay_push (rdtdepay, outbuf);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
dropping:
|
||||
{
|
||||
GST_WARNING_OBJECT (rdtdepay, "%d <= 100, dropping old packet", gap);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rdt_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||
{
|
||||
GstRDTDepay *rdtdepay;
|
||||
GstFlowReturn ret;
|
||||
GstClockTime timestamp;
|
||||
gboolean more;
|
||||
GstRDTPacket packet;
|
||||
|
||||
rdtdepay = GST_RDT_DEPAY (parent);
|
||||
|
||||
if (GST_BUFFER_IS_DISCONT (buf)) {
|
||||
GST_LOG_OBJECT (rdtdepay, "received discont");
|
||||
rdtdepay->discont = TRUE;
|
||||
}
|
||||
|
||||
if (rdtdepay->header) {
|
||||
GstBuffer *out;
|
||||
|
||||
out = rdtdepay->header;
|
||||
rdtdepay->header = NULL;
|
||||
|
||||
/* push header data first */
|
||||
gst_rdt_depay_push (rdtdepay, out);
|
||||
}
|
||||
|
||||
/* save timestamp */
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
ret = GST_FLOW_OK;
|
||||
|
||||
GST_LOG_OBJECT (rdtdepay, "received buffer timestamp %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (timestamp));
|
||||
|
||||
/* data is in RDT format. */
|
||||
more = gst_rdt_buffer_get_first_packet (buf, &packet);
|
||||
while (more) {
|
||||
GstRDTType type;
|
||||
|
||||
type = gst_rdt_packet_get_type (&packet);
|
||||
GST_DEBUG_OBJECT (rdtdepay, "Have packet of type %04x", type);
|
||||
|
||||
if (GST_RDT_IS_DATA_TYPE (type)) {
|
||||
GST_DEBUG_OBJECT (rdtdepay, "We have a data packet");
|
||||
ret = gst_rdt_depay_handle_data (rdtdepay, timestamp, &packet);
|
||||
} else {
|
||||
switch (type) {
|
||||
default:
|
||||
GST_DEBUG_OBJECT (rdtdepay, "Ignoring packet");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
more = gst_rdt_packet_move_to_next (&packet);
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_rdt_depay_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstRDTDepay *rdtdepay;
|
||||
GstStateChangeReturn ret;
|
||||
|
||||
rdtdepay = GST_RDT_DEPAY (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
gst_segment_init (&rdtdepay->segment, GST_FORMAT_UNDEFINED);
|
||||
rdtdepay->next_seqnum = -1;
|
||||
rdtdepay->need_newsegment = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
if (rdtdepay->header)
|
||||
gst_buffer_unref (rdtdepay->header);
|
||||
rdtdepay->header = NULL;
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2006> Lutz Mueller <lutz at topfrose dot de>
|
||||
* <2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RDT_DEPAY_H__
|
||||
#define __GST_RDT_DEPAY_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_RDT_DEPAY \
|
||||
(gst_rdt_depay_get_type())
|
||||
#define GST_RDT_DEPAY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RDT_DEPAY,GstRDTDepay))
|
||||
#define GST_RDT_DEPAY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RDT_DEPAY,GstRDTDepayClass))
|
||||
#define GST_IS_RDT_DEPAY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RDT_DEPAY))
|
||||
#define GST_IS_RDT_DEPAY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RDT_DEPAY))
|
||||
|
||||
typedef struct _GstRDTDepay GstRDTDepay;
|
||||
typedef struct _GstRDTDepayClass GstRDTDepayClass;
|
||||
|
||||
struct _GstRDTDepay
|
||||
{
|
||||
GstElement parent;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
guint clock_rate;
|
||||
GstClockTime npt_start;
|
||||
GstClockTime npt_stop;
|
||||
gdouble play_speed;
|
||||
gdouble play_scale;
|
||||
|
||||
guint32 next_seqnum;
|
||||
|
||||
gboolean discont;
|
||||
gboolean need_newsegment;
|
||||
GstSegment segment;
|
||||
GstBuffer *header;
|
||||
};
|
||||
|
||||
struct _GstRDTDepayClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_rdt_depay_get_type (void);
|
||||
|
||||
GST_ELEMENT_REGISTER_DECLARE (rdtdepay);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RDT_DEPAY_H__ */
|
|
@ -1,531 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rdtjitterbuffer.h"
|
||||
#include "gstrdtbuffer.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rdt_jitter_buffer_debug);
|
||||
#define GST_CAT_DEFAULT rdt_jitter_buffer_debug
|
||||
|
||||
#define MAX_WINDOW RDT_JITTER_BUFFER_MAX_WINDOW
|
||||
#define MAX_TIME (2 * GST_SECOND)
|
||||
|
||||
/* signals and args */
|
||||
enum
|
||||
{
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0
|
||||
};
|
||||
|
||||
/* GObject vmethods */
|
||||
static void rdt_jitter_buffer_finalize (GObject * object);
|
||||
|
||||
/* static guint rdt_jitter_buffer_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
G_DEFINE_TYPE (RDTJitterBuffer, rdt_jitter_buffer, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
rdt_jitter_buffer_class_init (RDTJitterBufferClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
|
||||
gobject_class->finalize = rdt_jitter_buffer_finalize;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rdt_jitter_buffer_debug, "rdtjitterbuffer", 0,
|
||||
"RDT Jitter Buffer");
|
||||
}
|
||||
|
||||
static void
|
||||
rdt_jitter_buffer_init (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
jbuf->packets = g_queue_new ();
|
||||
|
||||
rdt_jitter_buffer_reset_skew (jbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
rdt_jitter_buffer_finalize (GObject * object)
|
||||
{
|
||||
RDTJitterBuffer *jbuf;
|
||||
|
||||
jbuf = RDT_JITTER_BUFFER_CAST (object);
|
||||
|
||||
rdt_jitter_buffer_flush (jbuf);
|
||||
g_queue_free (jbuf->packets);
|
||||
|
||||
G_OBJECT_CLASS (rdt_jitter_buffer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_new:
|
||||
*
|
||||
* Create an #RDTJitterBuffer.
|
||||
*
|
||||
* Returns: a new #RDTJitterBuffer. Use g_object_unref() after usage.
|
||||
*/
|
||||
RDTJitterBuffer *
|
||||
rdt_jitter_buffer_new (void)
|
||||
{
|
||||
RDTJitterBuffer *jbuf;
|
||||
|
||||
jbuf = g_object_new (RDT_TYPE_JITTER_BUFFER, NULL);
|
||||
|
||||
return jbuf;
|
||||
}
|
||||
|
||||
void
|
||||
rdt_jitter_buffer_reset_skew (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
jbuf->base_time = -1;
|
||||
jbuf->base_rtptime = -1;
|
||||
jbuf->ext_rtptime = -1;
|
||||
jbuf->window_pos = 0;
|
||||
jbuf->window_filling = TRUE;
|
||||
jbuf->window_min = 0;
|
||||
jbuf->skew = 0;
|
||||
jbuf->prev_send_diff = -1;
|
||||
}
|
||||
|
||||
/* For the clock skew we use a windowed low point averaging algorithm as can be
|
||||
* found in http://www.grame.fr/pub/TR-050601.pdf. The idea is that the jitter is
|
||||
* composed of:
|
||||
*
|
||||
* J = N + n
|
||||
*
|
||||
* N : a constant network delay.
|
||||
* n : random added noise. The noise is concentrated around 0
|
||||
*
|
||||
* In the receiver we can track the elapsed time at the sender with:
|
||||
*
|
||||
* send_diff(i) = (Tsi - Ts0);
|
||||
*
|
||||
* Tsi : The time at the sender at packet i
|
||||
* Ts0 : The time at the sender at the first packet
|
||||
*
|
||||
* This is the difference between the RDT timestamp in the first received packet
|
||||
* and the current packet.
|
||||
*
|
||||
* At the receiver we have to deal with the jitter introduced by the network.
|
||||
*
|
||||
* recv_diff(i) = (Tri - Tr0)
|
||||
*
|
||||
* Tri : The time at the receiver at packet i
|
||||
* Tr0 : The time at the receiver at the first packet
|
||||
*
|
||||
* Both of these values contain a jitter Ji, a jitter for packet i, so we can
|
||||
* write:
|
||||
*
|
||||
* recv_diff(i) = (Cri + D + ni) - (Cr0 + D + n0))
|
||||
*
|
||||
* Cri : The time of the clock at the receiver for packet i
|
||||
* D + ni : The jitter when receiving packet i
|
||||
*
|
||||
* We see that the network delay is irrelevant here as we can eliminate D:
|
||||
*
|
||||
* recv_diff(i) = (Cri + ni) - (Cr0 + n0))
|
||||
*
|
||||
* The drift is now expressed as:
|
||||
*
|
||||
* Drift(i) = recv_diff(i) - send_diff(i);
|
||||
*
|
||||
* We now keep the W latest values of Drift and find the minimum (this is the
|
||||
* one with the lowest network jitter and thus the one which is least affected
|
||||
* by it). We average this lowest value to smooth out the resulting network skew.
|
||||
*
|
||||
* Both the window and the weighting used for averaging influence the accuracy
|
||||
* of the drift estimation. Finding the correct parameters turns out to be a
|
||||
* compromise between accuracy and inertia.
|
||||
*
|
||||
* We use a 2 second window or up to 512 data points, which is statistically big
|
||||
* enough to catch spikes (FIXME, detect spikes).
|
||||
* We also use a rather large weighting factor (125) to smoothly adapt. During
|
||||
* startup, when filling the window, we use a parabolic weighting factor, the
|
||||
* more the window is filled, the faster we move to the detected possible skew.
|
||||
*
|
||||
* Returns: @time adjusted with the clock skew.
|
||||
*/
|
||||
static GstClockTime
|
||||
calculate_skew (RDTJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
|
||||
guint32 clock_rate)
|
||||
{
|
||||
guint64 ext_rtptime;
|
||||
guint64 send_diff, recv_diff;
|
||||
gint64 delta;
|
||||
gint64 old;
|
||||
gint pos, i;
|
||||
GstClockTime gstrtptime, out_time;
|
||||
|
||||
//ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime);
|
||||
ext_rtptime = rtptime;
|
||||
|
||||
gstrtptime = gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, clock_rate);
|
||||
|
||||
again:
|
||||
/* first time, lock on to time and gstrtptime */
|
||||
if (jbuf->base_time == -1)
|
||||
jbuf->base_time = time;
|
||||
if (jbuf->base_rtptime == -1)
|
||||
jbuf->base_rtptime = gstrtptime;
|
||||
|
||||
if (gstrtptime >= jbuf->base_rtptime)
|
||||
send_diff = gstrtptime - jbuf->base_rtptime;
|
||||
else {
|
||||
/* elapsed time at sender, timestamps can go backwards and thus be smaller
|
||||
* than our base time, take a new base time in that case. */
|
||||
GST_DEBUG ("backward timestamps at server, taking new base time");
|
||||
jbuf->base_rtptime = gstrtptime;
|
||||
jbuf->base_time = time;
|
||||
send_diff = 0;
|
||||
}
|
||||
|
||||
GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
|
||||
GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
|
||||
GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
|
||||
GST_TIME_ARGS (send_diff));
|
||||
|
||||
if (jbuf->prev_send_diff != -1 && time != -1) {
|
||||
gint64 delta_diff;
|
||||
|
||||
if (send_diff > jbuf->prev_send_diff)
|
||||
delta_diff = send_diff - jbuf->prev_send_diff;
|
||||
else
|
||||
delta_diff = jbuf->prev_send_diff - send_diff;
|
||||
|
||||
/* server changed rtp timestamps too quickly, reset skew detection and start
|
||||
* again. This value is sortof arbitrary and can be a bad measurement up if
|
||||
* there are many packets missing because then we get a big gap that is
|
||||
* unrelated to a timestamp switch. */
|
||||
if (delta_diff > GST_SECOND) {
|
||||
GST_DEBUG ("delta changed too quickly %" GST_TIME_FORMAT " reset skew",
|
||||
GST_TIME_ARGS (delta_diff));
|
||||
rdt_jitter_buffer_reset_skew (jbuf);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
jbuf->prev_send_diff = send_diff;
|
||||
|
||||
/* we don't have an arrival timestamp so we can't do skew detection. we
|
||||
* should still apply a timestamp based on RDT timestamp and base_time */
|
||||
if (time == -1)
|
||||
goto no_skew;
|
||||
|
||||
/* elapsed time at receiver, includes the jitter */
|
||||
recv_diff = time - jbuf->base_time;
|
||||
|
||||
GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (jbuf->base_time),
|
||||
GST_TIME_ARGS (recv_diff));
|
||||
|
||||
/* measure the diff */
|
||||
delta = ((gint64) recv_diff) - ((gint64) send_diff);
|
||||
|
||||
pos = jbuf->window_pos;
|
||||
|
||||
if (jbuf->window_filling) {
|
||||
/* we are filling the window */
|
||||
GST_DEBUG ("filling %d, delta %" G_GINT64_FORMAT, pos, delta);
|
||||
jbuf->window[pos++] = delta;
|
||||
/* calc the min delta we observed */
|
||||
if (pos == 1 || delta < jbuf->window_min)
|
||||
jbuf->window_min = delta;
|
||||
|
||||
if (send_diff >= MAX_TIME || pos >= MAX_WINDOW) {
|
||||
jbuf->window_size = pos;
|
||||
|
||||
/* window filled */
|
||||
GST_DEBUG ("min %" G_GINT64_FORMAT, jbuf->window_min);
|
||||
|
||||
/* the skew is now the min */
|
||||
jbuf->skew = jbuf->window_min;
|
||||
jbuf->window_filling = FALSE;
|
||||
} else {
|
||||
gint perc_time, perc_window, perc;
|
||||
|
||||
/* figure out how much we filled the window, this depends on the amount of
|
||||
* time we have or the max number of points we keep. */
|
||||
perc_time = send_diff * 100 / MAX_TIME;
|
||||
perc_window = pos * 100 / MAX_WINDOW;
|
||||
perc = MAX (perc_time, perc_window);
|
||||
|
||||
/* make a parabolic function, the closer we get to the MAX, the more value
|
||||
* we give to the scaling factor of the new value */
|
||||
perc = perc * perc;
|
||||
|
||||
/* quickly go to the min value when we are filling up, slowly when we are
|
||||
* just starting because we're not sure it's a good value yet. */
|
||||
jbuf->skew =
|
||||
(perc * jbuf->window_min + ((10000 - perc) * jbuf->skew)) / 10000;
|
||||
jbuf->window_size = pos + 1;
|
||||
}
|
||||
} else {
|
||||
/* pick old value and store new value. We keep the previous value in order
|
||||
* to quickly check if the min of the window changed */
|
||||
old = jbuf->window[pos];
|
||||
jbuf->window[pos++] = delta;
|
||||
|
||||
if (delta <= jbuf->window_min) {
|
||||
/* if the new value we inserted is smaller or equal to the current min,
|
||||
* it becomes the new min */
|
||||
jbuf->window_min = delta;
|
||||
} else if (old == jbuf->window_min) {
|
||||
gint64 min = G_MAXINT64;
|
||||
|
||||
/* if we removed the old min, we have to find a new min */
|
||||
for (i = 0; i < jbuf->window_size; i++) {
|
||||
/* we found another value equal to the old min, we can stop searching now */
|
||||
if (jbuf->window[i] == old) {
|
||||
min = old;
|
||||
break;
|
||||
}
|
||||
if (jbuf->window[i] < min)
|
||||
min = jbuf->window[i];
|
||||
}
|
||||
jbuf->window_min = min;
|
||||
}
|
||||
/* average the min values */
|
||||
jbuf->skew = (jbuf->window_min + (124 * jbuf->skew)) / 125;
|
||||
GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
|
||||
delta, jbuf->window_min);
|
||||
}
|
||||
/* wrap around in the window */
|
||||
if (pos >= jbuf->window_size)
|
||||
pos = 0;
|
||||
jbuf->window_pos = pos;
|
||||
|
||||
no_skew:
|
||||
/* the output time is defined as the base timestamp plus the RDT time
|
||||
* adjusted for the clock skew .*/
|
||||
out_time = jbuf->base_time + send_diff + jbuf->skew;
|
||||
|
||||
GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
|
||||
jbuf->skew, GST_TIME_ARGS (out_time));
|
||||
|
||||
return out_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_insert:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
* @buf: a buffer
|
||||
* @time: a running_time when this buffer was received in nanoseconds
|
||||
* @clock_rate: the clock-rate of the payload of @buf
|
||||
* @tail: TRUE when the tail element changed.
|
||||
*
|
||||
* Inserts @buf into the packet queue of @jbuf. The sequence number of the
|
||||
* packet will be used to sort the packets. This function takes ownerhip of
|
||||
* @buf when the function returns %TRUE.
|
||||
* @buf should have writable metadata when calling this function.
|
||||
*
|
||||
* Returns: %FALSE if a packet with the same number already existed.
|
||||
*/
|
||||
gboolean
|
||||
rdt_jitter_buffer_insert (RDTJitterBuffer * jbuf, GstBuffer * buf,
|
||||
GstClockTime time, guint32 clock_rate, gboolean * tail)
|
||||
{
|
||||
GList *list;
|
||||
guint32 rtptime;
|
||||
guint16 seqnum;
|
||||
GstRDTPacket packet;
|
||||
gboolean more;
|
||||
|
||||
g_return_val_if_fail (jbuf != NULL, FALSE);
|
||||
g_return_val_if_fail (buf != NULL, FALSE);
|
||||
|
||||
more = gst_rdt_buffer_get_first_packet (buf, &packet);
|
||||
/* programmer error */
|
||||
g_return_val_if_fail (more == TRUE, FALSE);
|
||||
|
||||
seqnum = gst_rdt_packet_data_get_seq (&packet);
|
||||
/* do skew calculation by measuring the difference between rtptime and the
|
||||
* receive time, this function will retimestamp @buf with the skew corrected
|
||||
* running time. */
|
||||
rtptime = gst_rdt_packet_data_get_timestamp (&packet);
|
||||
|
||||
/* loop the list to skip strictly smaller seqnum buffers */
|
||||
for (list = jbuf->packets->head; list; list = g_list_next (list)) {
|
||||
guint16 qseq;
|
||||
gint gap;
|
||||
|
||||
more =
|
||||
gst_rdt_buffer_get_first_packet (GST_BUFFER_CAST (list->data), &packet);
|
||||
/* programmer error */
|
||||
g_return_val_if_fail (more == TRUE, FALSE);
|
||||
|
||||
qseq = gst_rdt_packet_data_get_seq (&packet);
|
||||
|
||||
/* compare the new seqnum to the one in the buffer */
|
||||
gap = gst_rdt_buffer_compare_seqnum (seqnum, qseq);
|
||||
|
||||
/* we hit a packet with the same seqnum, notify a duplicate */
|
||||
if (G_UNLIKELY (gap == 0))
|
||||
goto duplicate;
|
||||
|
||||
/* seqnum > qseq, we can stop looking */
|
||||
if (G_LIKELY (gap < 0))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (clock_rate) {
|
||||
time = calculate_skew (jbuf, rtptime, time, clock_rate);
|
||||
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||
}
|
||||
|
||||
if (list)
|
||||
g_queue_insert_before (jbuf->packets, list, buf);
|
||||
else
|
||||
g_queue_push_tail (jbuf->packets, buf);
|
||||
|
||||
/* tail was changed when we did not find a previous packet, we set the return
|
||||
* flag when requested. */
|
||||
if (tail)
|
||||
*tail = (list == NULL);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
duplicate:
|
||||
{
|
||||
GST_WARNING ("duplicate packet %d found", (gint) seqnum);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_pop:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
*
|
||||
* Pops the oldest buffer from the packet queue of @jbuf. The popped buffer will
|
||||
* have its timestamp adjusted with the incoming running_time and the detected
|
||||
* clock skew.
|
||||
*
|
||||
* Returns: a #GstBuffer or %NULL when there was no packet in the queue.
|
||||
*/
|
||||
GstBuffer *
|
||||
rdt_jitter_buffer_pop (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
g_return_val_if_fail (jbuf != NULL, FALSE);
|
||||
|
||||
buf = g_queue_pop_tail (jbuf->packets);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_peek:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
*
|
||||
* Peek the oldest buffer from the packet queue of @jbuf. Register a callback
|
||||
* with rdt_jitter_buffer_set_tail_changed() to be notified when an older packet
|
||||
* was inserted in the queue.
|
||||
*
|
||||
* Returns: a #GstBuffer or %NULL when there was no packet in the queue.
|
||||
*/
|
||||
GstBuffer *
|
||||
rdt_jitter_buffer_peek (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
g_return_val_if_fail (jbuf != NULL, FALSE);
|
||||
|
||||
buf = g_queue_peek_tail (jbuf->packets);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_flush:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
*
|
||||
* Flush all packets from the jitterbuffer.
|
||||
*/
|
||||
void
|
||||
rdt_jitter_buffer_flush (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
||||
g_return_if_fail (jbuf != NULL);
|
||||
|
||||
while ((buffer = g_queue_pop_head (jbuf->packets)))
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_num_packets:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
*
|
||||
* Get the number of packets currently in "jbuf.
|
||||
*
|
||||
* Returns: The number of packets in @jbuf.
|
||||
*/
|
||||
guint
|
||||
rdt_jitter_buffer_num_packets (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
g_return_val_if_fail (jbuf != NULL, 0);
|
||||
|
||||
return jbuf->packets->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* rdt_jitter_buffer_get_ts_diff:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
*
|
||||
* Get the difference between the timestamps of first and last packet in the
|
||||
* jitterbuffer.
|
||||
*
|
||||
* Returns: The difference expressed in the timestamp units of the packets.
|
||||
*/
|
||||
guint32
|
||||
rdt_jitter_buffer_get_ts_diff (RDTJitterBuffer * jbuf)
|
||||
{
|
||||
guint64 high_ts, low_ts;
|
||||
GstBuffer *high_buf, *low_buf;
|
||||
guint32 result;
|
||||
|
||||
g_return_val_if_fail (jbuf != NULL, 0);
|
||||
|
||||
high_buf = g_queue_peek_head (jbuf->packets);
|
||||
low_buf = g_queue_peek_tail (jbuf->packets);
|
||||
|
||||
if (!high_buf || !low_buf || high_buf == low_buf)
|
||||
return 0;
|
||||
|
||||
//high_ts = gst_rtp_buffer_get_timestamp (high_buf);
|
||||
//low_ts = gst_rtp_buffer_get_timestamp (low_buf);
|
||||
high_ts = 0;
|
||||
low_ts = 0;
|
||||
|
||||
/* it needs to work if ts wraps */
|
||||
if (high_ts >= low_ts) {
|
||||
result = (guint32) (high_ts - low_ts);
|
||||
} else {
|
||||
result = (guint32) (high_ts + G_MAXUINT32 + 1 - low_ts);
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __RDT_JITTER_BUFFER_H__
|
||||
#define __RDT_JITTER_BUFFER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
typedef struct _RDTJitterBuffer RDTJitterBuffer;
|
||||
typedef struct _RDTJitterBufferClass RDTJitterBufferClass;
|
||||
|
||||
#define RDT_TYPE_JITTER_BUFFER (rdt_jitter_buffer_get_type())
|
||||
#define RDT_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_CAST((src),RDT_TYPE_JITTER_BUFFER,RDTJitterBuffer))
|
||||
#define RDT_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RDT_TYPE_JITTER_BUFFER,RDTJitterBufferClass))
|
||||
#define RDT_IS_JITTER_BUFFER(src) (G_TYPE_CHECK_INSTANCE_TYPE((src),RDT_TYPE_JITTER_BUFFER))
|
||||
#define RDT_IS_JITTER_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),RDT_TYPE_JITTER_BUFFER))
|
||||
#define RDT_JITTER_BUFFER_CAST(src) ((RDTJitterBuffer *)(src))
|
||||
|
||||
/**
|
||||
* RTPTailChanged:
|
||||
* @jbuf: an #RDTJitterBuffer
|
||||
* @user_data: user data specified when registering
|
||||
*
|
||||
* This callback will be called when the tail buffer of @jbuf changed.
|
||||
*/
|
||||
typedef void (*RTPTailChanged) (RDTJitterBuffer *jbuf, gpointer user_data);
|
||||
|
||||
#define RDT_JITTER_BUFFER_MAX_WINDOW 512
|
||||
/**
|
||||
* RDTJitterBuffer:
|
||||
*
|
||||
* A JitterBuffer in the #RTPSession
|
||||
*/
|
||||
struct _RDTJitterBuffer {
|
||||
GObject object;
|
||||
|
||||
GQueue *packets;
|
||||
|
||||
/* for calculating skew */
|
||||
GstClockTime base_time;
|
||||
GstClockTime base_rtptime;
|
||||
guint64 ext_rtptime;
|
||||
gint64 window[RDT_JITTER_BUFFER_MAX_WINDOW];
|
||||
guint window_pos;
|
||||
guint window_size;
|
||||
gboolean window_filling;
|
||||
gint64 window_min;
|
||||
gint64 skew;
|
||||
gint64 prev_send_diff;
|
||||
};
|
||||
|
||||
struct _RDTJitterBufferClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType rdt_jitter_buffer_get_type (void);
|
||||
|
||||
/* managing lifetime */
|
||||
RDTJitterBuffer* rdt_jitter_buffer_new (void);
|
||||
|
||||
void rdt_jitter_buffer_reset_skew (RDTJitterBuffer *jbuf);
|
||||
|
||||
gboolean rdt_jitter_buffer_insert (RDTJitterBuffer *jbuf, GstBuffer *buf,
|
||||
GstClockTime time,
|
||||
guint32 clock_rate,
|
||||
gboolean *tail);
|
||||
GstBuffer * rdt_jitter_buffer_peek (RDTJitterBuffer *jbuf);
|
||||
GstBuffer * rdt_jitter_buffer_pop (RDTJitterBuffer *jbuf);
|
||||
|
||||
void rdt_jitter_buffer_flush (RDTJitterBuffer *jbuf);
|
||||
|
||||
guint rdt_jitter_buffer_num_packets (RDTJitterBuffer *jbuf);
|
||||
guint32 rdt_jitter_buffer_get_ts_diff (RDTJitterBuffer *jbuf);
|
||||
|
||||
#endif /* __RDT_JITTER_BUFFER_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,93 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/*
|
||||
* Unless otherwise indicated, Source Code is licensed under MIT license.
|
||||
* See further explanation attached in License Statement (distributed in the file
|
||||
* LICENSE).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RDT_MANAGER_H__
|
||||
#define __GST_RDT_MANAGER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_RDT_MANAGER (gst_rdt_manager_get_type())
|
||||
#define GST_IS_RDT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RDT_MANAGER))
|
||||
#define GST_IS_RDT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RDT_MANAGER))
|
||||
#define GST_RDT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RDT_MANAGER, GstRDTManager))
|
||||
#define GST_RDT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RDT_MANAGER, GstRDTManagerClass))
|
||||
|
||||
typedef struct _GstRDTManager GstRDTManager;
|
||||
typedef struct _GstRDTManagerClass GstRDTManagerClass;
|
||||
typedef struct _GstRDTManagerSession GstRDTManagerSession;
|
||||
|
||||
struct _GstRDTManager {
|
||||
GstElement element;
|
||||
|
||||
guint latency;
|
||||
GSList *sessions;
|
||||
GstClock *provided_clock;
|
||||
};
|
||||
|
||||
struct _GstRDTManagerClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* get the caps for pt */
|
||||
GstCaps* (*request_pt_map) (GstRDTManager *rtpdec, guint session, guint pt);
|
||||
|
||||
void (*clear_pt_map) (GstRDTManager *rtpdec);
|
||||
|
||||
void (*on_new_ssrc) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_ssrc_collision) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_ssrc_validated) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_ssrc_active) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_ssrc_sdes) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_bye_ssrc) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_bye_timeout) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_timeout) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
void (*on_npt_stop) (GstRDTManager *rtpdec, guint session, guint32 ssrc);
|
||||
};
|
||||
|
||||
GType gst_rdt_manager_get_type(void);
|
||||
|
||||
GST_ELEMENT_REGISTER_DECLARE (rdtmanager);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RDT_MANAGER_H__ */
|
|
@ -1,324 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/* Element-Checklist-Version: 5 */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "realhash.h"
|
||||
|
||||
void rtsp_ext_real_calc_response_and_checksum (char *response,
|
||||
char *chksum, char *challenge);
|
||||
|
||||
/*
|
||||
* The following code has been copied from
|
||||
* xine-lib-1.1.1/src/input/libreal/real.c.
|
||||
*/
|
||||
|
||||
static const unsigned char xor_table[] = {
|
||||
0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
|
||||
0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
|
||||
0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
|
||||
0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
|
||||
0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
#define LE_32(x) GST_READ_UINT32_LE(x)
|
||||
#define BE_32C(x,y) GST_WRITE_UINT32_BE(x,y)
|
||||
#define LE_32C(x,y) GST_WRITE_UINT32_LE(x,y)
|
||||
|
||||
static void
|
||||
hash (char *field, char *param)
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
|
||||
/* fill variables */
|
||||
a = LE_32 (field);
|
||||
b = LE_32 (field + 4);
|
||||
c = LE_32 (field + 8);
|
||||
d = LE_32 (field + 12);
|
||||
|
||||
a = ((b & c) | (~b & d)) + LE_32 ((param + 0x00)) + a - 0x28955B88;
|
||||
a = ((a << 0x07) | (a >> 0x19)) + b;
|
||||
d = ((a & b) | (~a & c)) + LE_32 ((param + 0x04)) + d - 0x173848AA;
|
||||
d = ((d << 0x0c) | (d >> 0x14)) + a;
|
||||
c = ((d & a) | (~d & b)) + LE_32 ((param + 0x08)) + c + 0x242070DB;
|
||||
c = ((c << 0x11) | (c >> 0x0f)) + d;
|
||||
b = ((c & d) | (~c & a)) + LE_32 ((param + 0x0c)) + b - 0x3E423112;
|
||||
b = ((b << 0x16) | (b >> 0x0a)) + c;
|
||||
a = ((b & c) | (~b & d)) + LE_32 ((param + 0x10)) + a - 0x0A83F051;
|
||||
a = ((a << 0x07) | (a >> 0x19)) + b;
|
||||
d = ((a & b) | (~a & c)) + LE_32 ((param + 0x14)) + d + 0x4787C62A;
|
||||
d = ((d << 0x0c) | (d >> 0x14)) + a;
|
||||
c = ((d & a) | (~d & b)) + LE_32 ((param + 0x18)) + c - 0x57CFB9ED;
|
||||
c = ((c << 0x11) | (c >> 0x0f)) + d;
|
||||
b = ((c & d) | (~c & a)) + LE_32 ((param + 0x1c)) + b - 0x02B96AFF;
|
||||
b = ((b << 0x16) | (b >> 0x0a)) + c;
|
||||
a = ((b & c) | (~b & d)) + LE_32 ((param + 0x20)) + a + 0x698098D8;
|
||||
a = ((a << 0x07) | (a >> 0x19)) + b;
|
||||
d = ((a & b) | (~a & c)) + LE_32 ((param + 0x24)) + d - 0x74BB0851;
|
||||
d = ((d << 0x0c) | (d >> 0x14)) + a;
|
||||
c = ((d & a) | (~d & b)) + LE_32 ((param + 0x28)) + c - 0x0000A44F;
|
||||
c = ((c << 0x11) | (c >> 0x0f)) + d;
|
||||
b = ((c & d) | (~c & a)) + LE_32 ((param + 0x2C)) + b - 0x76A32842;
|
||||
b = ((b << 0x16) | (b >> 0x0a)) + c;
|
||||
a = ((b & c) | (~b & d)) + LE_32 ((param + 0x30)) + a + 0x6B901122;
|
||||
a = ((a << 0x07) | (a >> 0x19)) + b;
|
||||
d = ((a & b) | (~a & c)) + LE_32 ((param + 0x34)) + d - 0x02678E6D;
|
||||
d = ((d << 0x0c) | (d >> 0x14)) + a;
|
||||
c = ((d & a) | (~d & b)) + LE_32 ((param + 0x38)) + c - 0x5986BC72;
|
||||
c = ((c << 0x11) | (c >> 0x0f)) + d;
|
||||
b = ((c & d) | (~c & a)) + LE_32 ((param + 0x3c)) + b + 0x49B40821;
|
||||
b = ((b << 0x16) | (b >> 0x0a)) + c;
|
||||
|
||||
a = ((b & d) | (~d & c)) + LE_32 ((param + 0x04)) + a - 0x09E1DA9E;
|
||||
a = ((a << 0x05) | (a >> 0x1b)) + b;
|
||||
d = ((a & c) | (~c & b)) + LE_32 ((param + 0x18)) + d - 0x3FBF4CC0;
|
||||
d = ((d << 0x09) | (d >> 0x17)) + a;
|
||||
c = ((d & b) | (~b & a)) + LE_32 ((param + 0x2c)) + c + 0x265E5A51;
|
||||
c = ((c << 0x0e) | (c >> 0x12)) + d;
|
||||
b = ((c & a) | (~a & d)) + LE_32 ((param + 0x00)) + b - 0x16493856;
|
||||
b = ((b << 0x14) | (b >> 0x0c)) + c;
|
||||
a = ((b & d) | (~d & c)) + LE_32 ((param + 0x14)) + a - 0x29D0EFA3;
|
||||
a = ((a << 0x05) | (a >> 0x1b)) + b;
|
||||
d = ((a & c) | (~c & b)) + LE_32 ((param + 0x28)) + d + 0x02441453;
|
||||
d = ((d << 0x09) | (d >> 0x17)) + a;
|
||||
c = ((d & b) | (~b & a)) + LE_32 ((param + 0x3c)) + c - 0x275E197F;
|
||||
c = ((c << 0x0e) | (c >> 0x12)) + d;
|
||||
b = ((c & a) | (~a & d)) + LE_32 ((param + 0x10)) + b - 0x182C0438;
|
||||
b = ((b << 0x14) | (b >> 0x0c)) + c;
|
||||
a = ((b & d) | (~d & c)) + LE_32 ((param + 0x24)) + a + 0x21E1CDE6;
|
||||
a = ((a << 0x05) | (a >> 0x1b)) + b;
|
||||
d = ((a & c) | (~c & b)) + LE_32 ((param + 0x38)) + d - 0x3CC8F82A;
|
||||
d = ((d << 0x09) | (d >> 0x17)) + a;
|
||||
c = ((d & b) | (~b & a)) + LE_32 ((param + 0x0c)) + c - 0x0B2AF279;
|
||||
c = ((c << 0x0e) | (c >> 0x12)) + d;
|
||||
b = ((c & a) | (~a & d)) + LE_32 ((param + 0x20)) + b + 0x455A14ED;
|
||||
b = ((b << 0x14) | (b >> 0x0c)) + c;
|
||||
a = ((b & d) | (~d & c)) + LE_32 ((param + 0x34)) + a - 0x561C16FB;
|
||||
a = ((a << 0x05) | (a >> 0x1b)) + b;
|
||||
d = ((a & c) | (~c & b)) + LE_32 ((param + 0x08)) + d - 0x03105C08;
|
||||
d = ((d << 0x09) | (d >> 0x17)) + a;
|
||||
c = ((d & b) | (~b & a)) + LE_32 ((param + 0x1c)) + c + 0x676F02D9;
|
||||
c = ((c << 0x0e) | (c >> 0x12)) + d;
|
||||
b = ((c & a) | (~a & d)) + LE_32 ((param + 0x30)) + b - 0x72D5B376;
|
||||
b = ((b << 0x14) | (b >> 0x0c)) + c;
|
||||
|
||||
a = (b ^ c ^ d) + LE_32 ((param + 0x14)) + a - 0x0005C6BE;
|
||||
a = ((a << 0x04) | (a >> 0x1c)) + b;
|
||||
d = (a ^ b ^ c) + LE_32 ((param + 0x20)) + d - 0x788E097F;
|
||||
d = ((d << 0x0b) | (d >> 0x15)) + a;
|
||||
c = (d ^ a ^ b) + LE_32 ((param + 0x2c)) + c + 0x6D9D6122;
|
||||
c = ((c << 0x10) | (c >> 0x10)) + d;
|
||||
b = (c ^ d ^ a) + LE_32 ((param + 0x38)) + b - 0x021AC7F4;
|
||||
b = ((b << 0x17) | (b >> 0x09)) + c;
|
||||
a = (b ^ c ^ d) + LE_32 ((param + 0x04)) + a - 0x5B4115BC;
|
||||
a = ((a << 0x04) | (a >> 0x1c)) + b;
|
||||
d = (a ^ b ^ c) + LE_32 ((param + 0x10)) + d + 0x4BDECFA9;
|
||||
d = ((d << 0x0b) | (d >> 0x15)) + a;
|
||||
c = (d ^ a ^ b) + LE_32 ((param + 0x1c)) + c - 0x0944B4A0;
|
||||
c = ((c << 0x10) | (c >> 0x10)) + d;
|
||||
b = (c ^ d ^ a) + LE_32 ((param + 0x28)) + b - 0x41404390;
|
||||
b = ((b << 0x17) | (b >> 0x09)) + c;
|
||||
a = (b ^ c ^ d) + LE_32 ((param + 0x34)) + a + 0x289B7EC6;
|
||||
a = ((a << 0x04) | (a >> 0x1c)) + b;
|
||||
d = (a ^ b ^ c) + LE_32 ((param + 0x00)) + d - 0x155ED806;
|
||||
d = ((d << 0x0b) | (d >> 0x15)) + a;
|
||||
c = (d ^ a ^ b) + LE_32 ((param + 0x0c)) + c - 0x2B10CF7B;
|
||||
c = ((c << 0x10) | (c >> 0x10)) + d;
|
||||
b = (c ^ d ^ a) + LE_32 ((param + 0x18)) + b + 0x04881D05;
|
||||
b = ((b << 0x17) | (b >> 0x09)) + c;
|
||||
a = (b ^ c ^ d) + LE_32 ((param + 0x24)) + a - 0x262B2FC7;
|
||||
a = ((a << 0x04) | (a >> 0x1c)) + b;
|
||||
d = (a ^ b ^ c) + LE_32 ((param + 0x30)) + d - 0x1924661B;
|
||||
d = ((d << 0x0b) | (d >> 0x15)) + a;
|
||||
c = (d ^ a ^ b) + LE_32 ((param + 0x3c)) + c + 0x1fa27cf8;
|
||||
c = ((c << 0x10) | (c >> 0x10)) + d;
|
||||
b = (c ^ d ^ a) + LE_32 ((param + 0x08)) + b - 0x3B53A99B;
|
||||
b = ((b << 0x17) | (b >> 0x09)) + c;
|
||||
|
||||
a = ((~d | b) ^ c) + LE_32 ((param + 0x00)) + a - 0x0BD6DDBC;
|
||||
a = ((a << 0x06) | (a >> 0x1a)) + b;
|
||||
d = ((~c | a) ^ b) + LE_32 ((param + 0x1c)) + d + 0x432AFF97;
|
||||
d = ((d << 0x0a) | (d >> 0x16)) + a;
|
||||
c = ((~b | d) ^ a) + LE_32 ((param + 0x38)) + c - 0x546BDC59;
|
||||
c = ((c << 0x0f) | (c >> 0x11)) + d;
|
||||
b = ((~a | c) ^ d) + LE_32 ((param + 0x14)) + b - 0x036C5FC7;
|
||||
b = ((b << 0x15) | (b >> 0x0b)) + c;
|
||||
a = ((~d | b) ^ c) + LE_32 ((param + 0x30)) + a + 0x655B59C3;
|
||||
a = ((a << 0x06) | (a >> 0x1a)) + b;
|
||||
d = ((~c | a) ^ b) + LE_32 ((param + 0x0C)) + d - 0x70F3336E;
|
||||
d = ((d << 0x0a) | (d >> 0x16)) + a;
|
||||
c = ((~b | d) ^ a) + LE_32 ((param + 0x28)) + c - 0x00100B83;
|
||||
c = ((c << 0x0f) | (c >> 0x11)) + d;
|
||||
b = ((~a | c) ^ d) + LE_32 ((param + 0x04)) + b - 0x7A7BA22F;
|
||||
b = ((b << 0x15) | (b >> 0x0b)) + c;
|
||||
a = ((~d | b) ^ c) + LE_32 ((param + 0x20)) + a + 0x6FA87E4F;
|
||||
a = ((a << 0x06) | (a >> 0x1a)) + b;
|
||||
d = ((~c | a) ^ b) + LE_32 ((param + 0x3c)) + d - 0x01D31920;
|
||||
d = ((d << 0x0a) | (d >> 0x16)) + a;
|
||||
c = ((~b | d) ^ a) + LE_32 ((param + 0x18)) + c - 0x5CFEBCEC;
|
||||
c = ((c << 0x0f) | (c >> 0x11)) + d;
|
||||
b = ((~a | c) ^ d) + LE_32 ((param + 0x34)) + b + 0x4E0811A1;
|
||||
b = ((b << 0x15) | (b >> 0x0b)) + c;
|
||||
a = ((~d | b) ^ c) + LE_32 ((param + 0x10)) + a - 0x08AC817E;
|
||||
a = ((a << 0x06) | (a >> 0x1a)) + b;
|
||||
d = ((~c | a) ^ b) + LE_32 ((param + 0x2c)) + d - 0x42C50DCB;
|
||||
d = ((d << 0x0a) | (d >> 0x16)) + a;
|
||||
c = ((~b | d) ^ a) + LE_32 ((param + 0x08)) + c + 0x2AD7D2BB;
|
||||
c = ((c << 0x0f) | (c >> 0x11)) + d;
|
||||
b = ((~a | c) ^ d) + LE_32 ((param + 0x24)) + b - 0x14792C6F;
|
||||
b = ((b << 0x15) | (b >> 0x0b)) + c;
|
||||
|
||||
a += LE_32 (field);
|
||||
b += LE_32 (field + 4);
|
||||
c += LE_32 (field + 8);
|
||||
d += LE_32 (field + 12);
|
||||
|
||||
LE_32C (field, a);
|
||||
LE_32C (field + 4, b);
|
||||
LE_32C (field + 8, c);
|
||||
LE_32C (field + 12, d);
|
||||
}
|
||||
|
||||
static void
|
||||
call_hash (char *key, char *challenge, int len)
|
||||
{
|
||||
uint8_t *ptr1, *ptr2;
|
||||
uint32_t a, b, c, d, tmp;
|
||||
|
||||
ptr1 = (uint8_t *) (key + 16);
|
||||
ptr2 = (uint8_t *) (key + 20);
|
||||
|
||||
a = LE_32 (ptr1);
|
||||
b = (a >> 3) & 0x3f;
|
||||
a += len * 8;
|
||||
LE_32C (ptr1, a);
|
||||
|
||||
if (a < (len << 3))
|
||||
ptr2 += 4;
|
||||
|
||||
tmp = LE_32 (ptr2) + (len >> 0x1d);
|
||||
LE_32C (ptr2, tmp);
|
||||
a = 64 - b;
|
||||
c = 0;
|
||||
if (a <= len) {
|
||||
|
||||
memcpy (key + b + 24, challenge, a);
|
||||
hash (key, key + 24);
|
||||
c = a;
|
||||
d = c + 0x3f;
|
||||
|
||||
while (d < len) {
|
||||
hash (key, challenge + d - 0x3f);
|
||||
d += 64;
|
||||
c += 64;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
|
||||
memcpy (key + b + 24, challenge + c, len - c);
|
||||
}
|
||||
|
||||
void
|
||||
gst_rtsp_ext_real_calc_response_and_checksum (char *response, char *chksum,
|
||||
char *challenge)
|
||||
{
|
||||
int ch_len, table_len, resp_len;
|
||||
int i;
|
||||
char *ptr;
|
||||
char buf[128];
|
||||
char field[128];
|
||||
char zres[20];
|
||||
char buf1[128];
|
||||
char buf2[128];
|
||||
|
||||
/* initialize return values */
|
||||
memset (response, 0, 64);
|
||||
memset (chksum, 0, 34);
|
||||
|
||||
/* initialize buffer */
|
||||
memset (buf, 0, 128);
|
||||
ptr = buf;
|
||||
BE_32C (ptr, 0xa1e9149d);
|
||||
ptr += 4;
|
||||
BE_32C (ptr, 0x0e6b3b59);
|
||||
ptr += 4;
|
||||
|
||||
if ((ch_len = MIN (strlen (challenge), 56)) == 40) {
|
||||
challenge[32] = 0;
|
||||
ch_len = 32;
|
||||
}
|
||||
memcpy (ptr, challenge, ch_len);
|
||||
|
||||
/* xor challenge bytewise with xor_table */
|
||||
table_len = MIN (strlen ((char *) xor_table), 56);
|
||||
for (i = 0; i < table_len; i++)
|
||||
ptr[i] = ptr[i] ^ xor_table[i];
|
||||
|
||||
/* initialize our field */
|
||||
BE_32C (field, 0x01234567);
|
||||
BE_32C (field + 4, 0x89ABCDEF);
|
||||
BE_32C (field + 8, 0xFEDCBA98);
|
||||
BE_32C (field + 12, 0x76543210);
|
||||
BE_32C (field + 16, 0x00000000);
|
||||
BE_32C (field + 20, 0x00000000);
|
||||
|
||||
/* calculate response */
|
||||
call_hash (field, buf, 64);
|
||||
memset (buf1, 0, 64);
|
||||
*buf1 = (char) 128;
|
||||
memcpy (buf2, field + 16, 8);
|
||||
i = (LE_32 ((buf2)) >> 3) & 0x3f;
|
||||
if (i < 56)
|
||||
i = 56 - i;
|
||||
else
|
||||
i = 120 - i;
|
||||
call_hash (field, buf1, i);
|
||||
call_hash (field, buf2, 8);
|
||||
memcpy (zres, field, 16);
|
||||
|
||||
/* convert zres to ascii string */
|
||||
for (i = 0; i < 16; i++) {
|
||||
char a, b;
|
||||
|
||||
a = (zres[i] >> 4) & 15;
|
||||
b = zres[i] & 15;
|
||||
|
||||
response[i * 2] = ((a < 10) ? (a + 48) : (a + 87)) & 255;
|
||||
response[i * 2 + 1] = ((b < 10) ? (b + 48) : (b + 87)) & 255;
|
||||
}
|
||||
|
||||
/* add tail */
|
||||
resp_len = strlen (response);
|
||||
strcpy (&response[resp_len], "01d0a8e3");
|
||||
|
||||
/* calculate checksum */
|
||||
for (i = 0; i < resp_len / 4; i++)
|
||||
chksum[i] = response[i * 4];
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RTSP_HASH_H__
|
||||
#define __GST_RTSP_HASH_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void
|
||||
gst_rtsp_ext_real_calc_response_and_checksum (char *response, char *chksum,
|
||||
char *challenge);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RTSP_HASH_H__ */
|
|
@ -23,10 +23,6 @@
|
|||
|
||||
#include "rmdemux.h"
|
||||
#include "rademux.h"
|
||||
#include "rdtdepay.h"
|
||||
#include "rdtmanager.h"
|
||||
#include "rtspreal.h"
|
||||
#include "pnmsrc.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
|
@ -35,10 +31,6 @@ plugin_init (GstPlugin * plugin)
|
|||
|
||||
ret |= GST_ELEMENT_REGISTER (rmdemux, plugin);
|
||||
ret |= GST_ELEMENT_REGISTER (rademux, plugin);
|
||||
ret |= GST_ELEMENT_REGISTER (rdtdepay, plugin);
|
||||
ret |= GST_ELEMENT_REGISTER (rdtmanager, plugin);
|
||||
ret |= GST_ELEMENT_REGISTER (rtspreal, plugin);
|
||||
ret |= GST_ELEMENT_REGISTER (pnmsrc, plugin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1,735 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
/* Element-Checklist-Version: 5 */
|
||||
|
||||
/**
|
||||
* SECTION:element-rtspreal
|
||||
* @title: rtspreal
|
||||
*
|
||||
* A RealMedia RTSP extension
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gst/rtsp/gstrtspextension.h>
|
||||
|
||||
#include "realhash.h"
|
||||
#include "rtspreal.h"
|
||||
#include "asmrules.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rtspreal_debug);
|
||||
#define GST_CAT_DEFAULT (rtspreal_debug)
|
||||
|
||||
#define SERVER_PREFIX "RealServer"
|
||||
#define DEFAULT_BANDWIDTH "10485800"
|
||||
|
||||
static GstRTSPResult
|
||||
rtsp_ext_real_get_transports (GstRTSPExtension * ext,
|
||||
GstRTSPLowerTrans protocols, gchar ** transport)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
GString *str;
|
||||
|
||||
if (!ctx->isreal)
|
||||
return GST_RTSP_OK;
|
||||
|
||||
GST_DEBUG_OBJECT (ext, "generating transports for %d", protocols);
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
/*
|
||||
if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) {
|
||||
g_string_append (str, "x-real-rdt/mcast;client_port=%%u1;mode=play,");
|
||||
}
|
||||
if (protocols & GST_RTSP_LOWER_TRANS_UDP) {
|
||||
g_string_append (str, "x-real-rdt/udp;client_port=%%u1;mode=play,");
|
||||
g_string_append (str, "x-pn-tng/udp;client_port=%%u1;mode=play,");
|
||||
}
|
||||
*/
|
||||
if (protocols & GST_RTSP_LOWER_TRANS_TCP) {
|
||||
g_string_append (str, "x-real-rdt/tcp;mode=play,");
|
||||
g_string_append (str, "x-pn-tng/tcp;mode=play,");
|
||||
}
|
||||
|
||||
/* if we added something, remove trailing ',' */
|
||||
if (str->len > 0)
|
||||
g_string_truncate (str, str->len - 1);
|
||||
|
||||
*transport = g_string_free (str, FALSE);
|
||||
|
||||
return GST_RTSP_OK;
|
||||
}
|
||||
|
||||
static GstRTSPResult
|
||||
rtsp_ext_real_before_send (GstRTSPExtension * ext, GstRTSPMessage * request)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
|
||||
switch (request->type_data.request.method) {
|
||||
case GST_RTSP_OPTIONS:
|
||||
{
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_USER_AGENT,
|
||||
//"RealMedia Player (" GST_PACKAGE_NAME ")");
|
||||
"RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_CHALLENGE,
|
||||
"9e26d33f2984236010ef6253fb1887f7");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_COMPANY_ID,
|
||||
"KnKV4M4I/B2FjJ1TToLycw==");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_GUID,
|
||||
"00000000-0000-0000-0000-000000000000");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_REGION_DATA, "0");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_PLAYER_START_TIME,
|
||||
"[28/03/2003:22:50:23 00:00]");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_ID,
|
||||
"Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
|
||||
ctx->isreal = FALSE;
|
||||
break;
|
||||
}
|
||||
case GST_RTSP_DESCRIBE:
|
||||
{
|
||||
if (ctx->isreal) {
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_BANDWIDTH,
|
||||
DEFAULT_BANDWIDTH);
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_GUID,
|
||||
"00000000-0000-0000-0000-000000000000");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_REGION_DATA, "0");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CLIENT_ID,
|
||||
"Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_MAX_ASM_WIDTH, "1");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_LANGUAGE, "en-US");
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE,
|
||||
"com.real.retain-entity-for-setup");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_RTSP_SETUP:
|
||||
{
|
||||
if (ctx->isreal) {
|
||||
gchar *value =
|
||||
g_strdup_printf ("%s, sd=%s", ctx->challenge2, ctx->checksum);
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_REAL_CHALLENGE2,
|
||||
value);
|
||||
gst_rtsp_message_add_header (request, GST_RTSP_HDR_IF_MATCH, ctx->etag);
|
||||
g_free (value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GST_RTSP_OK;
|
||||
}
|
||||
|
||||
static GstRTSPResult
|
||||
rtsp_ext_real_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
|
||||
GstRTSPMessage * resp)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
|
||||
switch (req->type_data.request.method) {
|
||||
case GST_RTSP_OPTIONS:
|
||||
{
|
||||
gchar *challenge1 = NULL;
|
||||
gchar *server = NULL;
|
||||
|
||||
gst_rtsp_message_get_header (resp, GST_RTSP_HDR_SERVER, &server, 0);
|
||||
|
||||
gst_rtsp_message_get_header (resp, GST_RTSP_HDR_REAL_CHALLENGE1,
|
||||
&challenge1, 0);
|
||||
if (!challenge1)
|
||||
goto no_challenge1;
|
||||
|
||||
gst_rtsp_ext_real_calc_response_and_checksum (ctx->challenge2,
|
||||
ctx->checksum, challenge1);
|
||||
|
||||
GST_DEBUG_OBJECT (ctx, "Found Real challenge tag");
|
||||
ctx->isreal = TRUE;
|
||||
break;
|
||||
}
|
||||
case GST_RTSP_DESCRIBE:
|
||||
{
|
||||
gchar *etag = NULL;
|
||||
guint len;
|
||||
|
||||
gst_rtsp_message_get_header (resp, GST_RTSP_HDR_ETAG, &etag, 0);
|
||||
if (etag) {
|
||||
len = sizeof (ctx->etag);
|
||||
strncpy (ctx->etag, etag, len);
|
||||
ctx->etag[len - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GST_RTSP_OK;
|
||||
|
||||
/* ERRORS */
|
||||
no_challenge1:
|
||||
{
|
||||
GST_DEBUG_OBJECT (ctx, "Could not find challenge tag.");
|
||||
ctx->isreal = FALSE;
|
||||
return GST_RTSP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#define ENSURE_SIZE(size) \
|
||||
G_STMT_START { \
|
||||
while (data_len < size) { \
|
||||
data_len += 1024; \
|
||||
data = g_realloc (data, data_len); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define READ_BUFFER_GEN(src, func, name, dest, dest_len) \
|
||||
G_STMT_START { \
|
||||
dest = (gchar *)func (src, name); \
|
||||
dest_len = 0; \
|
||||
if (!dest) { \
|
||||
dest = (char *) ""; \
|
||||
} \
|
||||
else if (!strncmp (dest, "buffer;\"", 8)) { \
|
||||
dest += 8; \
|
||||
dest_len = strlen (dest) - 1; \
|
||||
dest[dest_len] = '\0'; \
|
||||
g_base64_decode_inplace (dest, &dest_len); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define READ_BUFFER(sdp, name, dest, dest_len) \
|
||||
READ_BUFFER_GEN(sdp, gst_sdp_message_get_attribute_val, name, dest, dest_len)
|
||||
#define READ_BUFFER_M(media, name, dest, dest_len) \
|
||||
READ_BUFFER_GEN(media, gst_sdp_media_get_attribute_val, name, dest, dest_len)
|
||||
|
||||
#define READ_INT_GEN(src, func, name, dest) \
|
||||
G_STMT_START { \
|
||||
const gchar *val = func (src, name); \
|
||||
if (val && !strncmp (val, "integer;", 8)) \
|
||||
dest = atoi (val + 8); \
|
||||
else \
|
||||
dest = 0; \
|
||||
} G_STMT_END
|
||||
|
||||
#define READ_INT(sdp, name, dest) \
|
||||
READ_INT_GEN(sdp, gst_sdp_message_get_attribute_val, name, dest)
|
||||
#define READ_INT_M(media, name, dest) \
|
||||
READ_INT_GEN(media, gst_sdp_media_get_attribute_val, name, dest)
|
||||
|
||||
#define READ_STRING(media, name, dest, dest_len) \
|
||||
G_STMT_START { \
|
||||
const gchar *val = gst_sdp_media_get_attribute_val (media, name); \
|
||||
if (val && !strncmp (val, "string;\"", 8)) { \
|
||||
dest = (gchar *) val + 8; \
|
||||
dest_len = strlen (dest) - 1; \
|
||||
dest[dest_len] = '\0'; \
|
||||
} else { \
|
||||
dest = (char *) ""; \
|
||||
dest_len = 0; \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define WRITE_STRING1(datap, str, str_len) \
|
||||
G_STMT_START { \
|
||||
*datap = str_len; \
|
||||
memcpy ((datap) + 1, str, str_len); \
|
||||
datap += str_len + 1; \
|
||||
} G_STMT_END
|
||||
|
||||
#define WRITE_STRING2(datap, str, str_len) \
|
||||
G_STMT_START { \
|
||||
GST_WRITE_UINT16_BE (datap, str_len); \
|
||||
memcpy (datap + 2, str, str_len); \
|
||||
datap += str_len + 2; \
|
||||
} G_STMT_END
|
||||
|
||||
static GstRTSPResult
|
||||
rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
||||
GstStructure * props)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
guint size;
|
||||
gint i;
|
||||
gchar *title, *author, *copyright, *comment;
|
||||
gsize title_len, author_len, copyright_len, comment_len;
|
||||
guint8 *data = NULL, *datap;
|
||||
guint data_len = 0, offset;
|
||||
GstBuffer *buf;
|
||||
gchar *opaque_data;
|
||||
gsize opaque_data_len, asm_rule_book_len;
|
||||
GHashTable *vars;
|
||||
GString *rules;
|
||||
|
||||
/* don't bother for non-real formats */
|
||||
READ_INT (sdp, "IsRealDataType", ctx->isreal);
|
||||
if (!ctx->isreal)
|
||||
return TRUE;
|
||||
|
||||
/* Force PAUSE | PLAY */
|
||||
//src->methods |= GST_RTSP_PLAY | GST_RTSP_PAUSE;
|
||||
|
||||
ctx->n_streams = gst_sdp_message_medias_len (sdp);
|
||||
|
||||
ctx->max_bit_rate = 0;
|
||||
ctx->avg_bit_rate = 0;
|
||||
ctx->max_packet_size = 0;
|
||||
ctx->avg_packet_size = 0;
|
||||
ctx->duration = 0;
|
||||
|
||||
for (i = 0; i < ctx->n_streams; i++) {
|
||||
const GstSDPMedia *media;
|
||||
gint intval;
|
||||
|
||||
media = gst_sdp_message_get_media (sdp, i);
|
||||
|
||||
READ_INT_M (media, "MaxBitRate", intval);
|
||||
ctx->max_bit_rate += intval;
|
||||
READ_INT_M (media, "AvgBitRate", intval);
|
||||
ctx->avg_bit_rate += intval;
|
||||
READ_INT_M (media, "MaxPacketSize", intval);
|
||||
ctx->max_packet_size = MAX (ctx->max_packet_size, intval);
|
||||
READ_INT_M (media, "AvgPacketSize", intval);
|
||||
ctx->avg_packet_size = (ctx->avg_packet_size * i + intval) / (i + 1);
|
||||
READ_INT_M (media, "Duration", intval);
|
||||
ctx->duration = MAX (ctx->duration, intval);
|
||||
}
|
||||
|
||||
/* FIXME: use GstByteWriter to write the header */
|
||||
/* PROP */
|
||||
offset = 0;
|
||||
size = 50;
|
||||
ENSURE_SIZE (size);
|
||||
datap = data + offset;
|
||||
|
||||
memcpy (datap + 0, "PROP", 4);
|
||||
GST_WRITE_UINT32_BE (datap + 4, size);
|
||||
GST_WRITE_UINT16_BE (datap + 8, 0);
|
||||
GST_WRITE_UINT32_BE (datap + 10, ctx->max_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 14, ctx->avg_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 18, ctx->max_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 22, ctx->avg_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 26, 0);
|
||||
GST_WRITE_UINT32_BE (datap + 30, ctx->duration);
|
||||
GST_WRITE_UINT32_BE (datap + 34, 0);
|
||||
GST_WRITE_UINT32_BE (datap + 38, 0);
|
||||
GST_WRITE_UINT32_BE (datap + 42, 0);
|
||||
GST_WRITE_UINT16_BE (datap + 46, ctx->n_streams);
|
||||
GST_WRITE_UINT16_BE (datap + 48, 0);
|
||||
offset += size;
|
||||
|
||||
/* CONT */
|
||||
READ_BUFFER (sdp, "Title", title, title_len);
|
||||
READ_BUFFER (sdp, "Author", author, author_len);
|
||||
READ_BUFFER (sdp, "Comment", comment, comment_len);
|
||||
READ_BUFFER (sdp, "Copyright", copyright, copyright_len);
|
||||
|
||||
size = 18 + title_len + author_len + comment_len + copyright_len;
|
||||
ENSURE_SIZE (offset + size);
|
||||
datap = data + offset;
|
||||
|
||||
memcpy (datap, "CONT", 4);
|
||||
GST_WRITE_UINT32_BE (datap + 4, size);
|
||||
GST_WRITE_UINT16_BE (datap + 8, 0); /* Version */
|
||||
datap += 10;
|
||||
WRITE_STRING2 (datap, title, title_len);
|
||||
WRITE_STRING2 (datap, author, author_len);
|
||||
WRITE_STRING2 (datap, copyright, copyright_len);
|
||||
WRITE_STRING2 (datap, comment, comment_len);
|
||||
offset += size;
|
||||
|
||||
/* fix the hashtale for the rule parser */
|
||||
rules = g_string_new ("");
|
||||
vars = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (vars, (gchar *) "Bandwidth",
|
||||
(gchar *) DEFAULT_BANDWIDTH);
|
||||
|
||||
/* MDPR */
|
||||
for (i = 0; i < ctx->n_streams; i++) {
|
||||
const GstSDPMedia *media;
|
||||
guint32 len;
|
||||
GstRTSPRealStream *stream;
|
||||
gchar *str;
|
||||
gint rulematches[MAX_RULEMATCHES];
|
||||
gint sel, j, n;
|
||||
|
||||
media = gst_sdp_message_get_media (sdp, i);
|
||||
|
||||
if (media->media && !strcmp (media->media, "data"))
|
||||
continue;
|
||||
|
||||
stream = g_new0 (GstRTSPRealStream, 1);
|
||||
ctx->streams = g_list_append (ctx->streams, stream);
|
||||
|
||||
READ_INT_M (media, "MaxBitRate", stream->max_bit_rate);
|
||||
READ_INT_M (media, "AvgBitRate", stream->avg_bit_rate);
|
||||
READ_INT_M (media, "MaxPacketSize", stream->max_packet_size);
|
||||
READ_INT_M (media, "AvgPacketSize", stream->avg_packet_size);
|
||||
READ_INT_M (media, "StartTime", stream->start_time);
|
||||
READ_INT_M (media, "Preroll", stream->preroll);
|
||||
READ_INT_M (media, "Duration", stream->duration);
|
||||
READ_STRING (media, "StreamName", str, stream->stream_name_len);
|
||||
stream->stream_name = g_strndup (str, stream->stream_name_len);
|
||||
READ_STRING (media, "mimetype", str, stream->mime_type_len);
|
||||
stream->mime_type = g_strndup (str, stream->mime_type_len);
|
||||
|
||||
/* FIXME: Depending on the current bandwidth, we need to select one
|
||||
* bandwidth out of a list offered by the server. Someone needs to write
|
||||
* a parser for strings like
|
||||
*
|
||||
* #($Bandwidth < 67959),TimestampDelivery=T,DropByN=T,priority=9;
|
||||
* #($Bandwidth >= 67959) && ($Bandwidth < 167959),AverageBandwidth=67959,
|
||||
* Priority=9;#($Bandwidth >= 67959) && ($Bandwidth < 167959),
|
||||
* AverageBandwidth=0,Priority=5,OnDepend=\"1\";
|
||||
* #($Bandwidth >= 167959) && ($Bandwidth < 267959),
|
||||
* AverageBandwidth=167959,Priority=9;
|
||||
* #($Bandwidth >= 167959) && ($Bandwidth < 267959),AverageBandwidth=0,
|
||||
* Priority=5,OnDepend=\"3\";#($Bandwidth >= 267959),
|
||||
* AverageBandwidth=267959,Priority=9;#($Bandwidth >= 267959),
|
||||
* AverageBandwidth=0,Priority=5,OnDepend=\"5\";
|
||||
*
|
||||
* As I don't know how to do that, I just use the first entry (sel = 0).
|
||||
* But to give you a starting point, I offer you above string
|
||||
* in the variable 'asm_rule_book'.
|
||||
*/
|
||||
READ_STRING (media, "ASMRuleBook", str, asm_rule_book_len);
|
||||
stream->rulebook = gst_asm_rule_book_new (str);
|
||||
|
||||
n = gst_asm_rule_book_match (stream->rulebook, vars, rulematches);
|
||||
for (j = 0; j < n; j++) {
|
||||
g_string_append_printf (rules, "stream=%u;rule=%u,", i, rulematches[j]);
|
||||
}
|
||||
|
||||
/* get the MLTI for the first matched rules */
|
||||
sel = rulematches[0];
|
||||
|
||||
READ_BUFFER_M (media, "OpaqueData", opaque_data, opaque_data_len);
|
||||
|
||||
if (opaque_data_len < 4) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
if (strncmp (opaque_data, "MLTI", 4)) {
|
||||
GST_DEBUG_OBJECT (ctx, "no MLTI found, appending all");
|
||||
stream->type_specific_data_len = opaque_data_len;
|
||||
stream->type_specific_data = g_memdup2 (opaque_data, opaque_data_len);
|
||||
goto no_type_specific;
|
||||
}
|
||||
opaque_data += 4;
|
||||
opaque_data_len -= 4;
|
||||
|
||||
if (opaque_data_len < 2) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
stream->num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (sel >= stream->num_rules) {
|
||||
GST_DEBUG_OBJECT (ctx, "sel %d >= num_rules %d", sel, stream->num_rules);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
|
||||
if (opaque_data_len < 2 * sel) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT
|
||||
" < 2 * sel (%d)", opaque_data_len, 2 * sel);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
opaque_data += 2 * sel;
|
||||
opaque_data_len -= 2 * sel;
|
||||
|
||||
if (opaque_data_len < 2) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
stream->codec = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (opaque_data_len < 2 * (stream->num_rules - sel - 1)) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT
|
||||
" < %d", opaque_data_len, 2 * (stream->num_rules - sel - 1));
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
opaque_data += 2 * (stream->num_rules - sel - 1);
|
||||
opaque_data_len -= 2 * (stream->num_rules - sel - 1);
|
||||
|
||||
if (opaque_data_len < 2) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 2",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
stream->num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (stream->codec > stream->num_rules) {
|
||||
GST_DEBUG_OBJECT (ctx, "codec %d > num_rules %d", stream->codec,
|
||||
stream->num_rules);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
|
||||
for (j = 0; j < stream->codec; j++) {
|
||||
if (opaque_data_len < 4) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
len = GST_READ_UINT32_BE (opaque_data);
|
||||
opaque_data += 4;
|
||||
opaque_data_len -= 4;
|
||||
|
||||
if (opaque_data_len < len) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < len %d",
|
||||
opaque_data_len, len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
opaque_data += len;
|
||||
opaque_data_len -= len;
|
||||
}
|
||||
|
||||
if (opaque_data_len < 4) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < 4",
|
||||
opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
stream->type_specific_data_len = GST_READ_UINT32_BE (opaque_data);
|
||||
opaque_data += 4;
|
||||
opaque_data_len -= 4;
|
||||
|
||||
if (opaque_data_len < stream->type_specific_data_len) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %" G_GSIZE_FORMAT " < %d",
|
||||
opaque_data_len, stream->type_specific_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
stream->type_specific_data =
|
||||
g_memdup2 (opaque_data, stream->type_specific_data_len);
|
||||
|
||||
no_type_specific:
|
||||
size =
|
||||
46 + stream->stream_name_len + stream->mime_type_len +
|
||||
stream->type_specific_data_len;
|
||||
ENSURE_SIZE (offset + size);
|
||||
datap = data + offset;
|
||||
|
||||
memcpy (datap, "MDPR", 4);
|
||||
GST_WRITE_UINT32_BE (datap + 4, size);
|
||||
GST_WRITE_UINT16_BE (datap + 8, 0);
|
||||
GST_WRITE_UINT16_BE (datap + 10, i);
|
||||
GST_WRITE_UINT32_BE (datap + 12, stream->max_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 16, stream->avg_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 20, stream->max_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 24, stream->avg_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 28, stream->start_time);
|
||||
GST_WRITE_UINT32_BE (datap + 32, stream->preroll);
|
||||
GST_WRITE_UINT32_BE (datap + 36, stream->duration);
|
||||
datap += 40;
|
||||
WRITE_STRING1 (datap, stream->stream_name, stream->stream_name_len);
|
||||
WRITE_STRING1 (datap, stream->mime_type, stream->mime_type_len);
|
||||
GST_WRITE_UINT32_BE (datap, stream->type_specific_data_len);
|
||||
if (stream->type_specific_data_len)
|
||||
memcpy (datap + 4, stream->type_specific_data,
|
||||
stream->type_specific_data_len);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
/* destroy the rulebook hashtable now */
|
||||
g_hash_table_destroy (vars);
|
||||
|
||||
/* strip final , if we added some stream rules */
|
||||
if (rules->len > 0) {
|
||||
rules = g_string_truncate (rules, rules->len - 1);
|
||||
}
|
||||
|
||||
/* and store rules in the context */
|
||||
ctx->rules = g_string_free (rules, FALSE);
|
||||
|
||||
/* DATA */
|
||||
size = 18;
|
||||
ENSURE_SIZE (offset + size);
|
||||
datap = data + offset;
|
||||
|
||||
memcpy (datap, "DATA", 4);
|
||||
GST_WRITE_UINT32_BE (datap + 4, size);
|
||||
GST_WRITE_UINT16_BE (datap + 8, 0);
|
||||
GST_WRITE_UINT32_BE (datap + 10, 0); /* number of packets */
|
||||
GST_WRITE_UINT32_BE (datap + 14, 0); /* next data header */
|
||||
offset += size;
|
||||
|
||||
buf = gst_buffer_new_wrapped (data, offset);
|
||||
|
||||
/* Set on caps */
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
|
||||
gst_structure_set (props, "config", GST_TYPE_BUFFER, buf, NULL);
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
/* Overwrite encoding and media fields */
|
||||
gst_structure_set (props, "encoding-name", G_TYPE_STRING, "X-REAL-RDT", NULL);
|
||||
gst_structure_set (props, "media", G_TYPE_STRING, "application", NULL);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
strange_opaque_data:
|
||||
{
|
||||
g_string_free (rules, TRUE);
|
||||
g_hash_table_destroy (vars);
|
||||
g_free (data);
|
||||
|
||||
GST_ELEMENT_ERROR (ctx, RESOURCE, WRITE, ("Strange opaque data."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstRTSPResult
|
||||
rtsp_ext_real_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
GstRTSPResult res;
|
||||
GstRTSPMessage request = { 0 };
|
||||
GstRTSPMessage response = { 0 };
|
||||
gchar *req_url;
|
||||
|
||||
if (!ctx->isreal)
|
||||
return GST_RTSP_OK;
|
||||
|
||||
if (!ctx->rules)
|
||||
return GST_RTSP_OK;
|
||||
|
||||
req_url = gst_rtsp_url_get_request_uri (url);
|
||||
|
||||
/* create SET_PARAMETER */
|
||||
if ((res = gst_rtsp_message_init_request (&request, GST_RTSP_SET_PARAMETER,
|
||||
req_url)) < 0)
|
||||
goto create_request_failed;
|
||||
|
||||
g_free (req_url);
|
||||
|
||||
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SUBSCRIBE, ctx->rules);
|
||||
|
||||
/* send SET_PARAMETER */
|
||||
if ((res = gst_rtsp_extension_send (ext, &request, &response)) < 0)
|
||||
goto send_error;
|
||||
|
||||
gst_rtsp_message_unset (&request);
|
||||
gst_rtsp_message_unset (&response);
|
||||
|
||||
return GST_RTSP_OK;
|
||||
|
||||
/* ERRORS */
|
||||
create_request_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (ctx, LIBRARY, INIT,
|
||||
("Could not create request."), (NULL));
|
||||
g_free (req_url);
|
||||
goto reset;
|
||||
}
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (ctx, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
goto reset;
|
||||
}
|
||||
reset:
|
||||
{
|
||||
gst_rtsp_message_unset (&request);
|
||||
gst_rtsp_message_unset (&response);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static void gst_rtsp_real_extension_init (gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
static void gst_rtsp_real_finalize (GObject * obj);
|
||||
|
||||
#define gst_rtsp_real_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstRTSPReal, gst_rtsp_real, GST_TYPE_ELEMENT,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_RTSP_EXTENSION,
|
||||
gst_rtsp_real_extension_init));
|
||||
GST_ELEMENT_REGISTER_DEFINE (rtspreal, "rtspreal",
|
||||
GST_RANK_MARGINAL, GST_TYPE_RTSP_REAL);
|
||||
|
||||
static void
|
||||
gst_rtsp_real_class_init (GstRTSPRealClass * g_class)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) g_class;
|
||||
GstElementClass *gstelement_class = (GstElementClass *) g_class;
|
||||
|
||||
gobject_class->finalize = gst_rtsp_real_finalize;
|
||||
|
||||
gst_element_class_set_static_metadata (gstelement_class,
|
||||
"RealMedia RTSP Extension", "Network/Extension/Protocol",
|
||||
"Extends RTSP so that it can handle RealMedia setup",
|
||||
"Wim Taymans <wim.taymans@gmail.com>");
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtspreal_debug, "rtspreal", 0,
|
||||
"RealMedia RTSP extension");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_real_init (GstRTSPReal * rtspreal)
|
||||
{
|
||||
rtspreal->isreal = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_stream_free (GstRTSPRealStream * stream)
|
||||
{
|
||||
g_free (stream->stream_name);
|
||||
g_free (stream->mime_type);
|
||||
gst_asm_rule_book_free (stream->rulebook);
|
||||
g_free (stream->type_specific_data);
|
||||
|
||||
g_free (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_real_finalize (GObject * obj)
|
||||
{
|
||||
GstRTSPReal *r = (GstRTSPReal *) obj;
|
||||
|
||||
g_list_foreach (r->streams, (GFunc) gst_rtsp_stream_free, NULL);
|
||||
g_list_free (r->streams);
|
||||
g_free (r->rules);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_real_extension_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstRTSPExtensionInterface *iface = (GstRTSPExtensionInterface *) g_iface;
|
||||
|
||||
iface->before_send = rtsp_ext_real_before_send;
|
||||
iface->after_send = rtsp_ext_real_after_send;
|
||||
iface->parse_sdp = rtsp_ext_real_parse_sdp;
|
||||
iface->stream_select = rtsp_ext_real_stream_select;
|
||||
iface->get_transports = rtsp_ext_real_get_transports;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RTSP_REAL_H__
|
||||
#define __GST_RTSP_REAL_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "asmrules.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_RTSP_REAL (gst_rtsp_real_get_type())
|
||||
#define GST_IS_RTSP_REAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSP_REAL))
|
||||
#define GST_IS_RTSP_REAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSP_REAL))
|
||||
#define GST_RTSP_REAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSP_REAL, GstRTSPReal))
|
||||
#define GST_RTSP_REAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSP_REAL, GstRTSPRealClass))
|
||||
|
||||
typedef struct _GstRTSPReal GstRTSPReal;
|
||||
typedef struct _GstRTSPRealClass GstRTSPRealClass;
|
||||
|
||||
typedef struct _GstRTSPRealStream GstRTSPRealStream;
|
||||
|
||||
struct _GstRTSPRealStream {
|
||||
guint id;
|
||||
guint max_bit_rate;
|
||||
guint avg_bit_rate;
|
||||
guint max_packet_size;
|
||||
guint avg_packet_size;
|
||||
guint start_time;
|
||||
guint preroll;
|
||||
guint duration;
|
||||
gchar *stream_name;
|
||||
guint stream_name_len;
|
||||
gchar *mime_type;
|
||||
guint mime_type_len;
|
||||
|
||||
GstASMRuleBook *rulebook;
|
||||
|
||||
gchar *type_specific_data;
|
||||
guint type_specific_data_len;
|
||||
|
||||
guint16 num_rules, j, sel, codec;
|
||||
};
|
||||
|
||||
struct _GstRTSPReal {
|
||||
GstElement element;
|
||||
|
||||
gchar checksum[34];
|
||||
gchar challenge2[64];
|
||||
gchar etag[64];
|
||||
gboolean isreal;
|
||||
|
||||
guint n_streams;
|
||||
GList *streams;
|
||||
|
||||
guint max_bit_rate;
|
||||
guint avg_bit_rate;
|
||||
guint max_packet_size;
|
||||
guint avg_packet_size;
|
||||
guint duration;
|
||||
|
||||
gchar *rules;
|
||||
};
|
||||
|
||||
struct _GstRTSPRealClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_rtsp_real_get_type(void);
|
||||
|
||||
GST_ELEMENT_REGISTER_DECLARE (rtspreal);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RTSP_REAL_H__ */
|
Loading…
Reference in a new issue