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 @@
//#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;
printf("hello state=%d\n", rt->state);
if (rt->state == RTSP_STATE_PAUSED) {
snprintf(cmd, sizeof(cmd),
"PAUSE %s RTSP/1.0\r\n",
"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)
......
......@@ -50,6 +50,8 @@ typedef struct RTSPHeader {
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];
......
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