mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2024-11-28 05:50:43 +00:00
initial seek support - more generic play/pause support
Originally committed as revision 2495 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
fb2758c83d
commit
ff762d6ed2
@ -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) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
rtsp_close_streams(rt);
|
||||
@ -1020,18 +1044,46 @@ 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)
|
||||
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 @@ int rtsp_pause(AVFormatContext *s)
|
||||
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];
|
||||
RTSPState *rt = s->priv_data;
|
||||
|
||||
if (s->iformat != &rtsp_demux)
|
||||
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;
|
||||
|
||||
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;
|
||||
break;
|
||||
case RTSP_STATE_PAUSED:
|
||||
rt->state = RTSP_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtsp_read_close(AVFormatContext *s)
|
||||
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user