Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2015-02-17 14:16:02 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
4807f7850d8ce942d86f2e15df088a8a1b54ee18
4807f785
1 parent
604f4cc5
for #133, rtsp parse the announce packet, parse the sps/pps and audio sequence header by base64.
隐藏空白字符变更
内嵌
并排对比
正在显示
5 个修改的文件
包含
729 行增加
和
13 行删除
trunk/src/app/srs_app_rtsp.cpp
trunk/src/kernel/srs_kernel_utility.cpp
trunk/src/kernel/srs_kernel_utility.hpp
trunk/src/protocol/srs_rtsp_stack.cpp
trunk/src/protocol/srs_rtsp_stack.hpp
trunk/src/app/srs_app_rtsp.cpp
查看文件 @
4807f78
...
...
@@ -92,7 +92,14 @@ int SrsRtspConn::do_cycle()
if
(
req
->
is_options
())
{
if
((
ret
=
rtsp
->
send_message
(
new
SrsRtspOptionsResponse
(
req
->
seq
)))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: send response failed. ret=%d"
,
ret
);
srs_error
(
"rtsp: send OPTIONS response failed. ret=%d"
,
ret
);
}
return
ret
;
}
}
else
if
(
req
->
is_announce
())
{
if
((
ret
=
rtsp
->
send_message
(
new
SrsRtspResponse
(
req
->
seq
)))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: send ANNOUNCE response failed. ret=%d"
,
ret
);
}
return
ret
;
}
...
...
trunk/src/kernel/srs_kernel_utility.cpp
查看文件 @
4807f78
...
...
@@ -407,3 +407,217 @@ u_int32_t srs_crc32(const void* buf, int size)
return
mpegts_crc32
((
const
u_int8_t
*
)
buf
,
size
);
}
/*
* Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define UINT_MAX 0xffffffff
#ifndef AV_RB32
# define AV_RB32(x) \
(((uint32_t)((const u_int8_t*)(x))[0] << 24) | \
(((const u_int8_t*)(x))[1] << 16) | \
(((const u_int8_t*)(x))[2] << 8) | \
((const u_int8_t*)(x))[3])
#endif
#ifndef AV_WL32
# define AV_WL32(p, darg) do { \
unsigned d = (darg); \
((u_int8_t*)(p))[0] = (d); \
((u_int8_t*)(p))[1] = (d)>>8; \
((u_int8_t*)(p))[2] = (d)>>16; \
((u_int8_t*)(p))[3] = (d)>>24; \
} while(0)
#endif
# define AV_WN(s, p, v) AV_WL##s(p, v)
# if defined(AV_WN32) && !defined(AV_WL32)
# define AV_WL32(p, v) AV_WN32(p, v)
# elif !defined(AV_WN32) && defined(AV_WL32)
# define AV_WN32(p, v) AV_WL32(p, v)
# endif
#ifndef AV_WN32
# define AV_WN32(p, v) AV_WN(32, p, v)
#endif
#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff))
#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16))
#ifndef av_bswap32
static
const
u_int32_t
av_bswap32
(
u_int32_t
x
)
{
return
AV_BSWAP32C
(
x
);
}
#endif
#define av_be2ne32(x) av_bswap32(x)
/**
* @file
* @brief Base64 encode/decode
* @author Ryan Martell <rdm4@martellventures.com> (with lots of Michael)
*/
/* ---------------- private code */
static
const
u_int8_t
map2
[
256
]
=
{
0xfe
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x3e
,
0xff
,
0xff
,
0xff
,
0x3f
,
0x34
,
0x35
,
0x36
,
0x37
,
0x38
,
0x39
,
0x3a
,
0x3b
,
0x3c
,
0x3d
,
0xff
,
0xff
,
0xff
,
0xfe
,
0xff
,
0xff
,
0xff
,
0x00
,
0x01
,
0x02
,
0x03
,
0x04
,
0x05
,
0x06
,
0x07
,
0x08
,
0x09
,
0x0a
,
0x0b
,
0x0c
,
0x0d
,
0x0e
,
0x0f
,
0x10
,
0x11
,
0x12
,
0x13
,
0x14
,
0x15
,
0x16
,
0x17
,
0x18
,
0x19
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x1a
,
0x1b
,
0x1c
,
0x1d
,
0x1e
,
0x1f
,
0x20
,
0x21
,
0x22
,
0x23
,
0x24
,
0x25
,
0x26
,
0x27
,
0x28
,
0x29
,
0x2a
,
0x2b
,
0x2c
,
0x2d
,
0x2e
,
0x2f
,
0x30
,
0x31
,
0x32
,
0x33
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
};
#define BASE64_DEC_STEP(i) do { \
bits = map2[in[i]]; \
if (bits & 0x80) \
goto out ## i; \
v = i ? (v << 6) + bits : bits; \
} while(0)
int
srs_av_base64_decode
(
u_int8_t
*
out
,
const
char
*
in_str
,
int
out_size
)
{
u_int8_t
*
dst
=
out
;
u_int8_t
*
end
=
out
+
out_size
;
// no sign extension
const
u_int8_t
*
in
=
(
const
u_int8_t
*
)
in_str
;
unsigned
bits
=
0xff
;
unsigned
v
;
while
(
end
-
dst
>
3
)
{
BASE64_DEC_STEP
(
0
);
BASE64_DEC_STEP
(
1
);
BASE64_DEC_STEP
(
2
);
BASE64_DEC_STEP
(
3
);
// Using AV_WB32 directly confuses compiler
v
=
av_be2ne32
(
v
<<
8
);
AV_WN32
(
dst
,
v
);
dst
+=
3
;
in
+=
4
;
}
if
(
end
-
dst
)
{
BASE64_DEC_STEP
(
0
);
BASE64_DEC_STEP
(
1
);
BASE64_DEC_STEP
(
2
);
BASE64_DEC_STEP
(
3
);
*
dst
++
=
v
>>
16
;
if
(
end
-
dst
)
*
dst
++
=
v
>>
8
;
if
(
end
-
dst
)
*
dst
++
=
v
;
in
+=
4
;
}
while
(
1
)
{
BASE64_DEC_STEP
(
0
);
in
++
;
BASE64_DEC_STEP
(
0
);
in
++
;
BASE64_DEC_STEP
(
0
);
in
++
;
BASE64_DEC_STEP
(
0
);
in
++
;
}
out3:
*
dst
++
=
v
>>
10
;
v
<<=
2
;
out2:
*
dst
++
=
v
>>
4
;
out1:
out0:
return
bits
&
1
?
-
1
:
dst
-
out
;
}
/*****************************************************************************
* b64_encode: Stolen from VLC's http.c.
* Simplified by Michael.
* Fixed edge cases and made it work from data (vs. strings) by Ryan.
*****************************************************************************/
char
*
srs_av_base64_encode
(
char
*
out
,
int
out_size
,
const
u_int8_t
*
in
,
int
in_size
)
{
static
const
char
b64
[]
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
;
char
*
ret
,
*
dst
;
unsigned
i_bits
=
0
;
int
i_shift
=
0
;
int
bytes_remaining
=
in_size
;
if
(
in_size
>=
(
int
)(
UINT_MAX
/
4
)
||
out_size
<
SRS_AV_BASE64_SIZE
(
in_size
))
return
NULL
;
ret
=
dst
=
out
;
while
(
bytes_remaining
>
3
)
{
i_bits
=
AV_RB32
(
in
);
in
+=
3
;
bytes_remaining
-=
3
;
*
dst
++
=
b64
[
i_bits
>>
26
];
*
dst
++
=
b64
[(
i_bits
>>
20
)
&
0x3F
];
*
dst
++
=
b64
[(
i_bits
>>
14
)
&
0x3F
];
*
dst
++
=
b64
[(
i_bits
>>
8
)
&
0x3F
];
}
i_bits
=
0
;
while
(
bytes_remaining
)
{
i_bits
=
(
i_bits
<<
8
)
+
*
in
++
;
bytes_remaining
--
;
i_shift
+=
8
;
}
while
(
i_shift
>
0
)
{
*
dst
++
=
b64
[(
i_bits
<<
6
>>
i_shift
)
&
0x3f
];
i_shift
-=
6
;
}
while
((
dst
-
ret
)
&
3
)
*
dst
++
=
'='
;
*
dst
=
'\0'
;
return
ret
;
}
...
...
trunk/src/kernel/srs_kernel_utility.hpp
查看文件 @
4807f78
...
...
@@ -85,5 +85,35 @@ extern bool srs_aac_startswith_adts(SrsStream* stream);
*/
extern
u_int32_t
srs_crc32
(
const
void
*
buf
,
int
size
);
/**
* Decode a base64-encoded string.
*
* @param out buffer for decoded data
* @param in null-terminated input string
* @param out_size size in bytes of the out buffer, must be at
* least 3/4 of the length of in
* @return number of bytes written, or a negative value in case of
* invalid input
*/
extern
int
srs_av_base64_decode
(
u_int8_t
*
out
,
const
char
*
in
,
int
out_size
);
/**
* Encode data to base64 and null-terminate.
*
* @param out buffer for encoded data
* @param out_size size in bytes of the out buffer (including the
* null terminator), must be at least AV_BASE64_SIZE(in_size)
* @param in input buffer containing the data to encode
* @param in_size size in bytes of the in buffer
* @return out or NULL in case of error
*/
extern
char
*
srs_av_base64_encode
(
char
*
out
,
int
out_size
,
const
u_int8_t
*
in
,
int
in_size
);
/**
* Calculate the output size needed to base64-encode x bytes to a
* null-terminated string.
*/
#define SRS_AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
#endif
...
...
trunk/src/protocol/srs_rtsp_stack.cpp
查看文件 @
4807f78
...
...
@@ -32,6 +32,8 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_consts.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_utility.hpp>
#ifdef SRS_AUTO_STREAM_CASTER
...
...
@@ -116,13 +118,290 @@ std::string srs_generate_rtsp_method_str(SrsRtspMethod method)
}
}
SrsRtspSdp
::
SrsRtspSdp
()
{
state
=
SrsRtspSdpStateOthers
;
}
SrsRtspSdp
::~
SrsRtspSdp
()
{
}
int
SrsRtspSdp
::
parse
(
string
token
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
token
.
empty
())
{
srs_info
(
"rtsp: ignore empty token."
);
return
ret
;
}
size_t
pos
=
string
::
npos
;
char
*
start
=
(
char
*
)
token
.
data
();
char
*
end
=
start
+
(
int
)
token
.
length
();
char
*
p
=
start
;
// key, first 2bytes.
// v=0
// o=- 0 0 IN IP4 127.0.0.1
// s=No Name
// c=IN IP4 192.168.43.23
// t=0 0
// a=tool:libavformat 53.9.0
// m=video 0 RTP/AVP 96
// b=AS:850
// a=rtpmap:96 H264/90000
// a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAKKzRwFAFu/8ALQAiEAAAAwAQAAADAwjxgxHg,aOmrLIs=
// a=control:streamid=0
// m=audio 0 RTP/AVP 97
// b=AS:49
// a=rtpmap:97 MPEG4-GENERIC/44100/2
// a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=139056E5A0
// a=control:streamid=1
char
key
=
p
[
0
];
p
+=
2
;
// left bytes as attr string.
std
::
string
attr_str
;
if
(
end
-
p
)
{
attr_str
.
append
(
p
,
end
-
p
);
}
// parse the attributes from left bytes.
std
::
vector
<
std
::
string
>
attrs
;
while
(
p
<
end
)
{
// parse an attribute, split by SP.
char
*
pa
=
p
;
for
(;
p
<
end
&&
p
[
0
]
!=
__SRS_RTSP_SP
;
p
++
)
{
}
std
::
string
attr
;
if
(
p
>
pa
)
{
attr
.
append
(
pa
,
p
-
pa
);
attrs
.
push_back
(
attr
);
}
p
++
;
}
// parse the first attr as desc, update the first elem for desc.
// for example, the value can be "tool", "AS", "rtpmap", "fmtp", "control"
std
::
string
desc_key
;
if
(
attrs
.
size
()
>
0
)
{
std
::
string
attr
=
attrs
.
at
(
0
);
if
((
pos
=
attr
.
find
(
":"
))
!=
string
::
npos
)
{
desc_key
=
attr
.
substr
(
0
,
pos
);
attr
=
attr
.
substr
(
pos
+
1
);
attr_str
=
attr_str
.
substr
(
pos
+
1
);
attrs
[
0
]
=
attr
;
}
else
{
desc_key
=
attr
;
}
}
// interpret the attribute according by key.
switch
(
key
)
{
case
'v'
:
version
=
attr_str
;
break
;
case
'o'
:
owner_username
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
owner_session_id
=
(
attrs
.
size
()
>
1
)
?
attrs
[
1
]
:
""
;
owner_session_version
=
(
attrs
.
size
()
>
2
)
?
attrs
[
2
]
:
""
;
owner_network_type
=
(
attrs
.
size
()
>
3
)
?
attrs
[
3
]
:
""
;
owner_address_type
=
(
attrs
.
size
()
>
4
)
?
attrs
[
4
]
:
""
;
owner_address
=
(
attrs
.
size
()
>
5
)
?
attrs
[
5
]
:
""
;
break
;
case
's'
:
session_name
=
attr_str
;
break
;
case
'c'
:
connection_network_type
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
connection_address_type
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
connection_address
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
break
;
case
'a'
:
if
(
desc_key
==
"tool"
)
{
tool
=
attr_str
;
}
else
if
(
desc_key
==
"rtpmap"
)
{
if
(
state
==
SrsRtspSdpStateVideo
)
{
video_codec
=
(
attrs
.
size
()
>
1
)
?
attrs
[
1
]
:
""
;
if
((
pos
=
video_codec
.
find
(
"/"
))
!=
string
::
npos
)
{
video_sample_rate
=
video_codec
.
substr
(
pos
+
1
);
video_codec
=
video_codec
.
substr
(
0
,
pos
);
}
}
else
if
(
state
==
SrsRtspSdpStateAudio
)
{
audio_codec
=
(
attrs
.
size
()
>
1
)
?
attrs
[
1
]
:
""
;
if
((
pos
=
audio_codec
.
find
(
"/"
))
!=
string
::
npos
)
{
audio_sample_rate
=
audio_codec
.
substr
(
pos
+
1
);
audio_codec
=
audio_codec
.
substr
(
0
,
pos
);
}
if
((
pos
=
audio_codec
.
find
(
"/"
))
!=
string
::
npos
)
{
audio_channel
=
audio_codec
.
substr
(
pos
+
1
);
audio_codec
=
audio_codec
.
substr
(
0
,
pos
);
}
}
}
else
if
(
desc_key
==
"fmtp"
)
{
for
(
int
i
=
1
;
i
<
(
int
)
attrs
.
size
();
i
++
)
{
std
::
string
attr
=
attrs
.
at
(
i
);
if
((
ret
=
parse_fmtp_attribute
(
attr
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtsp: parse fmtp failed, attr=%s. ret=%d"
,
attr
.
c_str
(),
ret
);
return
ret
;
}
}
}
else
if
(
desc_key
==
"control"
)
{
for
(
int
i
=
0
;
i
<
(
int
)
attrs
.
size
();
i
++
)
{
std
::
string
attr
=
attrs
.
at
(
i
);
if
((
ret
=
parse_control_attribute
(
attr
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtsp: parse control failed, attr=%s. ret=%d"
,
attr
.
c_str
(),
ret
);
return
ret
;
}
}
}
break
;
case
'm'
:
if
(
desc_key
==
"video"
)
{
state
=
SrsRtspSdpStateVideo
;
video_port
=
(
attrs
.
size
()
>
1
)
?
attrs
[
1
]
:
""
;
video_protocol
=
(
attrs
.
size
()
>
2
)
?
attrs
[
2
]
:
""
;
video_transport_format
=
(
attrs
.
size
()
>
3
)
?
attrs
[
3
]
:
""
;
}
else
if
(
desc_key
==
"audio"
)
{
state
=
SrsRtspSdpStateAudio
;
audio_port
=
(
attrs
.
size
()
>
1
)
?
attrs
[
1
]
:
""
;
audio_protocol
=
(
attrs
.
size
()
>
2
)
?
attrs
[
2
]
:
""
;
audio_transport_format
=
(
attrs
.
size
()
>
3
)
?
attrs
[
3
]
:
""
;
}
break
;
case
'b'
:
if
(
desc_key
==
"AS"
)
{
if
(
state
==
SrsRtspSdpStateVideo
)
{
video_bandwidth_kbps
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
}
else
if
(
state
==
SrsRtspSdpStateAudio
)
{
audio_bandwidth_kbps
=
(
attrs
.
size
()
>
0
)
?
attrs
[
0
]
:
""
;
}
}
break
;
case
't'
:
default
:
break
;
}
return
ret
;
}
int
SrsRtspSdp
::
parse_fmtp_attribute
(
string
&
attr
)
{
int
ret
=
ERROR_SUCCESS
;
size_t
pos
=
string
::
npos
;
while
(
!
attr
.
empty
())
{
std
::
string
item
=
attr
;
if
((
pos
=
item
.
find
(
";"
))
!=
string
::
npos
)
{
item
=
attr
.
substr
(
0
,
pos
);
attr
=
attr
.
substr
(
pos
+
1
);
}
else
{
attr
=
""
;
}
std
::
string
item_key
=
item
,
item_value
;
if
((
pos
=
item
.
find
(
"="
))
!=
string
::
npos
)
{
item_key
=
item
.
substr
(
0
,
pos
);
item_value
=
item
.
substr
(
pos
+
1
);
}
if
(
state
==
SrsRtspSdpStateVideo
)
{
if
(
item_key
==
"packetization-mode"
)
{
video_packetization_mode
=
item_value
;
}
else
if
(
item_key
==
"sprop-parameter-sets"
)
{
video_sps
=
item_value
;
if
((
pos
=
video_sps
.
find
(
","
))
!=
string
::
npos
)
{
video_pps
=
video_sps
.
substr
(
pos
+
1
);
video_sps
=
video_sps
.
substr
(
0
,
pos
);
}
// decode the sps/pps by base64
video_sps
=
base64_decode
(
video_sps
);
video_pps
=
base64_decode
(
video_pps
);
}
}
else
if
(
state
==
SrsRtspSdpStateAudio
)
{
if
(
item_key
==
"profile-level-id"
)
{
audio_profile_level_id
=
item_value
;
}
else
if
(
item_key
==
"mode"
)
{
audio_mode
=
item_value
;
}
else
if
(
item_key
==
"sizelength"
)
{
audio_size_length
=
item_value
;
}
else
if
(
item_key
==
"indexlength"
)
{
audio_index_length
=
item_value
;
}
else
if
(
item_key
==
"indexdeltalength"
)
{
audio_index_delta_length
=
item_value
;
}
else
if
(
item_key
==
"config"
)
{
audio_sh
=
base64_decode
(
item_value
);
}
}
}
return
ret
;
}
int
SrsRtspSdp
::
parse_control_attribute
(
string
&
attr
)
{
int
ret
=
ERROR_SUCCESS
;
size_t
pos
=
string
::
npos
;
while
(
!
attr
.
empty
())
{
std
::
string
item
=
attr
;
if
((
pos
=
item
.
find
(
";"
))
!=
string
::
npos
)
{
item
=
attr
.
substr
(
0
,
pos
);
attr
=
attr
.
substr
(
pos
+
1
);
}
else
{
attr
=
""
;
}
std
::
string
item_key
=
item
,
item_value
;
if
((
pos
=
item
.
find
(
"="
))
!=
string
::
npos
)
{
item_key
=
item
.
substr
(
0
,
pos
);
item_value
=
item
.
substr
(
pos
+
1
);
}
if
(
state
==
SrsRtspSdpStateVideo
)
{
if
(
item_key
==
"streamid"
)
{
video_stream_id
=
item_value
;
}
}
else
if
(
state
==
SrsRtspSdpStateAudio
)
{
if
(
item_key
==
"streamid"
)
{
audio_stream_id
=
item_value
;
}
}
}
return
ret
;
}
string
SrsRtspSdp
::
base64_decode
(
string
value
)
{
if
(
value
.
empty
())
{
return
""
;
}
int
nb_output
=
(
int
)(
value
.
length
()
*
2
);
u_int8_t
*
output
=
new
u_int8_t
[
nb_output
];
SrsAutoFree
(
u_int8_t
,
output
);
int
ret
=
srs_av_base64_decode
(
output
,
(
char
*
)
value
.
c_str
(),
nb_output
);
if
(
ret
<=
0
)
{
return
""
;
}
std
::
string
plaintext
;
plaintext
.
append
((
char
*
)
output
,
ret
);
return
plaintext
;
}
SrsRtspRequest
::
SrsRtspRequest
()
{
seq
=
0
;
content_length
=
0
;
sdp
=
NULL
;
}
SrsRtspRequest
::~
SrsRtspRequest
()
{
srs_freep
(
sdp
);
}
bool
SrsRtspRequest
::
is_options
()
...
...
@@ -130,6 +409,11 @@ bool SrsRtspRequest::is_options()
return
method
==
__SRS_METHOD_OPTIONS
;
}
bool
SrsRtspRequest
::
is_announce
()
{
return
method
==
__SRS_METHOD_ANNOUNCE
;
}
SrsRtspResponse
::
SrsRtspResponse
(
int
cseq
)
{
seq
=
cseq
;
...
...
@@ -306,11 +590,29 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req)
std
::
string
seq
;
if
((
ret
=
recv_token_eof
(
seq
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: parse
seq failed. ret=%d"
,
ret
);
srs_error
(
"rtsp: parse
%s failed. ret=%d"
,
__SRS_TOKEN_CSEQ
,
ret
);
}
return
ret
;
}
req
->
seq
=
::
atoi
(
seq
.
c_str
());
req
->
seq
=
::
atol
(
seq
.
c_str
());
}
else
if
(
token
==
__SRS_TOKEN_CONTENT_TYPE
)
{
std
::
string
ct
;
if
((
ret
=
recv_token_eof
(
ct
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: parse %s failed. ret=%d"
,
__SRS_TOKEN_CONTENT_TYPE
,
ret
);
}
return
ret
;
}
req
->
content_type
=
ct
;
}
else
if
(
token
==
__SRS_TOKEN_CONTENT_LENGTH
)
{
std
::
string
cl
;
if
((
ret
=
recv_token_eof
(
cl
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: parse %s failed. ret=%d"
,
__SRS_TOKEN_CONTENT_LENGTH
,
ret
);
}
return
ret
;
}
req
->
content_length
=
::
atol
(
cl
.
c_str
());
}
else
{
// unknown header name, parse util EOF.
SrsRtspTokenState
state
=
SrsRtspTokenStateNormal
;
...
...
@@ -327,7 +629,30 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req)
}
}
// parse body.
// parse rdp body.
long
consumed
=
0
;
while
(
consumed
<
req
->
content_length
)
{
if
(
!
req
->
sdp
)
{
req
->
sdp
=
new
SrsRtspSdp
();
}
int
nb_token
=
0
;
std
::
string
token
;
if
((
ret
=
recv_token_util_eof
(
token
,
&
nb_token
))
!=
ERROR_SUCCESS
)
{
if
(
!
srs_is_client_gracefully_close
(
ret
))
{
srs_error
(
"rtsp: parse sdp token failed. ret=%d"
,
ret
);
}
return
ret
;
}
consumed
+=
nb_token
;
if
((
ret
=
req
->
sdp
->
parse
(
token
))
!=
ERROR_SUCCESS
)
{
srs_error
(
"rtsp: sdp parse token failed, token=%s. ret=%d"
,
token
.
c_str
(),
ret
);
return
ret
;
}
srs_info
(
"rtsp: %s"
,
token
.
c_str
());
}
srs_info
(
"rtsp: sdp parsed, size=%d"
,
consumed
);
return
ret
;
}
...
...
@@ -382,14 +707,14 @@ int SrsRtspStack::recv_token_eof(std::string& token)
return
ret
;
}
int
SrsRtspStack
::
recv_token_util_eof
(
std
::
string
&
token
)
int
SrsRtspStack
::
recv_token_util_eof
(
std
::
string
&
token
,
int
*
pconsumed
)
{
int
ret
=
ERROR_SUCCESS
;
SrsRtspTokenState
state
;
// use 0x00 as ignore the normal token flag.
if
((
ret
=
recv_token
(
token
,
state
,
0x00
))
!=
ERROR_SUCCESS
)
{
if
((
ret
=
recv_token
(
token
,
state
,
0x00
,
pconsumed
))
!=
ERROR_SUCCESS
)
{
if
(
ret
==
ERROR_RTSP_REQUEST_HEADER_EOF
)
{
return
ret
;
}
...
...
@@ -408,7 +733,7 @@ int SrsRtspStack::recv_token_util_eof(std::string& token)
return
ret
;
}
int
SrsRtspStack
::
recv_token
(
std
::
string
&
token
,
SrsRtspTokenState
&
state
,
char
normal_ch
)
int
SrsRtspStack
::
recv_token
(
std
::
string
&
token
,
SrsRtspTokenState
&
state
,
char
normal_ch
,
int
*
pconsumed
)
{
int
ret
=
ERROR_SUCCESS
;
...
...
@@ -474,6 +799,9 @@ int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char
// consume the token bytes.
srs_assert
(
p
-
start
);
buf
->
erase
(
p
-
start
);
if
(
pconsumed
)
{
*
pconsumed
=
p
-
start
;
}
break
;
}
...
...
trunk/src/protocol/srs_rtsp_stack.hpp
查看文件 @
4807f78
...
...
@@ -58,6 +58,8 @@ class ISrsProtocolReaderWriter;
// RTSP token
#define __SRS_TOKEN_CSEQ "CSeq"
#define __SRS_TOKEN_PUBLIC "Public"
#define __SRS_TOKEN_CONTENT_TYPE "Content-Type"
#define __SRS_TOKEN_CONTENT_LENGTH "Content-Length"
// RTSP methods
#define __SRS_METHOD_OPTIONS "OPTIONS"
...
...
@@ -77,6 +79,118 @@ class ISrsProtocolReaderWriter;
#define __SRS_VERSION "RTSP/1.0"
/**
* the rtsp sdp parse state.
*/
enum
SrsRtspSdpState
{
/**
* other sdp properties.
*/
SrsRtspSdpStateOthers
,
/**
* parse sdp audio state.
*/
SrsRtspSdpStateAudio
,
/**
* parse sdp video state.
*/
SrsRtspSdpStateVideo
,
};
/**
* the sdp in announce.
* Appendix C: Use of SDP for RTSP Session Descriptions
* The Session Description Protocol (SDP, RFC 2327 [6]) may be used to
* describe streams or presentations in RTSP.
*/
class
SrsRtspSdp
{
private
:
SrsRtspSdpState
state
;
public
:
/**
* the version of sdp.
*/
std
::
string
version
;
/**
* the owner/creator of sdp.
*/
std
::
string
owner_username
;
std
::
string
owner_session_id
;
std
::
string
owner_session_version
;
std
::
string
owner_network_type
;
std
::
string
owner_address_type
;
std
::
string
owner_address
;
/**
* the session name of sdp.
*/
std
::
string
session_name
;
/**
* the connection info of sdp.
*/
std
::
string
connection_network_type
;
std
::
string
connection_address_type
;
std
::
string
connection_address
;
/**
* the tool attribute of sdp.
*/
std
::
string
tool
;
/**
* the video attribute of sdp.
*/
std
::
string
video_port
;
std
::
string
video_protocol
;
std
::
string
video_transport_format
;
std
::
string
video_bandwidth_kbps
;
std
::
string
video_codec
;
std
::
string
video_sample_rate
;
std
::
string
video_stream_id
;
// fmtp
std
::
string
video_packetization_mode
;
std
::
string
video_sps
;
// sequence header: sps.
std
::
string
video_pps
;
// sequence header: pps.
/**
* the audio attribute of sdp.
*/
std
::
string
audio_port
;
std
::
string
audio_protocol
;
std
::
string
audio_transport_format
;
std
::
string
audio_bandwidth_kbps
;
std
::
string
audio_codec
;
std
::
string
audio_sample_rate
;
std
::
string
audio_channel
;
std
::
string
audio_stream_id
;
// fmtp
std
::
string
audio_profile_level_id
;
std
::
string
audio_mode
;
std
::
string
audio_size_length
;
std
::
string
audio_index_length
;
std
::
string
audio_index_delta_length
;
std
::
string
audio_sh
;
// sequence header.
public:
SrsRtspSdp
();
virtual
~
SrsRtspSdp
();
public
:
/**
* parse a line of token for sdp.
*/
virtual
int
parse
(
std
::
string
token
);
private
:
/**
* generally, the fmtp is the sequence header for video or audio.
*/
virtual
int
parse_fmtp_attribute
(
std
::
string
&
attr
);
/**
* generally, the control is the stream info for video or audio.
*/
virtual
int
parse_control_attribute
(
std
::
string
&
attr
);
/**
* decode the string by base64.
*/
virtual
std
::
string
base64_decode
(
std
::
string
value
);
};
/**
* the rtsp request message.
* 6 Request
* A request message from a client to a server or vice versa includes,
...
...
@@ -110,12 +224,33 @@ public:
* number as the original (i.e. the sequence number is not incremented
* for retransmissions of the same request).
*/
int
seq
;
long
seq
;
/**
* 12.16 Content-Type
* See [H14.18]. Note that the content types suitable for RTSP are
* likely to be restricted in practice to presentation descriptions and
* parameter-value types.
*/
std
::
string
content_type
;
/**
* 12.14 Content-Length
* This field contains the length of the content of the method (i.e.
* after the double CRLF following the last header). Unlike HTTP, it
* MUST be included in all messages that carry content beyond the header
* portion of the message. If it is missing, a default value of zero is
* assumed. It is interpreted according to [H14.14].
*/
long
content_length
;
/**
* the sdp in announce, NULL for no sdp.
*/
SrsRtspSdp
*
sdp
;
public
:
SrsRtspRequest
();
virtual
~
SrsRtspRequest
();
public
:
virtual
bool
is_options
();
virtual
bool
is_announce
();
};
/**
...
...
@@ -159,7 +294,7 @@ public:
* number as the original (i.e. the sequence number is not incremented
* for retransmissions of the same request).
*/
int
seq
;
long
seq
;
public
:
SrsRtspResponse
(
int
cseq
);
virtual
~
SrsRtspResponse
();
...
...
@@ -283,18 +418,20 @@ private:
virtual
int
recv_token_eof
(
std
::
string
&
token
);
/**
* read the token util got eof, for example, to read the response status Reason-Phrase
* @param pconsumed, output the token parsed length. NULL to ignore.
*/
virtual
int
recv_token_util_eof
(
std
::
string
&
token
);
virtual
int
recv_token_util_eof
(
std
::
string
&
token
,
int
*
pconsumed
=
NULL
);
/**
* read a token from io, split by SP, endswith CRLF:
* token1 SP token2 SP ... tokenN CRLF
* @param token, output the read token.
* @param state, output the token parse state.
* @param normal_ch, the char to indicates the normal token.
* the SP use to indicates the normal token, @see __SRS_RTSP_SP
* the 0x00 use to ignore normal token flag. @see recv_token_util_eof
* @param token, output the read token.
* @param state, output the token parse state.
* @param pconsumed, output the token parsed length. NULL to ignore.
*/
virtual
int
recv_token
(
std
::
string
&
token
,
SrsRtspTokenState
&
state
,
char
normal_ch
=
__SRS_RTSP_SP
);
virtual
int
recv_token
(
std
::
string
&
token
,
SrsRtspTokenState
&
state
,
char
normal_ch
=
__SRS_RTSP_SP
,
int
*
pconsumed
=
NULL
);
};
#endif
...
...
请
注册
或
登录
后发表评论