aboutsummaryrefslogtreecommitdiff
path: root/libavformat/rtsp.c
diff options
context:
space:
mode:
authorFabrice Bellard2003-11-10 18:39:26 +0000
committerFabrice Bellard2003-11-10 18:39:26 +0000
commitff762d6ed2cfeb9329f5fc8d711003f6f8624eee (patch)
treed1169f95c88c2c430f9db5bc97a9263cf78212f5 /libavformat/rtsp.c
parentfb2758c83d28bf8ec74d28e323da1c4a1a121637 (diff)
initial seek support - more generic play/pause support
Originally committed as revision 2495 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/rtsp.c')
-rw-r--r--libavformat/rtsp.c128
1 files changed, 91 insertions, 37 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 415740ea37..54ae6c1c3e 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -31,11 +31,20 @@
//#define DEBUG
//#define DEBUG_RTP_TCP
+enum RTSPClientState {
+ RTSP_STATE_IDLE,
+ RTSP_STATE_PLAYING,
+ RTSP_STATE_PAUSED,
+};
+
typedef struct RTSPState {
URLContext *rtsp_hd; /* RTSP TCP connexion handle */
int nb_rtsp_streams;
struct RTSPStream **rtsp_streams;
-
+
+ enum RTSPClientState state;
+ int64_t seek_timestamp;
+
/* XXX: currently we use unbuffered input */
// ByteIOContext rtsp_gb;
int seq; /* RTSP command sequence number */
@@ -59,9 +68,11 @@ typedef struct RTSPStream {
int sdp_payload_type; /* payload type - only used in SDP */
} RTSPStream;
+static int rtsp_read_play(AVFormatContext *s);
+
/* XXX: currently, the only way to change the protocols consists in
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);
#else
/* try it if a proxy is used */
@@ -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)
{
const char *p;
@@ -526,6 +557,8 @@ void rtsp_parse_line(RTSPHeader *reply, const char *buf)
rtsp_parse_transport(reply, p);
} else if (stristart(p, "CSeq:", &p)) {
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,
}
}
- /* 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
- /* open TCP with bufferized input */
- if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
- if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) {
- err = AVERROR_NOMEM;
+ rt->state = RTSP_STATE_IDLE;
+ rt->seek_timestamp = 0; /* default is to start stream at position
+ zero */
+ if (ap && ap->initial_pause) {
+ /* do not start immediately */
+ } else {
+ if (rtsp_read_play(s) < 0) {
+ err = AVERROR_INVALIDDATA;
goto fail;
}
}
-#endif
-
return 0;
fail:
rtsp_close_streams(rt);
@@ -1020,52 +1044,79 @@ static int rtsp_read_packet(AVFormatContext *s,
return 0;
}
-/* pause the stream */
-int rtsp_pause(AVFormatContext *s)
+static int rtsp_read_play(AVFormatContext *s)
{
- RTSPState *rt;
+ RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1;
char cmd[1024];
- if (s->iformat != &rtsp_demux)
- return -1;
-
- rt = s->priv_data;
-
- snprintf(cmd, sizeof(cmd),
- "PAUSE %s RTSP/1.0\r\n",
- s->filename);
+ printf("hello state=%d\n", rt->state);
+
+ if (rt->state == RTSP_STATE_PAUSED) {
+ snprintf(cmd, sizeof(cmd),
+ "PLAY %s RTSP/1.0\r\n",
+ 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);
if (reply->status_code != RTSP_STATUS_OK) {
return -1;
} else {
+ rt->state = RTSP_STATE_PLAYING;
return 0;
}
}
-/* resume the stream */
-int rtsp_resume(AVFormatContext *s)
+/* pause the stream */
+static int rtsp_read_pause(AVFormatContext *s)
{
- RTSPState *rt;
+ RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1;
char cmd[1024];
- if (s->iformat != &rtsp_demux)
- return -1;
-
rt = s->priv_data;
+ if (rt->state != RTSP_STATE_PLAYING)
+ return 0;
+
snprintf(cmd, sizeof(cmd),
- "PLAY %s RTSP/1.0\r\n",
+ "PAUSE %s RTSP/1.0\r\n",
s->filename);
rtsp_send_cmd(s, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
return -1;
} else {
+ rt->state = RTSP_STATE_PAUSED;
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)
{
RTSPState *rt = s->priv_data;
@@ -1101,7 +1152,10 @@ AVInputFormat rtsp_demux = {
rtsp_read_header,
rtsp_read_packet,
rtsp_read_close,
+ rtsp_read_seek,
.flags = AVFMT_NOFILE,
+ .read_play = rtsp_read_play,
+ .read_pause = rtsp_read_pause,
};
static int sdp_probe(AVProbeData *p1)