• 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/bitstream.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->parse_packet;
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);
00124     for (i=0;i<32;i++) response[i] = tolower(response[i]);
00125 
00126     /* add tail */
00127     strcpy (response + 32, "01d0a8e3");
00128 
00129     /* calculate checksum */
00130     for (i = 0; i < 8; i++)
00131         chksum[i] = response[i * 4];
00132     chksum[8] = 0;
00133 }
00134 
00135 static int
00136 rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
00137 {
00138     ByteIOContext pb;
00139     int size;
00140     uint32_t tag;
00141 
00156     if (!rdt->mlti_data)
00157         return -1;
00158     init_put_byte(&pb, rdt->mlti_data, rdt->mlti_data_size, 0,
00159                   NULL, NULL, NULL, NULL);
00160     tag = get_le32(&pb);
00161     if (tag == MKTAG('M', 'L', 'T', 'I')) {
00162         int num, chunk_nr;
00163 
00164         /* read index of MDPR chunk numbers */
00165         num = get_be16(&pb);
00166         if (rule_nr < 0 || rule_nr >= num)
00167             return -1;
00168         url_fskip(&pb, rule_nr * 2);
00169         chunk_nr = get_be16(&pb);
00170         url_fskip(&pb, (num - 1 - rule_nr) * 2);
00171 
00172         /* read MDPR chunks */
00173         num = get_be16(&pb);
00174         if (chunk_nr >= num)
00175             return -1;
00176         while (chunk_nr--)
00177             url_fskip(&pb, get_be32(&pb));
00178         size = get_be32(&pb);
00179     } else {
00180         size = rdt->mlti_data_size;
00181         url_fseek(&pb, 0, SEEK_SET);
00182     }
00183     if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size) < 0)
00184         return -1;
00185 
00186     return 0;
00187 }
00188 
00193 int
00194 ff_rdt_parse_header(const uint8_t *buf, int len,
00195                     int *pset_id, int *pseq_no, int *pstream_id,
00196                     int *pis_keyframe, uint32_t *ptimestamp)
00197 {
00198     GetBitContext gb;
00199     int consumed = 0, set_id, seq_no, stream_id, is_keyframe,
00200         len_included, need_reliable;
00201     uint32_t timestamp;
00202 
00203     /* skip status packets */
00204     while (len >= 5 && buf[1] == 0xFF /* status packet */) {
00205         int pkt_len;
00206 
00207         if (!(buf[0] & 0x80))
00208             return -1; /* not followed by a data packet */
00209 
00210         pkt_len = AV_RB16(buf+3);
00211         buf += pkt_len;
00212         len -= pkt_len;
00213         consumed += pkt_len;
00214     }
00215     if (len < 16)
00216         return -1;
00268     init_get_bits(&gb, buf, len << 3);
00269     len_included  = get_bits1(&gb);
00270     need_reliable = get_bits1(&gb);
00271     set_id        = get_bits(&gb, 5);
00272     skip_bits(&gb, 1);
00273     seq_no        = get_bits(&gb, 16);
00274     if (len_included)
00275         skip_bits(&gb, 16);
00276     skip_bits(&gb, 2);
00277     stream_id     = get_bits(&gb, 5);
00278     is_keyframe   = !get_bits1(&gb);
00279     timestamp     = get_bits_long(&gb, 32);
00280     if (set_id == 0x1f)
00281         set_id    = get_bits(&gb, 16);
00282     if (need_reliable)
00283         skip_bits(&gb, 16);
00284     if (stream_id == 0x1f)
00285         stream_id = get_bits(&gb, 16);
00286 
00287     if (pset_id)      *pset_id      = set_id;
00288     if (pseq_no)      *pseq_no      = seq_no;
00289     if (pstream_id)   *pstream_id   = stream_id;
00290     if (pis_keyframe) *pis_keyframe = is_keyframe;
00291     if (ptimestamp)   *ptimestamp   = timestamp;
00292 
00293     return consumed + (get_bits_count(&gb) >> 3);
00294 }
00295 
00297 static int
00298 rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st,
00299                   AVPacket *pkt, uint32_t *timestamp,
00300                   const uint8_t *buf, int len, int flags)
00301 {
00302     int seq = 1, res;
00303     ByteIOContext pb;
00304 
00305     if (rdt->audio_pkt_cnt == 0) {
00306         int pos;
00307 
00308         init_put_byte(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
00309         flags = (flags & RTP_FLAG_KEY) ? 2 : 0;
00310         res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
00311                                   &seq, &flags, timestamp);
00312         pos = url_ftell(&pb);
00313         if (res < 0)
00314             return res;
00315         rdt->audio_pkt_cnt = res;
00316         if (rdt->audio_pkt_cnt > 0 &&
00317             st->codec->codec_id == CODEC_ID_AAC) {
00318             memcpy (rdt->buffer, buf + pos, len - pos);
00319             rdt->rmctx->pb = av_alloc_put_byte (rdt->buffer, len - pos, 0,
00320                                                 NULL, NULL, NULL, NULL);
00321         }
00322     } else {
00323         rdt->audio_pkt_cnt =
00324             ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb,
00325                                   st, rdt->rmst[st->index], pkt);
00326         if (rdt->audio_pkt_cnt == 0 &&
00327             st->codec->codec_id == CODEC_ID_AAC)
00328             av_freep(&rdt->rmctx->pb);
00329     }
00330     pkt->stream_index = st->index;
00331     pkt->pts = *timestamp;
00332 
00333     return rdt->audio_pkt_cnt > 0;
00334 }
00335 
00336 int
00337 ff_rdt_parse_packet(RDTDemuxContext *s, AVPacket *pkt,
00338                     const uint8_t *buf, int len)
00339 {
00340     int seq_no, flags = 0, stream_id, set_id, is_keyframe;
00341     uint32_t timestamp;
00342     int rv= 0;
00343 
00344     if (!s->parse_packet)
00345         return -1;
00346 
00347     if (!buf && s->prev_stream_id != -1) {
00348         /* return the next packets, if any */
00349         timestamp= 0; 
00350         rv= s->parse_packet(s->ic, s->dynamic_protocol_context,
00351                             s->streams[s->prev_stream_id],
00352                             pkt, &timestamp, NULL, 0, flags);
00353         return rv;
00354     }
00355 
00356     if (len < 12)
00357         return -1;
00358     rv = ff_rdt_parse_header(buf, len, &set_id, &seq_no, &stream_id, &is_keyframe, &timestamp);
00359     if (rv < 0)
00360         return rv;
00361     if (is_keyframe &&
00362         (set_id != s->prev_set_id || timestamp != s->prev_timestamp ||
00363          stream_id != s->prev_stream_id)) {
00364         flags |= RTP_FLAG_KEY;
00365         s->prev_set_id    = set_id;
00366         s->prev_timestamp = timestamp;
00367     }
00368     s->prev_stream_id = stream_id;
00369     buf += rv;
00370     len -= rv;
00371 
00372      if (s->prev_stream_id >= s->n_streams) {
00373          s->prev_stream_id = -1;
00374          return -1;
00375      }
00376 
00377     rv = s->parse_packet(s->ic, s->dynamic_protocol_context,
00378                          s->streams[s->prev_stream_id],
00379                          pkt, &timestamp, buf, len, flags);
00380 
00381     return rv;
00382 }
00383 
00384 void
00385 ff_rdt_subscribe_rule (char *cmd, int size,
00386                        int stream_nr, int rule_nr)
00387 {
00388     av_strlcatf(cmd, size, "stream=%d;rule=%d,stream=%d;rule=%d",
00389                 stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
00390 }
00391 
00392 static unsigned char *
00393 rdt_parse_b64buf (unsigned int *target_len, const char *p)
00394 {
00395     unsigned char *target;
00396     int len = strlen(p);
00397     if (*p == '\"') {
00398         p++;
00399         len -= 2; /* skip embracing " at start/end */
00400     }
00401     *target_len = len * 3 / 4;
00402     target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
00403     av_base64_decode(target, p, *target_len);
00404     return target;
00405 }
00406 
00407 static int
00408 rdt_parse_sdp_line (AVFormatContext *s, int st_index,
00409                     PayloadContext *rdt, const char *line)
00410 {
00411     AVStream *stream = s->streams[st_index];
00412     const char *p = line;
00413 
00414     if (av_strstart(p, "OpaqueData:buffer;", &p)) {
00415         rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
00416     } else if (av_strstart(p, "StartTime:integer;", &p))
00417         stream->first_dts = atoi(p);
00418     else if (av_strstart(p, "ASMRuleBook:string;", &p)) {
00419         int n = st_index, first = -1;
00420 
00421         for (n = 0; n < s->nb_streams; n++)
00422             if (s->streams[n]->priv_data == stream->priv_data) {
00423                 if (first == -1) first = n;
00424                 rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream();
00425                 rdt_load_mdpr(rdt, s->streams[n], (n - first) * 2);
00426 
00427                 if (s->streams[n]->codec->codec_id == CODEC_ID_AAC)
00428                     s->streams[n]->codec->frame_size = 1; // FIXME
00429            }
00430     }
00431 
00432     return 0;
00433 }
00434 
00435 static void
00436 real_parse_asm_rule(AVStream *st, const char *p, const char *end)
00437 {
00438     do {
00439         /* can be either averagebandwidth= or AverageBandwidth= */
00440         if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%d", &st->codec->bit_rate) == 1)
00441             break;
00442         if (!(p = strchr(p, ',')) || p > end)
00443             p = end;
00444         p++;
00445     } while (p < end);
00446 }
00447 
00448 static AVStream *
00449 add_dstream(AVFormatContext *s, AVStream *orig_st)
00450 {
00451     AVStream *st;
00452 
00453     if (!(st = av_new_stream(s, 0)))
00454         return NULL;
00455     st->codec->codec_type = orig_st->codec->codec_type;
00456     st->priv_data         = orig_st->priv_data;
00457     st->first_dts         = orig_st->first_dts;
00458 
00459     return st;
00460 }
00461 
00462 static void
00463 real_parse_asm_rulebook(AVFormatContext *s, AVStream *orig_st,
00464                         const char *p)
00465 {
00466     const char *end;
00467     int n_rules, odd = 0;
00468     AVStream *st;
00469 
00484     if (*p == '\"') p++;
00485     for (n_rules = 0; s->nb_streams < MAX_STREAMS;) {
00486         if (!(end = strchr(p, ';')))
00487             break;
00488         if (!odd && end != p) {
00489             if (n_rules > 0)
00490                 st = add_dstream(s, orig_st);
00491             else
00492                 st = orig_st;
00493             real_parse_asm_rule(st, p, end);
00494             n_rules++;
00495         }
00496         p = end + 1;
00497         odd ^= 1;
00498     }
00499 }
00500 
00501 void
00502 ff_real_parse_sdp_a_line (AVFormatContext *s, int stream_index,
00503                           const char *line)
00504 {
00505     const char *p = line;
00506 
00507     if (av_strstart(p, "ASMRuleBook:string;", &p))
00508         real_parse_asm_rulebook(s, s->streams[stream_index], p);
00509 }
00510 
00511 static PayloadContext *
00512 rdt_new_extradata (void)
00513 {
00514     PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
00515 
00516     av_open_input_stream(&rdt->rmctx, NULL, "", &rdt_demuxer, NULL);
00517 
00518     return rdt;
00519 }
00520 
00521 static void
00522 rdt_free_extradata (PayloadContext *rdt)
00523 {
00524     int i;
00525 
00526     for (i = 0; i < MAX_STREAMS; i++)
00527         if (rdt->rmst[i]) {
00528             ff_rm_free_rmstream(rdt->rmst[i]);
00529             av_freep(&rdt->rmst[i]);
00530         }
00531     if (rdt->rmctx)
00532         av_close_input_stream(rdt->rmctx);
00533     av_freep(&rdt->mlti_data);
00534     av_free(rdt);
00535 }
00536 
00537 #define RDT_HANDLER(n, s, t) \
00538 static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
00539     s, \
00540     t, \
00541     CODEC_ID_NONE, \
00542     rdt_parse_sdp_line, \
00543     rdt_new_extradata, \
00544     rdt_free_extradata, \
00545     rdt_parse_packet \
00546 };
00547 
00548 RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", CODEC_TYPE_VIDEO);
00549 RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", CODEC_TYPE_AUDIO);
00550 RDT_HANDLER(video,      "x-pn-realvideo",                CODEC_TYPE_VIDEO);
00551 RDT_HANDLER(audio,      "x-pn-realaudio",                CODEC_TYPE_AUDIO);
00552 
00553 void av_register_rdt_dynamic_payload_handlers(void)
00554 {
00555     ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
00556     ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
00557     ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
00558     ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
00559 }

Generated on Tue Nov 4 2014 12:59:24 for ffmpeg by  doxygen 1.7.1