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 Fri Oct 26 02:35:41 2012 for FFmpeg by doxygen 1.5.8

AltStyle によって変換されたページ (->オリジナル) /