Commit ff762d6e authored by Fabrice Bellard's avatar Fabrice Bellard

initial seek support - more generic play/pause support

Originally committed as revision 2495 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent fb2758c8
...@@ -31,11 +31,20 @@ ...@@ -31,11 +31,20 @@
//#define DEBUG //#define DEBUG
//#define DEBUG_RTP_TCP //#define DEBUG_RTP_TCP
enum RTSPClientState {
RTSP_STATE_IDLE,
RTSP_STATE_PLAYING,
RTSP_STATE_PAUSED,
};
typedef struct RTSPState { typedef struct RTSPState {
URLContext *rtsp_hd; /* RTSP TCP connexion handle */ URLContext *rtsp_hd; /* RTSP TCP connexion handle */
int nb_rtsp_streams; int nb_rtsp_streams;
struct RTSPStream **rtsp_streams; struct RTSPStream **rtsp_streams;
enum RTSPClientState state;
int64_t seek_timestamp;
/* XXX: currently we use unbuffered input */ /* XXX: currently we use unbuffered input */
// ByteIOContext rtsp_gb; // ByteIOContext rtsp_gb;
int seq; /* RTSP command sequence number */ int seq; /* RTSP command sequence number */
...@@ -59,9 +68,11 @@ typedef struct RTSPStream { ...@@ -59,9 +68,11 @@ typedef struct RTSPStream {
int sdp_payload_type; /* payload type - only used in SDP */ int sdp_payload_type; /* payload type - only used in SDP */
} RTSPStream; } RTSPStream;
static int rtsp_read_play(AVFormatContext *s);
/* 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 #if 0
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 #else
/* try it if a proxy is used */ /* try it if a proxy is used */
...@@ -512,6 +523,26 @@ static void rtsp_parse_transport(RTSPHeader *reply, const char *p) ...@@ -512,6 +523,26 @@ static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
} }
} }
static void rtsp_parse_range_npt(RTSPHeader *reply, const char *p)
{
char buf[256];
skip_spaces(&p);
if (!stristart(p, "npt=", &p))
return;
reply->range_start = AV_NOPTS_VALUE;
reply->range_end = AV_NOPTS_VALUE;
get_word_sep(buf, sizeof(buf), "-", &p);
reply->range_start = parse_date(buf, 1);
if (*p == '-') {
p++;
get_word_sep(buf, sizeof(buf), "-", &p);
reply->range_end = parse_date(buf, 1);
}
}
void rtsp_parse_line(RTSPHeader *reply, const char *buf) void rtsp_parse_line(RTSPHeader *reply, const char *buf)
{ {
const char *p; const char *p;
...@@ -526,6 +557,8 @@ void rtsp_parse_line(RTSPHeader *reply, const char *buf) ...@@ -526,6 +557,8 @@ void rtsp_parse_line(RTSPHeader *reply, const char *buf)
rtsp_parse_transport(reply, p); rtsp_parse_transport(reply, p);
} else if (stristart(p, "CSeq:", &p)) { } else if (stristart(p, "CSeq:", &p)) {
reply->seq = strtol(p, NULL, 10); reply->seq = strtol(p, NULL, 10);
} else if (stristart(p, "Range:", &p)) {
rtsp_parse_range_npt(reply, p);
} }
} }
...@@ -856,27 +889,18 @@ static int rtsp_read_header(AVFormatContext *s, ...@@ -856,27 +889,18 @@ static int rtsp_read_header(AVFormatContext *s,
} }
} }
/* start playing */
snprintf(cmd, sizeof(cmd),
"PLAY %s RTSP/1.0\r\n"
"Range: npt=0-\r\n",
s->filename);
rtsp_send_cmd(s, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
err = AVERROR_INVALIDDATA;
goto fail;
}
#if 0 rt->state = RTSP_STATE_IDLE;
/* open TCP with bufferized input */ rt->seek_timestamp = 0; /* default is to start stream at position
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { zero */
if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) { if (ap && ap->initial_pause) {
err = AVERROR_NOMEM; /* do not start immediately */
} else {
if (rtsp_read_play(s) < 0) {
err = AVERROR_INVALIDDATA;
goto fail; goto fail;
} }
} }
#endif
return 0; return 0;
fail: fail:
rtsp_close_streams(rt); rtsp_close_streams(rt);
...@@ -1020,52 +1044,79 @@ static int rtsp_read_packet(AVFormatContext *s, ...@@ -1020,52 +1044,79 @@ static int rtsp_read_packet(AVFormatContext *s,
return 0; return 0;
} }
/* pause the stream */ static int rtsp_read_play(AVFormatContext *s)
int rtsp_pause(AVFormatContext *s)
{ {
RTSPState *rt; RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1; RTSPHeader reply1, *reply = &reply1;
char cmd[1024]; char cmd[1024];
if (s->iformat != &rtsp_demux) printf("hello state=%d\n", rt->state);
return -1;
rt = s->priv_data;
if (rt->state == RTSP_STATE_PAUSED) {
snprintf(cmd, sizeof(cmd), snprintf(cmd, sizeof(cmd),
"PAUSE %s RTSP/1.0\r\n", "PLAY %s RTSP/1.0\r\n",
s->filename); s->filename);
} else {
snprintf(cmd, sizeof(cmd),
"PLAY %s RTSP/1.0\r\n"
"Range: npt=%0.3f-\r\n",
s->filename,
(double)rt->seek_timestamp / AV_TIME_BASE);
}
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) {
return -1; return -1;
} else { } else {
rt->state = RTSP_STATE_PLAYING;
return 0; return 0;
} }
} }
/* resume the stream */ /* pause the stream */
int rtsp_resume(AVFormatContext *s) static int rtsp_read_pause(AVFormatContext *s)
{ {
RTSPState *rt; RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1; RTSPHeader reply1, *reply = &reply1;
char cmd[1024]; char cmd[1024];
if (s->iformat != &rtsp_demux)
return -1;
rt = s->priv_data; rt = s->priv_data;
if (rt->state != RTSP_STATE_PLAYING)
return 0;
snprintf(cmd, sizeof(cmd), snprintf(cmd, sizeof(cmd),
"PLAY %s RTSP/1.0\r\n", "PAUSE %s RTSP/1.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) {
return -1; return -1;
} else { } else {
rt->state = RTSP_STATE_PAUSED;
return 0; return 0;
} }
} }
static int rtsp_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp)
{
RTSPState *rt = s->priv_data;
rt->seek_timestamp = timestamp;
switch(rt->state) {
default:
case RTSP_STATE_IDLE:
break;
case RTSP_STATE_PLAYING:
if (rtsp_read_play(s) != 0)
return -1;
break;
case RTSP_STATE_PAUSED:
rt->state = RTSP_STATE_IDLE;
break;
}
return 0;
}
static int rtsp_read_close(AVFormatContext *s) static int rtsp_read_close(AVFormatContext *s)
{ {
RTSPState *rt = s->priv_data; RTSPState *rt = s->priv_data;
...@@ -1101,7 +1152,10 @@ AVInputFormat rtsp_demux = { ...@@ -1101,7 +1152,10 @@ AVInputFormat rtsp_demux = {
rtsp_read_header, rtsp_read_header,
rtsp_read_packet, rtsp_read_packet,
rtsp_read_close, rtsp_read_close,
rtsp_read_seek,
.flags = AVFMT_NOFILE, .flags = AVFMT_NOFILE,
.read_play = rtsp_read_play,
.read_pause = rtsp_read_pause,
}; };
static int sdp_probe(AVProbeData *p1) static int sdp_probe(AVProbeData *p1)
......
...@@ -50,6 +50,8 @@ typedef struct RTSPHeader { ...@@ -50,6 +50,8 @@ typedef struct RTSPHeader {
int content_length; int content_length;
enum RTSPStatusCode status_code; /* response code from server */ enum RTSPStatusCode status_code; /* response code from server */
int nb_transports; int nb_transports;
/* in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */
int64_t range_start, range_end;
RTSPTransportField transports[RTSP_MAX_TRANSPORTS]; RTSPTransportField transports[RTSP_MAX_TRANSPORTS];
int seq; /* sequence number */ int seq; /* sequence number */
char session_id[512]; char session_id[512];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment