00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023
00024 #include <sys/time.h>
00025 #if HAVE_POLL_H
00026 #include <poll.h>
00027 #endif
00028 #include "network.h"
00029 #include "os_support.h"
00030 #include "rtsp.h"
00031 #include "internal.h"
00032 #include "libavutil/intreadwrite.h"
00033 #include "libavutil/avstring.h"
00034
00035 #define SDP_MAX_SIZE 16384
00036
00037 int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
00038 {
00039 RTSPState *rt = s->priv_data;
00040 RTSPMessageHeader reply1, *reply = &reply1;
00041 int i;
00042 char *sdp;
00043 AVFormatContext sdp_ctx, *ctx_array[1];
00044
00045 s->start_time_realtime = av_gettime();
00046
00047
00048 sdp = av_mallocz(SDP_MAX_SIZE);
00049 if (sdp == NULL)
00050 return AVERROR(ENOMEM);
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 sdp_ctx = *s;
00064 ff_url_join(sdp_ctx.filename, sizeof(sdp_ctx.filename),
00065 "rtsp", NULL, addr, -1, NULL);
00066 ctx_array[0] = &sdp_ctx;
00067 if (avf_sdp_create(ctx_array, 1, sdp, SDP_MAX_SIZE)) {
00068 av_free(sdp);
00069 return AVERROR_INVALIDDATA;
00070 }
00071 av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp);
00072 ff_rtsp_send_cmd_with_content(s, "ANNOUNCE", rt->control_uri,
00073 "Content-Type: application/sdp\r\n",
00074 reply, NULL, sdp, strlen(sdp));
00075 av_free(sdp);
00076 if (reply->status_code != RTSP_STATUS_OK)
00077 return AVERROR_INVALIDDATA;
00078
00079
00080 for (i = 0; i < s->nb_streams; i++) {
00081 RTSPStream *rtsp_st;
00082
00083 rtsp_st = av_mallocz(sizeof(RTSPStream));
00084 if (!rtsp_st)
00085 return AVERROR(ENOMEM);
00086 dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);
00087
00088 rtsp_st->stream_index = i;
00089
00090 av_strlcpy(rtsp_st->control_url, rt->control_uri, sizeof(rtsp_st->control_url));
00091
00092 av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url),
00093 "/streamid=%d", i);
00094 }
00095
00096 return 0;
00097 }
00098
00099 static int rtsp_write_record(AVFormatContext *s)
00100 {
00101 RTSPState *rt = s->priv_data;
00102 RTSPMessageHeader reply1, *reply = &reply1;
00103 char cmd[1024];
00104
00105 snprintf(cmd, sizeof(cmd),
00106 "Range: npt=%0.3f-\r\n",
00107 (double) 0);
00108 ff_rtsp_send_cmd(s, "RECORD", rt->control_uri, cmd, reply, NULL);
00109 if (reply->status_code != RTSP_STATUS_OK)
00110 return -1;
00111 rt->state = RTSP_STATE_STREAMING;
00112 return 0;
00113 }
00114
00115 static int rtsp_write_header(AVFormatContext *s)
00116 {
00117 int ret;
00118
00119 ret = ff_rtsp_connect(s);
00120 if (ret)
00121 return ret;
00122
00123 if (rtsp_write_record(s) < 0) {
00124 ff_rtsp_close_streams(s);
00125 ff_rtsp_close_connections(s);
00126 return AVERROR_INVALIDDATA;
00127 }
00128 return 0;
00129 }
00130
00131 static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
00132 {
00133 RTSPState *rt = s->priv_data;
00134 AVFormatContext *rtpctx = rtsp_st->transport_priv;
00135 uint8_t *buf, *ptr;
00136 int size;
00137 uint8_t *interleave_header, *interleaved_packet;
00138
00139 size = url_close_dyn_buf(rtpctx->pb, &buf);
00140 ptr = buf;
00141 while (size > 4) {
00142 uint32_t packet_len = AV_RB32(ptr);
00143 int id;
00144
00145
00146
00147
00148
00149 interleaved_packet = interleave_header = ptr;
00150 ptr += 4;
00151 size -= 4;
00152 if (packet_len > size || packet_len < 2)
00153 break;
00154 if (ptr[1] >= RTCP_SR && ptr[1] <= RTCP_APP)
00155 id = rtsp_st->interleaved_max;
00156 else
00157 id = rtsp_st->interleaved_min;
00158 interleave_header[0] = '$';
00159 interleave_header[1] = id;
00160 AV_WB16(interleave_header + 2, packet_len);
00161 url_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len);
00162 ptr += packet_len;
00163 size -= packet_len;
00164 }
00165 av_free(buf);
00166 url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE);
00167 return 0;
00168 }
00169
00170 static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)
00171 {
00172 RTSPState *rt = s->priv_data;
00173 RTSPStream *rtsp_st;
00174 int n;
00175 struct pollfd p = {url_get_file_handle(rt->rtsp_hd), POLLIN, 0};
00176 AVFormatContext *rtpctx;
00177 int ret;
00178
00179 while (1) {
00180 n = poll(&p, 1, 0);
00181 if (n <= 0)
00182 break;
00183 if (p.revents & POLLIN) {
00184 RTSPMessageHeader reply;
00185
00186
00187
00188
00189
00190 ret = ff_rtsp_read_reply(s, &reply, NULL, 1, NULL);
00191 if (ret < 0)
00192 return AVERROR(EPIPE);
00193 if (ret == 1)
00194 ff_rtsp_skip_packet(s);
00195
00196 if (rt->state != RTSP_STATE_STREAMING)
00197 return AVERROR(EPIPE);
00198 }
00199 }
00200
00201 if (pkt->stream_index < 0 || pkt->stream_index >= rt->nb_rtsp_streams)
00202 return AVERROR_INVALIDDATA;
00203 rtsp_st = rt->rtsp_streams[pkt->stream_index];
00204 rtpctx = rtsp_st->transport_priv;
00205
00206 ret = ff_write_chained(rtpctx, 0, pkt, s);
00207
00208
00209
00210
00211 if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP)
00212 ret = tcp_write_packet(s, rtsp_st);
00213 return ret;
00214 }
00215
00216 static int rtsp_write_close(AVFormatContext *s)
00217 {
00218 RTSPState *rt = s->priv_data;
00219
00220 ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
00221
00222 ff_rtsp_close_streams(s);
00223 ff_rtsp_close_connections(s);
00224 ff_network_close();
00225 return 0;
00226 }
00227
00228 AVOutputFormat ff_rtsp_muxer = {
00229 "rtsp",
00230 NULL_IF_CONFIG_SMALL("RTSP output format"),
00231 NULL,
00232 NULL,
00233 sizeof(RTSPState),
00234 CODEC_ID_AAC,
00235 CODEC_ID_MPEG4,
00236 rtsp_write_header,
00237 rtsp_write_packet,
00238 rtsp_write_close,
00239 .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER,
00240 };
00241