• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/rdt.c

Go to the documentation of this file.
00001 /*
00002  * Realmedia RTSP protocol (RDT) support.
00003  * Copyright (c) 2007 Ronald S. Bultje
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00028 #include "avformat.h"
00029 #include "libavutil/avstring.h"
00030 #include "rtpdec.h"
00031 #include "rdt.h"
00032 #include "libavutil/base64.h"
00033 #include "libavutil/md5.h"
00034 #include "rm.h"
00035 #include "internal.h"
00036 #include "libavcodec/get_bits.h"
00037 
00038 struct RDTDemuxContext {
00039     AVFormatContext *ic; 
00045     AVStream **streams;
00046     int n_streams; 
00047     void *dynamic_protocol_context;
00048     DynamicPayloadPacketHandlerProc parse_packet;
00049     uint32_t prev_timestamp;
00050     int prev_set_id, prev_stream_id;
00051 };
00052 
00053 RDTDemuxContext *
00054 ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx,
00055                   void *priv_data, RTPDynamicProtocolHandler *handler)
00056 {
00057     RDTDemuxContext *s = av_mallocz(sizeof(RDTDemuxContext));
00058     if (!s)
00059         return NULL;
00060 
00061     s->ic = ic;
00062     s->streams = &ic->streams[first_stream_of_set_idx];
00063     do {
00064         s->n_streams++;
00065     } while (first_stream_of_set_idx + s->n_streams < ic->nb_streams &&
00066              s->streams[s->n_streams]->priv_data == s->streams[0]->priv_data);
00067     s->prev_set_id    = -1;
00068     s->prev_stream_id = -1;
00069     s->prev_timestamp = -1;
00070     s->parse_packet = handler ? handler->parse_packet : NULL;
00071     s->dynamic_protocol_context = priv_data;
00072 
00073     return s;
00074 }
00075 
00076 void
00077 ff_rdt_parse_close(RDTDemuxContext *s)
00078 {
00079     int i;
00080 
00081     for (i = 1; i < s->n_streams; i++)
00082         s->streams[i]->priv_data = NULL;
00083 
00084     av_free(s);
00085 }
00086 
00087 struct PayloadContext {
00088     AVFormatContext *rmctx;
00089     RMStream *rmst[MAX_STREAMS];
00090     uint8_t *mlti_data;
00091     unsigned int mlti_data_size;
00092     char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE];
00093     int audio_pkt_cnt; 
00094 };
00095 
00096 void
00097 ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
00098                                   const char *challenge)
00099 {
00100     int ch_len = strlen (challenge), i;
00101     unsigned char zres[16],
00102         buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
00103 #define XOR_TABLE_SIZE 37
00104     const unsigned char xor_table[XOR_TABLE_SIZE] = {
00105         0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
00106         0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
00107         0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
00108         0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
00109         0x10, 0x57, 0x05, 0x18, 0x54 };
00110 
00111     /* some (length) checks */
00112     if (ch_len == 40) /* what a hack... */
00113         ch_len = 32;
00114     else if (ch_len > 56)
00115         ch_len = 56;
00116     memcpy(buf + 8, challenge, ch_len);
00117 
00118     /* xor challenge bytewise with xor_table */
00119     for (i = 0; i < XOR_TABLE_SIZE; i++)
00120         buf[8 + i] ^= xor_table[i];
00121 
00122     av_md5_sum(zres, buf, 64);
00123     ff_data_to_hex(response, zres, 16, 1);
00124 
00125     /* add tail */
00126     strcpy (response + 32, "01d0a8e3");
00127 
00128     /* calculate checksum */
00129     for (i = 0; i < 8; i++)
00130         chksum[i] = response[i * 4];
00131     chksum[8] = 0;
00132 }
00133 
00134 static int
00135 rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
00136 {
00137     ByteIOContext pb;
00138     int size;
00139     uint32_t tag;
00140 
00155     if (!rdt->mlti_data)
00156         return -1;
00157     init_put_byte(&pb, rdt->mlti_data, rdt->mlti_data_size, 0,
00158                   NULL, NULL, NULL, NULL);
00159     tag = get_le32(&pb);
00160     if (tag == MKTAG('M', 'L', 'T', 'I')) {
00161         int num, chunk_nr;
00162 
00163         /* read index of MDPR chunk numbers */
00164         num = get_be16(&pb);
00165         if (rule_nr < 0 || rule_nr >= num)
00166             return -1;
00167         url_fskip(&pb, rule_nr * 2);
00168         chunk_nr = get_be16(&pb);
00169         url_fskip(&pb, (num - 1 - rule_nr) * 2);
00170 
00171         /* read MDPR chunks */
00172         num = get_be16(&pb);
00173         if (chunk_nr >= num)
00174             return -1;
00175         while (chunk_nr--)
00176             url_fskip(&pb, get_be32(&pb));
00177         size = get_be32(&pb);
00178     } else {
00179         size = rdt->mlti_data_size;
00180         url_fseek(&pb, 0, SEEK_SET);
00181     }
00182     if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size) < 0)
00183         return -1;
00184 
00185     return 0;
00186 }
00187 
00192 int
00193 ff_rdt_parse_header(const uint8_t *buf, int len,
00194                     int *pset_id, int *pseq_no, int *pstream_id,
00195                     int *pis_keyframe, uint32_t *ptimestamp)
00196 {
00197     GetBitContext gb;
00198     int consumed = 0, set_id, seq_no, stream_id, is_keyframe,
00199         len_included, need_reliable;
00200     uint32_t timestamp;
00201 
00202     /* skip status packets */
00203     while (len >= 5 && buf[1] == 0xFF /* status packet */) {
00204         int pkt_len;
00205 
00206         if (!(buf[0] & 0x80))
00207             return -1; /* not followed by a data packet */
00208 
00209         pkt_len = AV_RB16(buf+3);
00210         buf += pkt_len;
00211         len -= pkt_len;
00212         consumed += pkt_len;
00213     }
00214     if (len < 16)
00215         return -1;
00267     init_get_bits(&gb, buf, len << 3);
00268     len_included  = get_bits1(&gb);
00269     need_reliable = get_bits1(&gb);
00270     set_id        = get_bits(&gb, 5);
00271     skip_bits(&gb, 1);
00272     seq_no        = get_bits(&gb, 16);
00273     if (len_included)
00274         skip_bits(&gb, 16);
00275     skip_bits(&gb, 2);
00276     stream_id     = get_bits(&gb, 5);
00277     is_keyframe   = !get_bits1(&gb);
00278     timestamp     = get_bits_long(&gb, 32);
00279     if (set_id == 0x1f)
00280         set_id    = get_bits(&gb, 16);
00281     if (need_reliable)
00282         skip_bits(&gb, 16);
00283     if (stream_id == 0x1f)
00284         stream_id = get_bits(&gb, 16);
00285 
00286     if (pset_id)      *pset_id      = set_id;
00287     if (pseq_no)      *pseq_no      = seq_no;
00288     if (pstream_id)   *pstream_id   = stream_id;
00289     if (pis_keyframe) *pis_keyframe = is_keyframe;
00290     if (ptimestamp)   *ptimestamp   = timestamp;
00291 
00292     return consumed + (get_bits_count(&gb) >> 3);
00293 }
00294 
00296 static int
00297 rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st,
00298                   AVPacket *pkt, uint32_t *timestamp,
00299                   const uint8_t *buf, int len, int flags)
00300 {
00301     int seq = 1, res;
00302     ByteIOContext pb;
00303 
00304     if (rdt->audio_pkt_cnt == 0) {
00305         int pos;
00306 
00307         init_put_byte(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
00308         flags = (flags & RTP_FLAG_KEY) ? 2 : 0;
00309         res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
00310                                   &seq, flags, *timestamp);
00311         pos = url_ftell(&pb);
00312         if (res < 0)
00313             return res;
00314         if (res > 0) {
00315             if (st->codec->codec_id == CODEC_ID_AAC) {
00316                 memcpy (rdt->buffer, buf + pos, len - pos);
00317                 rdt->rmctx->pb = av_alloc_put_byte (rdt->buffer, len - pos, 0,
00318                                                     NULL, NULL, NULL, NULL);
00319             }
00320             goto get_cache;
00321         }
00322     } else {
00323 get_cache:
00324         rdt->audio_pkt_cnt =
00325             ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb,
00326                                   st, rdt->rmst[st->index], pkt);
00327         if (rdt->audio_pkt_cnt == 0 &&
00328             st->codec->codec_id == CODEC_ID_AAC)
00329             av_freep(&rdt->rmctx->pb);
00330     }
00331     pkt->stream_index = st->index;
00332     pkt->pts = *timestamp;
00333 
00334     return rdt->audio_pkt_cnt > 0;
00335 }
00336 
00337 int
00338 ff_rdt_parse_packet(RDTDemuxContext *s, AVPacket *pkt,
00339                     const uint8_t *buf, int len)
00340 {
00341     int seq_no, flags = 0, stream_id, set_id, is_keyframe;
00342     uint32_t timestamp;
00343     int rv= 0;
00344 
00345     if (!s->parse_packet)
00346         return -1;
00347 
00348     if (!buf && s->prev_stream_id != -1) {
00349         /* return the next packets, if any */
00350         timestamp= 0; 
00351         rv= s->parse_packet(s->ic, s->dynamic_protocol_context,
00352                             s->streams[s->prev_stream_id],
00353                             pkt, &timestamp, NULL, 0, flags);
00354         return rv;
00355     }
00356 
00357     if (len < 12)
00358         return -1;
00359     rv = ff_rdt_parse_header(buf, len, &set_id, &seq_no, &stream_id, &is_keyframe, &timestamp);
00360     if (rv < 0)
00361         return rv;
00362     if (is_keyframe &&
00363         (set_id != s->prev_set_id || timestamp != s->prev_timestamp ||
00364          stream_id != s->prev_stream_id)) {
00365         flags |= RTP_FLAG_KEY;
00366         s->prev_set_id    = set_id;
00367         s->prev_timestamp = timestamp;
00368     }
00369     s->prev_stream_id = stream_id;
00370     buf += rv;
00371     len -= rv;
00372 
00373      if (s->prev_stream_id >= s->n_streams) {
00374          s->prev_stream_id = -1;
00375          return -1;
00376      }
00377 
00378     rv = s->parse_packet(s->ic, s->dynamic_protocol_context,
00379                          s->streams[s->prev_stream_id],
00380                          pkt, &timestamp, buf, len, flags);
00381 
00382     return rv;
00383 }
00384 
00385 void
00386 ff_rdt_subscribe_rule (char *cmd, int size,
00387                        int stream_nr, int rule_nr)
00388 {
00389     av_strlcatf(cmd, size, "stream=%d;rule=%d,stream=%d;rule=%d",
00390                 stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
00391 }
00392 
00393 static unsigned char *
00394 rdt_parse_b64buf (unsigned int *target_len, const char *p)
00395 {
00396     unsigned char *target;
00397     int len = strlen(p);
00398     if (*p == '\"') {
00399         p++;
00400         len -= 2; /* skip embracing " at start/end */
00401     }
00402     *target_len = len * 3 / 4;
00403     target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
00404     av_base64_decode(target, p, *target_len);
00405     return target;
00406 }
00407 
00408 static int
00409 rdt_parse_sdp_line (AVFormatContext *s, int st_index,
00410                     PayloadContext *rdt, const char *line)
00411 {
00412     AVStream *stream = s->streams[st_index];
00413     const char *p = line;
00414 
00415     if (av_strstart(p, "OpaqueData:buffer;", &p)) {
00416         rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
00417     } else if (av_strstart(p, "StartTime:integer;", &p))
00418         stream->first_dts = atoi(p);
00419     else if (av_strstart(p, "ASMRuleBook:string;", &p)) {
00420         int n, first = -1;
00421 
00422         for (n = 0; n < s->nb_streams; n++)
00423             if (s->streams[n]->priv_data == stream->priv_data) {
00424                 if (first == -1) first = n;
00425                 rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream();
00426                 rdt_load_mdpr(rdt, s->streams[n], (n - first) * 2);
00427 
00428                 if (s->streams[n]->codec->codec_id == CODEC_ID_AAC)
00429                     s->streams[n]->codec->frame_size = 1; // FIXME
00430            }
00431     }
00432 
00433     return 0;
00434 }
00435 
00436 static void
00437 real_parse_asm_rule(AVStream *st, const char *p, const char *end)
00438 {
00439     do {
00440         /* can be either averagebandwidth= or AverageBandwidth= */
00441         if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%d", &st->codec->bit_rate) == 1)
00442             break;
00443         if (!(p = strchr(p, ',')) || p > end)
00444             p = end;
00445         p++;
00446     } while (p < end);
00447 }
00448 
00449 static AVStream *
00450 add_dstream(AVFormatContext *s, AVStream *orig_st)
00451 {
00452     AVStream *st;
00453 
00454     if (!(st = av_new_stream(s, 0)))
00455         return NULL;
00456     st->codec->codec_type = orig_st->codec->codec_type;
00457     st->priv_data         = orig_st->priv_data;
00458     st->first_dts         = orig_st->first_dts;
00459 
00460     return st;
00461 }
00462 
00463 static void
00464 real_parse_asm_rulebook(AVFormatContext *s, AVStream *orig_st,
00465                         const char *p)
00466 {
00467     const char *end;
00468     int n_rules, odd = 0;
00469     AVStream *st;
00470 
00485     if (*p == '\"') p++;
00486     for (n_rules = 0; s->nb_streams < MAX_STREAMS;) {
00487         if (!(end = strchr(p, ';')))
00488             break;
00489         if (!odd && end != p) {
00490             if (n_rules > 0)
00491                 st = add_dstream(s, orig_st);
00492             else
00493                 st = orig_st;
00494             real_parse_asm_rule(st, p, end);
00495             n_rules++;
00496         }
00497         p = end + 1;
00498         odd ^= 1;
00499     }
00500 }
00501 
00502 void
00503 ff_real_parse_sdp_a_line (AVFormatContext *s, int stream_index,
00504                           const char *line)
00505 {
00506     const char *p = line;
00507 
00508     if (av_strstart(p, "ASMRuleBook:string;", &p))
00509         real_parse_asm_rulebook(s, s->streams[stream_index], p);
00510 }
00511 
00512 static PayloadContext *
00513 rdt_new_context (void)
00514 {
00515     PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
00516 
00517     av_open_input_stream(&rdt->rmctx, NULL, "", &rdt_demuxer, NULL);
00518 
00519     return rdt;
00520 }
00521 
00522 static void
00523 rdt_free_context (PayloadContext *rdt)
00524 {
00525     int i;
00526 
00527     for (i = 0; i < MAX_STREAMS; i++)
00528         if (rdt->rmst[i]) {
00529             ff_rm_free_rmstream(rdt->rmst[i]);
00530             av_freep(&rdt->rmst[i]);
00531         }
00532     if (rdt->rmctx)
00533         av_close_input_stream(rdt->rmctx);
00534     av_freep(&rdt->mlti_data);
00535     av_free(rdt);
00536 }
00537 
00538 #define RDT_HANDLER(n, s, t) \
00539 static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
00540     .enc_name         = s, \
00541     .codec_type       = t, \
00542     .codec_id         = CODEC_ID_NONE, \
00543     .parse_sdp_a_line = rdt_parse_sdp_line, \
00544     .open             = rdt_new_context, \
00545     .close            = rdt_free_context, \
00546     .parse_packet     = rdt_parse_packet \
00547 };
00548 
00549 RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", AVMEDIA_TYPE_VIDEO);
00550 RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO);
00551 RDT_HANDLER(video,      "x-pn-realvideo",                AVMEDIA_TYPE_VIDEO);
00552 RDT_HANDLER(audio,      "x-pn-realaudio",                AVMEDIA_TYPE_AUDIO);
00553 
00554 void av_register_rdt_dynamic_payload_handlers(void)
00555 {
00556     ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
00557     ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
00558     ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
00559     ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
00560 }

Generated on Fri Sep 16 2011 17:17:50 for FFmpeg by  doxygen 1.7.1