• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • 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 "avio_internal.h"
00037 #include "libavcodec/get_bits.h"
00038 
00039 struct RDTDemuxContext {
00040     AVFormatContext *ic; 
00046     AVStream **streams;
00047     int n_streams; 
00048     void *dynamic_protocol_context;
00049     DynamicPayloadPacketHandlerProc parse_packet;
00050     uint32_t prev_timestamp;
00051     int prev_set_id, prev_stream_id;
00052 };
00053 
00054 RDTDemuxContext *
00055 ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx,
00056                   void *priv_data, RTPDynamicProtocolHandler *handler)
00057 {
00058     RDTDemuxContext *s = av_mallocz(sizeof(RDTDemuxContext));
00059     if (!s)
00060         return NULL;
00061 
00062     s->ic = ic;
00063     s->streams = &ic->streams[first_stream_of_set_idx];
00064     do {
00065         s->n_streams++;
00066     } while (first_stream_of_set_idx + s->n_streams < ic->nb_streams &&
00067              s->streams[s->n_streams]->id == s->streams[0]->id);
00068     s->prev_set_id    = -1;
00069     s->prev_stream_id = -1;
00070     s->prev_timestamp = -1;
00071     s->parse_packet = handler ? handler->parse_packet : NULL;
00072     s->dynamic_protocol_context = priv_data;
00073 
00074     return s;
00075 }
00076 
00077 void
00078 ff_rdt_parse_close(RDTDemuxContext *s)
00079 {
00080     av_free(s);
00081 }
00082 
00083 struct PayloadContext {
00084     AVFormatContext *rmctx;
00085     int nb_rmst;
00086     RMStream **rmst;
00087     uint8_t *mlti_data;
00088     unsigned int mlti_data_size;
00089     char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE];
00090     int audio_pkt_cnt; 
00091 };
00092 
00093 void
00094 ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
00095                                   const char *challenge)
00096 {
00097     int ch_len = strlen (challenge), i;
00098     unsigned char zres[16],
00099         buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
00100 #define XOR_TABLE_SIZE 37
00101     const unsigned char xor_table[XOR_TABLE_SIZE] = {
00102         0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
00103         0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
00104         0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
00105         0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
00106         0x10, 0x57, 0x05, 0x18, 0x54 };
00107 
00108     /* some (length) checks */
00109     if (ch_len == 40) /* what a hack... */
00110         ch_len = 32;
00111     else if (ch_len > 56)
00112         ch_len = 56;
00113     memcpy(buf + 8, challenge, ch_len);
00114 
00115     /* xor challenge bytewise with xor_table */
00116     for (i = 0; i < XOR_TABLE_SIZE; i++)
00117         buf[8 + i] ^= xor_table[i];
00118 
00119     av_md5_sum(zres, buf, 64);
00120     ff_data_to_hex(response, zres, 16, 1);
00121 
00122     /* add tail */
00123     strcpy (response + 32, "01d0a8e3");
00124 
00125     /* calculate checksum */
00126     for (i = 0; i < 8; i++)
00127         chksum[i] = response[i * 4];
00128     chksum[8] = 0;
00129 }
00130 
00131 static int
00132 rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
00133 {
00134     AVIOContext pb;
00135     int size;
00136     uint32_t tag;
00137 
00152     if (!rdt->mlti_data)
00153         return -1;
00154     ffio_init_context(&pb, rdt->mlti_data, rdt->mlti_data_size, 0,
00155                   NULL, NULL, NULL, NULL);
00156     tag = avio_rl32(&pb);
00157     if (tag == MKTAG('M', 'L', 'T', 'I')) {
00158         int num, chunk_nr;
00159 
00160         /* read index of MDPR chunk numbers */
00161         num = avio_rb16(&pb);
00162         if (rule_nr < 0 || rule_nr >= num)
00163             return -1;
00164         avio_skip(&pb, rule_nr * 2);
00165         chunk_nr = avio_rb16(&pb);
00166         avio_skip(&pb, (num - 1 - rule_nr) * 2);
00167 
00168         /* read MDPR chunks */
00169         num = avio_rb16(&pb);
00170         if (chunk_nr >= num)
00171             return -1;
00172         while (chunk_nr--)
00173             avio_skip(&pb, avio_rb32(&pb));
00174         size = avio_rb32(&pb);
00175     } else {
00176         size = rdt->mlti_data_size;
00177         avio_seek(&pb, 0, SEEK_SET);
00178     }
00179     if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size) < 0)
00180         return -1;
00181 
00182     return 0;
00183 }
00184 
00189 int
00190 ff_rdt_parse_header(const uint8_t *buf, int len,
00191                     int *pset_id, int *pseq_no, int *pstream_id,
00192                     int *pis_keyframe, uint32_t *ptimestamp)
00193 {
00194     GetBitContext gb;
00195     int consumed = 0, set_id, seq_no, stream_id, is_keyframe,
00196         len_included, need_reliable;
00197     uint32_t timestamp;
00198 
00199     /* skip status packets */
00200     while (len >= 5 && buf[1] == 0xFF /* status packet */) {
00201         int pkt_len;
00202 
00203         if (!(buf[0] & 0x80))
00204             return -1; /* not followed by a data packet */
00205 
00206         pkt_len = AV_RB16(buf+3);
00207         buf += pkt_len;
00208         len -= pkt_len;
00209         consumed += pkt_len;
00210     }
00211     if (len < 16)
00212         return -1;
00264     init_get_bits(&gb, buf, len << 3);
00265     len_included  = get_bits1(&gb);
00266     need_reliable = get_bits1(&gb);
00267     set_id        = get_bits(&gb, 5);
00268     skip_bits(&gb, 1);
00269     seq_no        = get_bits(&gb, 16);
00270     if (len_included)
00271         skip_bits(&gb, 16);
00272     skip_bits(&gb, 2);
00273     stream_id     = get_bits(&gb, 5);
00274     is_keyframe   = !get_bits1(&gb);
00275     timestamp     = get_bits_long(&gb, 32);
00276     if (set_id == 0x1f)
00277         set_id    = get_bits(&gb, 16);
00278     if (need_reliable)
00279         skip_bits(&gb, 16);
00280     if (stream_id == 0x1f)
00281         stream_id = get_bits(&gb, 16);
00282 
00283     if (pset_id)      *pset_id      = set_id;
00284     if (pseq_no)      *pseq_no      = seq_no;
00285     if (pstream_id)   *pstream_id   = stream_id;
00286     if (pis_keyframe) *pis_keyframe = is_keyframe;
00287     if (ptimestamp)   *ptimestamp   = timestamp;
00288 
00289     return consumed + (get_bits_count(&gb) >> 3);
00290 }
00291 
00293 static int
00294 rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st,
00295                   AVPacket *pkt, uint32_t *timestamp,
00296                   const uint8_t *buf, int len, int flags)
00297 {
00298     int seq = 1, res;
00299     AVIOContext pb;
00300 
00301     if (rdt->audio_pkt_cnt == 0) {
00302         int pos;
00303 
00304         ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
00305         flags = (flags & RTP_FLAG_KEY) ? 2 : 0;
00306         res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
00307                                   &seq, flags, *timestamp);
00308         pos = avio_tell(&pb);
00309         if (res < 0)
00310             return res;
00311         if (res > 0) {
00312             if (st->codec->codec_id == CODEC_ID_AAC) {
00313                 memcpy (rdt->buffer, buf + pos, len - pos);
00314                 rdt->rmctx->pb = avio_alloc_context (rdt->buffer, len - pos, 0,
00315                                                     NULL, NULL, NULL, NULL);
00316             }
00317             goto get_cache;
00318         }
00319     } else {
00320 get_cache:
00321         rdt->audio_pkt_cnt =
00322             ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb,
00323                                   st, rdt->rmst[st->index], pkt);
00324         if (rdt->audio_pkt_cnt == 0 &&
00325             st->codec->codec_id == CODEC_ID_AAC)
00326             av_freep(&rdt->rmctx->pb);
00327     }
00328     pkt->stream_index = st->index;
00329     pkt->pts = *timestamp;
00330 
00331     return rdt->audio_pkt_cnt > 0;
00332 }
00333 
00334 int
00335 ff_rdt_parse_packet(RDTDemuxContext *s, AVPacket *pkt,
00336                     uint8_t **bufptr, int len)
00337 {
00338     uint8_t *buf = bufptr ? *bufptr : NULL;
00339     int seq_no, flags = 0, stream_id, set_id, is_keyframe;
00340     uint32_t timestamp;
00341     int rv= 0;
00342 
00343     if (!s->parse_packet)
00344         return -1;
00345 
00346     if (!buf && s->prev_stream_id != -1) {
00347         /* return the next packets, if any */
00348         timestamp= 0; 
00349         rv= s->parse_packet(s->ic, s->dynamic_protocol_context,
00350                             s->streams[s->prev_stream_id],
00351                             pkt, &timestamp, NULL, 0, flags);
00352         return rv;
00353     }
00354 
00355     if (len < 12)
00356         return -1;
00357     rv = ff_rdt_parse_header(buf, len, &set_id, &seq_no, &stream_id, &is_keyframe, &timestamp);
00358     if (rv < 0)
00359         return rv;
00360     if (is_keyframe &&
00361         (set_id != s->prev_set_id || timestamp != s->prev_timestamp ||
00362          stream_id != s->prev_stream_id)) {
00363         flags |= RTP_FLAG_KEY;
00364         s->prev_set_id    = set_id;
00365         s->prev_timestamp = timestamp;
00366     }
00367     s->prev_stream_id = stream_id;
00368     buf += rv;
00369     len -= rv;
00370 
00371      if (s->prev_stream_id >= s->n_streams) {
00372          s->prev_stream_id = -1;
00373          return -1;
00374      }
00375 
00376     rv = s->parse_packet(s->ic, s->dynamic_protocol_context,
00377                          s->streams[s->prev_stream_id],
00378                          pkt, &timestamp, buf, len, flags);
00379 
00380     return rv;
00381 }
00382 
00383 void
00384 ff_rdt_subscribe_rule (char *cmd, int size,
00385                        int stream_nr, int rule_nr)
00386 {
00387     av_strlcatf(cmd, size, "stream=%d;rule=%d,stream=%d;rule=%d",
00388                 stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
00389 }
00390 
00391 static unsigned char *
00392 rdt_parse_b64buf (unsigned int *target_len, const char *p)
00393 {
00394     unsigned char *target;
00395     int len = strlen(p);
00396     if (*p == '\"') {
00397         p++;
00398         len -= 2; /* skip embracing " at start/end */
00399     }
00400     *target_len = len * 3 / 4;
00401     target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
00402     av_base64_decode(target, p, *target_len);
00403     return target;
00404 }
00405 
00406 static int
00407 rdt_parse_sdp_line (AVFormatContext *s, int st_index,
00408                     PayloadContext *rdt, const char *line)
00409 {
00410     AVStream *stream = s->streams[st_index];
00411     const char *p = line;
00412 
00413     if (av_strstart(p, "OpaqueData:buffer;", &p)) {
00414         rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
00415     } else if (av_strstart(p, "StartTime:integer;", &p))
00416         stream->first_dts = atoi(p);
00417     else if (av_strstart(p, "ASMRuleBook:string;", &p)) {
00418         int n, first = -1;
00419 
00420         for (n = 0; n < s->nb_streams; n++)
00421             if (s->streams[n]->id == stream->id) {
00422                 int count = s->streams[n]->index + 1;
00423                 if (first == -1) first = n;
00424                 if (rdt->nb_rmst < count) {
00425                     RMStream **rmst= av_realloc(rdt->rmst, count*sizeof(*rmst));
00426                     if (!rmst)
00427                         return AVERROR(ENOMEM);
00428                     memset(rmst + rdt->nb_rmst, 0,
00429                            (count - rdt->nb_rmst) * sizeof(*rmst));
00430                     rdt->rmst    = rmst;
00431                     rdt->nb_rmst = count;
00432                 }
00433                 rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream();
00434                 rdt_load_mdpr(rdt, s->streams[n], (n - first) * 2);
00435 
00436                 if (s->streams[n]->codec->codec_id == CODEC_ID_AAC)
00437                     s->streams[n]->codec->frame_size = 1; // FIXME
00438            }
00439     }
00440 
00441     return 0;
00442 }
00443 
00444 static void
00445 real_parse_asm_rule(AVStream *st, const char *p, const char *end)
00446 {
00447     do {
00448         /* can be either averagebandwidth= or AverageBandwidth= */
00449         if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%d", &st->codec->bit_rate) == 1)
00450             break;
00451         if (!(p = strchr(p, ',')) || p > end)
00452             p = end;
00453         p++;
00454     } while (p < end);
00455 }
00456 
00457 static AVStream *
00458 add_dstream(AVFormatContext *s, AVStream *orig_st)
00459 {
00460     AVStream *st;
00461 
00462     if (!(st = av_new_stream(s, orig_st->id)))
00463         return NULL;
00464     st->codec->codec_type = orig_st->codec->codec_type;
00465     st->first_dts         = orig_st->first_dts;
00466 
00467     return st;
00468 }
00469 
00470 static void
00471 real_parse_asm_rulebook(AVFormatContext *s, AVStream *orig_st,
00472                         const char *p)
00473 {
00474     const char *end;
00475     int n_rules = 0, odd = 0;
00476     AVStream *st;
00477 
00492     if (*p == '\"') p++;
00493     while (1) {
00494         if (!(end = strchr(p, ';')))
00495             break;
00496         if (!odd && end != p) {
00497             if (n_rules > 0)
00498                 st = add_dstream(s, orig_st);
00499             else
00500                 st = orig_st;
00501             if (!st)
00502                 break;
00503             real_parse_asm_rule(st, p, end);
00504             n_rules++;
00505         }
00506         p = end + 1;
00507         odd ^= 1;
00508     }
00509 }
00510 
00511 void
00512 ff_real_parse_sdp_a_line (AVFormatContext *s, int stream_index,
00513                           const char *line)
00514 {
00515     const char *p = line;
00516 
00517     if (av_strstart(p, "ASMRuleBook:string;", &p))
00518         real_parse_asm_rulebook(s, s->streams[stream_index], p);
00519 }
00520 
00521 static PayloadContext *
00522 rdt_new_context (void)
00523 {
00524     PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
00525 
00526     avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL);
00527 
00528     return rdt;
00529 }
00530 
00531 static void
00532 rdt_free_context (PayloadContext *rdt)
00533 {
00534     int i;
00535 
00536     for (i = 0; i < rdt->nb_rmst; i++)
00537         if (rdt->rmst[i]) {
00538             ff_rm_free_rmstream(rdt->rmst[i]);
00539             av_freep(&rdt->rmst[i]);
00540         }
00541     if (rdt->rmctx)
00542         av_close_input_file(rdt->rmctx);
00543     av_freep(&rdt->mlti_data);
00544     av_freep(&rdt->rmst);
00545     av_free(rdt);
00546 }
00547 
00548 #define RDT_HANDLER(n, s, t) \
00549 static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
00550     .enc_name         = s, \
00551     .codec_type       = t, \
00552     .codec_id         = CODEC_ID_NONE, \
00553     .parse_sdp_a_line = rdt_parse_sdp_line, \
00554     .alloc            = rdt_new_context, \
00555     .free             = rdt_free_context, \
00556     .parse_packet     = rdt_parse_packet \
00557 }
00558 
00559 RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", AVMEDIA_TYPE_VIDEO);
00560 RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO);
00561 RDT_HANDLER(video,      "x-pn-realvideo",                AVMEDIA_TYPE_VIDEO);
00562 RDT_HANDLER(audio,      "x-pn-realaudio",                AVMEDIA_TYPE_AUDIO);
00563 
00564 void av_register_rdt_dynamic_payload_handlers(void)
00565 {
00566     ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
00567     ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
00568     ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
00569     ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
00570 }

Generated on Fri Feb 22 2013 07:24:32 for FFmpeg by  doxygen 1.7.1