mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-11 02:24:13 +00:00
gst/realmedia/.cvsignore: Add test to ignore.
Original commit message from CVS: * gst/realmedia/.cvsignore: Add test to ignore. * gst/realmedia/Makefile.am: * gst/realmedia/asmrules.c: (gst_asm_node_new), (gst_asm_node_free), (gst_asm_operator_eval), (gst_asm_node_evaluate), (gst_asm_scan_new), (gst_asm_scan_free), (gst_asm_scan_string), (gst_asm_scan_number), (gst_asm_scan_identifier), (gst_asm_scan_print_token), (gst_asm_scan_next_token), (gst_asm_rule_new), (gst_asm_rule_free), (gst_asm_rule_add_property), (gst_asm_scan_parse_operand), (gst_asm_scan_parse_expression), (gst_asm_scan_parse_condition), (gst_asm_scan_parse_property), (gst_asm_scan_parse_rule), (gst_asm_rule_evaluate), (gst_asm_rule_book_new), (gst_asm_rule_book_n_rules), (gst_asm_rule_book_free), (gst_asm_rule_book_match), (main): * gst/realmedia/asmrules.h: Added asembler rule book parser and evaluator. * gst/realmedia/rtspreal.c: (rtsp_ext_real_parse_sdp), (rtsp_ext_real_stream_select), (gst_rtsp_real_plugin_init): * gst/realmedia/rtspreal.h: Keep per stream config info. Parse and evaluate asm rule books for stream selection.
This commit is contained in:
parent
5ef116fd1f
commit
04424d07ef
7 changed files with 1008 additions and 79 deletions
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
2007-08-02 Wim Taymans <wim.taymans@gmail.com>
|
||||
|
||||
* gst/realmedia/.cvsignore:
|
||||
Add test to ignore.
|
||||
|
||||
* gst/realmedia/Makefile.am:
|
||||
* gst/realmedia/asmrules.c: (gst_asm_node_new),
|
||||
(gst_asm_node_free), (gst_asm_operator_eval),
|
||||
(gst_asm_node_evaluate), (gst_asm_scan_new), (gst_asm_scan_free),
|
||||
(gst_asm_scan_string), (gst_asm_scan_number),
|
||||
(gst_asm_scan_identifier), (gst_asm_scan_print_token),
|
||||
(gst_asm_scan_next_token), (gst_asm_rule_new), (gst_asm_rule_free),
|
||||
(gst_asm_rule_add_property), (gst_asm_scan_parse_operand),
|
||||
(gst_asm_scan_parse_expression), (gst_asm_scan_parse_condition),
|
||||
(gst_asm_scan_parse_property), (gst_asm_scan_parse_rule),
|
||||
(gst_asm_rule_evaluate), (gst_asm_rule_book_new),
|
||||
(gst_asm_rule_book_n_rules), (gst_asm_rule_book_free),
|
||||
(gst_asm_rule_book_match), (main):
|
||||
* gst/realmedia/asmrules.h:
|
||||
Added asembler rule book parser and evaluator.
|
||||
|
||||
* gst/realmedia/rtspreal.c: (rtsp_ext_real_parse_sdp),
|
||||
(rtsp_ext_real_stream_select), (gst_rtsp_real_plugin_init):
|
||||
* gst/realmedia/rtspreal.h:
|
||||
Keep per stream config info.
|
||||
Parse and evaluate asm rule books for stream selection.
|
||||
|
||||
2007-07-31 Stefan Kost <ensonic@users.sf.net>
|
||||
|
||||
* gst/realmedia/rtspreal.c:
|
||||
|
|
1
gst/realmedia/.gitignore
vendored
Normal file
1
gst/realmedia/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
asmrules
|
|
@ -1,10 +1,17 @@
|
|||
plugin_LTLIBRARIES = libgstrmdemux.la
|
||||
|
||||
libgstrmdemux_la_SOURCES = rademux.c rmdemux.c rmutils.c rdtdepay.c rtspreal.c realhash.c
|
||||
libgstrmdemux_la_SOURCES = rademux.c rmdemux.c \
|
||||
rmutils.c rdtdepay.c \
|
||||
rtspreal.c realhash.c asmrules.c
|
||||
|
||||
libgstrmdemux_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
|
||||
libgstrmdemux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)\
|
||||
-lgstrtsp-@GST_MAJORMINOR@ -lgstsdp-@GST_MAJORMINOR@
|
||||
libgstrmdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rtspreal.h realhash.h
|
||||
noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rtspreal.h realhash.h asmrules.h
|
||||
|
||||
noinst_PROGRAMS = asmrules
|
||||
asmrules_CFLAGS = $(GST_CFLAGS) -DTEST
|
||||
asmrules_LDADD = $(GST_LIBS) $(LIBM)
|
||||
|
||||
|
|
702
gst/realmedia/asmrules.c
Normal file
702
gst/realmedia/asmrules.c
Normal file
|
@ -0,0 +1,702 @@
|
|||
/* 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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <string.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) == ';'))
|
||||
#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);
|
||||
}
|
||||
scan->val[i] = '\0';
|
||||
|
||||
if (ch == delim)
|
||||
ch = 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_unref (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 = 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 = 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");
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
gint
|
||||
gst_asm_rule_book_n_rules (GstASMRuleBook * book)
|
||||
{
|
||||
return book->n_rules;
|
||||
}
|
||||
|
||||
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\\\";";
|
||||
|
||||
vars = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (vars, "Bandwidth", "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_hash_table_unref (vars);
|
||||
|
||||
g_print ("%d rules matched\n", n);
|
||||
for (i = 0; i < n; i++) {
|
||||
g_print ("rule %d matched\n", rulematch[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
115
gst/realmedia/asmrules.h
Normal file
115
gst/realmedia/asmrules.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* 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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, 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__ */
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include "realhash.h"
|
||||
#include "rtspreal.h"
|
||||
#include "asmrules.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rtspreal_debug);
|
||||
#define GST_CAT_DEFAULT (rtspreal_debug)
|
||||
|
@ -256,18 +257,15 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
GstStructure * props)
|
||||
{
|
||||
GstRTSPReal *ctx = (GstRTSPReal *) ext;
|
||||
guint size, n_streams;
|
||||
guint size;
|
||||
gint i;
|
||||
guint32 max_bit_rate = 0, avg_bit_rate = 0;
|
||||
guint32 max_packet_size = 0, avg_packet_size = 0;
|
||||
guint32 start_time, preroll, duration = 0;
|
||||
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;
|
||||
gsize opaque_data_len, asm_rule_book_len;
|
||||
|
||||
/* don't bother for non-real formats */
|
||||
READ_INT (sdp, "IsRealDataType", ctx->isreal);
|
||||
|
@ -277,25 +275,33 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
/* Force PAUSE | PLAY */
|
||||
//src->methods |= GST_RTSP_PLAY | GST_RTSP_PAUSE;
|
||||
|
||||
n_streams = gst_sdp_message_medias_len (sdp);
|
||||
ctx->n_streams = gst_sdp_message_medias_len (sdp);
|
||||
|
||||
/* PROP */
|
||||
for (i = 0; i < n_streams; i++) {
|
||||
const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i);
|
||||
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);
|
||||
max_bit_rate += intval;
|
||||
ctx->max_bit_rate += intval;
|
||||
READ_INT_M (media, "AvgBitRate", intval);
|
||||
avg_bit_rate += intval;
|
||||
ctx->avg_bit_rate += intval;
|
||||
READ_INT_M (media, "MaxPacketSize", intval);
|
||||
max_packet_size = MAX (max_packet_size, intval);
|
||||
ctx->max_packet_size = MAX (ctx->max_packet_size, intval);
|
||||
READ_INT_M (media, "AvgPacketSize", intval);
|
||||
avg_packet_size = (avg_packet_size * i + intval) / (i + 1);
|
||||
ctx->avg_packet_size = (ctx->avg_packet_size * i + intval) / (i + 1);
|
||||
READ_INT_M (media, "Duration", intval);
|
||||
duration = MAX (duration, intval);
|
||||
ctx->duration = MAX (ctx->duration, intval);
|
||||
}
|
||||
|
||||
/* PROP */
|
||||
offset = 0;
|
||||
size = 50;
|
||||
ENSURE_SIZE (size);
|
||||
|
@ -304,16 +310,16 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
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, max_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 14, avg_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 18, max_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 22, avg_packet_size);
|
||||
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, duration);
|
||||
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, n_streams);
|
||||
GST_WRITE_UINT16_BE (datap + 46, ctx->n_streams);
|
||||
GST_WRITE_UINT16_BE (datap + 48, 0);
|
||||
offset += size;
|
||||
|
||||
|
@ -337,24 +343,29 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
offset += size;
|
||||
|
||||
/* MDPR */
|
||||
for (i = 0; i < n_streams; i++) {
|
||||
const GstSDPMedia *media = gst_sdp_message_get_media (sdp, i);
|
||||
gchar *asm_rule_book, *type_specific_data;
|
||||
guint asm_rule_book_len;
|
||||
gchar *stream_name, *mime_type;
|
||||
guint stream_name_len, mime_type_len;
|
||||
guint16 num_rules, j, sel, codec;
|
||||
guint32 type_specific_data_len, len;
|
||||
for (i = 0; i < ctx->n_streams; i++) {
|
||||
const GstSDPMedia *media;
|
||||
guint16 j, sel;
|
||||
guint32 len;
|
||||
GstRTSPRealStream *stream;
|
||||
gchar *str;
|
||||
|
||||
READ_INT_M (media, "MaxBitRate", max_bit_rate);
|
||||
READ_INT_M (media, "AvgBitRate", avg_bit_rate);
|
||||
READ_INT_M (media, "MaxPacketSize", max_packet_size);
|
||||
READ_INT_M (media, "AvgPacketSize", avg_packet_size);
|
||||
READ_INT_M (media, "StartTime", start_time);
|
||||
READ_INT_M (media, "Preroll", preroll);
|
||||
READ_INT_M (media, "Duration", duration);
|
||||
READ_STRING (media, "StreamName", stream_name, stream_name_len);
|
||||
READ_STRING (media, "mimetype", mime_type, mime_type_len);
|
||||
media = gst_sdp_message_get_media (sdp, i);
|
||||
|
||||
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
|
||||
* bandwith out of a list offered by the server. Someone needs to write
|
||||
|
@ -375,7 +386,8 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
* But to give you a starting point, I offer you above string
|
||||
* in the variable 'asm_rule_book'.
|
||||
*/
|
||||
READ_STRING (media, "ASMRuleBook", asm_rule_book, asm_rule_book_len);
|
||||
READ_STRING (media, "ASMRuleBook", str, asm_rule_book_len);
|
||||
stream->rulebook = gst_asm_rule_book_new (str);
|
||||
sel = 0;
|
||||
|
||||
READ_BUFFER_M (media, "OpaqueData", opaque_data, opaque_data_len);
|
||||
|
@ -386,8 +398,8 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
}
|
||||
if (strncmp (opaque_data, "MLTI", 4)) {
|
||||
GST_DEBUG_OBJECT (ctx, "no MLTI found, appending all");
|
||||
type_specific_data_len = opaque_data_len;
|
||||
type_specific_data = opaque_data;
|
||||
stream->type_specific_data_len = opaque_data_len;
|
||||
stream->type_specific_data = g_memdup (opaque_data, opaque_data_len);
|
||||
goto no_type_specific;
|
||||
}
|
||||
opaque_data += 4;
|
||||
|
@ -397,12 +409,12 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < 2", opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
stream->num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (sel >= num_rules) {
|
||||
GST_DEBUG_OBJECT (ctx, "sel %d >= num_rules %d", sel, num_rules);
|
||||
if (sel >= stream->num_rules) {
|
||||
GST_DEBUG_OBJECT (ctx, "sel %d >= num_rules %d", sel, stream->num_rules);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
|
||||
|
@ -418,32 +430,33 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < 2", opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
codec = GST_READ_UINT16_BE (opaque_data);
|
||||
stream->codec = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (opaque_data_len < 2 * (num_rules - sel - 1)) {
|
||||
if (opaque_data_len < 2 * (stream->num_rules - sel - 1)) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < %d", opaque_data_len,
|
||||
2 * (num_rules - sel - 1));
|
||||
2 * (stream->num_rules - sel - 1));
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
opaque_data += 2 * (num_rules - sel - 1);
|
||||
opaque_data_len -= 2 * (num_rules - sel - 1);
|
||||
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 %d < 2", opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
stream->num_rules = GST_READ_UINT16_BE (opaque_data);
|
||||
opaque_data += 2;
|
||||
opaque_data_len -= 2;
|
||||
|
||||
if (codec > num_rules) {
|
||||
GST_DEBUG_OBJECT (ctx, "codec %d > num_rules %d", codec, num_rules);
|
||||
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 < codec; j++) {
|
||||
for (j = 0; j < stream->codec; j++) {
|
||||
if (opaque_data_len < 4) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < 4", opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
|
@ -465,19 +478,22 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < 4", opaque_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
type_specific_data_len = GST_READ_UINT32_BE (opaque_data);
|
||||
stream->type_specific_data_len = GST_READ_UINT32_BE (opaque_data);
|
||||
opaque_data += 4;
|
||||
opaque_data_len -= 4;
|
||||
|
||||
if (opaque_data_len < type_specific_data_len) {
|
||||
if (opaque_data_len < stream->type_specific_data_len) {
|
||||
GST_DEBUG_OBJECT (ctx, "opaque_data_len %d < %d", opaque_data_len,
|
||||
type_specific_data_len);
|
||||
stream->type_specific_data_len);
|
||||
goto strange_opaque_data;
|
||||
}
|
||||
type_specific_data = opaque_data;
|
||||
stream->type_specific_data =
|
||||
g_memdup (opaque_data, stream->type_specific_data_len);
|
||||
|
||||
no_type_specific:
|
||||
size = 46 + stream_name_len + mime_type_len + type_specific_data_len;
|
||||
size =
|
||||
46 + stream->stream_name_len + stream->mime_type_len +
|
||||
stream->type_specific_data_len;
|
||||
ENSURE_SIZE (offset + size);
|
||||
datap = data + offset;
|
||||
|
||||
|
@ -485,19 +501,20 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
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, max_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 16, avg_bit_rate);
|
||||
GST_WRITE_UINT32_BE (datap + 20, max_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 24, avg_packet_size);
|
||||
GST_WRITE_UINT32_BE (datap + 28, start_time);
|
||||
GST_WRITE_UINT32_BE (datap + 32, preroll);
|
||||
GST_WRITE_UINT32_BE (datap + 36, duration);
|
||||
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_name, stream_name_len);
|
||||
WRITE_STRING1 (datap, mime_type, mime_type_len);
|
||||
GST_WRITE_UINT32_BE (datap, type_specific_data_len);
|
||||
if (type_specific_data_len)
|
||||
memcpy (datap + 4, type_specific_data, type_specific_data_len);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -522,7 +539,7 @@ rtsp_ext_real_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
|
|||
gst_structure_set (props, "config", GST_TYPE_BUFFER, buf, NULL);
|
||||
|
||||
/* Overwrite encoding and media fields */
|
||||
gst_structure_set (props, "encoding-name", G_TYPE_STRING, "x-real-rdt", NULL);
|
||||
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;
|
||||
|
@ -543,6 +560,10 @@ rtsp_ext_real_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
|
|||
GstRTSPMessage request = { 0 };
|
||||
GstRTSPMessage response = { 0 };
|
||||
gchar *req_url;
|
||||
GString *rules;
|
||||
GList *walk;
|
||||
gint i;
|
||||
GHashTable *vars;
|
||||
|
||||
if (!ctx->isreal)
|
||||
return GST_RTSP_OK;
|
||||
|
@ -556,13 +577,34 @@ rtsp_ext_real_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
|
|||
|
||||
g_free (req_url);
|
||||
|
||||
/* FIXME, do selection instead of hardcoded values */
|
||||
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SUBSCRIBE,
|
||||
//"stream=0;rule=5,stream=0;rule=6,stream=1;rule=0,stream=1;rule=1");
|
||||
//"stream=0;rule=0,stream=0;rule=1,stream=1;rule=0,stream=1;rule=1");
|
||||
//"stream=0;rule=5,stream=0;rule=6,stream=1;rule=2,stream=1;rule=3");
|
||||
"stream=0;rule=5,stream=0;rule=6,stream=1;rule=0,stream=1;rule=1");
|
||||
//"stream=0;rule=0,stream=0;rule=1");
|
||||
rules = g_string_new ("");
|
||||
vars = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
g_hash_table_insert (vars, "Bandwidth", "300000");
|
||||
|
||||
for (walk = ctx->streams, i = 0; walk; walk = g_list_next (walk), i++) {
|
||||
GstRTSPRealStream *stream;
|
||||
gint rulematches[MAX_RULEMATCHES];
|
||||
gint j, n;
|
||||
|
||||
stream = (GstRTSPRealStream *) walk->data;
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_unref (vars);
|
||||
|
||||
/* strip final , if we added some stream rules */
|
||||
if (rules->len > 0) {
|
||||
rules = g_string_truncate (rules, rules->len - 1);
|
||||
}
|
||||
|
||||
/* do selection */
|
||||
gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SUBSCRIBE, rules->str);
|
||||
|
||||
g_string_free (rules, TRUE);
|
||||
|
||||
/* send SET_PARAMETER */
|
||||
if ((res = gst_rtsp_extension_send (ext, &request, &response)) < 0)
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "asmrules.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_RTSP_REAL (gst_rtsp_real_get_type())
|
||||
|
@ -33,12 +35,45 @@ G_BEGIN_DECLS
|
|||
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];
|
||||
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;
|
||||
};
|
||||
|
||||
struct _GstRTSPRealClass {
|
||||
|
|
Loading…
Reference in a new issue