From 2326558d5277ec87ba6d607a01ec6acfc51c694c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 17 Jan 2013 14:34:59 +0200 Subject: rtpdec: Split mpegts parsing to a normal depacketizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets rid of a number of special cases from the common rtpdec code. Signed-off-by: Martin Storsjö --- libavformat/Makefile | 1 + libavformat/rtpdec.c | 56 ++++------------------- libavformat/rtpdec.h | 6 --- libavformat/rtpdec_formats.h | 1 + libavformat/rtpdec_mpegts.c | 106 +++++++++++++++++++++++++++++++++++++++++++ libavformat/rtsp.c | 16 +++++-- 6 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 libavformat/rtpdec_mpegts.c (limited to 'libavformat') diff --git a/libavformat/Makefile b/libavformat/Makefile index 111380a..a8a7530 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -35,6 +35,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 28b4033..7fa0a93 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" @@ -76,6 +75,7 @@ void av_register_rtp_dynamic_payload_handlers(void) ff_register_dynamic_payload_handler(&ff_mp4a_latm_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); @@ -481,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) @@ -499,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: @@ -591,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; @@ -645,26 +638,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) { @@ -704,6 +682,8 @@ static int rtp_parse_packet_internal(RTPDemuxContext *s, AVPacket *pkt, } pkt->stream_index = st->index; + } else { + return AVERROR(EINVAL); } // now perform timestamp things.... @@ -786,7 +766,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; @@ -797,7 +777,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; @@ -806,19 +786,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; } } @@ -894,9 +861,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 eaef993..a93963a 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 e449ddf..6c07791 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 0000000..e2c8977 --- /dev/null +++ b/libavformat/rtpdec_mpegts.c @@ -0,0 +1,106 @@ +/* + * RTP MPEG2TS depacketizer + * Copyright (c) 2003 Fabrice Bellard + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; 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 9a657fb..1ce28d6 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -180,7 +180,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(); @@ -382,8 +383,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 -- cgit v1.1