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