]> git.sesse.net Git - ffmpeg/blob - libavformat/rtspenc.c
Remove unnecessary inclusions of [sys/]time.h
[ffmpeg] / libavformat / rtspenc.c
1 /*
2  * RTSP muxer
3  * Copyright (c) 2010 Martin Storsjo
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "avformat.h"
23
24 #if HAVE_POLL_H
25 #include <poll.h>
26 #endif
27 #include "network.h"
28 #include "os_support.h"
29 #include "rtsp.h"
30 #include "internal.h"
31 #include "avio_internal.h"
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/avstring.h"
34 #include "url.h"
35
36 #define SDP_MAX_SIZE 16384
37
38 static const AVClass rtsp_muxer_class = {
39     .class_name = "RTSP muxer",
40     .item_name  = av_default_item_name,
41     .option     = ff_rtsp_options,
42     .version    = LIBAVUTIL_VERSION_INT,
43 };
44
45 int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
46 {
47     RTSPState *rt = s->priv_data;
48     RTSPMessageHeader reply1, *reply = &reply1;
49     int i;
50     char *sdp;
51     AVFormatContext sdp_ctx, *ctx_array[1];
52
53     s->start_time_realtime = av_gettime();
54
55     /* Announce the stream */
56     sdp = av_mallocz(SDP_MAX_SIZE);
57     if (sdp == NULL)
58         return AVERROR(ENOMEM);
59     /* We create the SDP based on the RTSP AVFormatContext where we
60      * aren't allowed to change the filename field. (We create the SDP
61      * based on the RTSP context since the contexts for the RTP streams
62      * don't exist yet.) In order to specify a custom URL with the actual
63      * peer IP instead of the originally specified hostname, we create
64      * a temporary copy of the AVFormatContext, where the custom URL is set.
65      *
66      * FIXME: Create the SDP without copying the AVFormatContext.
67      * This either requires setting up the RTP stream AVFormatContexts
68      * already here (complicating things immensely) or getting a more
69      * flexible SDP creation interface.
70      */
71     sdp_ctx = *s;
72     ff_url_join(sdp_ctx.filename, sizeof(sdp_ctx.filename),
73                 "rtsp", NULL, addr, -1, NULL);
74     ctx_array[0] = &sdp_ctx;
75     if (av_sdp_create(ctx_array, 1, sdp, SDP_MAX_SIZE)) {
76         av_free(sdp);
77         return AVERROR_INVALIDDATA;
78     }
79     av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp);
80     ff_rtsp_send_cmd_with_content(s, "ANNOUNCE", rt->control_uri,
81                                   "Content-Type: application/sdp\r\n",
82                                   reply, NULL, sdp, strlen(sdp));
83     av_free(sdp);
84     if (reply->status_code != RTSP_STATUS_OK)
85         return AVERROR_INVALIDDATA;
86
87     /* Set up the RTSPStreams for each AVStream */
88     for (i = 0; i < s->nb_streams; i++) {
89         RTSPStream *rtsp_st;
90
91         rtsp_st = av_mallocz(sizeof(RTSPStream));
92         if (!rtsp_st)
93             return AVERROR(ENOMEM);
94         dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st);
95
96         rtsp_st->stream_index = i;
97
98         av_strlcpy(rtsp_st->control_url, rt->control_uri, sizeof(rtsp_st->control_url));
99         /* Note, this must match the relative uri set in the sdp content */
100         av_strlcatf(rtsp_st->control_url, sizeof(rtsp_st->control_url),
101                     "/streamid=%d", i);
102     }
103
104     return 0;
105 }
106
107 static int rtsp_write_record(AVFormatContext *s)
108 {
109     RTSPState *rt = s->priv_data;
110     RTSPMessageHeader reply1, *reply = &reply1;
111     char cmd[1024];
112
113     snprintf(cmd, sizeof(cmd),
114              "Range: npt=0.000-\r\n");
115     ff_rtsp_send_cmd(s, "RECORD", rt->control_uri, cmd, reply, NULL);
116     if (reply->status_code != RTSP_STATUS_OK)
117         return -1;
118     rt->state = RTSP_STATE_STREAMING;
119     return 0;
120 }
121
122 static int rtsp_write_header(AVFormatContext *s)
123 {
124     int ret;
125
126     ret = ff_rtsp_connect(s);
127     if (ret)
128         return ret;
129
130     if (rtsp_write_record(s) < 0) {
131         ff_rtsp_close_streams(s);
132         ff_rtsp_close_connections(s);
133         return AVERROR_INVALIDDATA;
134     }
135     return 0;
136 }
137
138 static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st)
139 {
140     RTSPState *rt = s->priv_data;
141     AVFormatContext *rtpctx = rtsp_st->transport_priv;
142     uint8_t *buf, *ptr;
143     int size;
144     uint8_t *interleave_header, *interleaved_packet;
145
146     size = avio_close_dyn_buf(rtpctx->pb, &buf);
147     ptr = buf;
148     while (size > 4) {
149         uint32_t packet_len = AV_RB32(ptr);
150         int id;
151         /* The interleaving header is exactly 4 bytes, which happens to be
152          * the same size as the packet length header from
153          * ffio_open_dyn_packet_buf. So by writing the interleaving header
154          * over these bytes, we get a consecutive interleaved packet
155          * that can be written in one call. */
156         interleaved_packet = interleave_header = ptr;
157         ptr += 4;
158         size -= 4;
159         if (packet_len > size || packet_len < 2)
160             break;
161         if (RTP_PT_IS_RTCP(ptr[1]))
162             id = rtsp_st->interleaved_max; /* RTCP */
163         else
164             id = rtsp_st->interleaved_min; /* RTP */
165         interleave_header[0] = '$';
166         interleave_header[1] = id;
167         AV_WB16(interleave_header + 2, packet_len);
168         ffurl_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len);
169         ptr += packet_len;
170         size -= packet_len;
171     }
172     av_free(buf);
173     ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE);
174     return 0;
175 }
176
177 static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)
178 {
179     RTSPState *rt = s->priv_data;
180     RTSPStream *rtsp_st;
181     int n;
182     struct pollfd p = {ffurl_get_file_handle(rt->rtsp_hd), POLLIN, 0};
183     AVFormatContext *rtpctx;
184     int ret;
185
186     while (1) {
187         n = poll(&p, 1, 0);
188         if (n <= 0)
189             break;
190         if (p.revents & POLLIN) {
191             RTSPMessageHeader reply;
192
193             /* Don't let ff_rtsp_read_reply handle interleaved packets,
194              * since it would block and wait for an RTSP reply on the socket
195              * (which may not be coming any time soon) if it handles
196              * interleaved packets internally. */
197             ret = ff_rtsp_read_reply(s, &reply, NULL, 1, NULL);
198             if (ret < 0)
199                 return AVERROR(EPIPE);
200             if (ret == 1)
201                 ff_rtsp_skip_packet(s);
202             /* XXX: parse message */
203             if (rt->state != RTSP_STATE_STREAMING)
204                 return AVERROR(EPIPE);
205         }
206     }
207
208     if (pkt->stream_index < 0 || pkt->stream_index >= rt->nb_rtsp_streams)
209         return AVERROR_INVALIDDATA;
210     rtsp_st = rt->rtsp_streams[pkt->stream_index];
211     rtpctx = rtsp_st->transport_priv;
212
213     ret = ff_write_chained(rtpctx, 0, pkt, s);
214     /* ff_write_chained does all the RTP packetization. If using TCP as
215      * transport, rtpctx->pb is only a dyn_packet_buf that queues up the
216      * packets, so we need to send them out on the TCP connection separately.
217      */
218     if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP)
219         ret = tcp_write_packet(s, rtsp_st);
220     return ret;
221 }
222
223 static int rtsp_write_close(AVFormatContext *s)
224 {
225     RTSPState *rt = s->priv_data;
226
227     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
228
229     ff_rtsp_close_streams(s);
230     ff_rtsp_close_connections(s);
231     ff_network_close();
232     return 0;
233 }
234
235 AVOutputFormat ff_rtsp_muxer = {
236     .name              = "rtsp",
237     .long_name         = NULL_IF_CONFIG_SMALL("RTSP output format"),
238     .priv_data_size    = sizeof(RTSPState),
239     .audio_codec       = CODEC_ID_AAC,
240     .video_codec       = CODEC_ID_MPEG4,
241     .write_header      = rtsp_write_header,
242     .write_packet      = rtsp_write_packet,
243     .write_trailer     = rtsp_write_close,
244     .flags             = AVFMT_NOFILE | AVFMT_GLOBALHEADER,
245     .priv_class        = &rtsp_muxer_class,
246 };