fixed RTP/TCP client support
Originally committed as revision 2045 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
@@ -29,10 +29,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
|
//#define DEBUG_RTP_TCP
|
||||||
|
|
||||||
typedef struct RTSPState {
|
typedef struct RTSPState {
|
||||||
URLContext *rtsp_hd; /* RTSP TCP connexion handle */
|
URLContext *rtsp_hd; /* RTSP TCP connexion handle */
|
||||||
ByteIOContext rtsp_gb;
|
/* XXX: currently we use unbuffered input */
|
||||||
|
// ByteIOContext rtsp_gb;
|
||||||
int seq; /* RTSP command sequence number */
|
int seq; /* RTSP command sequence number */
|
||||||
char session_id[512];
|
char session_id[512];
|
||||||
enum RTSPProtocol protocol;
|
enum RTSPProtocol protocol;
|
||||||
@@ -55,7 +57,12 @@ int rtsp_abort_req = 0;
|
|||||||
|
|
||||||
/* XXX: currently, the only way to change the protocols consists in
|
/* XXX: currently, the only way to change the protocols consists in
|
||||||
changing this variable */
|
changing this variable */
|
||||||
|
#if 1
|
||||||
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST);
|
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST);
|
||||||
|
#else
|
||||||
|
/* try it if a proxy is used */
|
||||||
|
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* if non zero, then set a range for RTP ports */
|
/* if non zero, then set a range for RTP ports */
|
||||||
int rtsp_rtp_port_min = 0;
|
int rtsp_rtp_port_min = 0;
|
||||||
@@ -365,7 +372,7 @@ static int sdp_parse(AVFormatContext *s, const char *content)
|
|||||||
p++;
|
p++;
|
||||||
/* get the content */
|
/* get the content */
|
||||||
q = buf;
|
q = buf;
|
||||||
while (*p != '\n' && *p != '\0') {
|
while (*p != '\n' && *p != '\r' && *p != '\0') {
|
||||||
if ((q - buf) < sizeof(buf) - 1)
|
if ((q - buf) < sizeof(buf) - 1)
|
||||||
*q++ = *p;
|
*q++ = *p;
|
||||||
p++;
|
p++;
|
||||||
@@ -427,10 +434,11 @@ static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
|
|||||||
get_word_sep(profile, sizeof(profile), "/;,", &p);
|
get_word_sep(profile, sizeof(profile), "/;,", &p);
|
||||||
lower_transport[0] = '\0';
|
lower_transport[0] = '\0';
|
||||||
if (*p == '/') {
|
if (*p == '/') {
|
||||||
|
p++;
|
||||||
get_word_sep(lower_transport, sizeof(lower_transport),
|
get_word_sep(lower_transport, sizeof(lower_transport),
|
||||||
";,", &p);
|
";,", &p);
|
||||||
}
|
}
|
||||||
if (!strcmp(lower_transport, "TCP"))
|
if (!strcasecmp(lower_transport, "TCP"))
|
||||||
th->protocol = RTSP_PROTOCOL_RTP_TCP;
|
th->protocol = RTSP_PROTOCOL_RTP_TCP;
|
||||||
else
|
else
|
||||||
th->protocol = RTSP_PROTOCOL_RTP_UDP;
|
th->protocol = RTSP_PROTOCOL_RTP_UDP;
|
||||||
@@ -526,13 +534,13 @@ static void rtsp_send_cmd(AVFormatContext *s,
|
|||||||
|
|
||||||
rt->seq++;
|
rt->seq++;
|
||||||
pstrcpy(buf, sizeof(buf), cmd);
|
pstrcpy(buf, sizeof(buf), cmd);
|
||||||
snprintf(buf1, sizeof(buf1), "CSeq: %d\n", rt->seq);
|
snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
|
||||||
pstrcat(buf, sizeof(buf), buf1);
|
pstrcat(buf, sizeof(buf), buf1);
|
||||||
if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
|
if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
|
||||||
snprintf(buf1, sizeof(buf1), "Session: %s\n", rt->session_id);
|
snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
|
||||||
pstrcat(buf, sizeof(buf), buf1);
|
pstrcat(buf, sizeof(buf), buf1);
|
||||||
}
|
}
|
||||||
pstrcat(buf, sizeof(buf), "\n");
|
pstrcat(buf, sizeof(buf), "\r\n");
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("Sending:\n%s--\n", buf);
|
printf("Sending:\n%s--\n", buf);
|
||||||
#endif
|
#endif
|
||||||
@@ -626,8 +634,8 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
|
|
||||||
/* describe the stream */
|
/* describe the stream */
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"DESCRIBE %s RTSP/1.0\n"
|
"DESCRIBE %s RTSP/1.0\r\n"
|
||||||
"Accept: application/sdp\n",
|
"Accept: application/sdp\r\n",
|
||||||
s->filename);
|
s->filename);
|
||||||
rtsp_send_cmd(s, cmd, reply, &content);
|
rtsp_send_cmd(s, cmd, reply, &content);
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@@ -708,10 +716,9 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
sizeof(transport) - strlen(transport) - 1,
|
sizeof(transport) - strlen(transport) - 1,
|
||||||
"RTP/AVP/UDP;multicast");
|
"RTP/AVP/UDP;multicast");
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"SETUP %s RTSP/1.0\n"
|
"SETUP %s RTSP/1.0\r\n"
|
||||||
"Transport: %s\n",
|
"Transport: %s\r\n",
|
||||||
rtsp_st->control_url, transport);
|
rtsp_st->control_url, transport);
|
||||||
rtsp_send_cmd(s, cmd, reply, NULL);
|
rtsp_send_cmd(s, cmd, reply, NULL);
|
||||||
if (reply->status_code != RTSP_STATUS_OK ||
|
if (reply->status_code != RTSP_STATUS_OK ||
|
||||||
@@ -794,7 +801,8 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
|
|
||||||
/* start playing */
|
/* start playing */
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"PLAY %s RTSP/1.0\n",
|
"PLAY %s RTSP/1.0\r\n"
|
||||||
|
"Range: npt=0-\r\n",
|
||||||
s->filename);
|
s->filename);
|
||||||
rtsp_send_cmd(s, cmd, reply, NULL);
|
rtsp_send_cmd(s, cmd, reply, NULL);
|
||||||
if (reply->status_code != RTSP_STATUS_OK) {
|
if (reply->status_code != RTSP_STATUS_OK) {
|
||||||
@@ -802,6 +810,7 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* open TCP with bufferized input */
|
/* open TCP with bufferized input */
|
||||||
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
|
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
|
||||||
if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) {
|
if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) {
|
||||||
@@ -809,6 +818,7 @@ static int rtsp_read_header(AVFormatContext *s,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
@@ -830,33 +840,46 @@ static int tcp_read_packet(AVFormatContext *s,
|
|||||||
AVPacket *pkt)
|
AVPacket *pkt)
|
||||||
{
|
{
|
||||||
RTSPState *rt = s->priv_data;
|
RTSPState *rt = s->priv_data;
|
||||||
ByteIOContext *rtsp_gb = &rt->rtsp_gb;
|
int id, len, i, ret;
|
||||||
int c, id, len, i, ret;
|
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
RTSPStream *rtsp_st;
|
RTSPStream *rtsp_st;
|
||||||
char buf[RTP_MAX_PACKET_LENGTH];
|
uint8_t buf[RTP_MAX_PACKET_LENGTH];
|
||||||
|
|
||||||
|
#ifdef DEBUG_RTP_TCP
|
||||||
|
printf("tcp_read_packet:\n");
|
||||||
|
#endif
|
||||||
redo:
|
redo:
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = url_fgetc(rtsp_gb);
|
ret = url_read(rt->rtsp_hd, buf, 1);
|
||||||
if (c == URL_EOF)
|
#ifdef DEBUG_RTP_TCP
|
||||||
|
printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
|
||||||
|
#endif
|
||||||
|
if (ret != 1)
|
||||||
return AVERROR_IO;
|
return AVERROR_IO;
|
||||||
if (c == '$')
|
if (buf[0] == '$')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
id = get_byte(rtsp_gb);
|
ret = url_read(rt->rtsp_hd, buf, 3);
|
||||||
len = get_be16(rtsp_gb);
|
if (ret != 3)
|
||||||
|
return AVERROR_IO;
|
||||||
|
id = buf[0];
|
||||||
|
len = (buf[1] << 8) | buf[2];
|
||||||
|
#ifdef DEBUG_RTP_TCP
|
||||||
|
printf("id=%d len=%d\n", id, len);
|
||||||
|
#endif
|
||||||
if (len > RTP_MAX_PACKET_LENGTH || len < 12)
|
if (len > RTP_MAX_PACKET_LENGTH || len < 12)
|
||||||
goto redo;
|
goto redo;
|
||||||
/* get the data */
|
/* get the data */
|
||||||
get_buffer(rtsp_gb, buf, len);
|
ret = url_read(rt->rtsp_hd, buf, len);
|
||||||
|
if (ret != len)
|
||||||
|
return AVERROR_IO;
|
||||||
|
|
||||||
/* find the matching stream */
|
/* find the matching stream */
|
||||||
for(i = 0; i < s->nb_streams; i++) {
|
for(i = 0; i < s->nb_streams; i++) {
|
||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
rtsp_st = st->priv_data;
|
rtsp_st = st->priv_data;
|
||||||
if (i >= rtsp_st->interleaved_min &&
|
if (id >= rtsp_st->interleaved_min &&
|
||||||
i <= rtsp_st->interleaved_max)
|
id <= rtsp_st->interleaved_max)
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
goto redo;
|
goto redo;
|
||||||
@@ -945,13 +968,14 @@ static int rtsp_read_close(AVFormatContext *s)
|
|||||||
int i;
|
int i;
|
||||||
char cmd[1024];
|
char cmd[1024];
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* NOTE: it is valid to flush the buffer here */
|
/* NOTE: it is valid to flush the buffer here */
|
||||||
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
|
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
|
||||||
url_fclose(&rt->rtsp_gb);
|
url_fclose(&rt->rtsp_gb);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"TEARDOWN %s RTSP/1.0\n",
|
"TEARDOWN %s RTSP/1.0\r\n",
|
||||||
s->filename);
|
s->filename);
|
||||||
rtsp_send_cmd(s, cmd, reply, NULL);
|
rtsp_send_cmd(s, cmd, reply, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
|
|||||||
AVFormatParameters *ap)
|
AVFormatParameters *ap)
|
||||||
{
|
{
|
||||||
AVFormatContext *ic = NULL;
|
AVFormatContext *ic = NULL;
|
||||||
int err;
|
int err, must_open_file;
|
||||||
char buf[PROBE_BUF_SIZE];
|
char buf[PROBE_BUF_SIZE];
|
||||||
AVProbeData probe_data, *pd = &probe_data;
|
AVProbeData probe_data, *pd = &probe_data;
|
||||||
|
|
||||||
@@ -331,7 +331,15 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
|
|||||||
fmt = av_probe_input_format(pd, 0);
|
fmt = av_probe_input_format(pd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
|
/* do not open file if the format does not need it. XXX: specific
|
||||||
|
hack needed to handle RTSP/TCP */
|
||||||
|
must_open_file = 1;
|
||||||
|
if ((fmt->flags & AVFMT_NOFILE) ||
|
||||||
|
(fmt == &rtp_demux && !strcmp(filename, "null"))) {
|
||||||
|
must_open_file = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fmt || must_open_file) {
|
||||||
/* if no file needed do not try to open one */
|
/* if no file needed do not try to open one */
|
||||||
if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) {
|
if (url_fopen(&ic->pb, filename, URL_RDONLY) < 0) {
|
||||||
err = AVERROR_IO;
|
err = AVERROR_IO;
|
||||||
@@ -397,7 +405,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename,
|
|||||||
*ic_ptr = ic;
|
*ic_ptr = ic;
|
||||||
return 0;
|
return 0;
|
||||||
fail1:
|
fail1:
|
||||||
if (!fmt || !(fmt->flags & AVFMT_NOFILE)) {
|
if (!fmt || must_open_file) {
|
||||||
url_fclose(&ic->pb);
|
url_fclose(&ic->pb);
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
@@ -664,7 +672,7 @@ int av_find_stream_info(AVFormatContext *ic)
|
|||||||
*/
|
*/
|
||||||
void av_close_input_file(AVFormatContext *s)
|
void av_close_input_file(AVFormatContext *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i, must_open_file;
|
||||||
|
|
||||||
if (s->iformat->read_close)
|
if (s->iformat->read_close)
|
||||||
s->iformat->read_close(s);
|
s->iformat->read_close(s);
|
||||||
@@ -682,7 +690,12 @@ void av_close_input_file(AVFormatContext *s)
|
|||||||
}
|
}
|
||||||
s->packet_buffer = NULL;
|
s->packet_buffer = NULL;
|
||||||
}
|
}
|
||||||
if (!(s->iformat->flags & AVFMT_NOFILE)) {
|
must_open_file = 1;
|
||||||
|
if ((s->iformat->flags & AVFMT_NOFILE) ||
|
||||||
|
(s->iformat == &rtp_demux && !strcmp(s->filename, "null"))) {
|
||||||
|
must_open_file = 0;
|
||||||
|
}
|
||||||
|
if (must_open_file) {
|
||||||
url_fclose(&s->pb);
|
url_fclose(&s->pb);
|
||||||
}
|
}
|
||||||
av_freep(&s->priv_data);
|
av_freep(&s->priv_data);
|
||||||
|
|||||||
Reference in New Issue
Block a user