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