# HG changeset patch # User gpoirier # Date 1161887763 0 # Node ID 8fb4910bdcc00eb27a93021180c7a16e6e05eae4 # Parent 9720274e262171ddb6a83a7051b258c3360d9f23 Add support for H264 over RTP Patch by Ryan Martell % rdm4 A martellventures P com % Original thread: Date: Oct 9, 2006 4:55 PM Subject: [Ffmpeg-devel] RTP patches & RFC Actual committed patch: Date: Oct 26, 2006 4:29 PM diff -r 9720274e2621 -r 8fb4910bdcc0 allformats.c --- a/allformats.c Wed Oct 25 22:50:49 2006 +0000 +++ b/allformats.c Thu Oct 26 18:36:03 2006 +0000 @@ -416,6 +416,7 @@ #ifdef CONFIG_REDIR_DEMUXER av_register_input_format(&redir_demuxer); #endif + av_register_rtp_dynamic_payload_handlers(); #endif /* CONFIG_NETWORK */ #ifdef CONFIG_SEGAFILM_DEMUXER av_register_input_format(&segafilm_demuxer); diff -r 9720274e2621 -r 8fb4910bdcc0 allformats.h --- a/allformats.h Wed Oct 25 22:50:49 2006 +0000 +++ b/allformats.h Thu Oct 26 18:36:03 2006 +0000 @@ -170,6 +170,9 @@ /* rtsp.c */ int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f); +/* rtp.c */ +void av_register_rtp_dynamic_payload_handlers(); + #if 0 extern AVImageFormat pnm_image_format; diff -r 9720274e2621 -r 8fb4910bdcc0 rtp.c --- a/rtp.c Wed Oct 25 22:50:49 2006 +0000 +++ b/rtp.c Thu Oct 26 18:36:03 2006 +0000 @@ -33,6 +33,13 @@ #endif #include +#include "rtp_internal.h" + +//#define RTP_H264 +#ifdef RTP_H264 + #include "rtp_h264.h" +#endif + //#define DEBUG @@ -179,42 +186,26 @@ {-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1} }; -AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]= -{ - {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}, - {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC}, - {"", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE} -}; +/* statistics functions */ +RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler= NULL; + +static RTPDynamicProtocolHandler mp4v_es_handler= {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}; +static RTPDynamicProtocolHandler mpeg4_generic_handler= {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC}; -struct RTPDemuxContext { - AVFormatContext *ic; - AVStream *st; - int payload_type; - uint32_t ssrc; - uint16_t seq; - uint32_t timestamp; - uint32_t base_timestamp; - uint32_t cur_timestamp; - int max_payload_size; - MpegTSContext *ts; /* only used for MP2T payloads */ - int read_buf_index; - int read_buf_size; +static void register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) +{ + handler->next= RTPFirstDynamicPayloadHandler; + RTPFirstDynamicPayloadHandler= handler; +} - /* rtcp sender statistics receive */ - int64_t last_rtcp_ntp_time; - int64_t first_rtcp_ntp_time; - uint32_t last_rtcp_timestamp; - /* rtcp sender statistics */ - unsigned int packet_count; - unsigned int octet_count; - unsigned int last_octet_count; - int first_packet; - /* buffer for output */ - uint8_t buf[RTP_MAX_PACKET_LENGTH]; - uint8_t *buf_ptr; - /* special infos for au headers parsing */ - rtp_payload_data_t *rtp_payload_data; -}; +void av_register_rtp_dynamic_payload_handlers() +{ + register_dynamic_payload_handler(&mp4v_es_handler); + register_dynamic_payload_handler(&mpeg4_generic_handler); +#ifdef RTP_H264 + register_dynamic_payload_handler(&ff_h264_dynamic_handler); +#endif +} int rtp_get_codec_info(AVCodecContext *codec, int payload_type) { @@ -271,6 +262,7 @@ * open a new RTP parse context for stream 'st'. 'st' can be NULL for * MPEG2TS streams to indicate that they should be demuxed inside the * rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned) + * TODO: change this to not take rtp_payload data, and use the new dynamic payload system. */ RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, rtp_payload_data_t *rtp_payload_data) { @@ -298,6 +290,9 @@ case CODEC_ID_MP2: case CODEC_ID_MP3: case CODEC_ID_MPEG4: +#ifdef RTP_H264 + case CODEC_ID_H264: +#endif st->need_parsing = 1; break; default: @@ -374,6 +369,9 @@ if (!buf) { /* return the next packets, if any */ + if(s->st && s->parse_packet) { + return s->parse_packet(s, pkt, 0, NULL, 0); + } else { if (s->read_buf_index >= s->read_buf_size) return -1; ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index, @@ -385,6 +383,7 @@ return 1; else return 0; + } } if (len < 12) @@ -428,6 +427,7 @@ return 1; } } else { + // at this point, the RTP header has been stripped; This is ASSUMING that there is only 1 CSRC, which in't wise. switch(st->codec->codec_id) { case CODEC_ID_MP2: /* better than nothing: skip mpeg audio RTP header */ @@ -457,8 +457,12 @@ memcpy(pkt->data, buf, len); break; default: + if(s->parse_packet) { + return s->parse_packet(s, pkt, timestamp, buf, len); + } else { av_new_packet(pkt, len); memcpy(pkt->data, buf, len); + } break; } @@ -511,6 +515,7 @@ void rtp_parse_close(RTPDemuxContext *s) { + // TODO: fold this into the protocol specific data fields. if (!strcmp(AVRtpPayloadTypes[s->payload_type].enc_name, "MP2T")) { mpegts_parse_close(s->ts); } diff -r 9720274e2621 -r 8fb4910bdcc0 rtp.h --- a/rtp.h Wed Oct 25 22:50:49 2006 +0000 +++ b/rtp.h Thu Oct 26 18:36:03 2006 +0000 @@ -89,13 +89,6 @@ int audio_channels; } AVRtpPayloadType_t; -typedef struct AVRtpDynamicPayloadType_s /* payload type >= 96 */ -{ - const char enc_name[50]; /* XXX: still why 50 ? ;-) */ - enum CodecType codec_type; - enum CodecID codec_id; -} AVRtpDynamicPayloadType_t; - #if 0 typedef enum { RTCP_SR = 200, @@ -122,6 +115,4 @@ #endif extern AVRtpPayloadType_t AVRtpPayloadTypes[]; -extern AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]; - #endif /* RTP_H */ diff -r 9720274e2621 -r 8fb4910bdcc0 rtp_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rtp_internal.h Thu Oct 26 18:36:03 2006 +0000 @@ -0,0 +1,86 @@ +/* + * RTP definitions + * Copyright (c) 2006 Ryan Martell + * + * This library 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 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// this is a bit of a misnomer, because rtp & rtsp internal structures and prototypes are in here. +#ifndef RTP_INTERNAL_H +#define RTP_INTERNAL_H + +typedef int (*DynamicPayloadPacketHandlerProc) (struct RTPDemuxContext * s, + AVPacket * pkt, + uint32_t timestamp, + const uint8_t * buf, + int len); + +typedef struct RTPDynamicProtocolHandler_s { + // fields from AVRtpDynamicPayloadType_s + const char enc_name[50]; /* XXX: still why 50 ? ;-) */ + enum CodecType codec_type; + enum CodecID codec_id; + + // may be null + int (*parse_sdp_a_line) (AVStream * stream, + void *protocol_data, + const char *line); ///< Parse the a= line from the sdp field + void *(*open) (); ///< allocate any data needed by the rtp parsing for this dynamic data. + void (*close)(void *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data. + DynamicPayloadPacketHandlerProc parse_packet; ///< parse handler for this dynamic packet. + + struct RTPDynamicProtocolHandler_s *next; +} RTPDynamicProtocolHandler; + +// moved out of rtp.c, because the h264 decoder needs to know about this structure.. +struct RTPDemuxContext { + AVFormatContext *ic; + AVStream *st; + int payload_type; + uint32_t ssrc; + uint16_t seq; + uint32_t timestamp; + uint32_t base_timestamp; + uint32_t cur_timestamp; + int max_payload_size; + struct MpegTSContext *ts; /* only used for MP2T payloads */ + int read_buf_index; + int read_buf_size; + + /* rtcp sender statistics receive */ + int64_t last_rtcp_ntp_time; // TODO: move into statistics + int64_t first_rtcp_ntp_time; // TODO: move into statistics + uint32_t last_rtcp_timestamp; // TODO: move into statistics + + /* rtcp sender statistics */ + unsigned int packet_count; // TODO: move into statistics (outgoing) + unsigned int octet_count; // TODO: move into statistics (outgoing) + unsigned int last_octet_count; // TODO: move into statistics (outgoing) + int first_packet; + /* buffer for output */ + uint8_t buf[RTP_MAX_PACKET_LENGTH]; + uint8_t *buf_ptr; + + /* special infos for au headers parsing */ + rtp_payload_data_t *rtp_payload_data; // TODO: Move into dynamic payload handlers + + /* dynamic payload stuff */ + DynamicPayloadPacketHandlerProc parse_packet; ///< This is also copied from the dynamic protocol handler structure + void *dynamic_protocol_context; ///< This is a copy from the values setup from the sdp parsing, in rtsp.c don't free me. +}; + +extern RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler; +#endif /* RTP_INTERNAL_H */ + diff -r 9720274e2621 -r 8fb4910bdcc0 rtsp.c --- a/rtsp.c Wed Oct 25 22:50:49 2006 +0000 +++ b/rtsp.c Thu Oct 26 18:36:03 2006 +0000 @@ -30,6 +30,8 @@ # include "barpainet.h" #endif +#include "rtp_internal.h" + //#define DEBUG //#define DEBUG_RTP_TCP @@ -69,6 +71,9 @@ int sdp_ttl; /* IP TTL (from SDP content - not used in RTSP) */ int sdp_payload_type; /* payload type - only used in SDP */ rtp_payload_data_t rtp_payload_data; /* rtp payload parsing infos from SDP */ + + RTPDynamicProtocolHandler *dynamic_handler; ///< Only valid if it's a dynamic protocol. (This is the handler structure) + void *dynamic_protocol_context; ///< Only valid if it's a dynamic protocol. (This is any private data associated with the dynamic protocol) } RTSPStream; static int rtsp_read_play(AVFormatContext *s); @@ -142,7 +147,7 @@ /* parse the rtpmap description: /[/] */ -static int sdp_parse_rtpmap(AVCodecContext *codec, int payload_type, const char *p) +static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payload_type, const char *p) { char buf[256]; int i; @@ -153,12 +158,18 @@ see if we can handle this kind of payload */ get_word_sep(buf, sizeof(buf), "/", &p); if (payload_type >= RTP_PT_PRIVATE) { - /* We are in dynmaic payload type case ... search into AVRtpDynamicPayloadTypes[] */ - for (i = 0; AVRtpDynamicPayloadTypes[i].codec_id != CODEC_ID_NONE; ++i) - if (!strcmp(buf, AVRtpDynamicPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpDynamicPayloadTypes[i].codec_type)) { - codec->codec_id = AVRtpDynamicPayloadTypes[i].codec_id; + RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler; + while(handler) { + if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) { + codec->codec_id = handler->codec_id; + rtsp_st->dynamic_handler= handler; + if(handler->open) { + rtsp_st->dynamic_protocol_context= handler->open(); + } break; } + handler= handler->next; + } } else { /* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */ /* search into AVRtpPayloadTypes[] */ @@ -440,7 +451,7 @@ st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { - sdp_parse_rtpmap(st->codec, payload_type, p); + sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p); } } } else if (strstart(p, "fmtp:", &p)) { @@ -451,7 +462,13 @@ st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { + if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) { + if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) { + sdp_parse_fmtp(st, p); + } + } else { sdp_parse_fmtp(st, p); + } } } } @@ -788,6 +805,8 @@ rtp_parse_close(rtsp_st->rtp_ctx); if (rtsp_st->rtp_handle) url_close(rtsp_st->rtp_handle); + if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) + rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context); } av_free(rtsp_st); } @@ -980,6 +999,11 @@ if (!rtsp_st->rtp_ctx) { err = AVERROR_NOMEM; goto fail; + } else { + if(rtsp_st->dynamic_handler) { + rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context; + rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet; + } } } @@ -1326,6 +1350,11 @@ if (!rtsp_st->rtp_ctx) { err = AVERROR_NOMEM; goto fail; + } else { + if(rtsp_st->dynamic_handler) { + rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context; + rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet; + } } } return 0;