aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyan Martell <rdm4@martellventures.com>2006-10-26 18:36:03 +0000
committerGuillaume Poirier <gpoirier@mplayerhq.hu>2006-10-26 18:36:03 +0000
commit4934884a134418491fdcd704d80249efab16023d (patch)
tree74bd854f5f4ce9356c8ca814fc61ecadc4b23b75
parent18fd519f54bcd579107d14b80ebcc8899509d117 (diff)
downloadffmpeg-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.c1
-rw-r--r--libavformat/allformats.h3
-rw-r--r--libavformat/rtp.c73
-rw-r--r--libavformat/rtp.h9
-rw-r--r--libavformat/rtp_internal.h86
-rw-r--r--libavformat/rtsp.c41
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;