summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/rtmpproto.c298
-rw-r--r--libavformat/rtpdec_h264.c1
-rw-r--r--libavformat/rtpenc.c21
-rw-r--r--libavformat/rtsp.c51
-rw-r--r--libavformat/rtsp.h8
-rw-r--r--libavformat/version.h2
6 files changed, 224 insertions, 157 deletions
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 4120aa6b21..e48c740a2e 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -52,15 +52,17 @@
typedef enum {
STATE_START, ///< client has not done anything yet
STATE_HANDSHAKED, ///< client has performed handshake
- STATE_RELEASING, ///< client releasing stream before publish it (for output)
STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
- STATE_CONNECTING, ///< client connected to server successfully
- STATE_READY, ///< client has sent all needed commands and waits for server reply
STATE_PLAYING, ///< client has started receiving multimedia data from server
STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
STATE_STOPPED, ///< the broadcast has been stopped
} ClientState;
+typedef struct TrackedMethod {
+ char *name;
+ int id;
+} TrackedMethod;
+
/** protocol handler context */
typedef struct RTMPContext {
const AVClass *class;
@@ -86,7 +88,6 @@ typedef struct RTMPContext {
uint8_t flv_header[11]; ///< partial incoming flv packet header
int flv_header_bytes; ///< number of initialized bytes in flv_header
int nb_invokes; ///< keeps track of invoke messages
- int create_stream_invoke; ///< invoke id for the create stream command
char* tcurl; ///< url of the target stream
char* flashver; ///< version of the flash plugin
char* swfurl; ///< url of the swf player
@@ -96,6 +97,9 @@ typedef struct RTMPContext {
int client_buffer_time; ///< client buffer time in ms
int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
int encrypted; ///< use an encrypted connection (RTMPE only)
+ TrackedMethod*tracked_methods; ///< tracked methods buffer
+ int nb_tracked_methods; ///< number of tracked methods
+ int tracked_methods_size; ///< size of the tracked methods buffer
} RTMPContext;
#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
@@ -121,6 +125,72 @@ static const uint8_t rtmp_server_key[] = {
0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
};
+static int add_tracked_method(RTMPContext *rt, const char *name, int id)
+{
+ void *ptr;
+
+ if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
+ rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
+ ptr = av_realloc(rt->tracked_methods,
+ rt->tracked_methods_size * sizeof(*rt->tracked_methods));
+ if (!ptr)
+ return AVERROR(ENOMEM);
+ rt->tracked_methods = ptr;
+ }
+
+ rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
+ if (!rt->tracked_methods[rt->nb_tracked_methods].name)
+ return AVERROR(ENOMEM);
+ rt->tracked_methods[rt->nb_tracked_methods].id = id;
+ rt->nb_tracked_methods++;
+
+ return 0;
+}
+
+static void del_tracked_method(RTMPContext *rt, int index)
+{
+ memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
+ sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
+ rt->nb_tracked_methods--;
+}
+
+static void free_tracked_methods(RTMPContext *rt)
+{
+ int i;
+
+ for (i = 0; i < rt->nb_tracked_methods; i ++)
+ av_free(rt->tracked_methods[i].name);
+ av_free(rt->tracked_methods);
+}
+
+static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
+{
+ int ret;
+
+ if (pkt->type == RTMP_PT_INVOKE && track) {
+ GetByteContext gbc;
+ char name[128];
+ double pkt_id;
+ int len;
+
+ bytestream2_init(&gbc, pkt->data, pkt->data_size);
+ if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
+ goto fail;
+
+ if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
+ goto fail;
+
+ if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
+ goto fail;
+ }
+
+ ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
+ rt->prev_pkt[1]);
+fail:
+ ff_rtmp_packet_destroy(pkt);
+ return ret;
+}
+
static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
{
char *field, *value;
@@ -269,11 +339,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
pkt.data_size = p - pkt.data;
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 1);
}
/**
@@ -297,11 +363,7 @@ static int gen_release_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_null(&p);
ff_amf_write_string(&p, rt->playpath);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -325,11 +387,7 @@ static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_null(&p);
ff_amf_write_string(&p, rt->playpath);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -353,11 +411,7 @@ static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_null(&p);
ff_amf_write_string(&p, rt->playpath);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -380,13 +434,8 @@ static int gen_create_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_string(&p, "createStream");
ff_amf_write_number(&p, ++rt->nb_invokes);
ff_amf_write_null(&p);
- rt->create_stream_invoke = rt->nb_invokes;
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 1);
}
@@ -412,11 +461,7 @@ static int gen_delete_stream(URLContext *s, RTMPContext *rt)
ff_amf_write_null(&p);
ff_amf_write_number(&p, rt->main_channel_id);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -437,11 +482,7 @@ static int gen_buffer_time(URLContext *s, RTMPContext *rt)
bytestream_put_be32(&p, rt->main_channel_id);
bytestream_put_be32(&p, rt->client_buffer_time);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -469,11 +510,7 @@ static int gen_play(URLContext *s, RTMPContext *rt)
ff_amf_write_string(&p, rt->playpath);
ff_amf_write_number(&p, rt->live);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 1);
}
/**
@@ -500,11 +537,7 @@ static int gen_publish(URLContext *s, RTMPContext *rt)
ff_amf_write_string(&p, rt->playpath);
ff_amf_write_string(&p, "live");
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 1);
}
/**
@@ -529,11 +562,8 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
p = pkt.data;
bytestream_put_be16(&p, 7);
bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -551,11 +581,8 @@ static int gen_server_bw(URLContext *s, RTMPContext *rt)
p = pkt.data;
bytestream_put_be32(&p, rt->server_bw);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -576,11 +603,7 @@ static int gen_check_bw(URLContext *s, RTMPContext *rt)
ff_amf_write_number(&p, RTMP_NOTIFICATION);
ff_amf_write_null(&p);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
/**
@@ -598,11 +621,8 @@ static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
p = pkt.data;
bytestream_put_be32(&p, rt->bytes_read);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
- return ret;
+ return rtmp_send_packet(rt, &pkt, 0);
}
static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
@@ -622,11 +642,7 @@ static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
ff_amf_write_null(&p);
ff_amf_write_string(&p, subscribe);
- ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
- rt->prev_pkt[1]);
- ff_rtmp_packet_destroy(&pkt);
-
- return ret;
+ return rtmp_send_packet(rt, &pkt, 1);
}
int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
@@ -1010,7 +1026,8 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt)
RTMPContext *rt = s->priv_data;
int i, t;
const uint8_t *data_end = pkt->data + pkt->data_size;
- int ret;
+ char *tracked_method = NULL;
+ int ret = 0;
//TODO: check for the messages sent for wrong state?
if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
@@ -1021,68 +1038,72 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt)
av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
return -1;
} else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
- switch (rt->state) {
- case STATE_HANDSHAKED:
- if (!rt->is_input) {
- if ((ret = gen_release_stream(s, rt)) < 0)
- return ret;
- if ((ret = gen_fcpublish_stream(s, rt)) < 0)
- return ret;
- rt->state = STATE_RELEASING;
- } else {
- if ((ret = gen_server_bw(s, rt)) < 0)
- return ret;
- rt->state = STATE_CONNECTING;
- }
- if ((ret = gen_create_stream(s, rt)) < 0)
- return ret;
-
- if (rt->is_input) {
- /* Send the FCSubscribe command when the name of live
- * stream is defined by the user or if it's a live stream. */
- if (rt->subscribe) {
- if ((ret = gen_fcsubscribe_stream(s, rt,
- rt->subscribe)) < 0)
- return ret;
- } else if (rt->live == -1) {
- if ((ret = gen_fcsubscribe_stream(s, rt,
- rt->playpath)) < 0)
- return ret;
- }
- }
- break;
- case STATE_FCPUBLISH:
- rt->state = STATE_CONNECTING;
- break;
- case STATE_RELEASING:
- rt->state = STATE_FCPUBLISH;
- /* hack for Wowza Media Server, it does not send result for
- * releaseStream and FCPublish calls */
- if (!pkt->data[10]) {
- int pkt_id = av_int2double(AV_RB64(pkt->data + 11));
- if (pkt_id == rt->create_stream_invoke)
- rt->state = STATE_CONNECTING;
- }
- if (rt->state != STATE_CONNECTING)
- break;
- case STATE_CONNECTING:
- //extract a number from the result
- if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
- av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
- } else {
- rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
- }
- if (rt->is_input) {
- if ((ret = gen_play(s, rt)) < 0)
- return ret;
- if ((ret = gen_buffer_time(s, rt)) < 0)
- return ret;
- } else {
- if ((ret = gen_publish(s, rt)) < 0)
- return ret;
+ GetByteContext gbc;
+ double pkt_id;
+
+ bytestream2_init(&gbc, pkt->data + 10, pkt->data_size);
+ if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
+ return ret;
+
+ for (i = 0; i < rt->nb_tracked_methods; i++) {
+ if (rt->tracked_methods[i].id != pkt_id)
+ continue;
+
+ tracked_method = rt->tracked_methods[i].name;
+ del_tracked_method(rt, i);
+ break;
+ }
+
+ if (!tracked_method) {
+ /* Ignore this reply when the current method is not tracked. */
+ return 0;
+ }
+
+ if (!memcmp(tracked_method, "connect", 7)) {
+ if (!rt->is_input) {
+ if ((ret = gen_release_stream(s, rt)) < 0)
+ goto invoke_fail;
+
+ if ((ret = gen_fcpublish_stream(s, rt)) < 0)
+ goto invoke_fail;
+ } else {
+ if ((ret = gen_server_bw(s, rt)) < 0)
+ goto invoke_fail;
+ }
+
+ if ((ret = gen_create_stream(s, rt)) < 0)
+ goto invoke_fail;
+
+ if (rt->is_input) {
+ /* Send the FCSubscribe command when the name of live
+ * stream is defined by the user or if it's a live stream. */
+ if (rt->subscribe) {
+ if ((ret = gen_fcsubscribe_stream(s, rt,
+ rt->subscribe)) < 0)
+ goto invoke_fail;
+ } else if (rt->live == -1) {
+ if ((ret = gen_fcsubscribe_stream(s, rt,
+ rt->playpath)) < 0)
+ goto invoke_fail;
}
- rt->state = STATE_READY;
- break;
+ }
+ } else if (!memcmp(tracked_method, "createStream", 12)) {
+ //extract a number from the result
+ if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
+ av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
+ } else {
+ rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
+ }
+
+ if (!rt->is_input) {
+ if ((ret = gen_publish(s, rt)) < 0)
+ goto invoke_fail;
+ } else {
+ if ((ret = gen_play(s, rt)) < 0)
+ goto invoke_fail;
+ if ((ret = gen_buffer_time(s, rt)) < 0)
+ goto invoke_fail;
+ }
}
} else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
const uint8_t* ptr = pkt->data + 11;
@@ -1113,7 +1134,9 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt)
return ret;
}
- return 0;
+invoke_fail:
+ av_free(tracked_method);
+ return ret;
}
/**
@@ -1283,6 +1306,7 @@ static int rtmp_close(URLContext *h)
if (rt->state > STATE_HANDSHAKED)
ret = gen_delete_stream(h, rt);
+ free_tracked_methods(rt);
av_freep(&rt->flv_data);
ffurl_close(rt->stream);
return ret;
@@ -1570,10 +1594,8 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
if (rt->flv_off == rt->flv_size) {
rt->skip_bytes = 4;
- if ((ret = ff_rtmp_packet_write(rt->stream, &rt->out_pkt,
- rt->chunk_size, rt->prev_pkt[1])) < 0)
+ if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
return ret;
- ff_rtmp_packet_destroy(&rt->out_pkt);
rt->flv_size = 0;
rt->flv_off = 0;
rt->flv_header_bytes = 0;
diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c
index f8a2272203..61e038afeb 100644
--- a/libavformat/rtpdec_h264.c
+++ b/libavformat/rtpdec_h264.c
@@ -37,7 +37,6 @@
#include "libavutil/avstring.h"
#include "libavcodec/get_bits.h"
#include "avformat.h"
-#include "mpegts.h"
#include "network.h"
#include <assert.h>
diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
index 6af23f760a..7cd7034fbf 100644
--- a/libavformat/rtpenc.c
+++ b/libavformat/rtpenc.c
@@ -281,8 +281,8 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
/* send an integer number of samples and compute time stamp and fill
the rtp send buffer before sending. */
-static void rtp_send_samples(AVFormatContext *s1,
- const uint8_t *buf1, int size, int sample_size_bits)
+static int rtp_send_samples(AVFormatContext *s1,
+ const uint8_t *buf1, int size, int sample_size_bits)
{
RTPMuxContext *s = s1->priv_data;
int len, max_packet_size, n;
@@ -292,7 +292,7 @@ static void rtp_send_samples(AVFormatContext *s1,
max_packet_size = (s->max_payload_size / aligned_samples_size) * aligned_samples_size;
/* Not needed, but who knows. Don't check if samples aren't an even number of bytes. */
if ((sample_size_bits % 8) == 0 && ((8 * size) % sample_size_bits) != 0)
- av_abort();
+ return AVERROR(EINVAL);
n = 0;
while (size > 0) {
s->buf_ptr = s->buf;
@@ -307,6 +307,7 @@ static void rtp_send_samples(AVFormatContext *s1,
ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0);
n += (s->buf_ptr - s->buf);
}
+ return 0;
}
static void rtp_send_mpegaudio(AVFormatContext *s1,
@@ -461,25 +462,21 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_U8:
case AV_CODEC_ID_PCM_S8:
- rtp_send_samples(s1, pkt->data, size, 8 * st->codec->channels);
- break;
+ return rtp_send_samples(s1, pkt->data, size, 8 * st->codec->channels);
case AV_CODEC_ID_PCM_U16BE:
case AV_CODEC_ID_PCM_U16LE:
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_S16LE:
- rtp_send_samples(s1, pkt->data, size, 16 * st->codec->channels);
- break;
+ return rtp_send_samples(s1, pkt->data, size, 16 * st->codec->channels);
case AV_CODEC_ID_ADPCM_G722:
/* The actual sample size is half a byte per sample, but since the
* stream clock rate is 8000 Hz while the sample rate is 16000 Hz,
* the correct parameter for send_samples_bits is 8 bits per stream
* clock. */
- rtp_send_samples(s1, pkt->data, size, 8 * st->codec->channels);
- break;
+ return rtp_send_samples(s1, pkt->data, size, 8 * st->codec->channels);
case AV_CODEC_ID_ADPCM_G726:
- rtp_send_samples(s1, pkt->data, size,
- st->codec->bits_per_coded_sample * st->codec->channels);
- break;
+ return rtp_send_samples(s1, pkt->data, size,
+ st->codec->bits_per_coded_sample * st->codec->channels);
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MP3:
rtp_send_mpegaudio(s1, pkt->data, size);
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 633ec39ecb..b5e6858e00 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -46,6 +46,7 @@
#include "rtpenc_chain.h"
#include "url.h"
#include "rtpenc.h"
+#include "mpegts.h"
//#define DEBUG
@@ -370,7 +371,9 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
get_word(buf1, sizeof(buf1), &p); /* port */
rtsp_st->sdp_port = atoi(buf1);
- get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */
+ get_word(buf1, sizeof(buf1), &p); /* protocol */
+ if (!strcmp(buf1, "udp"))
+ rt->transport = RTSP_TRANSPORT_RAW;
/* XXX: handle list of formats */
get_word(buf1, sizeof(buf1), &p); /* format list */
@@ -378,6 +381,8 @@ 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);
} else if (rt->server_type == RTSP_SERVER_WMS &&
codec_type == AVMEDIA_TYPE_DATA) {
/* RTX stream, a stream that carries all the other actual
@@ -563,7 +568,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
avformat_free_context(rtpctx);
} else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC)
ff_rdt_parse_close(rtsp_st->transport_priv);
- else if (CONFIG_RTPDEC)
+ else if (rt->transport == RTSP_TRANSPORT_RAW && CONFIG_RTPDEC)
ff_rtp_parse_close(rtsp_st->transport_priv);
}
rtsp_st->transport_priv = NULL;
@@ -594,6 +599,8 @@ void ff_rtsp_close_streams(AVFormatContext *s)
if (rt->asf_ctx) {
avformat_close_input(&rt->asf_ctx);
}
+ if (rt->ts && CONFIG_RTPDEC)
+ ff_mpegts_parse_close(rt->ts);
av_free(rt->p);
av_free(rt->recvbuf);
}
@@ -617,6 +624,8 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
rtsp_st->rtp_handle = NULL;
if (ret < 0)
return ret;
+ } else if (rt->transport == RTSP_TRANSPORT_RAW) {
+ return 0; // Don't need to open any parser here
} else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC)
rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
rtsp_st->dynamic_protocol_context,
@@ -629,7 +638,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
if (!rtsp_st->transport_priv) {
return AVERROR(ENOMEM);
- } else if (rt->transport != RTSP_TRANSPORT_RDT && CONFIG_RTPDEC) {
+ } else if (rt->transport == RTSP_TRANSPORT_RTP && CONFIG_RTPDEC) {
if (rtsp_st->dynamic_handler) {
ff_rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
rtsp_st->dynamic_protocol_context,
@@ -698,6 +707,15 @@ static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p)
get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p);
profile[0] = '\0';
th->transport = RTSP_TRANSPORT_RDT;
+ } else if (!av_strcasecmp(transport_protocol, "raw")) {
+ get_word_sep(profile, sizeof(profile), "/;,", &p);
+ lower_transport[0] = '\0';
+ /* raw/raw/<protocol> */
+ if (*p == '/') {
+ get_word_sep(lower_transport, sizeof(lower_transport),
+ ";,", &p);
+ }
+ th->transport = RTSP_TRANSPORT_RAW;
}
if (!av_strcasecmp(lower_transport, "TCP"))
th->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
@@ -1187,6 +1205,8 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
if (rt->transport == RTSP_TRANSPORT_RDT)
trans_pref = "x-pn-tng";
+ else if (rt->transport == RTSP_TRANSPORT_RAW)
+ trans_pref = "RAW/RAW";
else
trans_pref = "RTP/AVP";
@@ -1753,8 +1773,15 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
if (rt->cur_transport_priv) {
if (rt->transport == RTSP_TRANSPORT_RDT) {
ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
- } else
+ } else if (rt->transport == RTSP_TRANSPORT_RTP) {
ret = ff_rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
+ } else if (rt->ts && CONFIG_RTPDEC) {
+ ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos);
+ if (ret >= 0) {
+ rt->recvbuf_pos += ret;
+ ret = rt->recvbuf_pos < rt->recvbuf_len;
+ }
+ }
if (ret == 0) {
rt->cur_transport_priv = NULL;
return 0;
@@ -1817,7 +1844,7 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR_EOF;
if (rt->transport == RTSP_TRANSPORT_RDT) {
ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
- } else {
+ } else if (rt->transport == RTSP_TRANSPORT_RTP) {
ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
if (ret < 0) {
/* Either bad packet, or a RTCP packet. Check if the
@@ -1856,6 +1883,20 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR_EOF;
}
}
+ } else if (rt->ts && CONFIG_RTPDEC) {
+ ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len);
+ if (ret >= 0) {
+ if (ret < len) {
+ rt->recvbuf_len = len;
+ rt->recvbuf_pos = ret;
+ rt->cur_transport_priv = rt->ts;
+ return 1;
+ } else {
+ ret = 0;
+ }
+ }
+ } else {
+ return AVERROR_INVALIDDATA;
}
end:
if (ret < 0)
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 6d9680161e..e55073c430 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -52,6 +52,7 @@ enum RTSPLowerTransport {
enum RTSPTransport {
RTSP_TRANSPORT_RTP, /**< Standards-compliant RTP */
RTSP_TRANSPORT_RDT, /**< Realmedia Data Transport */
+ RTSP_TRANSPORT_RAW, /**< Raw data (over UDP) */
RTSP_TRANSPORT_NB
};
@@ -310,6 +311,13 @@ typedef struct RTSPState {
* other cases, this is a copy of AVFormatContext->filename. */
char control_uri[1024];
+ /** The following are used for parsing raw mpegts in udp */
+ //@{
+ struct MpegTSContext *ts;
+ int recvbuf_pos;
+ int recvbuf_len;
+ //@}
+
/** Additional output handle, used when input and output are done
* separately, eg for HTTP tunneling. */
URLContext *rtsp_hd_out;
diff --git a/libavformat/version.h b/libavformat/version.h
index 53d9a06520..750b7652e2 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 54
#define LIBAVFORMAT_VERSION_MINOR 22
-#define LIBAVFORMAT_VERSION_MICRO 103
+#define LIBAVFORMAT_VERSION_MICRO 104
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \