diff --git a/libavformat/Makefile b/libavformat/Makefile index 2809911729..7d9f1d7ced 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -38,6 +38,7 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtpdec_jpeg.o \ rtpdec_latm.o \ rtpdec_mpeg4.o \ + rtpdec_mpegts.o \ rtpdec_qcelp.o \ rtpdec_qdm2.o \ rtpdec_qt.o \ diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 732ca26a58..77c6ba114a 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -24,7 +24,6 @@ #include "libavutil/time.h" #include "libavcodec/get_bits.h" #include "avformat.h" -#include "mpegts.h" #include "network.h" #include "srtp.h" #include "url.h" @@ -61,39 +60,37 @@ void ff_register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) void av_register_rtp_dynamic_payload_handlers(void) { - ff_register_dynamic_payload_handler(&ff_mp4v_es_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler); ff_register_dynamic_payload_handler(&ff_amr_nb_dynamic_handler); ff_register_dynamic_payload_handler(&ff_amr_wb_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_g726_16_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_g726_24_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_g726_32_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_g726_40_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h263_1998_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler); ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler); ff_register_dynamic_payload_handler(&ff_ilbc_dynamic_handler); ff_register_dynamic_payload_handler(&ff_jpeg_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler); ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler); - ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler); - ff_register_dynamic_payload_handler(&speex_dynamic_handler); - ff_register_dynamic_payload_handler(&opus_dynamic_handler); - + ff_register_dynamic_payload_handler(&ff_mp4v_es_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler); ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); - + ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); ff_register_dynamic_payload_handler(&ff_qt_rtp_aud_handler); ff_register_dynamic_payload_handler(&ff_qt_rtp_vid_handler); ff_register_dynamic_payload_handler(&ff_quicktime_rtp_aud_handler); ff_register_dynamic_payload_handler(&ff_quicktime_rtp_vid_handler); - - ff_register_dynamic_payload_handler(&ff_g726_16_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_24_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_32_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_40_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler); + ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler); + ff_register_dynamic_payload_handler(&opus_dynamic_handler); + ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler); + ff_register_dynamic_payload_handler(&speex_dynamic_handler); } RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, @@ -484,8 +481,7 @@ int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, /** * open a new RTP parse context for stream 'st'. 'st' can be NULL for - * MPEG2-TS streams to indicate that they should be demuxed inside the - * rtp demux (otherwise AV_CODEC_ID_MPEG2TS packets are returned) + * MPEG2-TS streams. */ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, int queue_size) @@ -502,13 +498,7 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, s->st = st; s->queue_size = queue_size; rtp_init_statistics(&s->statistics, 0); - if (!strcmp(ff_rtp_enc_name(payload_type), "MP2T")) { - s->ts = ff_mpegts_parse_open(s->ic); - if (s->ts == NULL) { - av_free(s); - return NULL; - } - } else if (st) { + if (st) { switch (st->codec->codec_id) { case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: @@ -594,7 +584,7 @@ static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, const uint8_t *buf, int len) { unsigned int ssrc, h; - int payload_type, seq, ret, flags = 0; + int payload_type, seq, flags = 0; int ext; AVStream *st; uint32_t timestamp; @@ -652,26 +642,11 @@ static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, buf += ext; } - if (!st) { - /* specific MPEG2-TS demux support */ - ret = ff_mpegts_parse_packet(s->ts, pkt, buf, len); - /* The only error that can be returned from ff_mpegts_parse_packet - * is "no more data to return from the provided buffer", so return - * AVERROR(EAGAIN) for all errors */ - if (ret < 0) - return AVERROR(EAGAIN); - if (ret < len) { - s->read_buf_size = FFMIN(len - ret, sizeof(s->buf)); - memcpy(s->buf, buf + ret, s->read_buf_size); - s->read_buf_index = 0; - return 1; - } - return 0; - } else if (s->handler && s->handler->parse_packet) { + if (s->handler && s->handler->parse_packet) { rv = s->handler->parse_packet(s->ic, s->dynamic_protocol_context, s->st, pkt, ×tamp, buf, len, seq, flags); - } else { + } else if (st) { /* At this point, the RTP header has been stripped; * This is ASSUMING that there is only 1 CSRC, which isn't wise. */ switch (st->codec->codec_id) { @@ -714,6 +689,8 @@ static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, } pkt->stream_index = st->index; + } else { + return AVERROR(EINVAL); } // now perform timestamp things.... @@ -796,7 +773,7 @@ static int rtp_parse_one_packet(RTPDemuxContext *s, AVPacket *pkt, uint8_t **bufptr, int len) { uint8_t *buf = bufptr ? *bufptr : NULL; - int ret, flags = 0; + int flags = 0; uint32_t timestamp; int rv = 0; @@ -807,7 +784,7 @@ static int rtp_parse_one_packet(RTPDemuxContext *s, AVPacket *pkt, if (s->prev_ret <= 0) return rtp_parse_queued_packet(s, pkt); /* return the next packets, if any */ - if (s->st && s->handler && s->handler->parse_packet) { + if (s->handler && s->handler->parse_packet) { /* timestamp should be overwritten by parse_packet, if not, * the packet is left with pts == AV_NOPTS_VALUE */ timestamp = RTP_NOTS_VALUE; @@ -816,19 +793,6 @@ static int rtp_parse_one_packet(RTPDemuxContext *s, AVPacket *pkt, flags); finalize_packet(s, pkt, timestamp); return rv; - } else { - // TODO: Move to a dynamic packet handler (like above) - if (s->read_buf_index >= s->read_buf_size) - return AVERROR(EAGAIN); - ret = ff_mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index, - s->read_buf_size - s->read_buf_index); - if (ret < 0) - return AVERROR(EAGAIN); - s->read_buf_index += ret; - if (s->read_buf_index < s->read_buf_size) - return 1; - else - return 0; } } @@ -904,9 +868,6 @@ int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, void ff_rtp_parse_close(RTPDemuxContext *s) { ff_rtp_reset_packet_queue(s); - if (!strcmp(ff_rtp_enc_name(s->payload_type), "MP2T")) { - ff_mpegts_parse_close(s->ts); - } ff_srtp_free(&s->srtp); av_free(s); } diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 0c5dcabc8b..e469c0f61c 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -160,9 +160,6 @@ struct RTPDemuxContext { int64_t unwrapped_timestamp; int64_t range_start_offset; int max_payload_size; - struct MpegTSContext *ts; /* only used for MP2T payloads */ - int read_buf_index; - int read_buf_size; /* used to send back RTCP RR */ char hostname[256]; @@ -192,9 +189,6 @@ struct RTPDemuxContext { unsigned int last_octet_count; int64_t last_feedback_time; - /* buffer for partially parsed packets */ - uint8_t buf[RTP_MAX_PACKET_LENGTH]; - /* dynamic payload stuff */ const RTPDynamicProtocolHandler *handler; PayloadContext *dynamic_protocol_context; diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h index 6b6fcd3a2b..4221a5fc72 100644 --- a/libavformat/rtpdec_formats.h +++ b/libavformat/rtpdec_formats.h @@ -50,6 +50,7 @@ extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler; extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler; extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler; extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; +extern RTPDynamicProtocolHandler ff_mpegts_dynamic_handler; extern RTPDynamicProtocolHandler ff_ms_rtp_asf_pfa_handler; extern RTPDynamicProtocolHandler ff_ms_rtp_asf_pfv_handler; extern RTPDynamicProtocolHandler ff_qcelp_dynamic_handler; diff --git a/libavformat/rtpdec_mpegts.c b/libavformat/rtpdec_mpegts.c new file mode 100644 index 0000000000..cbb8eb49f7 --- /dev/null +++ b/libavformat/rtpdec_mpegts.c @@ -0,0 +1,106 @@ +/* + * RTP MPEG2TS depacketizer + * Copyright (c) 2003 Fabrice Bellard + * + * 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 "mpegts.h" +#include "rtpdec_formats.h" + +struct PayloadContext { + struct MpegTSContext *ts; + int read_buf_index; + int read_buf_size; + uint8_t buf[RTP_MAX_PACKET_LENGTH]; +}; + +static PayloadContext *mpegts_new_context(void) +{ + return av_mallocz(sizeof(PayloadContext)); +} + +static void mpegts_free_context(PayloadContext *data) +{ + if (!data) + return; + if (data->ts) + ff_mpegts_parse_close(data->ts); + av_free(data); +} + +static int mpegts_init(AVFormatContext *ctx, int st_index, PayloadContext *data) +{ + data->ts = ff_mpegts_parse_open(ctx); + if (!data->ts) + return AVERROR(ENOMEM); + return 0; +} + +static int mpegts_handle_packet(AVFormatContext *ctx, PayloadContext *data, + AVStream *st, AVPacket *pkt, uint32_t *timestamp, + const uint8_t *buf, int len, uint16_t seq, + int flags) +{ + int ret; + + // We don't want to use the RTP timestamps at all. If the mpegts demuxer + // doesn't set any pts/dts, the generic rtpdec code shouldn't try to + // fill it in either, since the mpegts and RTP timestamps are in totally + // different ranges. + *timestamp = RTP_NOTS_VALUE; + + if (!data->ts) + return AVERROR(EINVAL); + + if (!buf) { + if (data->read_buf_index >= data->read_buf_size) + return AVERROR(EAGAIN); + ret = ff_mpegts_parse_packet(data->ts, pkt, data->buf + data->read_buf_index, + data->read_buf_size - data->read_buf_index); + if (ret < 0) + return AVERROR(EAGAIN); + data->read_buf_index += ret; + if (data->read_buf_index < data->read_buf_size) + return 1; + else + return 0; + } + + ret = ff_mpegts_parse_packet(data->ts, pkt, buf, len); + /* The only error that can be returned from ff_mpegts_parse_packet + * is "no more data to return from the provided buffer", so return + * AVERROR(EAGAIN) for all errors */ + if (ret < 0) + return AVERROR(EAGAIN); + if (ret < len) { + data->read_buf_size = FFMIN(len - ret, sizeof(data->buf)); + memcpy(data->buf, buf + ret, data->read_buf_size); + data->read_buf_index = 0; + return 1; + } + return 0; +} + +RTPDynamicProtocolHandler ff_mpegts_dynamic_handler = { + .codec_type = AVMEDIA_TYPE_DATA, + .parse_packet = mpegts_handle_packet, + .alloc = mpegts_new_context, + .init = mpegts_init, + .free = mpegts_free_context, + .static_payload_id = 33, +}; diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 23ce65c0bf..317893c5d0 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -181,7 +181,8 @@ static void init_rtp_handler(RTPDynamicProtocolHandler *handler, { if (!handler) return; - codec->codec_id = handler->codec_id; + if (codec) + codec->codec_id = handler->codec_id; rtsp_st->dynamic_handler = handler; if (handler->alloc) { rtsp_st->dynamic_protocol_context = handler->alloc(); @@ -383,8 +384,17 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { /* no corresponding stream */ - if (rt->transport == RTSP_TRANSPORT_RAW && !rt->ts && CONFIG_RTPDEC) - rt->ts = ff_mpegts_parse_open(s); + if (rt->transport == RTSP_TRANSPORT_RAW) { + if (!rt->ts && CONFIG_RTPDEC) + rt->ts = ff_mpegts_parse_open(s); + } else { + RTPDynamicProtocolHandler *handler; + handler = ff_rtp_handler_find_by_id( + rtsp_st->sdp_payload_type, AVMEDIA_TYPE_DATA); + init_rtp_handler(handler, rtsp_st, NULL); + if (handler && handler->init) + handler->init(s, -1, rtsp_st->dynamic_protocol_context); + } } else if (rt->server_type == RTSP_SERVER_WMS && codec_type == AVMEDIA_TYPE_DATA) { /* RTX stream, a stream that carries all the other actual