diff --git a/Changelog b/Changelog index 1410d783f721ddbbe61eda13024f84025448a624..cb276da2e22ba2e3fb3330d93974fc9aeb67bdf3 100644 --- a/Changelog +++ b/Changelog @@ -60,6 +60,7 @@ version : - WMAVoice decoder - FFprobe tool - AMR-NB decoder +- RTSP muxer diff --git a/configure b/configure index fccfee5563ab35e8f373950a865299e2760b3bc2..9a2a2e767bd949ccf5cff4f62aa184b8fa3e0340 100755 --- a/configure +++ b/configure @@ -1351,6 +1351,8 @@ mxf_d10_muxer_select="mxf_muxer" ogg_demuxer_select="golomb" psp_muxer_select="mov_muxer" rtsp_demuxer_deps="sdp_demuxer" +rtsp_muxer_deps="sdp_demuxer" +rtsp_muxer_select="rtp_muxer" sdp_demuxer_deps="rtp_protocol mpegts_demuxer" spdif_muxer_select="aac_parser" tg2_muxer_select="mov_muxer" diff --git a/doc/general.texi b/doc/general.texi index 816630011ed7710bcf9dfe000f172cf8e127e1ac..e4f44231919505294d701f507b7020b949c905fe 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -210,7 +210,7 @@ library: @item RTMP @tab X @tab X @tab Output is performed by publishing stream to RTMP server @item RTP @tab @tab X -@item RTSP @tab @tab X +@item RTSP @tab X @tab X @item SDP @tab @tab X @item Sega FILM/CPK @tab @tab X @tab Used in many Sega Saturn console games. diff --git a/libavformat/Makefile b/libavformat/Makefile index 8d2dbb3c919f296cbd46942adde7d734475fc817..48b8f80a74b95619f5cf3a0e43a56c4ebfad5523 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -210,6 +210,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ rtpenc_h264.o \ avc.o OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o +OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o \ rdt.o \ rtp.o \ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index e91325b5304c4689c2475237cc490f3821966d3b..090d134d7331054c09451076eb1a842916e8ebc7 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -172,7 +172,7 @@ void av_register_all(void) REGISTER_MUXDEMUX (ROQ, roq); REGISTER_DEMUXER (RPL, rpl); REGISTER_MUXER (RTP, rtp); - REGISTER_DEMUXER (RTSP, rtsp); + REGISTER_MUXDEMUX (RTSP, rtsp); REGISTER_DEMUXER (SDP, sdp); #if CONFIG_SDP_DEMUXER av_register_rtp_dynamic_payload_handlers(); diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 2e8770a0a37918f607d9676553c5806ee4213f50..4b0aa67ef6c2d8640982e098d3a6d32d882c149a 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -22,7 +22,7 @@ #define AVFORMAT_AVFORMAT_H #define LIBAVFORMAT_VERSION_MAJOR 52 -#define LIBAVFORMAT_VERSION_MINOR 52 +#define LIBAVFORMAT_VERSION_MINOR 53 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 26b9e9312be8aed8dfdc88b93965ba662772408c..23d56b6c0aa5e75cde562ee880537b6fdf5e9f88 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -691,7 +691,7 @@ static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) return 0; } -#if CONFIG_RTSP_DEMUXER +#if CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER static int rtsp_probe(AVProbeData *p) { if (av_strstart(p->filename, "rtsp:", NULL)) @@ -1533,7 +1533,9 @@ redirect: } return err; } +#endif +#if CONFIG_RTSP_DEMUXER static int rtsp_read_header(AVFormatContext *s, AVFormatParameters *ap) { diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c new file mode 100644 index 0000000000000000000000000000000000000000..c918b3e8c0341e3f717c864d25b9ee016a43a3b2 --- /dev/null +++ b/libavformat/rtspenc.c @@ -0,0 +1,131 @@ +/* + * RTSP muxer + * Copyright (c) 2010 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" + +#include +#if HAVE_SYS_SELECT_H +#include +#endif +#include "network.h" +#include "rtsp.h" + +static int rtsp_write_record(AVFormatContext *s) +{ + RTSPState *rt = s->priv_data; + RTSPMessageHeader reply1, *reply = &reply1; + char cmd[1024]; + + snprintf(cmd, sizeof(cmd), + "RECORD %s RTSP/1.0\r\n" + "Range: npt=%0.3f-\r\n", + s->filename, + (double) 0); + rtsp_send_cmd(s, cmd, reply, NULL); + if (reply->status_code != RTSP_STATUS_OK) + return -1; + rt->state = RTSP_STATE_STREAMING; + return 0; +} + +static int rtsp_write_header(AVFormatContext *s) +{ + RTSPState *rt = s->priv_data; + int ret; + + ret = rtsp_connect(s); + if (ret) + return ret; + + if (rtsp_write_record(s) < 0) { + rtsp_close_streams(s); + url_close(rt->rtsp_hd); + return AVERROR_INVALIDDATA; + } + return 0; +} + +static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + RTSPState *rt = s->priv_data; + RTSPStream *rtsp_st; + fd_set rfds; + int n, tcp_fd; + struct timeval tv; + AVFormatContext *rtpctx; + + FD_ZERO(&rfds); + tcp_fd = url_get_file_handle(rt->rtsp_hd); + FD_SET(tcp_fd, &rfds); + + tv.tv_sec = 0; + tv.tv_usec = 0; + n = select(tcp_fd + 1, &rfds, NULL, NULL, &tv); + if (n > 0) { + if (FD_ISSET(tcp_fd, &rfds)) { + RTSPMessageHeader reply; + + if (rtsp_read_reply(s, &reply, NULL, 0) < 0) + return AVERROR(EPIPE); + /* XXX: parse message */ + if (rt->state != RTSP_STATE_STREAMING) + return AVERROR(EPIPE); + } + } + + if (pkt->stream_index < 0 || pkt->stream_index >= rt->nb_rtsp_streams) + return AVERROR_INVALIDDATA; + rtsp_st = rt->rtsp_streams[pkt->stream_index]; + rtpctx = rtsp_st->transport_priv; + + pkt->stream_index = 0; + return av_write_frame(rtpctx, pkt); +} + +static int rtsp_write_close(AVFormatContext *s) +{ + RTSPState *rt = s->priv_data; + char cmd[1024]; + + snprintf(cmd, sizeof(cmd), + "TEARDOWN %s RTSP/1.0\r\n", + s->filename); + rtsp_send_cmd_async(s, cmd); + + rtsp_close_streams(s); + url_close(rt->rtsp_hd); + return 0; +} + +AVOutputFormat rtsp_muxer = { + "rtsp", + NULL_IF_CONFIG_SMALL("RTSP output format"), + NULL, + NULL, + sizeof(RTSPState), + CODEC_ID_PCM_MULAW, + CODEC_ID_NONE, + rtsp_write_header, + rtsp_write_packet, + rtsp_write_close, + .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER, +}; +