Libav 0.7.1
|
00001 /* 00002 * RTSP muxer 00003 * Copyright (c) 2010 Martin Storsjo 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* Announce the stream */ 00064 sdp = av_mallocz(SDP_MAX_SIZE); 00065 if (sdp == NULL) 00066 return AVERROR(ENOMEM); 00067 /* We create the SDP based on the RTSP AVFormatContext where we 00068 * aren't allowed to change the filename field. (We create the SDP 00069 * based on the RTSP context since the contexts for the RTP streams 00070 * don't exist yet.) In order to specify a custom URL with the actual 00071 * peer IP instead of the originally specified hostname, we create 00072 * a temporary copy of the AVFormatContext, where the custom URL is set. 00073 * 00074 * FIXME: Create the SDP without copying the AVFormatContext. 00075 * This either requires setting up the RTP stream AVFormatContexts 00076 * already here (complicating things immensely) or getting a more 00077 * flexible SDP creation interface. 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 /* Set up the RTSPStreams for each AVStream */ 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 /* Note, this must match the relative uri set in the sdp content */ 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 /* The interleaving header is exactly 4 bytes, which happens to be 00160 * the same size as the packet length header from 00161 * ffio_open_dyn_packet_buf. So by writing the interleaving header 00162 * over these bytes, we get a consecutive interleaved packet 00163 * that can be written in one call. */ 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; /* RTCP */ 00171 else 00172 id = rtsp_st->interleaved_min; /* RTP */ 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 /* Don't let ff_rtsp_read_reply handle interleaved packets, 00202 * since it would block and wait for an RTSP reply on the socket 00203 * (which may not be coming any time soon) if it handles 00204 * interleaved packets internally. */ 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 /* XXX: parse message */ 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 /* ff_write_chained does all the RTP packetization. If using TCP as 00223 * transport, rtpctx->pb is only a dyn_packet_buf that queues up the 00224 * packets, so we need to send them out on the TCP connection separately. 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