Mercurial > libavformat.hg
comparison rtsp.c @ 304:d58c8859ff8c libavformat
initial seek support - more generic play/pause support
author | bellard |
---|---|
date | Mon, 10 Nov 2003 18:39:26 +0000 |
parents | 6091b76cfc2a |
children | 845f9de2c883 |
comparison
equal
deleted
inserted
replaced
303:2833c2311b66 | 304:d58c8859ff8c |
---|---|
29 #endif | 29 #endif |
30 | 30 |
31 //#define DEBUG | 31 //#define DEBUG |
32 //#define DEBUG_RTP_TCP | 32 //#define DEBUG_RTP_TCP |
33 | 33 |
34 enum RTSPClientState { | |
35 RTSP_STATE_IDLE, | |
36 RTSP_STATE_PLAYING, | |
37 RTSP_STATE_PAUSED, | |
38 }; | |
39 | |
34 typedef struct RTSPState { | 40 typedef struct RTSPState { |
35 URLContext *rtsp_hd; /* RTSP TCP connexion handle */ | 41 URLContext *rtsp_hd; /* RTSP TCP connexion handle */ |
36 int nb_rtsp_streams; | 42 int nb_rtsp_streams; |
37 struct RTSPStream **rtsp_streams; | 43 struct RTSPStream **rtsp_streams; |
38 | 44 |
45 enum RTSPClientState state; | |
46 int64_t seek_timestamp; | |
47 | |
39 /* XXX: currently we use unbuffered input */ | 48 /* XXX: currently we use unbuffered input */ |
40 // ByteIOContext rtsp_gb; | 49 // ByteIOContext rtsp_gb; |
41 int seq; /* RTSP command sequence number */ | 50 int seq; /* RTSP command sequence number */ |
42 char session_id[512]; | 51 char session_id[512]; |
43 enum RTSPProtocol protocol; | 52 enum RTSPProtocol protocol; |
57 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */ | 66 struct in_addr sdp_ip; /* IP address (from SDP content - not used in RTSP) */ |
58 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ | 67 int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ |
59 int sdp_payload_type; /* payload type - only used in SDP */ | 68 int sdp_payload_type; /* payload type - only used in SDP */ |
60 } RTSPStream; | 69 } RTSPStream; |
61 | 70 |
71 static int rtsp_read_play(AVFormatContext *s); | |
72 | |
62 /* XXX: currently, the only way to change the protocols consists in | 73 /* XXX: currently, the only way to change the protocols consists in |
63 changing this variable */ | 74 changing this variable */ |
64 #if 1 | 75 #if 0 |
65 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST); | 76 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST); |
66 #else | 77 #else |
67 /* try it if a proxy is used */ | 78 /* try it if a proxy is used */ |
68 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP); | 79 int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP); |
69 #endif | 80 #endif |
510 | 521 |
511 reply->nb_transports++; | 522 reply->nb_transports++; |
512 } | 523 } |
513 } | 524 } |
514 | 525 |
526 static void rtsp_parse_range_npt(RTSPHeader *reply, const char *p) | |
527 { | |
528 char buf[256]; | |
529 | |
530 skip_spaces(&p); | |
531 if (!stristart(p, "npt=", &p)) | |
532 return; | |
533 | |
534 reply->range_start = AV_NOPTS_VALUE; | |
535 reply->range_end = AV_NOPTS_VALUE; | |
536 | |
537 get_word_sep(buf, sizeof(buf), "-", &p); | |
538 reply->range_start = parse_date(buf, 1); | |
539 if (*p == '-') { | |
540 p++; | |
541 get_word_sep(buf, sizeof(buf), "-", &p); | |
542 reply->range_end = parse_date(buf, 1); | |
543 } | |
544 } | |
545 | |
515 void rtsp_parse_line(RTSPHeader *reply, const char *buf) | 546 void rtsp_parse_line(RTSPHeader *reply, const char *buf) |
516 { | 547 { |
517 const char *p; | 548 const char *p; |
518 | 549 |
519 /* NOTE: we do case independent match for broken servers */ | 550 /* NOTE: we do case independent match for broken servers */ |
524 reply->content_length = strtol(p, NULL, 10); | 555 reply->content_length = strtol(p, NULL, 10); |
525 } else if (stristart(p, "Transport:", &p)) { | 556 } else if (stristart(p, "Transport:", &p)) { |
526 rtsp_parse_transport(reply, p); | 557 rtsp_parse_transport(reply, p); |
527 } else if (stristart(p, "CSeq:", &p)) { | 558 } else if (stristart(p, "CSeq:", &p)) { |
528 reply->seq = strtol(p, NULL, 10); | 559 reply->seq = strtol(p, NULL, 10); |
560 } else if (stristart(p, "Range:", &p)) { | |
561 rtsp_parse_range_npt(reply, p); | |
529 } | 562 } |
530 } | 563 } |
531 | 564 |
532 /* skip a RTP/TCP interleaved packet */ | 565 /* skip a RTP/TCP interleaved packet */ |
533 static void rtsp_skip_packet(AVFormatContext *s) | 566 static void rtsp_skip_packet(AVFormatContext *s) |
854 err = AVERROR_INVALIDDATA; | 887 err = AVERROR_INVALIDDATA; |
855 goto fail; | 888 goto fail; |
856 } | 889 } |
857 } | 890 } |
858 | 891 |
859 /* start playing */ | 892 |
860 snprintf(cmd, sizeof(cmd), | 893 rt->state = RTSP_STATE_IDLE; |
861 "PLAY %s RTSP/1.0\r\n" | 894 rt->seek_timestamp = 0; /* default is to start stream at position |
862 "Range: npt=0-\r\n", | 895 zero */ |
863 s->filename); | 896 if (ap && ap->initial_pause) { |
864 rtsp_send_cmd(s, cmd, reply, NULL); | 897 /* do not start immediately */ |
865 if (reply->status_code != RTSP_STATUS_OK) { | 898 } else { |
866 err = AVERROR_INVALIDDATA; | 899 if (rtsp_read_play(s) < 0) { |
867 goto fail; | 900 err = AVERROR_INVALIDDATA; |
868 } | |
869 | |
870 #if 0 | |
871 /* open TCP with bufferized input */ | |
872 if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { | |
873 if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) { | |
874 err = AVERROR_NOMEM; | |
875 goto fail; | 901 goto fail; |
876 } | 902 } |
877 } | 903 } |
878 #endif | |
879 | |
880 return 0; | 904 return 0; |
881 fail: | 905 fail: |
882 rtsp_close_streams(rt); | 906 rtsp_close_streams(rt); |
883 av_freep(&content); | 907 av_freep(&content); |
884 url_close(rt->rtsp_hd); | 908 url_close(rt->rtsp_hd); |
1018 rt->cur_rtp = rtsp_st->rtp_ctx; | 1042 rt->cur_rtp = rtsp_st->rtp_ctx; |
1019 } | 1043 } |
1020 return 0; | 1044 return 0; |
1021 } | 1045 } |
1022 | 1046 |
1023 /* pause the stream */ | 1047 static int rtsp_read_play(AVFormatContext *s) |
1024 int rtsp_pause(AVFormatContext *s) | 1048 { |
1025 { | 1049 RTSPState *rt = s->priv_data; |
1026 RTSPState *rt; | |
1027 RTSPHeader reply1, *reply = &reply1; | 1050 RTSPHeader reply1, *reply = &reply1; |
1028 char cmd[1024]; | 1051 char cmd[1024]; |
1029 | 1052 |
1030 if (s->iformat != &rtsp_demux) | 1053 printf("hello state=%d\n", rt->state); |
1054 | |
1055 if (rt->state == RTSP_STATE_PAUSED) { | |
1056 snprintf(cmd, sizeof(cmd), | |
1057 "PLAY %s RTSP/1.0\r\n", | |
1058 s->filename); | |
1059 } else { | |
1060 snprintf(cmd, sizeof(cmd), | |
1061 "PLAY %s RTSP/1.0\r\n" | |
1062 "Range: npt=%0.3f-\r\n", | |
1063 s->filename, | |
1064 (double)rt->seek_timestamp / AV_TIME_BASE); | |
1065 } | |
1066 rtsp_send_cmd(s, cmd, reply, NULL); | |
1067 if (reply->status_code != RTSP_STATUS_OK) { | |
1031 return -1; | 1068 return -1; |
1032 | 1069 } else { |
1070 rt->state = RTSP_STATE_PLAYING; | |
1071 return 0; | |
1072 } | |
1073 } | |
1074 | |
1075 /* pause the stream */ | |
1076 static int rtsp_read_pause(AVFormatContext *s) | |
1077 { | |
1078 RTSPState *rt = s->priv_data; | |
1079 RTSPHeader reply1, *reply = &reply1; | |
1080 char cmd[1024]; | |
1081 | |
1033 rt = s->priv_data; | 1082 rt = s->priv_data; |
1034 | 1083 |
1084 if (rt->state != RTSP_STATE_PLAYING) | |
1085 return 0; | |
1086 | |
1035 snprintf(cmd, sizeof(cmd), | 1087 snprintf(cmd, sizeof(cmd), |
1036 "PAUSE %s RTSP/1.0\r\n", | 1088 "PAUSE %s RTSP/1.0\r\n", |
1037 s->filename); | 1089 s->filename); |
1038 rtsp_send_cmd(s, cmd, reply, NULL); | 1090 rtsp_send_cmd(s, cmd, reply, NULL); |
1039 if (reply->status_code != RTSP_STATUS_OK) { | 1091 if (reply->status_code != RTSP_STATUS_OK) { |
1040 return -1; | 1092 return -1; |
1041 } else { | 1093 } else { |
1094 rt->state = RTSP_STATE_PAUSED; | |
1042 return 0; | 1095 return 0; |
1043 } | 1096 } |
1044 } | 1097 } |
1045 | 1098 |
1046 /* resume the stream */ | 1099 static int rtsp_read_seek(AVFormatContext *s, int stream_index, |
1047 int rtsp_resume(AVFormatContext *s) | 1100 int64_t timestamp) |
1048 { | 1101 { |
1049 RTSPState *rt; | 1102 RTSPState *rt = s->priv_data; |
1050 RTSPHeader reply1, *reply = &reply1; | |
1051 char cmd[1024]; | |
1052 | |
1053 if (s->iformat != &rtsp_demux) | |
1054 return -1; | |
1055 | 1103 |
1056 rt = s->priv_data; | 1104 rt->seek_timestamp = timestamp; |
1057 | 1105 switch(rt->state) { |
1058 snprintf(cmd, sizeof(cmd), | 1106 default: |
1059 "PLAY %s RTSP/1.0\r\n", | 1107 case RTSP_STATE_IDLE: |
1060 s->filename); | 1108 break; |
1061 rtsp_send_cmd(s, cmd, reply, NULL); | 1109 case RTSP_STATE_PLAYING: |
1062 if (reply->status_code != RTSP_STATUS_OK) { | 1110 if (rtsp_read_play(s) != 0) |
1063 return -1; | 1111 return -1; |
1064 } else { | 1112 break; |
1065 return 0; | 1113 case RTSP_STATE_PAUSED: |
1066 } | 1114 rt->state = RTSP_STATE_IDLE; |
1115 break; | |
1116 } | |
1117 return 0; | |
1067 } | 1118 } |
1068 | 1119 |
1069 static int rtsp_read_close(AVFormatContext *s) | 1120 static int rtsp_read_close(AVFormatContext *s) |
1070 { | 1121 { |
1071 RTSPState *rt = s->priv_data; | 1122 RTSPState *rt = s->priv_data; |
1099 sizeof(RTSPState), | 1150 sizeof(RTSPState), |
1100 rtsp_probe, | 1151 rtsp_probe, |
1101 rtsp_read_header, | 1152 rtsp_read_header, |
1102 rtsp_read_packet, | 1153 rtsp_read_packet, |
1103 rtsp_read_close, | 1154 rtsp_read_close, |
1155 rtsp_read_seek, | |
1104 .flags = AVFMT_NOFILE, | 1156 .flags = AVFMT_NOFILE, |
1157 .read_play = rtsp_read_play, | |
1158 .read_pause = rtsp_read_pause, | |
1105 }; | 1159 }; |
1106 | 1160 |
1107 static int sdp_probe(AVProbeData *p1) | 1161 static int sdp_probe(AVProbeData *p1) |
1108 { | 1162 { |
1109 const char *p; | 1163 const char *p; |