changeset 304:d58c8859ff8c libavformat

initial seek support - more generic play/pause support
author bellard
date Mon, 10 Nov 2003 18:39:26 +0000
parents 2833c2311b66
children ef53bff8bf23
files rtsp.c rtsp.h
diffstat 2 files changed, 98 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/rtsp.c	Mon Nov 10 18:37:55 2003 +0000
+++ b/rtsp.c	Mon Nov 10 18:39:26 2003 +0000
@@ -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 @@
     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_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 @@
         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 @@
         }
     }
                          
-    /* 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,18 +1044,46 @@
     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)
+    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;
+    }
+}
+
+/* pause the stream */
+static int rtsp_read_pause(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPHeader reply1, *reply = &reply1;
+    char cmd[1024];
+
     rt = s->priv_data;
     
+    if (rt->state != RTSP_STATE_PLAYING)
+        return 0;
+
     snprintf(cmd, sizeof(cmd), 
              "PAUSE %s RTSP/1.0\r\n",
              s->filename);
@@ -1039,31 +1091,30 @@
     if (reply->status_code != RTSP_STATUS_OK) {
         return -1;
     } else {
+        rt->state = RTSP_STATE_PAUSED;
         return 0;
     }
 }
 
-/* resume the stream */
-int rtsp_resume(AVFormatContext *s)
+static int rtsp_read_seek(AVFormatContext *s, int stream_index, 
+                          int64_t timestamp)
 {
-    RTSPState *rt;
-    RTSPHeader reply1, *reply = &reply1;
-    char cmd[1024];
-
-    if (s->iformat != &rtsp_demux)
-        return -1;
+    RTSPState *rt = s->priv_data;
     
-    rt = s->priv_data;
-    
-    snprintf(cmd, sizeof(cmd), 
-             "PLAY %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 {
-        return 0;
+    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)
@@ -1101,7 +1152,10 @@
     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)
--- a/rtsp.h	Mon Nov 10 18:37:55 2003 +0000
+++ b/rtsp.h	Mon Nov 10 18:39:26 2003 +0000
@@ -50,6 +50,8 @@
     int content_length;
     enum RTSPStatusCode status_code; /* response code from server */
     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];
     int seq; /* sequence number */
     char session_id[512];