Add dynamic payload handlers to rdt.c. These follow the same API as the ones
authorRonald S. Bultje <rsbultje@gmail.com>
Sun, 7 Sep 2008 01:21:24 +0000 (01:21 +0000)
committerRonald S. Bultje <rsbultje@gmail.com>
Sun, 7 Sep 2008 01:21:24 +0000 (01:21 +0000)
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

libavformat/allformats.c
libavformat/rdt.c
libavformat/rdt.h
libavformat/rm.h
libavformat/rmdec.c

index 528cdcd..49d65f0 100644 (file)
@@ -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);
index 1d0e455..e5a1f89 100644 (file)
 
 #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);
+}
index f7aad6d..5da9a78 100644 (file)
@@ -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 */
index a57e517..4ad1c30 100644 (file)
@@ -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.
index cb3863b..ee68ac1 100644 (file)
@@ -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
+};