Mercurial > mplayer.hg
changeset 9922:6cb7a295ab0e
Real rstp:// streaming support, ported from xine
author | rtognimp |
---|---|
date | Thu, 17 Apr 2003 20:39:41 +0000 |
parents | 61057de81510 |
children | 9eb5d5bd9aaa |
files | libmpdemux/Makefile libmpdemux/network.c libmpdemux/realrtsp/asmrp.c libmpdemux/realrtsp/asmrp.h libmpdemux/realrtsp/real.c libmpdemux/realrtsp/real.h libmpdemux/realrtsp/rmff.c libmpdemux/realrtsp/rmff.h libmpdemux/realrtsp/rtsp.c libmpdemux/realrtsp/rtsp.h libmpdemux/realrtsp/rtsp_session.c libmpdemux/realrtsp/rtsp_session.h libmpdemux/realrtsp/sdpplin.c libmpdemux/realrtsp/sdpplin.h libmpdemux/realrtsp/xbuffer.c libmpdemux/realrtsp/xbuffer.h |
diffstat | 16 files changed, 4377 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdemux/Makefile Thu Apr 17 19:32:46 2003 +0000 +++ b/libmpdemux/Makefile Thu Apr 17 20:39:41 2003 +0000 @@ -4,6 +4,7 @@ include ../config.mak SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c +SRCS += realrtsp/asmrp.c realrtsp/real.c realrtsp/rmff.c realrtsp/rtsp.c realrtsp/rtsp_session.c realrtsp/sdpplin.c realrtsp/xbuffer.c ifeq ($(XMMS_PLUGINS),yes) SRCS += demux_xmms.c endif
--- a/libmpdemux/network.c Thu Apr 17 19:32:46 2003 +0000 +++ b/libmpdemux/network.c Thu Apr 17 20:39:41 2003 +0000 @@ -28,6 +28,7 @@ #include "rtp.h" #endif #include "pnm.h" +#include "realrtsp/rtsp_session.h" #include "../version.h" @@ -582,6 +583,20 @@ // Checking for RTSP if( !strcasecmp(url->protocol, "rtsp") ) { + // Checking for Real rtsp:// + // Extension based detection, should be replaced with something based on server answer + extension = NULL; + if( url->file!=NULL ) + for( i=strlen(url->file) ; i>0 ; i-- ) + if( url->file[i]=='.' ) { + extension=(url->file)+i+1; + break; + } + if (!strcasecmp(extension, "rm")) { + *file_format = DEMUXER_TYPE_REAL; + return 0; + } + mp_msg(MSGT_NETWORK,MSGL_INFO,"Not a Realmedia rtsp url. Trying standard rtsp protocol.\n"); #ifdef STREAMING_LIVE_DOT_COM *file_format = DEMUXER_TYPE_RTP; return 0; @@ -864,6 +879,48 @@ } +int +realrtsp_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { + return rtsp_session_read(stream_ctrl->data, buffer, size); +} + + +int +realrtsp_streaming_start( stream_t *stream ) { + int fd; + rtsp_session_t *rtsp; + char *mrl; + int port; + char aport[10]; + if( stream==NULL ) return -1; + + fd = connect2Server( stream->streaming_ctrl->url->hostname, + port = (stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 554) ); + printf("rtsp:// fd=%d\n",fd); + if(fd<0) return -1; + + sprintf(aport,"%d",port); + mrl = (char *)malloc(strlen(stream->streaming_ctrl->url->url)+1+10+1); + strcpy(mrl,stream->streaming_ctrl->url->url); + strcat(mrl,":"); + strcat(mrl,aport); + rtsp = rtsp_session_start(fd,mrl, stream->streaming_ctrl->url->file, + stream->streaming_ctrl->url->hostname, port); + free(mrl); + if(!rtsp) return -1; + + stream->fd=fd; + stream->streaming_ctrl->data=rtsp; + + stream->streaming_ctrl->streaming_read = realrtsp_streaming_read; +// stream->streaming_ctrl->streaming_seek = nop_streaming_seek; + stream->streaming_ctrl->prebuffer_size = 128*1024; // 8 KBytes + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + return 0; +} + + #ifndef STREAMING_LIVE_DOT_COM // Start listening on a UDP port. If multicast, join the group. int @@ -1008,6 +1065,12 @@ ret = pnm_streaming_start( stream ); } else + if( (!strcasecmp( stream->streaming_ctrl->url->protocol, "rtsp")) && + (*demuxer_type == DEMUXER_TYPE_REAL)) { + stream->fd = -1; + ret = realrtsp_streaming_start( stream ); + } else + // For connection-oriented streams, we can usually determine the streaming type. switch( *demuxer_type ) { case DEMUXER_TYPE_ASF:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/asmrp.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,670 @@ +/* + * This file was ported to MPlayer from xine CVS asmrp.c,v 1.2 2002/12/17 16:49:48 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * a parser for real's asm rules + * + * grammar for these rules: + * + + rule_book = { rule } + rule = ( '#' condition { ',' assignment } | [ assignment {',' assignment} ]) ';' + assignment = id '=' const + const = ( number | string ) + condition = comp_expr { ( '&&' | '||' ) comp_expr } + comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } + operand = ( '$' id | num | '(' condition ')' ) + + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* +#define LOG +*/ + +#define ASMRP_SYM_NONE 0 +#define ASMRP_SYM_EOF 1 + +#define ASMRP_SYM_NUM 2 +#define ASMRP_SYM_ID 3 +#define ASMRP_SYM_STRING 4 + +#define ASMRP_SYM_HASH 10 +#define ASMRP_SYM_SEMICOLON 11 +#define ASMRP_SYM_COMMA 12 +#define ASMRP_SYM_EQUALS 13 +#define ASMRP_SYM_AND 14 +#define ASMRP_SYM_OR 15 +#define ASMRP_SYM_LESS 16 +#define ASMRP_SYM_LEQ 17 +#define ASMRP_SYM_GEQ 18 +#define ASMRP_SYM_GREATER 19 +#define ASMRP_SYM_DOLLAR 20 +#define ASMRP_SYM_LPAREN 21 +#define ASMRP_SYM_RPAREN 22 + +#define ASMRP_MAX_ID 1024 + +#define ASMRP_MAX_SYMTAB 10 + +typedef struct { + char *id; + int v; +} asmrp_sym_t; + +typedef struct { + + /* public part */ + + int sym; + int num; + + char str[ASMRP_MAX_ID]; + + /* private part */ + + char *buf; + int pos; + char ch; + + asmrp_sym_t sym_tab[ASMRP_MAX_SYMTAB]; + int sym_tab_num; + +} asmrp_t; + +static asmrp_t *asmrp_new () { + + asmrp_t *p; + + p = malloc (sizeof (asmrp_t)); + + p->sym_tab_num = 0; + p->sym = ASMRP_SYM_NONE; + + return p; +} + +static void asmrp_dispose (asmrp_t *p) { + + int i; + + for (i=0; i<p->sym_tab_num; i++) + free (p->sym_tab[i].id); + + free (p); +} + +static void asmrp_getch (asmrp_t *p) { + p->ch = p->buf[p->pos]; + p->pos++; + +#ifdef LOG + printf ("%c\n", p->ch); +#endif + +} + +static void asmrp_init (asmrp_t *p, const char *str) { + + p->buf = strdup (str); + p->pos = 0; + + asmrp_getch (p); +} + +static void asmrp_number (asmrp_t *p) { + + int num; + + num = 0; + while ( (p->ch>='0') && (p->ch<='9') ) { + + num = num*10 + (p->ch - '0'); + + asmrp_getch (p); + } + + p->sym = ASMRP_SYM_NUM; + p->num = num; +} + +static void asmrp_string (asmrp_t *p) { + + int l; + + l = 0; + + while ( (p->ch!='"') && (p->ch>=32) ) { + + p->str[l] = p->ch; + + l++; + asmrp_getch (p); + } + p->str[l]=0; + + if (p->ch=='"') + asmrp_getch (p); + + p->sym = ASMRP_SYM_STRING; +} + +static void asmrp_identifier (asmrp_t *p) { + + int l; + + l = 0; + + while ( ((p->ch>='A') && (p->ch<='z')) + || ((p->ch>='0') && (p->ch<='9'))) { + + p->str[l] = p->ch; + + l++; + asmrp_getch (p); + } + p->str[l]=0; + + p->sym = ASMRP_SYM_ID; +} + +#ifdef LOG +static void asmrp_print_sym (asmrp_t *p) { + + printf ("symbol: "); + + switch (p->sym) { + + case ASMRP_SYM_NONE: + printf ("NONE\n"); + break; + + case ASMRP_SYM_EOF: + printf ("EOF\n"); + break; + + case ASMRP_SYM_NUM: + printf ("NUM %d\n", p->num); + break; + + case ASMRP_SYM_ID: + printf ("ID '%s'\n", p->str); + break; + + case ASMRP_SYM_STRING: + printf ("STRING \"%s\"\n", p->str); + break; + + case ASMRP_SYM_HASH: + printf ("#\n"); + break; + + case ASMRP_SYM_SEMICOLON: + printf (";\n"); + break; + case ASMRP_SYM_COMMA: + printf (",\n"); + break; + case ASMRP_SYM_EQUALS: + printf ("==\n"); + break; + case ASMRP_SYM_AND: + printf ("&&\n"); + break; + case ASMRP_SYM_OR: + printf ("||\n"); + break; + case ASMRP_SYM_LESS: + printf ("<\n"); + break; + case ASMRP_SYM_LEQ: + printf ("<=\n"); + break; + case ASMRP_SYM_GEQ: + printf (">=\n"); + break; + case ASMRP_SYM_GREATER: + printf (">\n"); + break; + case ASMRP_SYM_DOLLAR: + printf ("$\n"); + break; + case ASMRP_SYM_LPAREN: + printf ("(\n"); + break; + case ASMRP_SYM_RPAREN: + printf (")\n"); + break; + + default: + printf ("unknown symbol %d\n", p->sym); + } +} +#endif + +static void asmrp_get_sym (asmrp_t *p) { + + while (p->ch <= 32) { + if (p->ch == 0) { + p->sym = ASMRP_SYM_EOF; + return; + } + + asmrp_getch (p); + } + + if (p->ch == '\\') + asmrp_getch (p); + + switch (p->ch) { + + case '#': + p->sym = ASMRP_SYM_HASH; + asmrp_getch (p); + break; + case ';': + p->sym = ASMRP_SYM_SEMICOLON; + asmrp_getch (p); + break; + case ',': + p->sym = ASMRP_SYM_COMMA; + asmrp_getch (p); + break; + case '=': + p->sym = ASMRP_SYM_EQUALS; + asmrp_getch (p); + if (p->ch=='=') + asmrp_getch (p); + break; + case '&': + p->sym = ASMRP_SYM_AND; + asmrp_getch (p); + if (p->ch=='&') + asmrp_getch (p); + break; + case '|': + p->sym = ASMRP_SYM_OR; + asmrp_getch (p); + if (p->ch=='|') + asmrp_getch (p); + break; + case '<': + p->sym = ASMRP_SYM_LESS; + asmrp_getch (p); + if (p->ch=='=') { + p->sym = ASMRP_SYM_LEQ; + asmrp_getch (p); + } + break; + case '>': + p->sym = ASMRP_SYM_GREATER; + asmrp_getch (p); + if (p->ch=='=') { + p->sym = ASMRP_SYM_GEQ; + asmrp_getch (p); + } + break; + case '$': + p->sym = ASMRP_SYM_DOLLAR; + asmrp_getch (p); + break; + case '(': + p->sym = ASMRP_SYM_LPAREN; + asmrp_getch (p); + break; + case ')': + p->sym = ASMRP_SYM_RPAREN; + asmrp_getch (p); + break; + + case '"': + asmrp_getch (p); + asmrp_string (p); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + asmrp_number (p); + break; + + default: + asmrp_identifier (p); + } + +#ifdef LOG + asmrp_print_sym (p); +#endif + +} + +static int asmrp_find_id (asmrp_t *p, char *s) { + + int i; + + for (i=0; i<p->sym_tab_num; i++) { + if (!strcmp (s, p->sym_tab[i].id)) + return i; + } + + return -1; +} + +static int asmrp_set_id (asmrp_t *p, char *s, int v) { + + int i; + + i = asmrp_find_id (p, s); + + if (i<0) { + i = p->sym_tab_num; + p->sym_tab_num++; + p->sym_tab[i].id = strdup (s); + +#ifdef LOG + printf ("new symbol '%s'\n", s); +#endif + + } + + p->sym_tab[i].v = v; + +#ifdef LOG + printf ("symbol '%s' assigned %d\n", s, v); +#endif + + return i; +} + +static int asmrp_condition (asmrp_t *p) ; + +static int asmrp_operand (asmrp_t *p) { + + int i, ret; + +#ifdef LOG + printf ("operand\n"); +#endif + + ret = 0; + + switch (p->sym) { + + case ASMRP_SYM_DOLLAR: + + asmrp_get_sym (p); + + if (p->sym != ASMRP_SYM_ID) { + printf ("error: identifier expected.\n"); + abort(); + } + + i = asmrp_find_id (p, p->str); + if (i<0) { + printf ("error: unknown identifier %s\n", p->str); + } + ret = p->sym_tab[i].v; + + asmrp_get_sym (p); + break; + + case ASMRP_SYM_NUM: + ret = p->num; + + asmrp_get_sym (p); + break; + + case ASMRP_SYM_LPAREN: + asmrp_get_sym (p); + + ret = asmrp_condition (p); + + if (p->sym != ASMRP_SYM_RPAREN) { + printf ("error: ) expected.\n"); + abort(); + } + + asmrp_get_sym (p); + break; + + default: + printf ("syntax error, $ number or ( expected\n"); + abort(); + } + +#ifdef LOG + printf ("operand done, =%d\n", ret); +#endif + + return ret; +} + +static int asmrp_comp_expression (asmrp_t *p) { + + int a; + +#ifdef LOG + printf ("comp_expression\n"); +#endif + + a = asmrp_operand (p); + + while ( (p->sym == ASMRP_SYM_LESS) + || (p->sym == ASMRP_SYM_LEQ) + || (p->sym == ASMRP_SYM_EQUALS) + || (p->sym == ASMRP_SYM_GEQ) + || (p->sym == ASMRP_SYM_GREATER) ) { + int op = p->sym; + int b; + + asmrp_get_sym (p); + + b = asmrp_operand (p); + + switch (op) { + case ASMRP_SYM_LESS: + a = a<b; + break; + case ASMRP_SYM_LEQ: + a = a<=b; + break; + case ASMRP_SYM_EQUALS: + a = a==b; + break; + case ASMRP_SYM_GEQ: + a = a>=b; + break; + case ASMRP_SYM_GREATER: + a = a>b; + break; + } + + } + +#ifdef LOG + printf ("comp_expression done = %d\n", a); +#endif + return a; +} + +static int asmrp_condition (asmrp_t *p) { + + int a; + +#ifdef LOG + printf ("condition\n"); +#endif + + a = asmrp_comp_expression (p); + + while ( (p->sym == ASMRP_SYM_AND) || (p->sym == ASMRP_SYM_OR) ) { + int op, b; + + op = p->sym; + + asmrp_get_sym (p); + + b = asmrp_comp_expression (p); + + switch (op) { + case ASMRP_SYM_AND: + a = a & b; + break; + case ASMRP_SYM_OR: + a = a | b; + break; + } + } + +#ifdef LOG + printf ("condition done = %d\n", a); +#endif + return a; +} + +static void asmrp_assignment (asmrp_t *p) { + +#ifdef LOG + printf ("assignment\n"); +#endif + + if (p->sym != ASMRP_SYM_ID) { + printf ("error: identifier expected\n"); + abort (); + } + asmrp_get_sym (p); + + if (p->sym != ASMRP_SYM_EQUALS) { + printf ("error: = expected\n"); + abort (); + } + asmrp_get_sym (p); + + if ( (p->sym != ASMRP_SYM_NUM) && (p->sym != ASMRP_SYM_STRING) + && (p->sym != ASMRP_SYM_ID)) { + printf ("error: number or string expected\n"); + abort (); + } + asmrp_get_sym (p); + +#ifdef LOG + printf ("assignment done\n"); +#endif +} + +static int asmrp_rule (asmrp_t *p) { + + int ret; + +#ifdef LOG + printf ("rule\n"); +#endif + + ret = 1; + + if (p->sym == ASMRP_SYM_HASH) { + + asmrp_get_sym (p); + ret = asmrp_condition (p); + + while (p->sym == ASMRP_SYM_COMMA) { + + asmrp_get_sym (p); + + asmrp_assignment (p); + } + + } else if (p->sym != ASMRP_SYM_SEMICOLON) { + + asmrp_assignment (p); + + while (p->sym == ASMRP_SYM_COMMA) { + + asmrp_get_sym (p); + asmrp_assignment (p); + } + } + +#ifdef LOG + printf ("rule done = %d\n", ret); +#endif + + if (p->sym != ASMRP_SYM_SEMICOLON) { + printf ("semicolon expected.\n"); + abort (); + } + + asmrp_get_sym (p); + + return ret; +} + +static int asmrp_eval (asmrp_t *p, int *matches) { + + int rule_num, num_matches; + +#ifdef LOG + printf ("eval\n"); +#endif + + asmrp_get_sym (p); + + rule_num = 0; num_matches = 0; + while (p->sym != ASMRP_SYM_EOF) { + + if (asmrp_rule (p)) { +#ifdef LOG + printf ("rule #%d is true\n", rule_num); +#endif + matches[num_matches] = rule_num; + num_matches++; + } + + rule_num++; + } + + matches[num_matches] = -1; + return num_matches; +} + +int asmrp_match (const char *rules, int bandwidth, int *matches) { + + asmrp_t *p; + int num_matches; + + p = asmrp_new (); + + asmrp_init (p, rules); + + asmrp_set_id (p, "Bandwidth", bandwidth); + asmrp_set_id (p, "OldPNMPlayer", 0); + + num_matches = asmrp_eval (p, matches); + + asmrp_dispose (p); + + return num_matches; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/asmrp.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,45 @@ +/* + * This file was ported to MPlayer from xine CVS asmrp.h,v 1.1 2002/12/12 22:14:54 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * a parser for real's asm rules + * + * grammar for these rules: + * + + rule_book = { '#' rule ';'} + rule = condition {',' assignment} + assignment = id '=' const + const = ( number | string ) + condition = comp_expr { ( '&&' | '||' ) comp_expr } + comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } + operand = ( '$' id | num | '(' condition ')' ) + + */ + +#ifndef HAVE_ASMRP_H +#define HAVE_ASMRP_H + +int asmrp_match (const char *rules, int bandwidth, int *matches) ; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/real.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,744 @@ +/* + * This file was ported to MPlayer from xine CVS real.c,v 1.8 2003/03/30 17:11:50 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * special functions for real streams. + * adopted from joschkas real tools. + * + */ + +#include <stdio.h> +#include <string.h> + +#include "real.h" +#include "asmrp.h" +#include "sdpplin.h" + +/* +#define LOG +*/ + +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 BE_32C(x,y) x[3]=(char)(y & 0xff);\ + x[2]=(char)((y >> 8) & 0xff);\ + x[1]=(char)((y >> 16) & 0xff);\ + x[0]=(char)((y >> 24) & 0xff); + +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) + +#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ + (((uint8_t*)(x))[1] << 16) | \ + (((uint8_t*)(x))[2] << 8) | \ + ((uint8_t*)(x))[3]) + +#define MAX(x,y) ((x>y) ? x : y) + +#ifdef LOG +static void hexdump (const char *buf, int length) { + + int i; + + printf (" hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\n "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} +#endif + + +static void hash(char *field, char *param) { + + uint32_t a, b, c, d; + + + /* fill variables */ + memcpy(&a, field, sizeof(uint32_t)); + memcpy(&b, &field[4], sizeof(uint32_t)); + memcpy(&c, &field[8], sizeof(uint32_t)); + memcpy(&d, &field[12], sizeof(uint32_t)); + +#ifdef LOG + printf("real: hash input: %x %x %x %x\n", a, b, c, d); + printf("real: hash parameter:\n"); + hexdump(param, 64); +#endif + + a = ((b & c) | (~b & d)) + *((uint32_t*)(param+0x00)) + a - 0x28955B88; + a = ((a << 0x07) | (a >> 0x19)) + b; + d = ((a & b) | (~a & c)) + *((uint32_t*)(param+0x04)) + d - 0x173848AA; + d = ((d << 0x0c) | (d >> 0x14)) + a; + c = ((d & a) | (~d & b)) + *((uint32_t*)(param+0x08)) + c + 0x242070DB; + c = ((c << 0x11) | (c >> 0x0f)) + d; + b = ((c & d) | (~c & a)) + *((uint32_t*)(param+0x0c)) + b - 0x3E423112; + b = ((b << 0x16) | (b >> 0x0a)) + c; + a = ((b & c) | (~b & d)) + *((uint32_t*)(param+0x10)) + a - 0x0A83F051; + a = ((a << 0x07) | (a >> 0x19)) + b; + d = ((a & b) | (~a & c)) + *((uint32_t*)(param+0x14)) + d + 0x4787C62A; + d = ((d << 0x0c) | (d >> 0x14)) + a; + c = ((d & a) | (~d & b)) + *((uint32_t*)(param+0x18)) + c - 0x57CFB9ED; + c = ((c << 0x11) | (c >> 0x0f)) + d; + b = ((c & d) | (~c & a)) + *((uint32_t*)(param+0x1c)) + b - 0x02B96AFF; + b = ((b << 0x16) | (b >> 0x0a)) + c; + a = ((b & c) | (~b & d)) + *((uint32_t*)(param+0x20)) + a + 0x698098D8; + a = ((a << 0x07) | (a >> 0x19)) + b; + d = ((a & b) | (~a & c)) + *((uint32_t*)(param+0x24)) + d - 0x74BB0851; + d = ((d << 0x0c) | (d >> 0x14)) + a; + c = ((d & a) | (~d & b)) + *((uint32_t*)(param+0x28)) + c - 0x0000A44F; + c = ((c << 0x11) | (c >> 0x0f)) + d; + b = ((c & d) | (~c & a)) + *((uint32_t*)(param+0x2C)) + b - 0x76A32842; + b = ((b << 0x16) | (b >> 0x0a)) + c; + a = ((b & c) | (~b & d)) + *((uint32_t*)(param+0x30)) + a + 0x6B901122; + a = ((a << 0x07) | (a >> 0x19)) + b; + d = ((a & b) | (~a & c)) + *((uint32_t*)(param+0x34)) + d - 0x02678E6D; + d = ((d << 0x0c) | (d >> 0x14)) + a; + c = ((d & a) | (~d & b)) + *((uint32_t*)(param+0x38)) + c - 0x5986BC72; + c = ((c << 0x11) | (c >> 0x0f)) + d; + b = ((c & d) | (~c & a)) + *((uint32_t*)(param+0x3c)) + b + 0x49B40821; + b = ((b << 0x16) | (b >> 0x0a)) + c; + + a = ((b & d) | (~d & c)) + *((uint32_t*)(param+0x04)) + a - 0x09E1DA9E; + a = ((a << 0x05) | (a >> 0x1b)) + b; + d = ((a & c) | (~c & b)) + *((uint32_t*)(param+0x18)) + d - 0x3FBF4CC0; + d = ((d << 0x09) | (d >> 0x17)) + a; + c = ((d & b) | (~b & a)) + *((uint32_t*)(param+0x2c)) + c + 0x265E5A51; + c = ((c << 0x0e) | (c >> 0x12)) + d; + b = ((c & a) | (~a & d)) + *((uint32_t*)(param+0x00)) + b - 0x16493856; + b = ((b << 0x14) | (b >> 0x0c)) + c; + a = ((b & d) | (~d & c)) + *((uint32_t*)(param+0x14)) + a - 0x29D0EFA3; + a = ((a << 0x05) | (a >> 0x1b)) + b; + d = ((a & c) | (~c & b)) + *((uint32_t*)(param+0x28)) + d + 0x02441453; + d = ((d << 0x09) | (d >> 0x17)) + a; + c = ((d & b) | (~b & a)) + *((uint32_t*)(param+0x3c)) + c - 0x275E197F; + c = ((c << 0x0e) | (c >> 0x12)) + d; + b = ((c & a) | (~a & d)) + *((uint32_t*)(param+0x10)) + b - 0x182C0438; + b = ((b << 0x14) | (b >> 0x0c)) + c; + a = ((b & d) | (~d & c)) + *((uint32_t*)(param+0x24)) + a + 0x21E1CDE6; + a = ((a << 0x05) | (a >> 0x1b)) + b; + d = ((a & c) | (~c & b)) + *((uint32_t*)(param+0x38)) + d - 0x3CC8F82A; + d = ((d << 0x09) | (d >> 0x17)) + a; + c = ((d & b) | (~b & a)) + *((uint32_t*)(param+0x0c)) + c - 0x0B2AF279; + c = ((c << 0x0e) | (c >> 0x12)) + d; + b = ((c & a) | (~a & d)) + *((uint32_t*)(param+0x20)) + b + 0x455A14ED; + b = ((b << 0x14) | (b >> 0x0c)) + c; + a = ((b & d) | (~d & c)) + *((uint32_t*)(param+0x34)) + a - 0x561C16FB; + a = ((a << 0x05) | (a >> 0x1b)) + b; + d = ((a & c) | (~c & b)) + *((uint32_t*)(param+0x08)) + d - 0x03105C08; + d = ((d << 0x09) | (d >> 0x17)) + a; + c = ((d & b) | (~b & a)) + *((uint32_t*)(param+0x1c)) + c + 0x676F02D9; + c = ((c << 0x0e) | (c >> 0x12)) + d; + b = ((c & a) | (~a & d)) + *((uint32_t*)(param+0x30)) + b - 0x72D5B376; + b = ((b << 0x14) | (b >> 0x0c)) + c; + + a = (b ^ c ^ d) + *((uint32_t*)(param+0x14)) + a - 0x0005C6BE; + a = ((a << 0x04) | (a >> 0x1c)) + b; + d = (a ^ b ^ c) + *((uint32_t*)(param+0x20)) + d - 0x788E097F; + d = ((d << 0x0b) | (d >> 0x15)) + a; + c = (d ^ a ^ b) + *((uint32_t*)(param+0x2c)) + c + 0x6D9D6122; + c = ((c << 0x10) | (c >> 0x10)) + d; + b = (c ^ d ^ a) + *((uint32_t*)(param+0x38)) + b - 0x021AC7F4; + b = ((b << 0x17) | (b >> 0x09)) + c; + a = (b ^ c ^ d) + *((uint32_t*)(param+0x04)) + a - 0x5B4115BC; + a = ((a << 0x04) | (a >> 0x1c)) + b; + d = (a ^ b ^ c) + *((uint32_t*)(param+0x10)) + d + 0x4BDECFA9; + d = ((d << 0x0b) | (d >> 0x15)) + a; + c = (d ^ a ^ b) + *((uint32_t*)(param+0x1c)) + c - 0x0944B4A0; + c = ((c << 0x10) | (c >> 0x10)) + d; + b = (c ^ d ^ a) + *((uint32_t*)(param+0x28)) + b - 0x41404390; + b = ((b << 0x17) | (b >> 0x09)) + c; + a = (b ^ c ^ d) + *((uint32_t*)(param+0x34)) + a + 0x289B7EC6; + a = ((a << 0x04) | (a >> 0x1c)) + b; + d = (a ^ b ^ c) + *((uint32_t*)(param+0x00)) + d - 0x155ED806; + d = ((d << 0x0b) | (d >> 0x15)) + a; + c = (d ^ a ^ b) + *((uint32_t*)(param+0x0c)) + c - 0x2B10CF7B; + c = ((c << 0x10) | (c >> 0x10)) + d; + b = (c ^ d ^ a) + *((uint32_t*)(param+0x18)) + b + 0x04881D05; + b = ((b << 0x17) | (b >> 0x09)) + c; + a = (b ^ c ^ d) + *((uint32_t*)(param+0x24)) + a - 0x262B2FC7; + a = ((a << 0x04) | (a >> 0x1c)) + b; + d = (a ^ b ^ c) + *((uint32_t*)(param+0x30)) + d - 0x1924661B; + d = ((d << 0x0b) | (d >> 0x15)) + a; + c = (d ^ a ^ b) + *((uint32_t*)(param+0x3c)) + c + 0x1fa27cf8; + c = ((c << 0x10) | (c >> 0x10)) + d; + b = (c ^ d ^ a) + *((uint32_t*)(param+0x08)) + b - 0x3B53A99B; + b = ((b << 0x17) | (b >> 0x09)) + c; + + a = ((~d | b) ^ c) + *((uint32_t*)(param+0x00)) + a - 0x0BD6DDBC; + a = ((a << 0x06) | (a >> 0x1a)) + b; + d = ((~c | a) ^ b) + *((uint32_t*)(param+0x1c)) + d + 0x432AFF97; + d = ((d << 0x0a) | (d >> 0x16)) + a; + c = ((~b | d) ^ a) + *((uint32_t*)(param+0x38)) + c - 0x546BDC59; + c = ((c << 0x0f) | (c >> 0x11)) + d; + b = ((~a | c) ^ d) + *((uint32_t*)(param+0x14)) + b - 0x036C5FC7; + b = ((b << 0x15) | (b >> 0x0b)) + c; + a = ((~d | b) ^ c) + *((uint32_t*)(param+0x30)) + a + 0x655B59C3; + a = ((a << 0x06) | (a >> 0x1a)) + b; + d = ((~c | a) ^ b) + *((uint32_t*)(param+0x0C)) + d - 0x70F3336E; + d = ((d << 0x0a) | (d >> 0x16)) + a; + c = ((~b | d) ^ a) + *((uint32_t*)(param+0x28)) + c - 0x00100B83; + c = ((c << 0x0f) | (c >> 0x11)) + d; + b = ((~a | c) ^ d) + *((uint32_t*)(param+0x04)) + b - 0x7A7BA22F; + b = ((b << 0x15) | (b >> 0x0b)) + c; + a = ((~d | b) ^ c) + *((uint32_t*)(param+0x20)) + a + 0x6FA87E4F; + a = ((a << 0x06) | (a >> 0x1a)) + b; + d = ((~c | a) ^ b) + *((uint32_t*)(param+0x3c)) + d - 0x01D31920; + d = ((d << 0x0a) | (d >> 0x16)) + a; + c = ((~b | d) ^ a) + *((uint32_t*)(param+0x18)) + c - 0x5CFEBCEC; + c = ((c << 0x0f) | (c >> 0x11)) + d; + b = ((~a | c) ^ d) + *((uint32_t*)(param+0x34)) + b + 0x4E0811A1; + b = ((b << 0x15) | (b >> 0x0b)) + c; + a = ((~d | b) ^ c) + *((uint32_t*)(param+0x10)) + a - 0x08AC817E; + a = ((a << 0x06) | (a >> 0x1a)) + b; + d = ((~c | a) ^ b) + *((uint32_t*)(param+0x2c)) + d - 0x42C50DCB; + d = ((d << 0x0a) | (d >> 0x16)) + a; + c = ((~b | d) ^ a) + *((uint32_t*)(param+0x08)) + c + 0x2AD7D2BB; + c = ((c << 0x0f) | (c >> 0x11)) + d; + b = ((~a | c) ^ d) + *((uint32_t*)(param+0x24)) + b - 0x14792C6F; + b = ((b << 0x15) | (b >> 0x0b)) + c; + +#ifdef LOG + printf("real: hash output: %x %x %x %x\n", a, b, c, d); +#endif + + *((uint32_t *)(field+0)) += a; + *((uint32_t *)(field+4)) += b; + *((uint32_t *)(field+8)) += c; + *((uint32_t *)(field+12)) += d; +} + +static void call_hash (char *key, char *challenge, int len) { + + uint32_t *ptr1, *ptr2; + uint32_t a, b, c, d; + + ptr1=(uint32_t*)(key+16); + ptr2=(uint32_t*)(key+20); + + a = *ptr1; + b = (a >> 3) & 0x3f; + a += len * 8; + *ptr1 = a; + + if (a < (len << 3)) + { +#ifdef LOG + printf("not verified: (len << 3) > a true\n"); +#endif + ptr2 += 4; + } + + *ptr2 += (len >> 0x1d); + 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 ) { + +#ifdef LOG + printf("not verified: while ( d < len )\n"); +#endif + hash(key, challenge+d-0x3f); + d += 64; + c += 64; + } + b = 0; + } + + memcpy(key+b+24, challenge+c, len-c); +} + +static void calc_response (char *result, char *field) { + + char buf1[128]; + char buf2[128]; + int i; + + memset (buf1, 0, 64); + *buf1 = 128; + + memcpy (buf2, field+16, 8); + + i = ( *((uint32_t*)(buf2)) >> 3 ) & 0x3f; + + if (i < 56) { + i = 56 - i; + } else { +#ifdef LOG + printf("not verified: ! (i < 56)\n"); +#endif + i = 120 - i; + } + + call_hash (field, buf1, i); + call_hash (field, buf2, 8); + + memcpy (result, field, 16); + +} + + +static void calc_response_string (char *result, char *challenge) { + + char field[128]; + char zres[20]; + int 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, challenge, 64); + calc_response(zres,field); + + /* convert zres to ascii string */ + for (i=0; i<16; i++ ) { + char a, b; + + a = (zres[i] >> 4) & 15; + b = zres[i] & 15; + + result[i*2] = ((a<10) ? (a+48) : (a+87)) & 255; + result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255; + } +} + +void 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]; + + /* 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; + + /* some (length) checks */ + if (challenge != NULL) + { + ch_len = strlen (challenge); + + if (ch_len == 40) /* what a hack... */ + { + challenge[32]=0; + ch_len=32; + } + if ( ch_len > 56 ) ch_len=56; + + /* copy challenge to buf */ + memcpy(ptr, challenge, ch_len); + } + + if (xor_table != NULL) + { + table_len = strlen(xor_table); + + if (table_len > 56) table_len=56; + + /* xor challenge bytewise with xor_table */ + for (i=0; i<table_len; i++) + ptr[i] = ptr[i] ^ xor_table[i]; + } + + calc_response_string (response, buf); + + /* 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]; +} + + +/* + * takes a MLTI-Chunk and a rule number got from match_asm_rule, + * returns a pointer to selected data and number of bytes in that. + */ + +static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char *out) { + + int numrules, codec, size; + int i; + + /* MLTI chunk should begin with MLTI */ + + if ((mlti_chunk[0] != 'M') + ||(mlti_chunk[1] != 'L') + ||(mlti_chunk[2] != 'T') + ||(mlti_chunk[3] != 'I')) + { +#ifdef LOG + printf("libreal: MLTI tag not detected, copying data\n"); +#endif + memcpy(out, mlti_chunk, mlti_size); + return mlti_size; + } + + mlti_chunk+=4; + + /* next 16 bits are the number of rules */ + numrules=BE_16(mlti_chunk); + if (selection >= numrules) return 0; + + /* now <numrules> indices of codecs follows */ + /* we skip to selection */ + mlti_chunk+=(selection+1)*2; + + /* get our index */ + codec=BE_16(mlti_chunk); + + /* skip to number of codecs */ + mlti_chunk+=(numrules-selection)*2; + + /* get number of codecs */ + numrules=BE_16(mlti_chunk); + + if (codec >= numrules) { + printf("codec index >= number of codecs. %i %i\n", codec, numrules); + return 0; + } + + mlti_chunk+=2; + + /* now seek to selected codec */ + for (i=0; i<codec; i++) { + size=BE_32(mlti_chunk); + mlti_chunk+=size+4; + } + + size=BE_32(mlti_chunk); + +#ifdef LOG + hexdump(mlti_chunk+4, size); +#endif + memcpy(out,mlti_chunk+4, size); + return size; +} + +/* + * looking at stream description. + */ + +rmff_header_t *real_parse_sdp(char *data, char *stream_rules, uint32_t bandwidth) { + + sdpplin_t *desc; + rmff_header_t *header; + char buf[2048]; + int len, i; + int max_bit_rate=0; + int avg_bit_rate=0; + int max_packet_size=0; + int avg_packet_size=0; + int duration=0; + + + if (!data) return NULL; + + desc=sdpplin_parse(data); + + if (!desc) return NULL; + + header=calloc(1,sizeof(rmff_header_t)); + + header->fileheader=rmff_new_fileheader(4+desc->stream_count); + header->cont=rmff_new_cont( + desc->title, + desc->author, + desc->copyright, + desc->abstract); + header->data=rmff_new_dataheader(0,0); + header->streams=calloc(1,sizeof(rmff_mdpr_t*)*(desc->stream_count+1)); +#ifdef LOG + printf("number of streams: %u\n", desc->stream_count); +#endif + + for (i=0; i<desc->stream_count; i++) { + + int j=0; + int n; + char b[64]; + int rulematches[16]; + +#ifdef LOG + printf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth); +#endif + n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches); + for (j=0; j<n; j++) { +#ifdef LOG + printf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id); +#endif + sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]); + strcat(stream_rules, b); + } + + if (!desc->stream[i]->mlti_data) return NULL; + + len=select_mlti_data(desc->stream[i]->mlti_data, desc->stream[i]->mlti_data_size, rulematches[0], buf); + + header->streams[i]=rmff_new_mdpr( + desc->stream[i]->stream_id, + desc->stream[i]->max_bit_rate, + desc->stream[i]->avg_bit_rate, + desc->stream[i]->max_packet_size, + desc->stream[i]->avg_packet_size, + desc->stream[i]->start_time, + desc->stream[i]->preroll, + desc->stream[i]->duration, + desc->stream[i]->stream_name, + desc->stream[i]->mime_type, + len, + buf); + + duration=MAX(duration,desc->stream[i]->duration); + max_bit_rate+=desc->stream[i]->max_bit_rate; + avg_bit_rate+=desc->stream[i]->avg_bit_rate; + max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size); + if (avg_packet_size) + avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2; + else + avg_packet_size=desc->stream[i]->avg_packet_size; + } + + if (stream_rules) + stream_rules[strlen(stream_rules)-1]=0; /* delete last ',' in stream_rules */ + + header->prop=rmff_new_prop( + max_bit_rate, + avg_bit_rate, + max_packet_size, + avg_packet_size, + 0, + duration, + 0, + 0, + 0, + desc->stream_count, + desc->flags); + + rmff_fix_header(header); + + return header; +} + +int real_get_rdt_chunk(rtsp_t *rtsp_session, char *buffer) { + + int n=1; + uint8_t header[8]; + rmff_pheader_t ph; + int size; + int flags1; + int unknown1; + uint32_t ts; + + n=rtsp_read_data(rtsp_session, header, 8); + if (n<8) return 0; + if (header[0] != 0x24) + { + printf("rdt chunk not recognized: got 0x%02x\n", header[0]); + return 0; + } + size=(header[1]<<12)+(header[2]<<8)+(header[3]); + flags1=header[4]; + if ((flags1!=0x40)&&(flags1!=0x42)) + { +#ifdef LOG + printf("got flags1: 0x%02x\n",flags1); +#endif + header[0]=header[5]; + header[1]=header[6]; + header[2]=header[7]; + n=rtsp_read_data(rtsp_session, header+3, 5); + if (n<5) return 0; +#ifdef LOG + printf("ignoring bytes:\n"); + hexdump(header, 8); +#endif + n=rtsp_read_data(rtsp_session, header+4, 4); + if (n<4) return 0; + flags1=header[4]; + size-=9; + } + unknown1=(header[5]<<12)+(header[6]<<8)+(header[7]); + n=rtsp_read_data(rtsp_session, header, 6); + if (n<6) return 0; + ts=BE_32(header); + +#ifdef LOG + printf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n", + ts, size, flags1, unknown1, header[4], header[5]); +#endif + size+=2; + + ph.object_version=0; + ph.length=size; + ph.stream_number=(flags1>>1)&1; + ph.timestamp=ts; + ph.reserved=0; + ph.flags=0; /* TODO: determine keyframe flag and insert here? */ + rmff_dump_pheader(&ph, buffer); + size-=12; + n=rtsp_read_data(rtsp_session, buffer+12, size); + + return n+12; +} + +rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth) { + + char *description=NULL; + char *session_id=NULL; + rmff_header_t *h; + char *challenge1; + char challenge2[64]; + char checksum[34]; + char subscribe[256]; + char buf[256]; + char *mrl=rtsp_get_mrl(rtsp_session); + unsigned int size; + int status; + + /* get challenge */ + challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1")); +#ifdef LOG + printf("real: Challenge1: %s\n", challenge1); +#endif + + /* request stream description */ + rtsp_schedule_field(rtsp_session, "Accept: application/sdp"); + sprintf(buf, "Bandwidth: %u", bandwidth); + rtsp_schedule_field(rtsp_session, buf); + rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000"); + rtsp_schedule_field(rtsp_session, "RegionData: 0"); + rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); + rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1"); + rtsp_schedule_field(rtsp_session, "Language: en-US"); + rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup"); + status=rtsp_request_describe(rtsp_session,NULL); + + if ( status<200 || status>299 ) + { + char *alert=rtsp_search_answers(rtsp_session,"Alert"); + if (alert) { + printf("real: got message from server:\n%s\n", alert); + } + rtsp_send_ok(rtsp_session); + return NULL; + } + + /* receive description */ + size=0; + if (!rtsp_search_answers(rtsp_session,"Content-length")) + printf("real: got no Content-length!\n"); + else + size=atoi(rtsp_search_answers(rtsp_session,"Content-length")); + + if (!rtsp_search_answers(rtsp_session,"ETag")) + printf("real: got no ETag!\n"); + else + session_id=strdup(rtsp_search_answers(rtsp_session,"ETag")); + +#ifdef LOG + printf("real: Stream description size: %i\n", size); +#endif + + description=malloc(sizeof(char)*(size+1)); + + rtsp_read_data(rtsp_session, description, size); + description[size]=0; + + /* parse sdp (sdpplin) and create a header and a subscribe string */ + strcpy(subscribe, "Subscribe: "); + h=real_parse_sdp(description, subscribe+11, bandwidth); + if (!h) return NULL; + rmff_fix_header(h); + +#ifdef LOG + printf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n", + h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams); +#endif + + /* setup our streams */ + real_calc_response_and_checksum (challenge2, checksum, challenge1); + sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum); + rtsp_schedule_field(rtsp_session, buf); + sprintf(buf, "If-Match: %s", session_id); + rtsp_schedule_field(rtsp_session, buf); + rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); + sprintf(buf, "%s/streamid=0", mrl); + rtsp_request_setup(rtsp_session,buf); + + if (h->prop->num_streams > 1) { + rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); + sprintf(buf, "If-Match: %s", session_id); + rtsp_schedule_field(rtsp_session, buf); + + sprintf(buf, "%s/streamid=1", mrl); + rtsp_request_setup(rtsp_session,buf); + } + /* set stream parameter (bandwidth) with our subscribe string */ + rtsp_schedule_field(rtsp_session, subscribe); + rtsp_request_setparameter(rtsp_session,NULL); + + /* and finally send a play request */ + rtsp_schedule_field(rtsp_session, "Range: npt=0-"); + rtsp_request_play(rtsp_session,NULL); + + return h; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/real.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,52 @@ +/* + * This file was ported to MPlayer from xine CVS real.h,v 1.2 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * special functions for real streams. + * adopted from joschkas real tools. + * + */ + +#ifndef HAVE_REAL_H +#define HAVE_REAL_H + +#include "rmff.h" +#include "rtsp.h" + +#ifdef __CYGWIN__ +#define uint32_t unsigned int +#define uint16_t unsigned short int +#define uint8_t unsigned char +#endif + +/* + * calculates response and checksum of a given challenge + * (RealChallenge1 in rtsp). See implementation for details. + */ +void real_calc_response_and_checksum (char *response, char *chksum, char *challenge); +int real_get_rdt_chunk(rtsp_t *rtsp_session, char *buffer); +rmff_header_t *real_parse_sdp(char *data, char *stream_rules, uint32_t bandwidth); +rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rmff.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,907 @@ +/* + * This file was ported to MPlayer from xine CVS rmff.c,v 1.3 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * functions for real media file format + * adopted from joschkas real tools + */ + +#include "rmff.h" +#include "xbuffer.h" + +/* +#define LOG +*/ + +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) +#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ + (((uint8_t*)(x))[1] << 16) | \ + (((uint8_t*)(x))[2] << 8) | \ + ((uint8_t*)(x))[3]) + +static void hexdump (const char *buf, int length) { + + int i; + + printf ("rmff: ascii>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + printf ("%c", c); + else + printf ("."); + } + printf ("\n"); + + printf ("rmff: hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\nrmff: "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} + +/* + * writes header data to a buffer + */ + +static void rmff_dump_fileheader(rmff_fileheader_t *fileheader, char *buffer) { + + if (!fileheader) return; + fileheader->object_id=BE_32(&fileheader->object_id); + fileheader->size=BE_32(&fileheader->size); + fileheader->object_version=BE_16(&fileheader->object_version); + fileheader->file_version=BE_32(&fileheader->file_version); + fileheader->num_headers=BE_32(&fileheader->num_headers); + + memcpy(buffer, fileheader, 8); + memcpy(&buffer[8], &fileheader->object_version, 2); + memcpy(&buffer[10], &fileheader->file_version, 8); + + fileheader->size=BE_32(&fileheader->size); + fileheader->object_version=BE_16(&fileheader->object_version); + fileheader->file_version=BE_32(&fileheader->file_version); + fileheader->num_headers=BE_32(&fileheader->num_headers); + fileheader->object_id=BE_32(&fileheader->object_id); +} + +static void rmff_dump_prop(rmff_prop_t *prop, char *buffer) { + + if (!prop) return; + prop->object_id=BE_32(&prop->object_id); + prop->size=BE_32(&prop->size); + prop->object_version=BE_16(&prop->object_version); + prop->max_bit_rate=BE_32(&prop->max_bit_rate); + prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); + prop->max_packet_size=BE_32(&prop->max_packet_size); + prop->avg_packet_size=BE_32(&prop->avg_packet_size); + prop->num_packets=BE_32(&prop->num_packets); + prop->duration=BE_32(&prop->duration); + prop->preroll=BE_32(&prop->preroll); + prop->index_offset=BE_32(&prop->index_offset); + prop->data_offset=BE_32(&prop->data_offset); + prop->num_streams=BE_16(&prop->num_streams); + prop->flags=BE_16(&prop->flags); + + memcpy(buffer, prop, 8); + memcpy(&buffer[8], &prop->object_version, 2); + memcpy(&buffer[10], &prop->max_bit_rate, 36); + memcpy(&buffer[46], &prop->num_streams, 2); + memcpy(&buffer[48], &prop->flags, 2); + + prop->size=BE_32(&prop->size); + prop->object_version=BE_16(&prop->object_version); + prop->max_bit_rate=BE_32(&prop->max_bit_rate); + prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); + prop->max_packet_size=BE_32(&prop->max_packet_size); + prop->avg_packet_size=BE_32(&prop->avg_packet_size); + prop->num_packets=BE_32(&prop->num_packets); + prop->duration=BE_32(&prop->duration); + prop->preroll=BE_32(&prop->preroll); + prop->index_offset=BE_32(&prop->index_offset); + prop->data_offset=BE_32(&prop->data_offset); + prop->num_streams=BE_16(&prop->num_streams); + prop->flags=BE_16(&prop->flags); + prop->object_id=BE_32(&prop->object_id); +} + +static void rmff_dump_mdpr(rmff_mdpr_t *mdpr, char *buffer) { + + int s1, s2, s3; + + if (!mdpr) return; + mdpr->object_id=BE_32(&mdpr->object_id); + mdpr->size=BE_32(&mdpr->size); + mdpr->object_version=BE_16(&mdpr->object_version); + mdpr->stream_number=BE_16(&mdpr->stream_number); + mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); + mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); + mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); + mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); + mdpr->start_time=BE_32(&mdpr->start_time); + mdpr->preroll=BE_32(&mdpr->preroll); + mdpr->duration=BE_32(&mdpr->duration); + + memcpy(buffer, mdpr, 8); + memcpy(&buffer[8], &mdpr->object_version, 2); + memcpy(&buffer[10], &mdpr->stream_number, 2); + memcpy(&buffer[12], &mdpr->max_bit_rate, 28); + memcpy(&buffer[40], &mdpr->stream_name_size, 1); + s1=mdpr->stream_name_size; + memcpy(&buffer[41], mdpr->stream_name, s1); + + memcpy(&buffer[41+s1], &mdpr->mime_type_size, 1); + s2=mdpr->mime_type_size; + memcpy(&buffer[42+s1], mdpr->mime_type, s2); + + mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); + memcpy(&buffer[42+s1+s2], &mdpr->type_specific_len, 4); + mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); + s3=mdpr->type_specific_len; + memcpy(&buffer[46+s1+s2], mdpr->type_specific_data, s3); + + mdpr->size=BE_32(&mdpr->size); + mdpr->stream_number=BE_16(&mdpr->stream_number); + mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); + mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); + mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); + mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); + mdpr->start_time=BE_32(&mdpr->start_time); + mdpr->preroll=BE_32(&mdpr->preroll); + mdpr->duration=BE_32(&mdpr->duration); + mdpr->object_id=BE_32(&mdpr->object_id); + +} + +static void rmff_dump_cont(rmff_cont_t *cont, char *buffer) { + + int p; + + if (!cont) return; + cont->object_id=BE_32(&cont->object_id); + cont->size=BE_32(&cont->size); + cont->object_version=BE_16(&cont->object_version); + + memcpy(buffer, cont, 8); + memcpy(&buffer[8], &cont->object_version, 2); + + cont->title_len=BE_16(&cont->title_len); + memcpy(&buffer[10], &cont->title_len, 2); + cont->title_len=BE_16(&cont->title_len); + memcpy(&buffer[12], cont->title, cont->title_len); + p=12+cont->title_len; + + cont->author_len=BE_16(&cont->author_len); + memcpy(&buffer[p], &cont->author_len, 2); + cont->author_len=BE_16(&cont->author_len); + memcpy(&buffer[p+2], cont->author, cont->author_len); + p+=2+cont->author_len; + + cont->copyright_len=BE_16(&cont->copyright_len); + memcpy(&buffer[p], &cont->copyright_len, 2); + cont->copyright_len=BE_16(&cont->copyright_len); + memcpy(&buffer[p+2], cont->copyright, cont->copyright_len); + p+=2+cont->copyright_len; + + cont->comment_len=BE_16(&cont->comment_len); + memcpy(&buffer[p], &cont->comment_len, 2); + cont->comment_len=BE_16(&cont->comment_len); + memcpy(&buffer[p+2], cont->comment, cont->comment_len); + + cont->size=BE_32(&cont->size); + cont->object_version=BE_16(&cont->object_version); + cont->object_id=BE_32(&cont->object_id); +} + +static void rmff_dump_dataheader(rmff_data_t *data, char *buffer) { + + if (!data) return; + data->object_id=BE_32(&data->object_id); + data->size=BE_32(&data->size); + data->object_version=BE_16(&data->object_version); + data->num_packets=BE_32(&data->num_packets); + data->next_data_header=BE_32(&data->next_data_header); + + memcpy(buffer, data, 8); + memcpy(&buffer[8], &data->object_version, 2); + memcpy(&buffer[10], &data->num_packets, 8); + + data->num_packets=BE_32(&data->num_packets); + data->next_data_header=BE_32(&data->next_data_header); + data->size=BE_32(&data->size); + data->object_version=BE_16(&data->object_version); + data->object_id=BE_32(&data->object_id); +} + +int rmff_dump_header(rmff_header_t *h, char *buffer, int max) { + + int written=0; + rmff_mdpr_t **stream=h->streams; + + rmff_dump_fileheader(h->fileheader, &buffer[written]); + written+=h->fileheader->size; + rmff_dump_prop(h->prop, &buffer[written]); + written+=h->prop->size; + rmff_dump_cont(h->cont, &buffer[written]); + written+=h->cont->size; + if (stream) + { + while(*stream) + { + rmff_dump_mdpr(*stream, &buffer[written]); + written+=(*stream)->size; + stream++; + } + } + + rmff_dump_dataheader(h->data, &buffer[written]); + written+=18; + + return written; +} + +void rmff_dump_pheader(rmff_pheader_t *h, char *data) { + + data[0]=(h->object_version>>8) & 0xff; + data[1]=h->object_version & 0xff; + data[2]=(h->length>>8) & 0xff; + data[3]=h->length & 0xff; + data[4]=(h->stream_number>>8) & 0xff; + data[5]=h->stream_number & 0xff; + data[6]=(h->timestamp>>24) & 0xff; + data[7]=(h->timestamp>>16) & 0xff; + data[8]=(h->timestamp>>8) & 0xff; + data[9]=h->timestamp & 0xff; + data[10]=h->reserved; + data[11]=h->flags; +} + +static rmff_fileheader_t *rmff_scan_fileheader(const char *data) { + + rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); + + fileheader->object_id=BE_32(data); + fileheader->size=BE_32(&data[4]); + fileheader->object_version=BE_16(&data[8]); + if (fileheader->object_version != 0) + { + printf("warning: unknown object version in .RMF: 0x%04x\n", + fileheader->object_version); + } + fileheader->file_version=BE_32(&data[10]); + fileheader->num_headers=BE_32(&data[14]); + + return fileheader; +} + +static rmff_prop_t *rmff_scan_prop(const char *data) { + + rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); + + prop->object_id=BE_32(data); + prop->size=BE_32(&data[4]); + prop->object_version=BE_16(&data[8]); + if (prop->object_version != 0) + { + printf("warning: unknown object version in PROP: 0x%04x\n", + prop->object_version); + } + prop->max_bit_rate=BE_32(&data[10]); + prop->avg_bit_rate=BE_32(&data[14]); + prop->max_packet_size=BE_32(&data[18]); + prop->avg_packet_size=BE_32(&data[22]); + prop->num_packets=BE_32(&data[26]); + prop->duration=BE_32(&data[30]); + prop->preroll=BE_32(&data[34]); + prop->index_offset=BE_32(&data[38]); + prop->data_offset=BE_32(&data[42]); + prop->num_streams=BE_16(&data[46]); + prop->flags=BE_16(&data[48]); + + return prop; +} + +static rmff_mdpr_t *rmff_scan_mdpr(const char *data) { + + rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); + + mdpr->object_id=BE_32(data); + mdpr->size=BE_32(&data[4]); + mdpr->object_version=BE_16(&data[8]); + if (mdpr->object_version != 0) + { + printf("warning: unknown object version in MDPR: 0x%04x\n", + mdpr->object_version); + } + mdpr->stream_number=BE_16(&data[10]); + mdpr->max_bit_rate=BE_32(&data[12]); + mdpr->avg_bit_rate=BE_32(&data[16]); + mdpr->max_packet_size=BE_32(&data[20]); + mdpr->avg_packet_size=BE_32(&data[24]); + mdpr->start_time=BE_32(&data[28]); + mdpr->preroll=BE_32(&data[32]); + mdpr->duration=BE_32(&data[36]); + + mdpr->stream_name_size=data[40]; + mdpr->stream_name=malloc(sizeof(char)*(mdpr->stream_name_size+1)); + memcpy(mdpr->stream_name, &data[41], mdpr->stream_name_size); + mdpr->stream_name[mdpr->stream_name_size]=0; + + mdpr->mime_type_size=data[41+mdpr->stream_name_size]; + mdpr->mime_type=malloc(sizeof(char)*(mdpr->mime_type_size+1)); + memcpy(mdpr->mime_type, &data[42+mdpr->stream_name_size], mdpr->mime_type_size); + mdpr->mime_type[mdpr->mime_type_size]=0; + + mdpr->type_specific_len=BE_32(&data[42+mdpr->stream_name_size+mdpr->mime_type_size]); + mdpr->type_specific_data=malloc(sizeof(char)*(mdpr->type_specific_len)); + memcpy(mdpr->type_specific_data, + &data[46+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len); + + return mdpr; +} + +static rmff_cont_t *rmff_scan_cont(const char *data) { + + rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); + int pos; + + cont->object_id=BE_32(data); + cont->size=BE_32(&data[4]); + cont->object_version=BE_16(&data[8]); + if (cont->object_version != 0) + { + printf("warning: unknown object version in CONT: 0x%04x\n", + cont->object_version); + } + cont->title_len=BE_16(&data[10]); + cont->title=malloc(sizeof(char)*(cont->title_len+1)); + memcpy(cont->title, &data[12], cont->title_len); + cont->title[cont->title_len]=0; + pos=cont->title_len+12; + cont->author_len=BE_16(&data[pos]); + cont->author=malloc(sizeof(char)*(cont->author_len+1)); + memcpy(cont->author, &data[pos+2], cont->author_len); + cont->author[cont->author_len]=0; + pos=pos+2+cont->author_len; + cont->copyright_len=BE_16(&data[pos]); + cont->copyright=malloc(sizeof(char)*(cont->copyright_len+1)); + memcpy(cont->copyright, &data[pos+2], cont->copyright_len); + cont->copyright[cont->copyright_len]=0; + pos=pos+2+cont->copyright_len; + cont->comment_len=BE_16(&data[pos]); + cont->comment=malloc(sizeof(char)*(cont->comment_len+1)); + memcpy(cont->comment, &data[pos+2], cont->comment_len); + cont->comment[cont->comment_len]=0; + + return cont; +} + +static rmff_data_t *rmff_scan_dataheader(const char *data) { + + rmff_data_t *dh=malloc(sizeof(rmff_data_t)); + + dh->object_id=BE_32(data); + dh->size=BE_32(&data[4]); + dh->object_version=BE_16(&data[8]); + if (dh->object_version != 0) + { + printf("warning: unknown object version in DATA: 0x%04x\n", + dh->object_version); + } + dh->num_packets=BE_32(&data[10]); + dh->next_data_header=BE_32(&data[14]); + + return dh; +} + +rmff_header_t *rmff_scan_header(const char *data) { + + rmff_header_t *header=malloc(sizeof(rmff_header_t)); + rmff_mdpr_t *mdpr=NULL; + int chunk_size; + uint32_t chunk_type; + const char *ptr=data; + int i; + + header->fileheader=NULL; + header->prop=NULL; + header->cont=NULL; + header->data=NULL; + + chunk_type = BE_32(ptr); + if (chunk_type != RMF_TAG) + { + printf("rmff: not an real media file header (.RMF tag not found).\n"); + free(header); + return NULL; + } + header->fileheader=rmff_scan_fileheader(ptr); + ptr += header->fileheader->size; + + header->streams=malloc(sizeof(rmff_mdpr_t*)*(header->fileheader->num_headers)); + for (i=0; i<header->fileheader->num_headers; i++) { + header->streams[i]=NULL; + } + + for (i=1; i<header->fileheader->num_headers; i++) { + chunk_type = BE_32(ptr); + + if (ptr[0] == 0) + { + printf("rmff: warning: only %d of %d header found.\n", i, header->fileheader->num_headers); + break; + } + + chunk_size=1; + switch (chunk_type) { + case PROP_TAG: + header->prop=rmff_scan_prop(ptr); + chunk_size=header->prop->size; + break; + case MDPR_TAG: + mdpr=rmff_scan_mdpr(ptr); + chunk_size=mdpr->size; + header->streams[mdpr->stream_number]=mdpr; + break; + case CONT_TAG: + header->cont=rmff_scan_cont(ptr); + chunk_size=header->cont->size; + break; + case DATA_TAG: + header->data=rmff_scan_dataheader(ptr); + chunk_size=34; /* hard coded header size */ + break; + default: + printf("unknown chunk\n"); + hexdump(ptr,10); + chunk_size=1; + break; + } + ptr+=chunk_size; + } + + return header; +} + +rmff_header_t *rmff_scan_header_stream(int fd) { + + rmff_header_t *header; + char *buf=xbuffer_init(1024); + int index=0; + uint32_t chunk_type; + uint32_t chunk_size; + + do { + buf = xbuffer_ensure_size(buf, index+8); + read(fd, buf+index, 8); + chunk_type=BE_32(buf+index); index+=4; + chunk_size=BE_32(buf+index); index+=4; + + switch (chunk_type) { + case DATA_TAG: + chunk_size=18; + case MDPR_TAG: + case CONT_TAG: + case RMF_TAG: + case PROP_TAG: + buf = xbuffer_ensure_size(buf, index+chunk_size-8); + read(fd, buf+index, (chunk_size-8)); + index+=(chunk_size-8); + break; + default: + printf("rmff_scan_header_stream: unknown chunk"); + hexdump(buf+index-8, 8); + chunk_type=DATA_TAG; + } + } while (chunk_type != DATA_TAG); + + header = rmff_scan_header(buf); + + xbuffer_free(buf); + + return header; +} + +void rmff_scan_pheader(rmff_pheader_t *h, char *data) { + + h->object_version=BE_16(data); + h->length=BE_16(data+2); + h->stream_number=BE_16(data+4); + h->timestamp=BE_32(data+6); + h->reserved=(uint8_t)data[10]; + h->flags=(uint8_t)data[11]; +} + +rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers) { + + rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); + + fileheader->object_id=RMF_TAG; + fileheader->size=18; + fileheader->object_version=0; + fileheader->file_version=0; + fileheader->num_headers=num_headers; + + return fileheader; +} + +rmff_prop_t *rmff_new_prop ( + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t num_packets, + uint32_t duration, + uint32_t preroll, + uint32_t index_offset, + uint32_t data_offset, + uint16_t num_streams, + uint16_t flags ) { + + rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); + + prop->object_id=PROP_TAG; + prop->size=50; + prop->object_version=0; + + prop->max_bit_rate=max_bit_rate; + prop->avg_bit_rate=avg_bit_rate; + prop->max_packet_size=max_packet_size; + prop->avg_packet_size=avg_packet_size; + prop->num_packets=num_packets; + prop->duration=duration; + prop->preroll=preroll; + prop->index_offset=index_offset; + prop->data_offset=data_offset; + prop->num_streams=num_streams; + prop->flags=flags; + + return prop; +} + +rmff_mdpr_t *rmff_new_mdpr( + uint16_t stream_number, + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t start_time, + uint32_t preroll, + uint32_t duration, + const char *stream_name, + const char *mime_type, + uint32_t type_specific_len, + const char *type_specific_data ) { + + rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); + + mdpr->object_id=MDPR_TAG; + mdpr->object_version=0; + + mdpr->stream_number=stream_number; + mdpr->max_bit_rate=max_bit_rate; + mdpr->avg_bit_rate=avg_bit_rate; + mdpr->max_packet_size=max_packet_size; + mdpr->avg_packet_size=avg_packet_size; + mdpr->start_time=start_time; + mdpr->preroll=preroll; + mdpr->duration=duration; + mdpr->stream_name_size=0; + if (stream_name) { + mdpr->stream_name=strdup(stream_name); + mdpr->stream_name_size=strlen(stream_name); + } + mdpr->mime_type_size=0; + if (mime_type) { + mdpr->mime_type=strdup(mime_type); + mdpr->mime_type_size=strlen(mime_type); + } + mdpr->type_specific_len=type_specific_len; + mdpr->type_specific_data=malloc(sizeof(char)*type_specific_len); + memcpy(mdpr->type_specific_data,type_specific_data,type_specific_len); + mdpr->mlti_data=NULL; + + mdpr->size=mdpr->stream_name_size+mdpr->mime_type_size+mdpr->type_specific_len+46; + + return mdpr; +} + +rmff_cont_t *rmff_new_cont(const char *title, const char *author, const char *copyright, const char *comment) { + + rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); + + cont->object_id=CONT_TAG; + cont->object_version=0; + + cont->title=NULL; + cont->author=NULL; + cont->copyright=NULL; + cont->comment=NULL; + + cont->title_len=0; + cont->author_len=0; + cont->copyright_len=0; + cont->comment_len=0; + + if (title) { + cont->title_len=strlen(title); + cont->title=strdup(title); + } + if (author) { + cont->author_len=strlen(author); + cont->author=strdup(author); + } + if (copyright) { + cont->copyright_len=strlen(copyright); + cont->copyright=strdup(copyright); + } + if (comment) { + cont->comment_len=strlen(comment); + cont->comment=strdup(comment); + } + cont->size=cont->title_len+cont->author_len+cont->copyright_len+cont->comment_len+18; + + return cont; +} + +rmff_data_t *rmff_new_dataheader(uint32_t num_packets, uint32_t next_data_header) { + + rmff_data_t *data=malloc(sizeof(rmff_data_t)); + + data->object_id=DATA_TAG; + data->size=18; + data->object_version=0; + data->num_packets=num_packets; + data->next_data_header=next_data_header; + + return data; +} + +void rmff_print_header(rmff_header_t *h) { + + rmff_mdpr_t **stream; + + if(!h) { + printf("rmff_print_header: NULL given\n"); + return; + } + if(h->fileheader) + { + printf("\nFILE:\n"); + printf("file version : %d\n", h->fileheader->file_version); + printf("number of headers : %d\n", h->fileheader->num_headers); + } + if(h->cont) + { + printf("\nCONTENT:\n"); + printf("title : %s\n", h->cont->title); + printf("author : %s\n", h->cont->author); + printf("copyright : %s\n", h->cont->copyright); + printf("comment : %s\n", h->cont->comment); + } + if(h->prop) + { + printf("\nSTREAM PROPERTIES:\n"); + printf("bit rate (max/avg) : %i/%i\n", h->prop->max_bit_rate, h->prop->avg_bit_rate); + printf("packet size (max/avg) : %i/%i bytes\n", h->prop->max_packet_size, h->prop->avg_packet_size); + printf("packets : %i\n", h->prop->num_packets); + printf("duration : %i ms\n", h->prop->duration); + printf("pre-buffer : %i ms\n", h->prop->preroll); + printf("index offset : %i bytes\n", h->prop->index_offset); + printf("data offset : %i bytes\n", h->prop->data_offset); + printf("media streams : %i\n", h->prop->num_streams); + printf("flags : "); + if (h->prop->flags & PN_SAVE_ENABLED) printf("save_enabled "); + if (h->prop->flags & PN_PERFECT_PLAY_ENABLED) printf("perfect_play_enabled "); + if (h->prop->flags & PN_LIVE_BROADCAST) printf("live_broadcast "); + printf("\n"); + } + stream=h->streams; + if(stream) + { + while (*stream) + { + printf("\nSTREAM %i:\n", (*stream)->stream_number); + printf("stream name [mime type] : %s [%s]\n", (*stream)->stream_name, (*stream)->mime_type); + printf("bit rate (max/avg) : %i/%i\n", (*stream)->max_bit_rate, (*stream)->avg_bit_rate); + printf("packet size (max/avg) : %i/%i bytes\n", (*stream)->max_packet_size, (*stream)->avg_packet_size); + printf("start time : %i\n", (*stream)->start_time); + printf("pre-buffer : %i ms\n", (*stream)->preroll); + printf("duration : %i ms\n", (*stream)->duration); + printf("type specific data:\n"); + hexdump((*stream)->type_specific_data, (*stream)->type_specific_len); + stream++; + } + } + if(h->data) + { + printf("\nDATA:\n"); + printf("size : %i\n", h->data->size); + printf("packets : %i\n", h->data->num_packets); + printf("next DATA : 0x%08x\n", h->data->next_data_header); + } +} + +void rmff_fix_header(rmff_header_t *h) { + + int num_headers=0; + int header_size=0; + rmff_mdpr_t **streams; + int num_streams=0; + + if (!h) { + printf("rmff_fix_header: fatal: no header given.\n"); + return; + } + + if (!h->streams) { + printf("rmff_fix_header: warning: no MDPR chunks\n"); + } else + { + streams=h->streams; + while (*streams) + { + num_streams++; + num_headers++; + header_size+=(*streams)->size; + streams++; + } + } + + if (h->prop) { + if (h->prop->size != 50) + { +#ifdef LOG + printf("rmff_fix_header: correcting prop.size from %i to %i\n", h->prop->size, 50); +#endif + h->prop->size=50; + } + if (h->prop->num_streams != num_streams) + { +#ifdef LOG + printf("rmff_fix_header: correcting prop.num_streams from %i to %i\n", h->prop->num_streams, num_streams); +#endif + h->prop->num_streams=num_streams; + } + num_headers++; + header_size+=50; + } else + printf("rmff_fix_header: warning: no PROP chunk.\n"); + + if (h->cont) { + num_headers++; + header_size+=h->cont->size; + } else + printf("rmff_fix_header: warning: no CONT chunk.\n"); + + if (!h->data) { +#ifdef LOG + printf("rmff_fix_header: no DATA chunk, creating one\n"); +#endif + h->data=malloc(sizeof(rmff_data_t)); + h->data->object_id=DATA_TAG; + h->data->object_version=0; + h->data->size=34; + h->data->num_packets=0; + h->data->next_data_header=0; + } + num_headers++; + + + if (!h->fileheader) { +#ifdef LOG + printf("rmff_fix_header: no fileheader, creating one"); +#endif + h->fileheader=malloc(sizeof(rmff_fileheader_t)); + h->fileheader->object_id=RMF_TAG; + h->fileheader->size=34; + h->fileheader->object_version=0; + h->fileheader->file_version=0; + h->fileheader->num_headers=num_headers+1; + } + header_size+=h->fileheader->size; + num_headers++; + + if(h->fileheader->num_headers != num_headers) { +#ifdef LOG + printf("rmff_fix_header: setting num_headers from %i to %i\n", h->fileheader->num_headers, num_headers); +#endif + h->fileheader->num_headers=num_headers; + } + + if(h->prop) { + if (h->prop->data_offset != header_size) { +#ifdef LOG + printf("rmff_fix_header: setting prop.data_offset from %i to %i\n", h->prop->data_offset, header_size); +#endif + h->prop->data_offset=header_size; + } + if (h->prop->num_packets == 0) { + int p=(int)(h->prop->avg_bit_rate/8.0*(h->prop->duration/1000.0)/h->prop->avg_packet_size); +#ifdef LOG + printf("rmff_fix_header: assuming prop.num_packets=%i\n", p); +#endif + h->prop->num_packets=p; + } + if (h->data->num_packets == 0) { +#ifdef LOG + printf("rmff_fix_header: assuming data.num_packets=%i\n", h->prop->num_packets); +#endif + h->data->num_packets=h->prop->num_packets; + } + +#ifdef LOG + printf("rmff_fix_header: assuming data.size=%i\n", h->prop->num_packets*h->prop->avg_packet_size); +#endif + h->data->size=h->prop->num_packets*h->prop->avg_packet_size; + } +} + +int rmff_get_header_size(rmff_header_t *h) { + + if (!h) return 0; + if (!h->prop) return -1; + + return h->prop->data_offset+18; + +} + +void rmff_free_header(rmff_header_t *h) { + + if (!h) return; + + if (h->fileheader) free(h->fileheader); + if (h->prop) free(h->prop); + if (h->data) free(h->data); + if (h->cont) + { + free(h->cont->title); + free(h->cont->author); + free(h->cont->copyright); + free(h->cont->comment); + free(h->cont); + } + if (h->streams) + { + rmff_mdpr_t **s=h->streams; + + while(*s) { + free((*s)->stream_name); + free((*s)->mime_type); + free((*s)->type_specific_data); + free(*s); + s++; + } + free(h->streams); + } + free(h); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rmff.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,270 @@ +/* + * This file was ported to MPlayer from xine CVS rmff.h,v 1.3 2003/02/10 22:11:10 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * some functions for real media file headers + * adopted from joschkas real tools + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> + + +#ifndef HAVE_RMFF_H +#define HAVE_RMFF_H + + +#define RMFF_HEADER_SIZE 0x12 + +#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ + (((long)(unsigned char)(ch3) ) | \ + ( (long)(unsigned char)(ch2) << 8 ) | \ + ( (long)(unsigned char)(ch1) << 16 ) | \ + ( (long)(unsigned char)(ch0) << 24 ) ) + + +#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') +#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') +#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') +#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') +#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') +#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') +#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) + +#define MLTI_TAG FOURCC_TAG('M', 'L', 'T', 'I') + +/* prop flags */ +#define PN_SAVE_ENABLED 0x01 +#define PN_PERFECT_PLAY_ENABLED 0x02 +#define PN_LIVE_BROADCAST 0x04 + +#ifdef __CYGWIN__ +#define uint32_t unsigned int +#define uint16_t unsigned short int +#define uint8_t unsigned char +#endif + +/* + * rm header data structs + */ + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t file_version; + uint32_t num_headers; +} rmff_fileheader_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t max_bit_rate; + uint32_t avg_bit_rate; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t num_packets; + uint32_t duration; + uint32_t preroll; + uint32_t index_offset; + uint32_t data_offset; + uint16_t num_streams; + uint16_t flags; + +} rmff_prop_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint16_t stream_number; + uint32_t max_bit_rate; + uint32_t avg_bit_rate; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t start_time; + uint32_t preroll; + uint32_t duration; + uint8_t stream_name_size; + char *stream_name; + uint8_t mime_type_size; + char *mime_type; + uint32_t type_specific_len; + char *type_specific_data; + + int mlti_data_size; + char *mlti_data; + +} rmff_mdpr_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint16_t title_len; + char *title; + uint16_t author_len; + char *author; + uint16_t copyright_len; + char *copyright; + uint16_t comment_len; + char *comment; + +} rmff_cont_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t num_packets; + uint32_t next_data_header; /* rarely used */ +} rmff_data_t; + +typedef struct { + + rmff_fileheader_t *fileheader; + rmff_prop_t *prop; + rmff_mdpr_t **streams; + rmff_cont_t *cont; + rmff_data_t *data; +} rmff_header_t; + +typedef struct { + + uint16_t object_version; + + uint16_t length; + uint16_t stream_number; + uint32_t timestamp; + uint8_t reserved; + uint8_t flags; + +} rmff_pheader_t; + +/* + * constructors for header structs + */ + +rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers); + +rmff_prop_t *rmff_new_prop ( + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t num_packets, + uint32_t duration, + uint32_t preroll, + uint32_t index_offset, + uint32_t data_offset, + uint16_t num_streams, + uint16_t flags ); + +rmff_mdpr_t *rmff_new_mdpr( + uint16_t stream_number, + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t start_time, + uint32_t preroll, + uint32_t duration, + const char *stream_name, + const char *mime_type, + uint32_t type_specific_len, + const char *type_specific_data ); + +rmff_cont_t *rmff_new_cont( + const char *title, + const char *author, + const char *copyright, + const char *comment); + +rmff_data_t *rmff_new_dataheader( + uint32_t num_packets, uint32_t next_data_header); + +/* + * reads header infos from data and returns a newly allocated header struct + */ +rmff_header_t *rmff_scan_header(const char *data); + +/* + * scans a data packet header. Notice, that this function does not allocate + * the header struct itself. + */ +void rmff_scan_pheader(rmff_pheader_t *h, char *data); + +/* + * reads header infos from stream and returns a newly allocated header struct + */ +rmff_header_t *rmff_scan_header_stream(int fd); + +/* + * prints header information in human readible form to stdout + */ +void rmff_print_header(rmff_header_t *h); + +/* + * does some checks and fixes header if possible + */ +void rmff_fix_header(rmff_header_t *h); + +/* + * returns the size of the header (incl. first data-header) + */ +int rmff_get_header_size(rmff_header_t *h); + +/* + * dumps the header <h> to <buffer>. <max> is the size of <buffer> + */ +int rmff_dump_header(rmff_header_t *h, char *buffer, int max); + +/* + * dumps a packet header + */ +void rmff_dump_pheader(rmff_pheader_t *h, char *data); + +/* + * frees a header struct + */ +void rmff_free_header(rmff_header_t *h); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rtsp.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,774 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp.c,v 1.9 2003/04/10 02:30:48 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * a minimalistic implementation of rtsp protocol, + * *not* RFC 2326 compilant yet. + */ + +#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "rtsp.h" + +/* +#define LOG +*/ + +#define BUF_SIZE 4096 +#define HEADER_SIZE 1024 +#define MAX_FIELDS 256 + +struct rtsp_s { + + int s; + + char *host; + int port; + char *path; + char *mrl; + char *user_agent; + + char *server; + unsigned int server_state; + uint32_t server_caps; + + char buffer[BUF_SIZE]; /* scratch buffer */ + + unsigned int cseq; + char *session; + + char *answers[MAX_FIELDS]; /* data of last message */ + char *scheduled[MAX_FIELDS]; /* will be sent with next message */ +}; + +/* + * constants + */ + +const char rtsp_protocol_version[]="RTSP/1.0"; + +/* server states */ +#define RTSP_CONNECTED 1 +#define RTSP_INIT 2 +#define RTSP_READY 4 +#define RTSP_PLAYING 8 +#define RTSP_RECORDING 16 + +/* server capabilities */ +#define RTSP_OPTIONS 0x001 +#define RTSP_DESCRIBE 0x002 +#define RTSP_ANNOUNCE 0x004 +#define RTSP_SETUP 0x008 +#define RTSP_GET_PARAMETER 0x010 +#define RTSP_SET_PARAMETER 0x020 +#define RTSP_TEARDOWN 0x040 +#define RTSP_PLAY 0x080 +#define RTSP_RECORD 0x100 + +/* + * network utilities + */ + +static int host_connect_attempt(struct in_addr ia, int port) { + + int s; + struct sockaddr_in sin; + + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s == -1) { + printf ("rtsp: socket(): %s\n", strerror(errno)); + return -1; + } + + sin.sin_family = AF_INET; + sin.sin_addr = ia; + sin.sin_port = htons(port); + + if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 + && errno != EINPROGRESS) { + printf ("rtsp: connect(): %s\n", strerror(errno)); + close(s); + return -1; + } + + return s; +} + +static int host_connect(const char *host, int port) { + + struct hostent *h; + int i, s; + + h = gethostbyname(host); + if (h == NULL) { + printf ("rtsp: unable to resolve '%s'.\n", host); + return -1; + } + + for (i = 0; h->h_addr_list[i]; i++) { + struct in_addr ia; + + memcpy (&ia, h->h_addr_list[i], 4); + s = host_connect_attempt(ia, port); + if(s != -1) + return s; + } + printf ("rtsp: unable to connect to '%s'.\n", host); + return -1; +} + +static int write_stream(int s, const char *buf, int len) { + int total, timeout; + + total = 0; timeout = 30; + while (total < len){ + int n; + + n = write (s, &buf[total], len - total); + + if (n > 0) + total += n; + else if (n < 0) { + if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { + sleep (1); timeout--; + } else + return -1; + } + } + + return total; +} + +static ssize_t read_stream(int fd, void *buf, size_t count) { + + ssize_t ret, total; + + total = 0; + + while (total < count) { + + ret=read (fd, ((uint8_t*)buf)+total, count-total); + + if (ret<0) { + if(errno == EAGAIN) { + fd_set rset; + struct timeval timeout; + + FD_ZERO (&rset); + FD_SET (fd, &rset); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { + return -1; + } + continue; + } + + printf ("rtsp: read error.\n"); + return ret; + } else + total += ret; + + /* end of stream */ + if (!ret) break; + } + + return total; +} + +/* + * debugging utilities + */ +#if 0 +static void hexdump (char *buf, int length) { + + int i; + + printf ("rtsp: ascii>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + printf ("%c", c); + else + printf ("."); + } + printf ("\n"); + + printf ("rtsp: hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\nrtsp: "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} +#endif + +/* + * rtsp_get gets a line from stream + * and returns a null terminated string. + */ + +static char *rtsp_get(rtsp_t *s) { + + int n=0; + char *string; + + while (n<BUF_SIZE) { + read_stream(s->s, &s->buffer[n], 1); + if ((s->buffer[n-1]==0x0d)&&(s->buffer[n]==0x0a)) break; + n++; + } + + if (n>=BUF_SIZE) { + printf("librtsp: buffer overflow in rtsp_get\n"); + exit(1); + } + string=malloc(sizeof(char)*n); + memcpy(string,s->buffer,n-1); + string[n-1]=0; + +#ifdef LOG + printf("librtsp: << '%s'\n", string); +#endif + + + return string; +} + +/* + * rtsp_put puts a line on stream + */ + +static void rtsp_put(rtsp_t *s, const char *string) { + + int len=strlen(string); + char *buf=malloc(sizeof(char)*len+2); + +#ifdef LOG + printf("librtsp: >> '%s'", string); +#endif + + memcpy(buf,string,len); + buf[len]=0x0d; + buf[len+1]=0x0a; + + write_stream(s->s, buf, len+2); + +#ifdef LOG + printf(" done.\n"); +#endif + + free(buf); +} + +/* + * extract server status code + */ + +static int rtsp_get_code(const char *string) { + + char buf[4]; + int code=0; + + if (!strncmp(string, rtsp_protocol_version, strlen(rtsp_protocol_version))) + { + memcpy(buf, string+strlen(rtsp_protocol_version)+1, 3); + buf[3]=0; + code=atoi(buf); + } else if (!strncmp(string, "SET_PARAMETER",8)) + { + return RTSP_STATUS_SET_PARAMETER; + } + + if(code != 200) printf("librtsp: server responds: '%s'\n",string); + + return code; +} + +/* + * send a request + */ + +static void rtsp_send_request(rtsp_t *s, const char *type, const char *what) { + + char **payload=s->scheduled; + sprintf(s->buffer,"%s %s %s",type, what, rtsp_protocol_version); + rtsp_put(s,s->buffer); + if (payload) + while (*payload) { + rtsp_put(s,*payload); + payload++; + } + rtsp_put(s,""); + rtsp_unschedule_all(s); +} + +/* + * schedule standard fields + */ + +static void rtsp_schedule_standard(rtsp_t *s) { + + sprintf(s->buffer, "Cseq: %u", s->cseq); + rtsp_schedule_field(s, s->buffer); + if (s->session) { + sprintf(s->buffer, "Session: %s", s->session); + rtsp_schedule_field(s, s->buffer); + } +} +/* + * get the answers, if server responses with something != 200, return NULL + */ + +static int rtsp_get_answers(rtsp_t *s) { + + char *answer=NULL; + unsigned int answer_seq; + char **answer_ptr=s->answers; + int code; + + answer=rtsp_get(s); + code=rtsp_get_code(answer); + free(answer); + + rtsp_free_answers(s); + + do { /* while we get answer lines */ + + answer=rtsp_get(s); + + if (!strncmp(answer,"Cseq:",5)) { + sscanf(answer,"Cseq: %u",&answer_seq); + if (s->cseq != answer_seq) { +#ifdef LOG + printf("librtsp: warning: Cseq mismatch. got %u, assumed %u", answer_seq, s->cseq); +#endif + s->cseq=answer_seq; + } + } + if (!strncmp(answer,"Server:",7)) { + sscanf(answer,"Server: %s",s->buffer); + if (s->server) free(s->server); + s->server=strdup(s->buffer); + } + if (!strncmp(answer,"Session:",8)) { + memset(s->buffer,0, BUF_SIZE); + sscanf(answer,"Session: %s",s->buffer); + if (s->session) { + if (strcmp(s->buffer, s->session)) { + printf("rtsp: warning: setting NEW session: %s\n", s->buffer); + free(s->session); + s->session=strdup(s->buffer); + } + } else + { +#ifdef LOG + printf("rtsp: setting session id to: %s\n", s->buffer); +#endif + s->session=strdup(s->buffer); + } + } + *answer_ptr=answer; + answer_ptr++; + } while (strlen(answer)!=0); + + s->cseq++; + + *answer_ptr=NULL; + rtsp_schedule_standard(s); + + return code; +} + +/* + * send an ok message + */ + +int rtsp_send_ok(rtsp_t *s) { + char cseq[16]; + + rtsp_put(s, "RTSP/1.0 200 OK"); + sprintf(cseq,"CSeq: %u", s->cseq); + rtsp_put(s, cseq); + rtsp_put(s, ""); + return 0; +} + +/* + * implementation of must-have rtsp requests; functions return + * server status code. + */ + +int rtsp_request_options(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(sizeof(char)*(strlen(s->host)+16)); + sprintf(buf,"rtsp://%s:%i", s->host, s->port); + } + rtsp_send_request(s,"OPTIONS",buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_describe(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,"DESCRIBE",buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_setup(rtsp_t *s, const char *what) { + + rtsp_send_request(s,"SETUP",what); + + return rtsp_get_answers(s); +} + +int rtsp_request_setparameter(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,"SET_PARAMETER",buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_play(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(sizeof(char)*(strlen(s->host)+strlen(s->path)+16)); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,"PLAY",buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_tearoff(rtsp_t *s, const char *what) { + + rtsp_send_request(s,"TEAROFF",what); + + return rtsp_get_answers(s); +} + +/* + * read opaque data from stream + */ + +int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size) { + + int i,seq; + + if (size>=4) { + i=read_stream(s->s, buffer, 4); + if (i<4) return i; + if ((buffer[0]=='S')&&(buffer[1]=='E')&&(buffer[2]=='T')&&(buffer[3]=='_')) + { + char *rest=rtsp_get(s); + /* a real server wanna play table tennis? */ + memcpy(s->buffer, buffer, 4); + strcpy(s->buffer+4, rest); + seq=-1; + do { + free(rest); + rest=rtsp_get(s); + if (!strncmp(rest,"Cseq:",5)) + sscanf(rest,"Cseq: %u",&seq); + } while (strlen(rest)!=0); + free(rest); + if (seq<0) { +#ifdef LOG + printf("rtsp: warning: cseq not recognized!\n"); +#endif + seq=1; + } + /* lets make the server happy */ + rtsp_put(s, "RTSP/1.0 451 Parameter Not Understood"); + rest=malloc(sizeof(char)*16); + sprintf(rest,"CSeq: %u", seq); + rtsp_put(s, rest); + rtsp_put(s, ""); + i=read_stream(s->s, buffer, size); + } else + { + i=read_stream(s->s, buffer+4, size-4); + i+=4; + } + } else + i=read_stream(s->s, buffer, size); +#ifdef LOG + printf("librtsp: << %d of %d bytes\n", i, size); +#endif + + return i; +} + +/* + * connect to a rtsp server + */ + +//rtsp_t *rtsp_connect(const char *mrl, const char *user_agent) { +rtsp_t *rtsp_connect(int fd, char* mrl, char *path, char *host, int port, char *user_agent) { + + rtsp_t *s=malloc(sizeof(rtsp_t)); + int i; + + for (i=0; i<MAX_FIELDS; i++) { + s->answers[i]=NULL; + s->scheduled[i]=NULL; + } + + s->server=NULL; + s->server_state=0; + s->server_caps=0; + + s->cseq=0; + s->session=NULL; + + if (user_agent) + s->user_agent=strdup(user_agent); + else + s->user_agent=strdup("User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)"); + + s->mrl = strdup(mrl); + s->host = strdup(host); + s->port = port; + s->path = strdup(path); + s->s = fd; + + if (s->s < 0) { + printf ("rtsp: failed to connect to '%s'\n", s->host); + rtsp_close(s); + return NULL; + } + + s->server_state=RTSP_CONNECTED; + + /* now lets send an options request. */ + rtsp_schedule_field(s, "CSeq: 1"); + rtsp_schedule_field(s, s->user_agent); + rtsp_schedule_field(s, "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7"); + rtsp_schedule_field(s, "PlayerStarttime: [28/03/2003:22:50:23 00:00]"); + rtsp_schedule_field(s, "CompanyID: KnKV4M4I/B2FjJ1TToLycw=="); + rtsp_schedule_field(s, "GUID: 00000000-0000-0000-0000-000000000000"); + rtsp_schedule_field(s, "RegionData: 0"); + rtsp_schedule_field(s, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); + /*rtsp_schedule_field(s, "Pragma: initiate-session");*/ + rtsp_request_options(s, NULL); + + return s; +} + + +/* + * closes an rtsp connection + */ + +void rtsp_close(rtsp_t *s) { + + if (s->server_state) close(s->s); /* TODO: send a TEAROFF */ + if (s->path) free(s->path); + if (s->host) free(s->host); + if (s->mrl) free(s->mrl); + if (s->session) free(s->session); + if (s->user_agent) free(s->user_agent); + rtsp_free_answers(s); + rtsp_unschedule_all(s); + free(s); +} + +/* + * search in answers for tags. returns a pointer to the content + * after the first matched tag. returns NULL if no match found. + */ + +char *rtsp_search_answers(rtsp_t *s, const char *tag) { + + char **answer; + char *ptr; + + if (!s->answers) return NULL; + answer=s->answers; + + while (*answer) { + if (!strncasecmp(*answer,tag,strlen(tag))) { + ptr=strchr(*answer,':'); + ptr++; + while(*ptr==' ') ptr++; + return ptr; + } + answer++; + } + + return NULL; +} + +/* + * session id management + */ + +void rtsp_set_session(rtsp_t *s, const char *id) { + + if (s->session) free(s->session); + + s->session=strdup(id); + +} + +char *rtsp_get_session(rtsp_t *s) { + + return s->session; + +} + +char *rtsp_get_mrl(rtsp_t *s) { + + return s->mrl; + +} + +/* + * schedules a field for transmission + */ + +void rtsp_schedule_field(rtsp_t *s, const char *string) { + + int i=0; + + if (!string) return; + + while(s->scheduled[i]) { + i++; + } + s->scheduled[i]=strdup(string); +} + +/* + * removes the first scheduled field which prefix matches string. + */ + +void rtsp_unschedule_field(rtsp_t *s, const char *string) { + + char **ptr=s->scheduled; + + if (!string) return; + + while(*ptr) { + if (!strncmp(*ptr, string, strlen(string))) + break; + } + if (*ptr) free(*ptr); + ptr++; + do { + *(ptr-1)=*ptr; + } while(*ptr); +} + +/* + * unschedule all fields + */ + +void rtsp_unschedule_all(rtsp_t *s) { + + char **ptr; + + if (!s->scheduled) return; + ptr=s->scheduled; + + while (*ptr) { + free(*ptr); + *ptr=NULL; + ptr++; + } +} +/* + * free answers + */ + +void rtsp_free_answers(rtsp_t *s) { + + char **answer; + + if (!s->answers) return; + answer=s->answers; + + while (*answer) { + free(*answer); + *answer=NULL; + answer++; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rtsp.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,79 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp.h,v 1.2 2002/12/16 21:50:55 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * a minimalistic implementation of rtsp protocol, + * *not* RFC 2326 compilant yet. + */ + +#ifndef HAVE_RTSP_H +#define HAVE_RTSP_H + + +#ifdef __CYGWIN__ +#define uint32_t unsigned int +#define uint16_t unsigned short int +#define uint8_t unsigned char +#endif + +/* some codes returned by rtsp_request_* functions */ + +#define RTSP_STATUS_SET_PARAMETER 10 +#define RTSP_STATUS_OK 200 + +typedef struct rtsp_s rtsp_t; + +rtsp_t* rtsp_connect (int fd, char *mrl, char *path, char *host, int port, char *user_agent); + +int rtsp_request_options(rtsp_t *s, const char *what); +int rtsp_request_describe(rtsp_t *s, const char *what); +int rtsp_request_setup(rtsp_t *s, const char *what); +int rtsp_request_setparameter(rtsp_t *s, const char *what); +int rtsp_request_play(rtsp_t *s, const char *what); +int rtsp_request_tearoff(rtsp_t *s, const char *what); + +int rtsp_send_ok(rtsp_t *s); + +int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size); + +char* rtsp_search_answers(rtsp_t *s, const char *tag); +void rtsp_add_to_payload(char **payload, const char *string); + +void rtsp_free_answers(rtsp_t *this); + +int rtsp_read (rtsp_t *this, char *data, int len); +void rtsp_close (rtsp_t *this); + +void rtsp_set_session(rtsp_t *s, const char *id); +char *rtsp_get_session(rtsp_t *s); + +char *rtsp_get_mrl(rtsp_t *s); + +/*int rtsp_peek_header (rtsp_t *this, char *data); */ + +void rtsp_schedule_field(rtsp_t *s, const char *string); +void rtsp_unschedule_field(rtsp_t *s, const char *string); +void rtsp_unschedule_all(rtsp_t *s); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rtsp_session.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,190 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp_session.c,v 1.9 2003/02/11 16:20:40 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * high level interface to rtsp servers. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> + +#include "rtsp.h" +#include "rtsp_session.h" +#include "real.h" +#include "rmff.h" +#include "asmrp.h" + +/* +#define LOG +*/ + +#define BUF_SIZE 4096 +#define HEADER_SIZE 4096 + +struct rtsp_session_s { + + rtsp_t *s; + + /* receive buffer */ + uint8_t recv[BUF_SIZE]; + int recv_size; + int recv_read; + + /* header buffer */ + uint8_t header[HEADER_SIZE]; + int header_len; + int header_read; + +}; + +//rtsp_session_t *rtsp_session_start(char *mrl) { +rtsp_session_t *rtsp_session_start(int fd, char *mrl, char *path, char *host, int port) { + + rtsp_session_t *rtsp_session=malloc(sizeof(rtsp_session_t)); + char *server; + char *mrl_line = NULL; + rmff_header_t *h; + uint32_t bandwidth=10485800; + +connect: + + /* connect to server */ + rtsp_session->s=rtsp_connect(fd,mrl,path,host,port,NULL); + if (!rtsp_session->s) + { + printf("rtsp_session: failed to connect to server %s\n", path); + free(rtsp_session); + return NULL; + } + + /* looking for server type */ + if (rtsp_search_answers(rtsp_session->s,"Server")) + server=strdup(rtsp_search_answers(rtsp_session->s,"Server")); + else { + if (rtsp_search_answers(rtsp_session->s,"RealChallenge1")) + server=strdup("Real"); + else + server=strdup("unknown"); + } + if (strstr(server,"Real")) + { + /* we are talking to a real server ... */ + + h=real_setup_and_get_header(rtsp_session->s, bandwidth); + if (!h) { + /* got an redirect? */ + if (rtsp_search_answers(rtsp_session->s, "Location")) + { + free(mrl_line); + mrl_line=strdup(rtsp_search_answers(rtsp_session->s, "Location")); + printf("rtsp_session: redirected to %s\n", mrl_line); + rtsp_close(rtsp_session->s); + free(server); + /* FIXME: this won't work in MPlayer, connection opened by caller */ + goto connect; /* *shudder* i made a design mistake somewhere */ + } else + { + printf("rtsp_session: session can not be established.\n"); + rtsp_close(rtsp_session->s); + free(rtsp_session); + return NULL; + } + } + + rtsp_session->header_len=rmff_dump_header(h,rtsp_session->header,1024); + + memcpy(rtsp_session->recv, rtsp_session->header, rtsp_session->header_len); + rtsp_session->recv_size = rtsp_session->header_len; + rtsp_session->recv_read = 0; + + } else + { + printf("rtsp_session: rtsp server type is '%s' instead of Real. Please report.\n",server); + rtsp_close(rtsp_session->s); + free(server); + free(rtsp_session); + return NULL; + } + free(server); + + return rtsp_session; +} + +int rtsp_session_read (rtsp_session_t *this, char *data, int len) { + + int to_copy=len; + char *dest=data; + char *source=this->recv + this->recv_read; + int fill=this->recv_size - this->recv_read; + + if (len < 0) return 0; + while (to_copy > fill) { + + memcpy(dest, source, fill); + to_copy -= fill; + dest += fill; + this->recv_read = 0; + source = this->recv; + this->recv_size = real_get_rdt_chunk (this->s, source); + fill = this->recv_size; + + if (this->recv_size == 0) { +#ifdef LOG + printf ("librtsp: %d of %d bytes provided\n", len-to_copy, len); +#endif + return len-to_copy; + } + } + + memcpy(dest, source, to_copy); + this->recv_read += to_copy; + +#ifdef LOG + printf ("librtsp: %d bytes provided\n", len); +#endif + + return len; +} + +int rtsp_session_peek_header(rtsp_session_t *this, char *buf, int maxsize) { + + int len; + + len = (this->header_len < maxsize) ? this->header_len : maxsize; + + memcpy(buf, this->header, len); + return len; +} + +void rtsp_session_end(rtsp_session_t *session) { + + rtsp_close(session->s); + free(session); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/rtsp_session.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,41 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp_session.h,v 1.4 2003/01/31 14:06:18 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * high level interface to rtsp servers. + */ + +#ifndef HAVE_RTSP_SESSION_H +#define HAVE_RTSP_SESSION_H + +typedef struct rtsp_session_s rtsp_session_t; + +rtsp_session_t *rtsp_session_start(int fd, char *mrl, char *path, char *host, int port); + +int rtsp_session_read(rtsp_session_t *session, char *data, int len); + +int rtsp_session_peek_header(rtsp_session_t *this, char *buf, int maxsize); + +void rtsp_session_end(rtsp_session_t *session); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/sdpplin.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,315 @@ +/* + * This file was ported to MPlayer from xine CVS sdpplin.c,v 1.1 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * sdp/sdpplin parser. + * + */ + +#include "rmff.h" +#include "rtsp.h" +#include "sdpplin.h" +#include "xbuffer.h" + +/* +#define LOG +*/ + +/* + * Decodes base64 strings (based upon b64 package) + */ + +static char *b64_decode(const char *in, char *out, int *size) +{ + char dtable[256]; /* Encode / decode table */ + int i,j,k; + + for (i = 0; i < 255; i++) { + dtable[i] = 0x80; + } + for (i = 'A'; i <= 'Z'; i++) { + dtable[i] = 0 + (i - 'A'); + } + for (i = 'a'; i <= 'z'; i++) { + dtable[i] = 26 + (i - 'a'); + } + for (i = '0'; i <= '9'; i++) { + dtable[i] = 52 + (i - '0'); + } + dtable['+'] = 62; + dtable['/'] = 63; + dtable['='] = 0; + + k=0; + + /*CONSTANTCONDITION*/ + for (j=0; j<strlen(in); j+=4) + { + char a[4], b[4]; + + for (i = 0; i < 4; i++) { + int c = in[i+j]; + + if (dtable[c] & 0x80) { + printf("Illegal character '%c' in input.\n", c); +// exit(1); + return NULL; + } + a[i] = (char) c; + b[i] = (char) dtable[c]; + } + out = xbuffer_ensure_size(out, k+3); + out[k++] = (b[0] << 2) | (b[1] >> 4); + out[k++] = (b[1] << 4) | (b[2] >> 2); + out[k++] = (b[2] << 6) | b[3]; + i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); + if (i < 3) { + out[k]=0; + *size=k; + return out; + } + } + out[k]=0; + *size=k; + return out; +} + +static char *nl(char *data) { + + return strchr(data,'\n')+1; +} + +static int filter(const char *in, const char *filter, char **out) { + + int flen=strlen(filter); + int len=strchr(in,'\n')-in; + + if (!strncmp(in,filter,flen)) + { + if(in[flen]=='"') flen++; + if(in[len-1]==13) len--; + if(in[len-1]=='"') len--; + *out = xbuffer_copyin(*out, 0, in+flen, len-flen+1); + (*out)[len-flen]=0; + + return len-flen; + } + + return 0; +} +static sdpplin_stream_t *sdpplin_parse_stream(char **data) { + + sdpplin_stream_t *desc=calloc(1,sizeof(sdpplin_stream_t)); + char *buf=xbuffer_init(32); + char *decoded=xbuffer_init(32); + int handled; + + if (filter(*data, "m=", &buf)) { + desc->id = strdup(buf); + } else + { + printf("sdpplin: no m= found.\n"); + free(desc); + xbuffer_free(buf); + return NULL; + } + *data=nl(*data); + + while (**data && *data[0]!='m') { + + handled=0; + + if(filter(*data,"a=control:streamid=",&buf)) { + desc->stream_id=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=MaxBitRate:integer;",&buf)) { + desc->max_bit_rate=atoi(buf); + if (!desc->avg_bit_rate) + desc->avg_bit_rate=desc->max_bit_rate; + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=MaxPacketSize:integer;",&buf)) { + desc->max_packet_size=atoi(buf); + if (!desc->avg_packet_size) + desc->avg_packet_size=desc->max_packet_size; + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=StartTime:integer;",&buf)) { + desc->start_time=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=Preroll:integer;",&buf)) { + desc->preroll=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=length:npt=",&buf)) { + desc->duration=(uint32_t)(atof(buf)*1000); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=StreamName:string;",&buf)) { + desc->stream_name=strdup(buf); + desc->stream_name_size=strlen(desc->stream_name); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=mimetype:string;",&buf)) { + desc->mime_type=strdup(buf); + desc->mime_type_size=strlen(desc->mime_type); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=OpaqueData:buffer;",&buf)) { + decoded = b64_decode(buf, decoded, &(desc->mlti_data_size)); + desc->mlti_data=malloc(sizeof(char)*desc->mlti_data_size); + memcpy(desc->mlti_data, decoded, desc->mlti_data_size); + handled=1; + *data=nl(*data); +#ifdef LOG + printf("mlti_data_size: %i\n", desc->mlti_data_size); +#endif + } + + if(filter(*data,"a=ASMRuleBook:string;",&buf)) { + desc->asm_rule_book=strdup(buf); + handled=1; + *data=nl(*data); + } + + if(!handled) { +#ifdef LOG + int len=strchr(*data,'\n')-(*data); + buf = xbuffer_copyin(buf, 0, *data, len+1); + buf[len]=0; + printf("libreal: sdpplin: not handled: '%s'\n", buf); +#endif + *data=nl(*data); + } + } + + xbuffer_free(buf); + xbuffer_free(decoded); + + return desc; +} + +sdpplin_t *sdpplin_parse(char *data) { + + sdpplin_t *desc=calloc(1,sizeof(sdpplin_t)); + sdpplin_stream_t *stream; + char *buf=xbuffer_init(32); + char *decoded=xbuffer_init(32); + int handled; + int len; + + while (*data) { + + handled=0; + + if (filter(data, "m=", &buf)) { + stream=sdpplin_parse_stream(&data); +#ifdef LOG + printf("got data for stream id %u\n", stream->stream_id); +#endif + desc->stream[stream->stream_id]=stream; + continue; + } + + if(filter(data,"a=Title:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->title=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Author:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->author=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Copyright:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->copyright=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Abstract:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->abstract=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=StreamCount:integer;",&buf)) { + desc->stream_count=atoi(buf); + desc->stream=malloc(sizeof(sdpplin_stream_t*)*desc->stream_count); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Flags:integer;",&buf)) { + desc->flags=atoi(buf); + handled=1; + data=nl(data); + } + + if(!handled) { +#ifdef LOG + int len=strchr(data,'\n')-data; + buf = xbuffer_copyin(buf, 0, data, len+1); + buf[len]=0; + printf("libreal: sdpplin: not handled: '%s'\n", buf); +#endif + data=nl(data); + } + } + + xbuffer_free(buf); + xbuffer_free(decoded); + + return desc; +} + +void sdpplin_free(sdpplin_t *description) { + + /* TODO: free strings */ + free(description); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/sdpplin.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,115 @@ +/* + * This file was ported to MPlayer from xine CVS sdpplin.h,v 1.1 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * sdp/sdpplin parser. + * + */ + +#ifndef HAVE_SDPPLIN_H +#define HAVE_SDPPLIN_H + +#include "rmff.h" +#include "rtsp.h" + +#ifdef __CYGWIN__ +#define uint32_t unsigned int +#define uint16_t unsigned short int +#define uint8_t unsigned char +#endif + +typedef struct { + + char *id; + char *bandwidth; + + int stream_id; + char *range; + char *length; + char *rtpmap; + char *mimetype; + int min_switch_overlap; + int start_time; + int end_one_rule_end_all; + int avg_bit_rate; + int max_bit_rate; + int avg_packet_size; + int max_packet_size; + int end_time; + int seek_greater_on_switch; + int preroll; + + int duration; + char *stream_name; + int stream_name_size; + char *mime_type; + int mime_type_size; + char *mlti_data; + int mlti_data_size; + int rmff_flags_length; + char *rmff_flags; + int asm_rule_book_length; + char *asm_rule_book; + +} sdpplin_stream_t; + +typedef struct { + + int sdp_version, sdpplin_version; + char *owner; + char *session_name; + char *session_info; + char *uri; + char *email; + char *phone; + char *connection; + char *bandwidth; + + int flags; + int is_real_data_type; + int stream_count; + char *title; + char *author; + char *copyright; + char *keywords; + int asm_rule_book_length; + char *asm_rule_book; + char *abstract; + char *range; + int avg_bit_rate; + int max_bit_rate; + int avg_packet_size; + int max_packet_size; + int preroll; + int duration; + + sdpplin_stream_t **stream; + +} sdpplin_t; + +sdpplin_t *sdpplin_parse(char *data); + +void sdpplin_free(sdpplin_t *description); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/xbuffer.c Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,86 @@ +/* + * xbuffer code + * + * Includes a minimalistic replacement for xine_buffer functions used in + * Real streaming code. Only function needed by this code are implemented. + * + * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project + * + * WARNING: do not mix original xine_buffer functions with this code! + * xbuffers behave like xine_buffers, but are not byte-compatible with them. + * You must take care of pointers returned by xbuffers functions (no macro to + * do it automatically) + * + */ + +#include <stdlib.h> +#include <inttypes.h> +#include "xbuffer.h" + + +typedef struct { + uint32_t size; + uint32_t chunk_size; +} xbuffer_header_t; + +#define XBUFFER_HEADER_SIZE sizeof (xbuffer_header_t) + + + +void *xbuffer_init(int chunk_size) { + uint8_t *data=calloc(1,chunk_size+XBUFFER_HEADER_SIZE); + + xbuffer_header_t *header=(xbuffer_header_t*)data; + + header->size=chunk_size; + header->chunk_size=chunk_size; + + return data+XBUFFER_HEADER_SIZE; +} + + + +void *xbuffer_free(void *buf) { + if (!buf) { + return NULL; + } + + free(((uint8_t*)buf)-XBUFFER_HEADER_SIZE); + + return NULL; +} + + + +void *xbuffer_copyin(void *buf, int index, const void *data, int len) { + if (!buf || !data) { + return NULL; + } + + buf = xbuffer_ensure_size(buf, index+len); + memcpy(((uint8_t*)buf)+index, data, len); + + return buf; +} + + + +void *xbuffer_ensure_size(void *buf, int size) { + xbuffer_header_t *xbuf; + int new_size; + + if (!buf) { + return 0; + } + + xbuf = ((xbuffer_header_t*)(((uint8_t*)buf)-XBUFFER_HEADER_SIZE)); + + if (xbuf->size < size) { + new_size = size + xbuf->chunk_size - (size % xbuf->chunk_size); + xbuf->size = new_size; + buf = ((uint8_t*)realloc(((uint8_t*)buf)-XBUFFER_HEADER_SIZE, + new_size+XBUFFER_HEADER_SIZE)) + XBUFFER_HEADER_SIZE; + } + + return buf; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/realrtsp/xbuffer.h Thu Apr 17 20:39:41 2003 +0000 @@ -0,0 +1,25 @@ +/* + * xbuffer code + * + * Includes a minimalistic replacement for xine_buffer functions used in + * Real streaming code. Only function needed by this code are implemented. + * + * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project + * + * WARNING: do not mix original xine_buffer functions with this code! + * xbuffers behave like xine_buffers, but are not byte-compatible with them. + * You must take care of pointers returned by xbuffers functions (no macro to + * do it automatically) + * + */ + + +#ifndef _XCL_H_ +#define _XCL_H_ + +void *xbuffer_init(int chunk_size); +void *xbuffer_free(void *buf); +void *xbuffer_copyin(void *buf, int index, const void *data, int len); +void *xbuffer_ensure_size(void *buf, int size); + +#endif