ffmpeg / libavformat / rtspenc.c @ 72415b2a
History | View | Annotate | Download (5.21 KB)
1 | 6f5a3d0a | Martin Storsjö | /*
|
---|---|---|---|
2 | * RTSP muxer
|
||
3 | * Copyright (c) 2010 Martin Storsjo
|
||
4 | *
|
||
5 | * This file is part of FFmpeg.
|
||
6 | *
|
||
7 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; 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 | #include <sys/time.h> |
||
25 | #if HAVE_SYS_SELECT_H
|
||
26 | #include <sys/select.h> |
||
27 | #endif
|
||
28 | #include "network.h" |
||
29 | #include "rtsp.h" |
||
30 | b7dc88fc | Martin Storsjö | #include <libavutil/intreadwrite.h> |
31 | 6f5a3d0a | Martin Storsjö | |
32 | static int rtsp_write_record(AVFormatContext *s) |
||
33 | { |
||
34 | RTSPState *rt = s->priv_data; |
||
35 | RTSPMessageHeader reply1, *reply = &reply1; |
||
36 | char cmd[1024]; |
||
37 | |||
38 | snprintf(cmd, sizeof(cmd),
|
||
39 | "Range: npt=%0.3f-\r\n",
|
||
40 | (double) 0); |
||
41 | b17d11c6 | Martin Storsjö | ff_rtsp_send_cmd(s, "RECORD", rt->control_uri, cmd, reply, NULL); |
42 | 6f5a3d0a | Martin Storsjö | if (reply->status_code != RTSP_STATUS_OK)
|
43 | return -1; |
||
44 | rt->state = RTSP_STATE_STREAMING; |
||
45 | return 0; |
||
46 | } |
||
47 | |||
48 | static int rtsp_write_header(AVFormatContext *s) |
||
49 | { |
||
50 | RTSPState *rt = s->priv_data; |
||
51 | int ret;
|
||
52 | |||
53 | 3307e6ea | Ronald S. Bultje | ret = ff_rtsp_connect(s); |
54 | 6f5a3d0a | Martin Storsjö | if (ret)
|
55 | return ret;
|
||
56 | |||
57 | if (rtsp_write_record(s) < 0) { |
||
58 | 3307e6ea | Ronald S. Bultje | ff_rtsp_close_streams(s); |
59 | 6f5a3d0a | Martin Storsjö | url_close(rt->rtsp_hd); |
60 | return AVERROR_INVALIDDATA;
|
||
61 | } |
||
62 | return 0; |
||
63 | } |
||
64 | |||
65 | b7dc88fc | Martin Storsjö | static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) |
66 | { |
||
67 | RTSPState *rt = s->priv_data; |
||
68 | AVFormatContext *rtpctx = rtsp_st->transport_priv; |
||
69 | uint8_t *buf, *ptr; |
||
70 | int size;
|
||
71 | uint8_t interleave_header[4];
|
||
72 | |||
73 | size = url_close_dyn_buf(rtpctx->pb, &buf); |
||
74 | ptr = buf; |
||
75 | while (size > 4) { |
||
76 | uint32_t packet_len = AV_RB32(ptr); |
||
77 | int id;
|
||
78 | ptr += 4;
|
||
79 | size -= 4;
|
||
80 | if (packet_len > size || packet_len < 2) |
||
81 | break;
|
||
82 | if (ptr[1] >= 200 && ptr[1] <= 204) |
||
83 | id = rtsp_st->interleaved_max; /* RTCP */
|
||
84 | else
|
||
85 | id = rtsp_st->interleaved_min; /* RTP */
|
||
86 | interleave_header[0] = '$'; |
||
87 | interleave_header[1] = id;
|
||
88 | AV_WB16(interleave_header + 2, packet_len);
|
||
89 | url_write(rt->rtsp_hd, interleave_header, 4);
|
||
90 | url_write(rt->rtsp_hd, ptr, packet_len); |
||
91 | ptr += packet_len; |
||
92 | size -= packet_len; |
||
93 | } |
||
94 | av_free(buf); |
||
95 | url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); |
||
96 | return 0; |
||
97 | } |
||
98 | |||
99 | 6f5a3d0a | Martin Storsjö | static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) |
100 | { |
||
101 | RTSPState *rt = s->priv_data; |
||
102 | RTSPStream *rtsp_st; |
||
103 | fd_set rfds; |
||
104 | int n, tcp_fd;
|
||
105 | struct timeval tv;
|
||
106 | AVFormatContext *rtpctx; |
||
107 | 50ff78db | Martin Storsjö | AVPacket local_pkt; |
108 | ad2ae6db | Martin Storsjö | int ret;
|
109 | 6f5a3d0a | Martin Storsjö | |
110 | tcp_fd = url_get_file_handle(rt->rtsp_hd); |
||
111 | |||
112 | ad2ae6db | Martin Storsjö | while (1) { |
113 | FD_ZERO(&rfds); |
||
114 | FD_SET(tcp_fd, &rfds); |
||
115 | db128802 | Martin Storsjö | tv.tv_sec = 0;
|
116 | tv.tv_usec = 0;
|
||
117 | n = select(tcp_fd + 1, &rfds, NULL, NULL, &tv); |
||
118 | ad2ae6db | Martin Storsjö | if (n <= 0) |
119 | break;
|
||
120 | 6f5a3d0a | Martin Storsjö | if (FD_ISSET(tcp_fd, &rfds)) {
|
121 | RTSPMessageHeader reply; |
||
122 | |||
123 | ad2ae6db | Martin Storsjö | /* Don't let ff_rtsp_read_reply handle interleaved packets,
|
124 | * since it would block and wait for an RTSP reply on the socket
|
||
125 | * (which may not be coming any time soon) if it handles
|
||
126 | * interleaved packets internally. */
|
||
127 | ret = ff_rtsp_read_reply(s, &reply, NULL, 1); |
||
128 | if (ret < 0) |
||
129 | 6f5a3d0a | Martin Storsjö | return AVERROR(EPIPE);
|
130 | ad2ae6db | Martin Storsjö | if (ret == 1) |
131 | ff_rtsp_skip_packet(s); |
||
132 | 6f5a3d0a | Martin Storsjö | /* XXX: parse message */
|
133 | if (rt->state != RTSP_STATE_STREAMING)
|
||
134 | return AVERROR(EPIPE);
|
||
135 | } |
||
136 | } |
||
137 | |||
138 | if (pkt->stream_index < 0 || pkt->stream_index >= rt->nb_rtsp_streams) |
||
139 | return AVERROR_INVALIDDATA;
|
||
140 | rtsp_st = rt->rtsp_streams[pkt->stream_index]; |
||
141 | rtpctx = rtsp_st->transport_priv; |
||
142 | |||
143 | 50ff78db | Martin Storsjö | /* Use a local packet for writing to the chained muxer, otherwise
|
144 | * the internal stream_index = 0 becomes visible to the muxer user. */
|
||
145 | local_pkt = *pkt; |
||
146 | local_pkt.stream_index = 0;
|
||
147 | b7dc88fc | Martin Storsjö | ret = av_write_frame(rtpctx, &local_pkt); |
148 | /* av_write_frame does all the RTP packetization. If using TCP as
|
||
149 | * transport, rtpctx->pb is only a dyn_packet_buf that queues up the
|
||
150 | * packets, so we need to send them out on the TCP connection separately.
|
||
151 | */
|
||
152 | if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP)
|
||
153 | ret = tcp_write_packet(s, rtsp_st); |
||
154 | return ret;
|
||
155 | 6f5a3d0a | Martin Storsjö | } |
156 | |||
157 | static int rtsp_write_close(AVFormatContext *s) |
||
158 | { |
||
159 | RTSPState *rt = s->priv_data; |
||
160 | |||
161 | b17d11c6 | Martin Storsjö | ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL); |
162 | 6f5a3d0a | Martin Storsjö | |
163 | 3307e6ea | Ronald S. Bultje | ff_rtsp_close_streams(s); |
164 | 6f5a3d0a | Martin Storsjö | url_close(rt->rtsp_hd); |
165 | 57b5555c | Martin Storsjö | ff_network_close(); |
166 | 6f5a3d0a | Martin Storsjö | return 0; |
167 | } |
||
168 | |||
169 | AVOutputFormat rtsp_muxer = { |
||
170 | "rtsp",
|
||
171 | NULL_IF_CONFIG_SMALL("RTSP output format"),
|
||
172 | NULL,
|
||
173 | NULL,
|
||
174 | sizeof(RTSPState),
|
||
175 | CODEC_ID_PCM_MULAW, |
||
176 | CODEC_ID_NONE, |
||
177 | rtsp_write_header, |
||
178 | rtsp_write_packet, |
||
179 | rtsp_write_close, |
||
180 | .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER, |
||
181 | }; |