diff options
author | Ryan Martell <rdm4@martellventures.com> | 2006-10-26 18:36:03 +0000 |
---|---|---|
committer | Guillaume Poirier <gpoirier@mplayerhq.hu> | 2006-10-26 18:36:03 +0000 |
commit | 4934884a134418491fdcd704d80249efab16023d (patch) | |
tree | 74bd854f5f4ce9356c8ca814fc61ecadc4b23b75 | |
parent | 18fd519f54bcd579107d14b80ebcc8899509d117 (diff) | |
download | ffmpeg-4934884a134418491fdcd704d80249efab16023d.tar.gz |
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
Originally committed as revision 6798 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavformat/allformats.c | 1 | ||||
-rw-r--r-- | libavformat/allformats.h | 3 | ||||
-rw-r--r-- | libavformat/rtp.c | 73 | ||||
-rw-r--r-- | libavformat/rtp.h | 9 | ||||
-rw-r--r-- | libavformat/rtp_internal.h | 86 | ||||
-rw-r--r-- | libavformat/rtsp.c | 41 |
6 files changed, 164 insertions, 49 deletions
diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 5967b971f4..dafbfb4e8a 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -416,6 +416,7 @@ void av_register_all(void) #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 --git a/libavformat/allformats.h b/libavformat/allformats.h index d63f044105..27f0952098 100644 --- a/libavformat/allformats.h +++ b/libavformat/allformats.h @@ -170,6 +170,9 @@ int pcm_read_seek(AVFormatContext *s, /* 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 --git a/libavformat/rtp.c b/libavformat/rtp.c index 65c8d0b37d..c2c880decd 100644 --- a/libavformat/rtp.c +++ b/libavformat/rtp.c @@ -33,6 +33,13 @@ #endif #include <netdb.h> +#include "rtp_internal.h" + +//#define RTP_H264 +#ifdef RTP_H264 + #include "rtp_h264.h" +#endif + //#define DEBUG @@ -179,42 +186,26 @@ AVRtpPayloadType_t AVRtpPayloadTypes[]= {-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1} }; -AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]= +/* 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}; + +static void register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) { - {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}, - {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_MPEG4AAC}, - {"", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE} -}; + handler->next= RTPFirstDynamicPayloadHandler; + RTPFirstDynamicPayloadHandler= handler; +} -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; - - /* 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 @@ static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int l * 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 @@ RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_t 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 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, 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 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, return 1; else return 0; + } } if (len < 12) @@ -428,6 +427,7 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, 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 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, 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 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, 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 --git a/libavformat/rtp.h b/libavformat/rtp.h index 90cc085b47..9ce6f90d49 100644 --- a/libavformat/rtp.h +++ b/libavformat/rtp.h @@ -89,13 +89,6 @@ typedef struct AVRtpPayloadType_s 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 @@ typedef enum { #endif extern AVRtpPayloadType_t AVRtpPayloadTypes[]; -extern AVRtpDynamicPayloadType_t AVRtpDynamicPayloadTypes[]; - #endif /* RTP_H */ diff --git a/libavformat/rtp_internal.h b/libavformat/rtp_internal.h new file mode 100644 index 0000000000..f8b0202df4 --- /dev/null +++ b/libavformat/rtp_internal.h @@ -0,0 +1,86 @@ +/* + * RTP definitions + * Copyright (c) 2006 Ryan Martell <rdm4@martellventures.com> + * + * 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 --git a/libavformat/rtsp.c b/libavformat/rtsp.c index b17c6528fe..c9ba8a064b 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -30,6 +30,8 @@ # include "barpainet.h" #endif +#include "rtp_internal.h" + //#define DEBUG //#define DEBUG_RTP_TCP @@ -69,6 +71,9 @@ typedef struct RTSPStream { 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 @@ static void get_word(char *buf, int buf_size, const char **pp) /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ -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 @@ static int sdp_parse_rtpmap(AVCodecContext *codec, int payload_type, const char 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 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, 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 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, 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 @@ static void rtsp_close_streams(RTSPState *rt) 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 @@ static int rtsp_read_header(AVFormatContext *s, 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 @@ static int sdp_read_header(AVFormatContext *s, 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; |