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, ×tamp, 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, ×tamp); 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, ×tamp, 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 }