Libav 0.7.1
|
00001 /* 00002 * Realmedia RTSP protocol (RDT) support. 00003 * Copyright (c) 2007 Ronald S. Bultje 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav 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 * Libav 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 Libav; 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, ×tamp, 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, ×tamp); 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, ×tamp, 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 }