Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabrice Bellard <fabrice@bellard.org>2003-10-29 17:25:27 +0300
committerFabrice Bellard <fabrice@bellard.org>2003-10-29 17:25:27 +0300
commit8b1ab7bf219791efafa11fb4bc260f14c02160b5 (patch)
tree2826478251e812c4f42b2540f2d1de0cc5650c2b /libavformat/rtp.c
parentda24c5e330ab90b5249f4fb94044b78919f64d4f (diff)
added MPEG2TS support in RTP, SDP and RTSP - replaced fake RTP demux by a specific API
Originally committed as revision 2448 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/rtp.c')
-rw-r--r--libavformat/rtp.c332
1 files changed, 184 insertions, 148 deletions
diff --git a/libavformat/rtp.c b/libavformat/rtp.c
index 113828475e..244bf77d37 100644
--- a/libavformat/rtp.c
+++ b/libavformat/rtp.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "avformat.h"
+#include "mpegts.h"
#include <unistd.h>
#include <sys/types.h>
@@ -72,23 +73,9 @@ typedef enum {
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
-enum RTPPayloadType {
- RTP_PT_ULAW = 0,
- RTP_PT_GSM = 3,
- RTP_PT_G723 = 4,
- RTP_PT_ALAW = 8,
- RTP_PT_S16BE_STEREO = 10,
- RTP_PT_S16BE_MONO = 11,
- RTP_PT_MPEGAUDIO = 14,
- RTP_PT_JPEG = 26,
- RTP_PT_H261 = 31,
- RTP_PT_MPEGVIDEO = 32,
- RTP_PT_MPEG2TS = 33,
- RTP_PT_H263 = 34, /* old H263 encapsulation */
- RTP_PT_PRIVATE = 96,
-};
-
-typedef struct RTPContext {
+struct RTPDemuxContext {
+ AVFormatContext *ic;
+ AVStream *st;
int payload_type;
uint32_t ssrc;
uint16_t seq;
@@ -96,6 +83,10 @@ typedef struct RTPContext {
uint32_t base_timestamp;
uint32_t cur_timestamp;
int max_payload_size;
+ MpegTSContext *ts; /* only used for RTP_PT_MPEG2TS 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;
@@ -108,40 +99,51 @@ typedef struct RTPContext {
/* buffer for output */
uint8_t buf[RTP_MAX_PACKET_LENGTH];
uint8_t *buf_ptr;
-} RTPContext;
+};
int rtp_get_codec_info(AVCodecContext *codec, int payload_type)
{
switch(payload_type) {
case RTP_PT_ULAW:
+ codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_id = CODEC_ID_PCM_MULAW;
codec->channels = 1;
codec->sample_rate = 8000;
break;
case RTP_PT_ALAW:
+ codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_id = CODEC_ID_PCM_ALAW;
codec->channels = 1;
codec->sample_rate = 8000;
break;
case RTP_PT_S16BE_STEREO:
+ codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_id = CODEC_ID_PCM_S16BE;
codec->channels = 2;
codec->sample_rate = 44100;
break;
case RTP_PT_S16BE_MONO:
+ codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_id = CODEC_ID_PCM_S16BE;
codec->channels = 1;
codec->sample_rate = 44100;
break;
case RTP_PT_MPEGAUDIO:
+ codec->codec_type = CODEC_TYPE_AUDIO;
codec->codec_id = CODEC_ID_MP2;
break;
case RTP_PT_JPEG:
+ codec->codec_type = CODEC_TYPE_VIDEO;
codec->codec_id = CODEC_ID_MJPEG;
break;
case RTP_PT_MPEGVIDEO:
+ codec->codec_type = CODEC_TYPE_VIDEO;
codec->codec_id = CODEC_ID_MPEG1VIDEO;
break;
+ case RTP_PT_MPEG2TS:
+ codec->codec_type = CODEC_TYPE_DATA;
+ codec->codec_id = CODEC_ID_MPEG2TS;
+ break;
default:
return -1;
}
@@ -179,6 +181,9 @@ int rtp_get_payload_type(AVCodecContext *codec)
case CODEC_ID_MPEG1VIDEO:
payload_type = RTP_PT_MPEGVIDEO;
break;
+ case CODEC_ID_MPEG2TS:
+ payload_type = RTP_PT_MPEG2TS;
+ break;
default:
break;
}
@@ -195,10 +200,8 @@ static inline uint64_t decode_be64(const uint8_t *p)
return ((uint64_t)decode_be32(p) << 32) | decode_be32(p + 4);
}
-static int rtcp_parse_packet(AVFormatContext *s1, const unsigned char *buf, int len)
+static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int len)
{
- RTPContext *s = s1->priv_data;
-
if (buf[1] != 200)
return -1;
s->last_rtcp_ntp_time = decode_be64(buf + 8);
@@ -209,30 +212,71 @@ static int rtcp_parse_packet(AVFormatContext *s1, const unsigned char *buf, int
}
/**
- * Parse an RTP packet directly sent as raw data. Can only be used if
- * 'raw' is given as input file
- * @param s1 media file context
+ * 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)
+ */
+RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type)
+{
+ RTPDemuxContext *s;
+
+ s = av_mallocz(sizeof(RTPDemuxContext));
+ if (!s)
+ return NULL;
+ s->payload_type = payload_type;
+ s->last_rtcp_ntp_time = AV_NOPTS_VALUE;
+ s->first_rtcp_ntp_time = AV_NOPTS_VALUE;
+ s->ic = s1;
+ s->st = st;
+ if (payload_type == RTP_PT_MPEG2TS) {
+ s->ts = mpegts_parse_open(s->ic);
+ if (s->ts == NULL) {
+ av_free(s);
+ return NULL;
+ }
+ }
+ return s;
+}
+
+/**
+ * Parse an RTP or RTCP packet directly sent as a buffer.
+ * @param s RTP parse context.
* @param pkt returned packet
- * @param buf input buffer
+ * @param buf input buffer or NULL to read the next packets
* @param len buffer len
- * @return zero if no error.
+ * @return 0 if a packet is returned, 1 if a packet is returned and more can follow
+ * (use buf as NULL to read the next). -1 if no packet (error or no more packet).
*/
-int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt,
- const unsigned char *buf, int len)
+int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt,
+ const uint8_t *buf, int len)
{
- RTPContext *s = s1->priv_data;
unsigned int ssrc, h;
- int payload_type, seq, delta_timestamp;
+ int payload_type, seq, delta_timestamp, ret;
AVStream *st;
uint32_t timestamp;
+ if (!buf) {
+ /* return the next packets, if any */
+ if (s->read_buf_index >= s->read_buf_size)
+ return -1;
+ ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index,
+ s->read_buf_size - s->read_buf_index);
+ if (ret < 0)
+ return -1;
+ s->read_buf_index += ret;
+ if (s->read_buf_index < s->read_buf_size)
+ return 1;
+ else
+ return 0;
+ }
+
if (len < 12)
return -1;
if ((buf[0] & 0xc0) != (RTP_VERSION << 6))
return -1;
if (buf[1] >= 200 && buf[1] <= 204) {
- rtcp_parse_packet(s1, buf, len);
+ rtcp_parse_packet(s, buf, len);
return -1;
}
payload_type = buf[1] & 0x7f;
@@ -240,20 +284,6 @@ int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt,
timestamp = decode_be32(buf + 4);
ssrc = decode_be32(buf + 8);
- if (s->payload_type < 0) {
- s->payload_type = payload_type;
-
- if (payload_type == RTP_PT_MPEG2TS) {
- /* XXX: special case : not a single codec but a whole stream */
- return -1;
- } else {
- st = av_new_stream(s1, 0);
- if (!st)
- return -1;
- rtp_get_codec_info(&st->codec, payload_type);
- }
- }
-
/* NOTE: we can handle only one payload type */
if (s->payload_type != payload_type)
return -1;
@@ -266,107 +296,91 @@ int rtp_parse_packet(AVFormatContext *s1, AVPacket *pkt,
#endif
len -= 12;
buf += 12;
- st = s1->streams[0];
- switch(st->codec.codec_id) {
- case CODEC_ID_MP2:
- /* better than nothing: skip mpeg audio RTP header */
- if (len <= 4)
- return -1;
- h = decode_be32(buf);
- len -= 4;
- buf += 4;
- av_new_packet(pkt, len);
- memcpy(pkt->data, buf, len);
- break;
- case CODEC_ID_MPEG1VIDEO:
- /* better than nothing: skip mpeg audio RTP header */
- if (len <= 4)
+
+ st = s->st;
+ if (!st) {
+ /* specific MPEG2TS demux support */
+ ret = mpegts_parse_packet(s->ts, pkt, buf, len);
+ if (ret < 0)
return -1;
- h = decode_be32(buf);
- buf += 4;
- len -= 4;
- if (h & (1 << 26)) {
- /* mpeg2 */
+ if (ret < len) {
+ s->read_buf_size = len - ret;
+ memcpy(s->buf, buf + ret, s->read_buf_size);
+ s->read_buf_index = 0;
+ return 1;
+ }
+ } else {
+ switch(st->codec.codec_id) {
+ case CODEC_ID_MP2:
+ /* better than nothing: skip mpeg audio RTP header */
+ if (len <= 4)
+ return -1;
+ h = decode_be32(buf);
+ len -= 4;
+ buf += 4;
+ av_new_packet(pkt, len);
+ memcpy(pkt->data, buf, len);
+ break;
+ case CODEC_ID_MPEG1VIDEO:
+ /* better than nothing: skip mpeg audio RTP header */
if (len <= 4)
return -1;
+ h = decode_be32(buf);
buf += 4;
len -= 4;
+ if (h & (1 << 26)) {
+ /* mpeg2 */
+ if (len <= 4)
+ return -1;
+ buf += 4;
+ len -= 4;
+ }
+ av_new_packet(pkt, len);
+ memcpy(pkt->data, buf, len);
+ break;
+ default:
+ av_new_packet(pkt, len);
+ memcpy(pkt->data, buf, len);
+ break;
}
- av_new_packet(pkt, len);
- memcpy(pkt->data, buf, len);
- break;
- default:
- av_new_packet(pkt, len);
- memcpy(pkt->data, buf, len);
- break;
- }
-
- switch(st->codec.codec_id) {
- case CODEC_ID_MP2:
- case CODEC_ID_MPEG1VIDEO:
- if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) {
- int64_t addend;
- /* XXX: is it really necessary to unify the timestamp base ? */
- /* compute pts from timestamp with received ntp_time */
- delta_timestamp = timestamp - s->last_rtcp_timestamp;
- /* convert to 90 kHz without overflow */
- addend = (s->last_rtcp_ntp_time - s->first_rtcp_ntp_time) >> 14;
- addend = (addend * 5625) >> 14;
- pkt->pts = addend + delta_timestamp;
+
+ switch(st->codec.codec_id) {
+ case CODEC_ID_MP2:
+ case CODEC_ID_MPEG1VIDEO:
+ if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) {
+ int64_t addend;
+ /* XXX: is it really necessary to unify the timestamp base ? */
+ /* compute pts from timestamp with received ntp_time */
+ delta_timestamp = timestamp - s->last_rtcp_timestamp;
+ /* convert to 90 kHz without overflow */
+ addend = (s->last_rtcp_ntp_time - s->first_rtcp_ntp_time) >> 14;
+ addend = (addend * 5625) >> 14;
+ pkt->pts = addend + delta_timestamp;
+ }
+ break;
+ default:
+ /* no timestamp info yet */
+ break;
}
- break;
- default:
- /* no timestamp info yet */
- break;
+ pkt->stream_index = s->st->index;
}
return 0;
}
-static int rtp_read_header(AVFormatContext *s1,
- AVFormatParameters *ap)
+void rtp_parse_close(RTPDemuxContext *s)
{
- RTPContext *s = s1->priv_data;
- s->payload_type = -1;
- s->last_rtcp_ntp_time = AV_NOPTS_VALUE;
- s->first_rtcp_ntp_time = AV_NOPTS_VALUE;
- return 0;
-}
-
-static int rtp_read_packet(AVFormatContext *s1, AVPacket *pkt)
-{
- char buf[RTP_MAX_PACKET_LENGTH];
- int ret;
-
- /* XXX: needs a better API for packet handling ? */
- for(;;) {
- ret = url_read(url_fileno(&s1->pb), buf, sizeof(buf));
- if (ret < 0)
- return AVERROR_IO;
- if (rtp_parse_packet(s1, pkt, buf, ret) == 0)
- break;
+ if (s->payload_type == RTP_PT_MPEG2TS) {
+ mpegts_parse_close(s->ts);
}
- return 0;
-}
-
-static int rtp_read_close(AVFormatContext *s1)
-{
- // RTPContext *s = s1->priv_data;
- return 0;
-}
-
-static int rtp_probe(AVProbeData *p)
-{
- if (strstart(p->filename, "rtp://", NULL))
- return AVPROBE_SCORE_MAX;
- return 0;
+ av_free(s);
}
/* rtp output */
static int rtp_write_header(AVFormatContext *s1)
{
- RTPContext *s = s1->priv_data;
- int payload_type, max_packet_size;
+ RTPDemuxContext *s = s1->priv_data;
+ int payload_type, max_packet_size, n;
AVStream *st;
if (s1->nb_streams != 1)
@@ -397,6 +411,13 @@ static int rtp_write_header(AVFormatContext *s1)
case CODEC_ID_MPEG1VIDEO:
s->cur_timestamp = 0;
break;
+ case CODEC_ID_MPEG2TS:
+ n = s->max_payload_size / TS_PACKET_SIZE;
+ if (n < 1)
+ n = 1;
+ s->max_payload_size = n * TS_PACKET_SIZE;
+ s->buf_ptr = s->buf;
+ break;
default:
s->buf_ptr = s->buf;
break;
@@ -408,7 +429,7 @@ static int rtp_write_header(AVFormatContext *s1)
/* send an rtcp sender report packet */
static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
#if defined(DEBUG)
printf("RTCP: %02x %Lx %x\n", s->payload_type, ntp_time, s->timestamp);
#endif
@@ -427,7 +448,7 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
must update the timestamp itself */
static void rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
#ifdef DEBUG
printf("rtp_send_data size=%d\n", len);
@@ -453,7 +474,7 @@ static void rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len)
static void rtp_send_samples(AVFormatContext *s1,
const uint8_t *buf1, int size, int sample_size)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
int len, max_packet_size, n;
max_packet_size = (s->max_payload_size / sample_size) * sample_size;
@@ -486,7 +507,7 @@ static void rtp_send_samples(AVFormatContext *s1,
static void rtp_send_mpegaudio(AVFormatContext *s1,
const uint8_t *buf1, int size)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, count, max_packet_size;
@@ -542,7 +563,7 @@ static void rtp_send_mpegaudio(AVFormatContext *s1,
static void rtp_send_mpegvideo(AVFormatContext *s1,
const uint8_t *buf1, int size)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, h, max_packet_size;
uint8_t *q;
@@ -589,7 +610,7 @@ static void rtp_send_mpegvideo(AVFormatContext *s1,
static void rtp_send_raw(AVFormatContext *s1,
const uint8_t *buf1, int size)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int len, max_packet_size;
@@ -611,11 +632,35 @@ static void rtp_send_raw(AVFormatContext *s1,
s->cur_timestamp++;
}
+/* NOTE: size is assumed to be an integer multiple of TS_PACKET_SIZE */
+static void rtp_send_mpegts_raw(AVFormatContext *s1,
+ const uint8_t *buf1, int size)
+{
+ RTPDemuxContext *s = s1->priv_data;
+ int len, out_len;
+
+ while (size >= TS_PACKET_SIZE) {
+ len = s->max_payload_size - (s->buf_ptr - s->buf);
+ if (len > size)
+ len = size;
+ memcpy(s->buf_ptr, buf1, len);
+ buf1 += len;
+ size -= len;
+ s->buf_ptr += len;
+
+ out_len = s->buf_ptr - s->buf;
+ if (out_len >= s->max_payload_size) {
+ rtp_send_data(s1, s->buf, out_len);
+ s->buf_ptr = s->buf;
+ }
+ }
+}
+
/* write an RTP packet. 'buf1' must contain a single specific frame. */
static int rtp_write_packet(AVFormatContext *s1, int stream_index,
const uint8_t *buf1, int size, int64_t pts)
{
- RTPContext *s = s1->priv_data;
+ RTPDemuxContext *s = s1->priv_data;
AVStream *st = s1->streams[0];
int rtcp_bytes;
int64_t ntp_time;
@@ -656,6 +701,9 @@ static int rtp_write_packet(AVFormatContext *s1, int stream_index,
case CODEC_ID_MPEG1VIDEO:
rtp_send_mpegvideo(s1, buf1, size);
break;
+ case CODEC_ID_MPEG2TS:
+ rtp_send_mpegts_raw(s1, buf1, size);
+ break;
default:
/* better than nothing : send the codec raw data */
rtp_send_raw(s1, buf1, size);
@@ -666,27 +714,16 @@ static int rtp_write_packet(AVFormatContext *s1, int stream_index,
static int rtp_write_trailer(AVFormatContext *s1)
{
- // RTPContext *s = s1->priv_data;
+ // RTPDemuxContext *s = s1->priv_data;
return 0;
}
-AVInputFormat rtp_demux = {
- "rtp",
- "RTP input format",
- sizeof(RTPContext),
- rtp_probe,
- rtp_read_header,
- rtp_read_packet,
- rtp_read_close,
- .flags = AVFMT_NOHEADER,
-};
-
AVOutputFormat rtp_mux = {
"rtp",
"RTP output format",
NULL,
NULL,
- sizeof(RTPContext),
+ sizeof(RTPDemuxContext),
CODEC_ID_PCM_MULAW,
CODEC_ID_NONE,
rtp_write_header,
@@ -697,6 +734,5 @@ AVOutputFormat rtp_mux = {
int rtp_init(void)
{
av_register_output_format(&rtp_mux);
- av_register_input_format(&rtp_demux);
return 0;
}