summaryrefslogtreecommitdiffstats
path: root/libavformat
diff options
context:
space:
mode:
authorRonald S. Bultje <rsbultje@gmail.com>2008-09-07 01:21:24 +0000
committerRonald S. Bultje <rsbultje@gmail.com>2008-09-07 01:21:24 +0000
commitff13ba92fd6bfee75db3d1e2f593474946cbfb68 (patch)
tree51a913896024f614bb913ce6a6e6ab1ad65aa009 /libavformat
parent0369d2b045f41ab274fca700e23811ec5918b857 (diff)
downloadffmpeg-streaming-ff13ba92fd6bfee75db3d1e2f593474946cbfb68.zip
ffmpeg-streaming-ff13ba92fd6bfee75db3d1e2f593474946cbfb68.tar.gz
Add dynamic payload handlers to rdt.c. These follow the same API as the ones
in rtpdec.c, so that they can be shared and used in the same way in rtsp.c. The handlers, since they are specific for RDT, are registered in rdt.c and a new registration function is thus called from allformats.c. The dynamic payload handler also implements RDT-specific SDP-line parsing for OpaqueData and StartTime, which are specific for RDT and needed for proper playback. OpaqueData contains one or a list ("MLTI") of "MDPR" chunks that can be parsed by the rmdec.c function ff_rm_read_mdpr_codecdata(). To use this function, we create a new rdt_demuxer, which has the same private data as the rm_demuxer. The resulting AVFormatContext created with _open_stream() can thus be used to call functions in the RM demuxer. See discussion in "Realmedia patch" thread on ML. Originally committed as revision 15234 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/allformats.c2
-rw-r--r--libavformat/rdt.c136
-rw-r--r--libavformat/rdt.h5
-rw-r--r--libavformat/rm.h3
-rw-r--r--libavformat/rmdec.c7
5 files changed, 153 insertions, 0 deletions
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 528cdcd..49d65f0 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -20,6 +20,7 @@
*/
#include "avformat.h"
#include "rtp_internal.h"
+#include "rdt.h"
#define REGISTER_MUXER(X,x) { \
extern AVOutputFormat x##_muxer; \
@@ -165,6 +166,7 @@ void av_register_all(void)
REGISTER_DEMUXER (SDP, sdp);
#ifdef CONFIG_SDP_DEMUXER
av_register_rtp_dynamic_payload_handlers();
+ av_register_rdt_dynamic_payload_handlers();
#endif
REGISTER_DEMUXER (SEGAFILM, segafilm);
REGISTER_DEMUXER (SHORTEN, shorten);
diff --git a/libavformat/rdt.c b/libavformat/rdt.c
index 1d0e455..e5a1f89 100644
--- a/libavformat/rdt.c
+++ b/libavformat/rdt.c
@@ -27,12 +27,19 @@
#include "avformat.h"
#include "libavutil/avstring.h"
+#include "rtp_internal.h"
#include "rdt.h"
#include "libavutil/base64.h"
#include "libavutil/md5.h"
#include "rm.h"
#include "internal.h"
+typedef struct rdt_data {
+ AVFormatContext *rmctx;
+ uint8_t *mlti_data;
+ unsigned int mlti_data_size;
+} rdt_data;
+
void
ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
const char *challenge)
@@ -71,3 +78,132 @@ ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
chksum[i] = response[i * 4];
chksum[8] = 0;
}
+
+static int
+rdt_load_mdpr (rdt_data *rdt, AVStream *st, int rule_nr)
+{
+ ByteIOContext *pb;
+ int size;
+ uint32_t tag;
+
+ /**
+ * Layout of the MLTI chunk:
+ * 4:MLTI
+ * 2:<number of streams>
+ * Then for each stream ([number_of_streams] times):
+ * 2:<mdpr index>
+ * 2:<number of mdpr chunks>
+ * Then for each mdpr chunk ([number_of_mdpr_chunks] times):
+ * 4:<size>
+ * [size]:<data>
+ * we skip MDPR chunks until we reach the one of the stream
+ * we're interested in, and forward that ([size]+[data]) to
+ * the RM demuxer to parse the stream-specific header data.
+ */
+ if (!rdt->mlti_data)
+ return -1;
+ url_open_buf(&pb, rdt->mlti_data, rdt->mlti_data_size, URL_RDONLY);
+ tag = get_le32(pb);
+ if (tag == MKTAG('M', 'L', 'T', 'I')) {
+ int num, chunk_nr;
+
+ /* read index of MDPR chunk numbers */
+ num = get_be16(pb);
+ if (rule_nr < 0 || rule_nr >= num)
+ return -1;
+ url_fskip(pb, rule_nr * 2);
+ chunk_nr = get_be16(pb);
+ url_fskip(pb, (num - 1 - rule_nr) * 2);
+
+ /* read MDPR chunks */
+ num = get_be16(pb);
+ if (chunk_nr >= num)
+ return -1;
+ while (chunk_nr--)
+ url_fskip(pb, get_be32(pb));
+ size = get_be32(pb);
+ } else {
+ size = rdt->mlti_data_size;
+ url_fseek(pb, 0, SEEK_SET);
+ }
+ rdt->rmctx->pb = pb;
+ if (ff_rm_read_mdpr_codecdata(rdt->rmctx, st, size) < 0)
+ return -1;
+
+ url_close_buf(pb);
+ return 0;
+}
+
+static unsigned char *
+rdt_parse_b64buf (unsigned int *target_len, const char *p)
+{
+ unsigned char *target;
+ int len = strlen(p);
+ if (*p == '\"') {
+ p++;
+ len -= 2; /* skip embracing " at start/end */
+ }
+ *target_len = len * 3 / 4;
+ target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_base64_decode(target, p, *target_len);
+ return target;
+}
+
+static int
+rdt_parse_sdp_line (AVStream *stream, void *d, const char *line)
+{
+ rdt_data *rdt = d;
+ const char *p = line;
+
+ if (av_strstart(p, "OpaqueData:buffer;", &p)) {
+ rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
+ rdt_load_mdpr(rdt, stream, 0);
+ } else if (av_strstart(p, "StartTime:integer;", &p))
+ stream->first_dts = atoi(p);
+
+ return 0;
+}
+
+static void *
+rdt_new_extradata (void)
+{
+ rdt_data *rdt = av_mallocz(sizeof(rdt_data));
+
+ av_open_input_stream(&rdt->rmctx, NULL, "", &rdt_demuxer, NULL);
+
+ return rdt;
+}
+
+static void
+rdt_free_extradata (void *d)
+{
+ rdt_data *rdt = d;
+
+ if (rdt->rmctx)
+ av_close_input_stream(rdt->rmctx);
+ av_freep(&rdt->mlti_data);
+ av_free(rdt);
+}
+
+#define RDT_HANDLER(n, s, t) \
+static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
+ s, \
+ t, \
+ CODEC_ID_NONE, \
+ rdt_parse_sdp_line, \
+ rdt_new_extradata, \
+ rdt_free_extradata \
+};
+
+RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", CODEC_TYPE_VIDEO);
+RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", CODEC_TYPE_AUDIO);
+RDT_HANDLER(video, "x-pn-realvideo", CODEC_TYPE_VIDEO);
+RDT_HANDLER(audio, "x-pn-realaudio", CODEC_TYPE_AUDIO);
+
+void av_register_rdt_dynamic_payload_handlers(void)
+{
+ ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
+ ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
+ ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
+ ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
+}
diff --git a/libavformat/rdt.h b/libavformat/rdt.h
index f7aad6d..5da9a78 100644
--- a/libavformat/rdt.h
+++ b/libavformat/rdt.h
@@ -37,4 +37,9 @@
void ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
const char *challenge);
+/**
+ * Register RDT-related dynamic payload handlers with our cache.
+ */
+void av_register_rdt_dynamic_payload_handlers(void);
+
#endif /* AVFORMAT_RDT_H */
diff --git a/libavformat/rm.h b/libavformat/rm.h
index a57e517..4ad1c30 100644
--- a/libavformat/rm.h
+++ b/libavformat/rm.h
@@ -63,6 +63,9 @@ typedef struct {
int sub_packet_lengths[16]; /// Length of each aac subpacket
} RMContext;
+/*< input format for Realmedia-style RTSP streams */
+extern AVInputFormat rdt_demuxer;
+
/**
* Read the MDPR chunk, which contains stream-specific codec initialization
* parameters.
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index cb3863b..ee68ac1 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -795,3 +795,10 @@ AVInputFormat rm_demuxer = {
NULL,
rm_read_dts,
};
+
+AVInputFormat rdt_demuxer = {
+ "rdt",
+ NULL_IF_CONFIG_SMALL("RDT demuxer"),
+ sizeof(RMContext),
+ NULL, NULL, NULL, rm_read_close, NULL, NULL
+};
OpenPOWER on IntegriCloud