for #133, rtsp parse the announce packet, parse the sps/pps and audio sequence header by base64.
正在显示
5 个修改的文件
包含
729 行增加
和
13 行删除
| @@ -92,7 +92,14 @@ int SrsRtspConn::do_cycle() | @@ -92,7 +92,14 @@ int SrsRtspConn::do_cycle() | ||
| 92 | if (req->is_options()) { | 92 | if (req->is_options()) { |
| 93 | if ((ret = rtsp->send_message(new SrsRtspOptionsResponse(req->seq))) != ERROR_SUCCESS) { | 93 | if ((ret = rtsp->send_message(new SrsRtspOptionsResponse(req->seq))) != ERROR_SUCCESS) { |
| 94 | if (!srs_is_client_gracefully_close(ret)) { | 94 | if (!srs_is_client_gracefully_close(ret)) { |
| 95 | - srs_error("rtsp: send response failed. ret=%d", ret); | 95 | + srs_error("rtsp: send OPTIONS response failed. ret=%d", ret); |
| 96 | + } | ||
| 97 | + return ret; | ||
| 98 | + } | ||
| 99 | + } else if (req->is_announce()) { | ||
| 100 | + if ((ret = rtsp->send_message(new SrsRtspResponse(req->seq))) != ERROR_SUCCESS) { | ||
| 101 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 102 | + srs_error("rtsp: send ANNOUNCE response failed. ret=%d", ret); | ||
| 96 | } | 103 | } |
| 97 | return ret; | 104 | return ret; |
| 98 | } | 105 | } |
| @@ -407,3 +407,217 @@ u_int32_t srs_crc32(const void* buf, int size) | @@ -407,3 +407,217 @@ u_int32_t srs_crc32(const void* buf, int size) | ||
| 407 | return mpegts_crc32((const u_int8_t*)buf, size); | 407 | return mpegts_crc32((const u_int8_t*)buf, size); |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | +/* | ||
| 411 | + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) | ||
| 412 | + * | ||
| 413 | + * This file is part of FFmpeg. | ||
| 414 | + * | ||
| 415 | + * FFmpeg is free software; you can redistribute it and/or | ||
| 416 | + * modify it under the terms of the GNU Lesser General Public | ||
| 417 | + * License as published by the Free Software Foundation; either | ||
| 418 | + * version 2.1 of the License, or (at your option) any later version. | ||
| 419 | + * | ||
| 420 | + * FFmpeg is distributed in the hope that it will be useful, | ||
| 421 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 422 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 423 | + * Lesser General Public License for more details. | ||
| 424 | + * | ||
| 425 | + * You should have received a copy of the GNU Lesser General Public | ||
| 426 | + * License along with FFmpeg; if not, write to the Free Software | ||
| 427 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 428 | + */ | ||
| 429 | + | ||
| 430 | +#define UINT_MAX 0xffffffff | ||
| 431 | + | ||
| 432 | +#ifndef AV_RB32 | ||
| 433 | +# define AV_RB32(x) \ | ||
| 434 | + (((uint32_t)((const u_int8_t*)(x))[0] << 24) | \ | ||
| 435 | + (((const u_int8_t*)(x))[1] << 16) | \ | ||
| 436 | + (((const u_int8_t*)(x))[2] << 8) | \ | ||
| 437 | + ((const u_int8_t*)(x))[3]) | ||
| 438 | +#endif | ||
| 439 | + | ||
| 440 | +#ifndef AV_WL32 | ||
| 441 | +# define AV_WL32(p, darg) do { \ | ||
| 442 | + unsigned d = (darg); \ | ||
| 443 | + ((u_int8_t*)(p))[0] = (d); \ | ||
| 444 | + ((u_int8_t*)(p))[1] = (d)>>8; \ | ||
| 445 | + ((u_int8_t*)(p))[2] = (d)>>16; \ | ||
| 446 | + ((u_int8_t*)(p))[3] = (d)>>24; \ | ||
| 447 | + } while(0) | ||
| 448 | +#endif | ||
| 449 | + | ||
| 450 | +# define AV_WN(s, p, v) AV_WL##s(p, v) | ||
| 451 | + | ||
| 452 | +# if defined(AV_WN32) && !defined(AV_WL32) | ||
| 453 | +# define AV_WL32(p, v) AV_WN32(p, v) | ||
| 454 | +# elif !defined(AV_WN32) && defined(AV_WL32) | ||
| 455 | +# define AV_WN32(p, v) AV_WL32(p, v) | ||
| 456 | +# endif | ||
| 457 | + | ||
| 458 | +#ifndef AV_WN32 | ||
| 459 | +# define AV_WN32(p, v) AV_WN(32, p, v) | ||
| 460 | +#endif | ||
| 461 | + | ||
| 462 | +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) | ||
| 463 | +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) | ||
| 464 | + | ||
| 465 | +#ifndef av_bswap32 | ||
| 466 | +static const u_int32_t av_bswap32(u_int32_t x) | ||
| 467 | +{ | ||
| 468 | + return AV_BSWAP32C(x); | ||
| 469 | +} | ||
| 470 | +#endif | ||
| 471 | + | ||
| 472 | +#define av_be2ne32(x) av_bswap32(x) | ||
| 473 | + | ||
| 474 | +/** | ||
| 475 | + * @file | ||
| 476 | + * @brief Base64 encode/decode | ||
| 477 | + * @author Ryan Martell <rdm4@martellventures.com> (with lots of Michael) | ||
| 478 | + */ | ||
| 479 | + | ||
| 480 | +/* ---------------- private code */ | ||
| 481 | +static const u_int8_t map2[256] = | ||
| 482 | +{ | ||
| 483 | + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 484 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 485 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 486 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 487 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 488 | + 0xff, 0xff, 0xff, | ||
| 489 | + | ||
| 490 | + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, | ||
| 491 | + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, | ||
| 492 | + 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01, | ||
| 493 | + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, | ||
| 494 | + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, | ||
| 495 | + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, | ||
| 496 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, | ||
| 497 | + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, | ||
| 498 | + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, | ||
| 499 | + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, | ||
| 500 | + | ||
| 501 | + 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 502 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 503 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 504 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 505 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 506 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 507 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 508 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 509 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 510 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 511 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 512 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 513 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 514 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 515 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 516 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 517 | + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
| 518 | +}; | ||
| 519 | + | ||
| 520 | +#define BASE64_DEC_STEP(i) do { \ | ||
| 521 | + bits = map2[in[i]]; \ | ||
| 522 | + if (bits & 0x80) \ | ||
| 523 | + goto out ## i; \ | ||
| 524 | + v = i ? (v << 6) + bits : bits; \ | ||
| 525 | +} while(0) | ||
| 526 | + | ||
| 527 | +int srs_av_base64_decode(u_int8_t* out, const char* in_str, int out_size) | ||
| 528 | +{ | ||
| 529 | + u_int8_t *dst = out; | ||
| 530 | + u_int8_t *end = out + out_size; | ||
| 531 | + // no sign extension | ||
| 532 | + const u_int8_t *in = (const u_int8_t*)in_str; | ||
| 533 | + unsigned bits = 0xff; | ||
| 534 | + unsigned v; | ||
| 535 | + | ||
| 536 | + while (end - dst > 3) { | ||
| 537 | + BASE64_DEC_STEP(0); | ||
| 538 | + BASE64_DEC_STEP(1); | ||
| 539 | + BASE64_DEC_STEP(2); | ||
| 540 | + BASE64_DEC_STEP(3); | ||
| 541 | + // Using AV_WB32 directly confuses compiler | ||
| 542 | + v = av_be2ne32(v << 8); | ||
| 543 | + AV_WN32(dst, v); | ||
| 544 | + dst += 3; | ||
| 545 | + in += 4; | ||
| 546 | + } | ||
| 547 | + if (end - dst) { | ||
| 548 | + BASE64_DEC_STEP(0); | ||
| 549 | + BASE64_DEC_STEP(1); | ||
| 550 | + BASE64_DEC_STEP(2); | ||
| 551 | + BASE64_DEC_STEP(3); | ||
| 552 | + *dst++ = v >> 16; | ||
| 553 | + if (end - dst) | ||
| 554 | + *dst++ = v >> 8; | ||
| 555 | + if (end - dst) | ||
| 556 | + *dst++ = v; | ||
| 557 | + in += 4; | ||
| 558 | + } | ||
| 559 | + while (1) { | ||
| 560 | + BASE64_DEC_STEP(0); | ||
| 561 | + in++; | ||
| 562 | + BASE64_DEC_STEP(0); | ||
| 563 | + in++; | ||
| 564 | + BASE64_DEC_STEP(0); | ||
| 565 | + in++; | ||
| 566 | + BASE64_DEC_STEP(0); | ||
| 567 | + in++; | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | +out3: | ||
| 571 | + *dst++ = v >> 10; | ||
| 572 | + v <<= 2; | ||
| 573 | +out2: | ||
| 574 | + *dst++ = v >> 4; | ||
| 575 | +out1: | ||
| 576 | +out0: | ||
| 577 | + return bits & 1 ? -1 : dst - out; | ||
| 578 | +} | ||
| 579 | + | ||
| 580 | +/***************************************************************************** | ||
| 581 | +* b64_encode: Stolen from VLC's http.c. | ||
| 582 | +* Simplified by Michael. | ||
| 583 | +* Fixed edge cases and made it work from data (vs. strings) by Ryan. | ||
| 584 | +*****************************************************************************/ | ||
| 585 | + | ||
| 586 | +char* srs_av_base64_encode(char* out, int out_size, const u_int8_t* in, int in_size) | ||
| 587 | +{ | ||
| 588 | + static const char b64[] = | ||
| 589 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
| 590 | + char *ret, *dst; | ||
| 591 | + unsigned i_bits = 0; | ||
| 592 | + int i_shift = 0; | ||
| 593 | + int bytes_remaining = in_size; | ||
| 594 | + | ||
| 595 | + if (in_size >= (int)(UINT_MAX / 4) || | ||
| 596 | + out_size < SRS_AV_BASE64_SIZE(in_size)) | ||
| 597 | + return NULL; | ||
| 598 | + ret = dst = out; | ||
| 599 | + while (bytes_remaining > 3) { | ||
| 600 | + i_bits = AV_RB32(in); | ||
| 601 | + in += 3; bytes_remaining -= 3; | ||
| 602 | + *dst++ = b64[ i_bits>>26 ]; | ||
| 603 | + *dst++ = b64[(i_bits>>20) & 0x3F]; | ||
| 604 | + *dst++ = b64[(i_bits>>14) & 0x3F]; | ||
| 605 | + *dst++ = b64[(i_bits>>8 ) & 0x3F]; | ||
| 606 | + } | ||
| 607 | + i_bits = 0; | ||
| 608 | + while (bytes_remaining) { | ||
| 609 | + i_bits = (i_bits << 8) + *in++; | ||
| 610 | + bytes_remaining--; | ||
| 611 | + i_shift += 8; | ||
| 612 | + } | ||
| 613 | + while (i_shift > 0) { | ||
| 614 | + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; | ||
| 615 | + i_shift -= 6; | ||
| 616 | + } | ||
| 617 | + while ((dst - ret) & 3) | ||
| 618 | + *dst++ = '='; | ||
| 619 | + *dst = '\0'; | ||
| 620 | + | ||
| 621 | + return ret; | ||
| 622 | +} | ||
| 623 | + |
| @@ -85,5 +85,35 @@ extern bool srs_aac_startswith_adts(SrsStream* stream); | @@ -85,5 +85,35 @@ extern bool srs_aac_startswith_adts(SrsStream* stream); | ||
| 85 | */ | 85 | */ |
| 86 | extern u_int32_t srs_crc32(const void* buf, int size); | 86 | extern u_int32_t srs_crc32(const void* buf, int size); |
| 87 | 87 | ||
| 88 | +/** | ||
| 89 | +* Decode a base64-encoded string. | ||
| 90 | +* | ||
| 91 | +* @param out buffer for decoded data | ||
| 92 | +* @param in null-terminated input string | ||
| 93 | +* @param out_size size in bytes of the out buffer, must be at | ||
| 94 | +* least 3/4 of the length of in | ||
| 95 | +* @return number of bytes written, or a negative value in case of | ||
| 96 | +* invalid input | ||
| 97 | +*/ | ||
| 98 | +extern int srs_av_base64_decode(u_int8_t* out, const char* in, int out_size); | ||
| 99 | + | ||
| 100 | +/** | ||
| 101 | +* Encode data to base64 and null-terminate. | ||
| 102 | +* | ||
| 103 | +* @param out buffer for encoded data | ||
| 104 | +* @param out_size size in bytes of the out buffer (including the | ||
| 105 | +* null terminator), must be at least AV_BASE64_SIZE(in_size) | ||
| 106 | +* @param in input buffer containing the data to encode | ||
| 107 | +* @param in_size size in bytes of the in buffer | ||
| 108 | +* @return out or NULL in case of error | ||
| 109 | +*/ | ||
| 110 | +extern char* srs_av_base64_encode(char* out, int out_size, const u_int8_t* in, int in_size); | ||
| 111 | + | ||
| 112 | +/** | ||
| 113 | + * Calculate the output size needed to base64-encode x bytes to a | ||
| 114 | + * null-terminated string. | ||
| 115 | + */ | ||
| 116 | +#define SRS_AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) | ||
| 117 | + | ||
| 88 | #endif | 118 | #endif |
| 89 | 119 |
| @@ -32,6 +32,8 @@ using namespace std; | @@ -32,6 +32,8 @@ using namespace std; | ||
| 32 | #include <srs_kernel_error.hpp> | 32 | #include <srs_kernel_error.hpp> |
| 33 | #include <srs_kernel_log.hpp> | 33 | #include <srs_kernel_log.hpp> |
| 34 | #include <srs_kernel_consts.hpp> | 34 | #include <srs_kernel_consts.hpp> |
| 35 | +#include <srs_core_autofree.hpp> | ||
| 36 | +#include <srs_kernel_utility.hpp> | ||
| 35 | 37 | ||
| 36 | #ifdef SRS_AUTO_STREAM_CASTER | 38 | #ifdef SRS_AUTO_STREAM_CASTER |
| 37 | 39 | ||
| @@ -116,13 +118,290 @@ std::string srs_generate_rtsp_method_str(SrsRtspMethod method) | @@ -116,13 +118,290 @@ std::string srs_generate_rtsp_method_str(SrsRtspMethod method) | ||
| 116 | } | 118 | } |
| 117 | } | 119 | } |
| 118 | 120 | ||
| 121 | +SrsRtspSdp::SrsRtspSdp() | ||
| 122 | +{ | ||
| 123 | + state = SrsRtspSdpStateOthers; | ||
| 124 | +} | ||
| 125 | + | ||
| 126 | +SrsRtspSdp::~SrsRtspSdp() | ||
| 127 | +{ | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +int SrsRtspSdp::parse(string token) | ||
| 131 | +{ | ||
| 132 | + int ret = ERROR_SUCCESS; | ||
| 133 | + | ||
| 134 | + if (token.empty()) { | ||
| 135 | + srs_info("rtsp: ignore empty token."); | ||
| 136 | + return ret; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + size_t pos = string::npos; | ||
| 140 | + | ||
| 141 | + char* start = (char*)token.data(); | ||
| 142 | + char* end = start + (int)token.length(); | ||
| 143 | + char* p = start; | ||
| 144 | + | ||
| 145 | + // key, first 2bytes. | ||
| 146 | + // v=0 | ||
| 147 | + // o=- 0 0 IN IP4 127.0.0.1 | ||
| 148 | + // s=No Name | ||
| 149 | + // c=IN IP4 192.168.43.23 | ||
| 150 | + // t=0 0 | ||
| 151 | + // a=tool:libavformat 53.9.0 | ||
| 152 | + // m=video 0 RTP/AVP 96 | ||
| 153 | + // b=AS:850 | ||
| 154 | + // a=rtpmap:96 H264/90000 | ||
| 155 | + // a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAKKzRwFAFu/8ALQAiEAAAAwAQAAADAwjxgxHg,aOmrLIs= | ||
| 156 | + // a=control:streamid=0 | ||
| 157 | + // m=audio 0 RTP/AVP 97 | ||
| 158 | + // b=AS:49 | ||
| 159 | + // a=rtpmap:97 MPEG4-GENERIC/44100/2 | ||
| 160 | + // a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=139056E5A0 | ||
| 161 | + // a=control:streamid=1 | ||
| 162 | + char key = p[0]; | ||
| 163 | + p += 2; | ||
| 164 | + | ||
| 165 | + // left bytes as attr string. | ||
| 166 | + std::string attr_str; | ||
| 167 | + if (end - p) { | ||
| 168 | + attr_str.append(p, end - p); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + // parse the attributes from left bytes. | ||
| 172 | + std::vector<std::string> attrs; | ||
| 173 | + while (p < end) { | ||
| 174 | + // parse an attribute, split by SP. | ||
| 175 | + char* pa = p; | ||
| 176 | + for (; p < end && p[0] != __SRS_RTSP_SP; p++) { | ||
| 177 | + } | ||
| 178 | + std::string attr; | ||
| 179 | + if (p > pa) { | ||
| 180 | + attr.append(pa, p - pa); | ||
| 181 | + attrs.push_back(attr); | ||
| 182 | + } | ||
| 183 | + p++; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + // parse the first attr as desc, update the first elem for desc. | ||
| 187 | + // for example, the value can be "tool", "AS", "rtpmap", "fmtp", "control" | ||
| 188 | + std::string desc_key; | ||
| 189 | + if (attrs.size() > 0) { | ||
| 190 | + std::string attr = attrs.at(0); | ||
| 191 | + if ((pos = attr.find(":")) != string::npos) { | ||
| 192 | + desc_key = attr.substr(0, pos); | ||
| 193 | + attr = attr.substr(pos + 1); | ||
| 194 | + attr_str = attr_str.substr(pos + 1); | ||
| 195 | + attrs[0] = attr; | ||
| 196 | + } else { | ||
| 197 | + desc_key = attr; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + // interpret the attribute according by key. | ||
| 202 | + switch (key) { | ||
| 203 | + case 'v': version = attr_str; break; | ||
| 204 | + case 'o': | ||
| 205 | + owner_username = (attrs.size() > 0)? attrs[0]:""; | ||
| 206 | + owner_session_id = (attrs.size() > 1)? attrs[1]:""; | ||
| 207 | + owner_session_version = (attrs.size() > 2)? attrs[2]:""; | ||
| 208 | + owner_network_type = (attrs.size() > 3)? attrs[3]:""; | ||
| 209 | + owner_address_type = (attrs.size() > 4)? attrs[4]:""; | ||
| 210 | + owner_address = (attrs.size() > 5)? attrs[5]:""; | ||
| 211 | + break; | ||
| 212 | + case 's': session_name = attr_str; break; | ||
| 213 | + case 'c': | ||
| 214 | + connection_network_type = (attrs.size() > 0)? attrs[0]:""; | ||
| 215 | + connection_address_type = (attrs.size() > 0)? attrs[0]:""; | ||
| 216 | + connection_address = (attrs.size() > 0)? attrs[0]:""; | ||
| 217 | + break; | ||
| 218 | + case 'a': | ||
| 219 | + if (desc_key == "tool") { | ||
| 220 | + tool = attr_str; | ||
| 221 | + } else if (desc_key == "rtpmap") { | ||
| 222 | + if (state == SrsRtspSdpStateVideo) { | ||
| 223 | + video_codec = (attrs.size() > 1)? attrs[1]:""; | ||
| 224 | + if ((pos = video_codec.find("/")) != string::npos) { | ||
| 225 | + video_sample_rate = video_codec.substr(pos + 1); | ||
| 226 | + video_codec = video_codec.substr(0, pos); | ||
| 227 | + } | ||
| 228 | + } else if (state == SrsRtspSdpStateAudio) { | ||
| 229 | + audio_codec = (attrs.size() > 1)? attrs[1]:""; | ||
| 230 | + if ((pos = audio_codec.find("/")) != string::npos) { | ||
| 231 | + audio_sample_rate = audio_codec.substr(pos + 1); | ||
| 232 | + audio_codec = audio_codec.substr(0, pos); | ||
| 233 | + } | ||
| 234 | + if ((pos = audio_codec.find("/")) != string::npos) { | ||
| 235 | + audio_channel = audio_codec.substr(pos + 1); | ||
| 236 | + audio_codec = audio_codec.substr(0, pos); | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | + } else if (desc_key == "fmtp") { | ||
| 240 | + for (int i = 1; i < (int)attrs.size(); i++) { | ||
| 241 | + std::string attr = attrs.at(i); | ||
| 242 | + if ((ret = parse_fmtp_attribute(attr)) != ERROR_SUCCESS) { | ||
| 243 | + srs_error("rtsp: parse fmtp failed, attr=%s. ret=%d", attr.c_str(), ret); | ||
| 244 | + return ret; | ||
| 245 | + } | ||
| 246 | + } | ||
| 247 | + } else if (desc_key == "control") { | ||
| 248 | + for (int i = 0; i < (int)attrs.size(); i++) { | ||
| 249 | + std::string attr = attrs.at(i); | ||
| 250 | + if ((ret = parse_control_attribute(attr)) != ERROR_SUCCESS) { | ||
| 251 | + srs_error("rtsp: parse control failed, attr=%s. ret=%d", attr.c_str(), ret); | ||
| 252 | + return ret; | ||
| 253 | + } | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + break; | ||
| 257 | + case 'm': | ||
| 258 | + if (desc_key == "video") { | ||
| 259 | + state = SrsRtspSdpStateVideo; | ||
| 260 | + video_port = (attrs.size() > 1)? attrs[1]:""; | ||
| 261 | + video_protocol = (attrs.size() > 2)? attrs[2]:""; | ||
| 262 | + video_transport_format = (attrs.size() > 3)? attrs[3]:""; | ||
| 263 | + } else if (desc_key == "audio") { | ||
| 264 | + state = SrsRtspSdpStateAudio; | ||
| 265 | + audio_port = (attrs.size() > 1)? attrs[1]:""; | ||
| 266 | + audio_protocol = (attrs.size() > 2)? attrs[2]:""; | ||
| 267 | + audio_transport_format = (attrs.size() > 3)? attrs[3]:""; | ||
| 268 | + } | ||
| 269 | + break; | ||
| 270 | + case 'b': | ||
| 271 | + if (desc_key == "AS") { | ||
| 272 | + if (state == SrsRtspSdpStateVideo) { | ||
| 273 | + video_bandwidth_kbps = (attrs.size() > 0)? attrs[0]:""; | ||
| 274 | + } else if (state == SrsRtspSdpStateAudio) { | ||
| 275 | + audio_bandwidth_kbps = (attrs.size() > 0)? attrs[0]:""; | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | + break; | ||
| 279 | + case 't': | ||
| 280 | + default: break; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + return ret; | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +int SrsRtspSdp::parse_fmtp_attribute(string& attr) | ||
| 287 | +{ | ||
| 288 | + int ret = ERROR_SUCCESS; | ||
| 289 | + | ||
| 290 | + size_t pos = string::npos; | ||
| 291 | + | ||
| 292 | + while (!attr.empty()) { | ||
| 293 | + std::string item = attr; | ||
| 294 | + if ((pos = item.find(";")) != string::npos) { | ||
| 295 | + item = attr.substr(0, pos); | ||
| 296 | + attr = attr.substr(pos + 1); | ||
| 297 | + } else { | ||
| 298 | + attr = ""; | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + std::string item_key = item, item_value; | ||
| 302 | + if ((pos = item.find("=")) != string::npos) { | ||
| 303 | + item_key = item.substr(0, pos); | ||
| 304 | + item_value = item.substr(pos + 1); | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + if (state == SrsRtspSdpStateVideo) { | ||
| 308 | + if (item_key == "packetization-mode") { | ||
| 309 | + video_packetization_mode = item_value; | ||
| 310 | + } else if (item_key == "sprop-parameter-sets") { | ||
| 311 | + video_sps = item_value; | ||
| 312 | + if ((pos = video_sps.find(",")) != string::npos) { | ||
| 313 | + video_pps = video_sps.substr(pos + 1); | ||
| 314 | + video_sps = video_sps.substr(0, pos); | ||
| 315 | + } | ||
| 316 | + // decode the sps/pps by base64 | ||
| 317 | + video_sps = base64_decode(video_sps); | ||
| 318 | + video_pps = base64_decode(video_pps); | ||
| 319 | + } | ||
| 320 | + } else if (state == SrsRtspSdpStateAudio) { | ||
| 321 | + if (item_key == "profile-level-id") { | ||
| 322 | + audio_profile_level_id = item_value; | ||
| 323 | + } else if (item_key == "mode") { | ||
| 324 | + audio_mode = item_value; | ||
| 325 | + } else if (item_key == "sizelength") { | ||
| 326 | + audio_size_length = item_value; | ||
| 327 | + } else if (item_key == "indexlength") { | ||
| 328 | + audio_index_length = item_value; | ||
| 329 | + } else if (item_key == "indexdeltalength") { | ||
| 330 | + audio_index_delta_length = item_value; | ||
| 331 | + } else if (item_key == "config") { | ||
| 332 | + audio_sh = base64_decode(item_value); | ||
| 333 | + } | ||
| 334 | + } | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + return ret; | ||
| 338 | +} | ||
| 339 | + | ||
| 340 | +int SrsRtspSdp::parse_control_attribute(string& attr) | ||
| 341 | +{ | ||
| 342 | + int ret = ERROR_SUCCESS; | ||
| 343 | + | ||
| 344 | + size_t pos = string::npos; | ||
| 345 | + | ||
| 346 | + while (!attr.empty()) { | ||
| 347 | + std::string item = attr; | ||
| 348 | + if ((pos = item.find(";")) != string::npos) { | ||
| 349 | + item = attr.substr(0, pos); | ||
| 350 | + attr = attr.substr(pos + 1); | ||
| 351 | + } else { | ||
| 352 | + attr = ""; | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + std::string item_key = item, item_value; | ||
| 356 | + if ((pos = item.find("=")) != string::npos) { | ||
| 357 | + item_key = item.substr(0, pos); | ||
| 358 | + item_value = item.substr(pos + 1); | ||
| 359 | + } | ||
| 360 | + | ||
| 361 | + if (state == SrsRtspSdpStateVideo) { | ||
| 362 | + if (item_key == "streamid") { | ||
| 363 | + video_stream_id = item_value; | ||
| 364 | + } | ||
| 365 | + } else if (state == SrsRtspSdpStateAudio) { | ||
| 366 | + if (item_key == "streamid") { | ||
| 367 | + audio_stream_id = item_value; | ||
| 368 | + } | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + | ||
| 372 | + return ret; | ||
| 373 | +} | ||
| 374 | + | ||
| 375 | +string SrsRtspSdp::base64_decode(string value) | ||
| 376 | +{ | ||
| 377 | + if (value.empty()) { | ||
| 378 | + return ""; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + int nb_output = (int)(value.length() * 2); | ||
| 382 | + u_int8_t* output = new u_int8_t[nb_output]; | ||
| 383 | + SrsAutoFree(u_int8_t, output); | ||
| 384 | + | ||
| 385 | + int ret = srs_av_base64_decode(output, (char*)value.c_str(), nb_output); | ||
| 386 | + if (ret <= 0) { | ||
| 387 | + return ""; | ||
| 388 | + } | ||
| 389 | + | ||
| 390 | + std::string plaintext; | ||
| 391 | + plaintext.append((char*)output, ret); | ||
| 392 | + return plaintext; | ||
| 393 | +} | ||
| 394 | + | ||
| 119 | SrsRtspRequest::SrsRtspRequest() | 395 | SrsRtspRequest::SrsRtspRequest() |
| 120 | { | 396 | { |
| 121 | seq = 0; | 397 | seq = 0; |
| 398 | + content_length = 0; | ||
| 399 | + sdp = NULL; | ||
| 122 | } | 400 | } |
| 123 | 401 | ||
| 124 | SrsRtspRequest::~SrsRtspRequest() | 402 | SrsRtspRequest::~SrsRtspRequest() |
| 125 | { | 403 | { |
| 404 | + srs_freep(sdp); | ||
| 126 | } | 405 | } |
| 127 | 406 | ||
| 128 | bool SrsRtspRequest::is_options() | 407 | bool SrsRtspRequest::is_options() |
| @@ -130,6 +409,11 @@ bool SrsRtspRequest::is_options() | @@ -130,6 +409,11 @@ bool SrsRtspRequest::is_options() | ||
| 130 | return method == __SRS_METHOD_OPTIONS; | 409 | return method == __SRS_METHOD_OPTIONS; |
| 131 | } | 410 | } |
| 132 | 411 | ||
| 412 | +bool SrsRtspRequest::is_announce() | ||
| 413 | +{ | ||
| 414 | + return method == __SRS_METHOD_ANNOUNCE; | ||
| 415 | +} | ||
| 416 | + | ||
| 133 | SrsRtspResponse::SrsRtspResponse(int cseq) | 417 | SrsRtspResponse::SrsRtspResponse(int cseq) |
| 134 | { | 418 | { |
| 135 | seq = cseq; | 419 | seq = cseq; |
| @@ -306,11 +590,29 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req) | @@ -306,11 +590,29 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req) | ||
| 306 | std::string seq; | 590 | std::string seq; |
| 307 | if ((ret = recv_token_eof(seq)) != ERROR_SUCCESS) { | 591 | if ((ret = recv_token_eof(seq)) != ERROR_SUCCESS) { |
| 308 | if (!srs_is_client_gracefully_close(ret)) { | 592 | if (!srs_is_client_gracefully_close(ret)) { |
| 309 | - srs_error("rtsp: parse seq failed. ret=%d", ret); | 593 | + srs_error("rtsp: parse %s failed. ret=%d", __SRS_TOKEN_CSEQ, ret); |
| 310 | } | 594 | } |
| 311 | return ret; | 595 | return ret; |
| 312 | } | 596 | } |
| 313 | - req->seq = ::atoi(seq.c_str()); | 597 | + req->seq = ::atol(seq.c_str()); |
| 598 | + } else if (token == __SRS_TOKEN_CONTENT_TYPE) { | ||
| 599 | + std::string ct; | ||
| 600 | + if ((ret = recv_token_eof(ct)) != ERROR_SUCCESS) { | ||
| 601 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 602 | + srs_error("rtsp: parse %s failed. ret=%d", __SRS_TOKEN_CONTENT_TYPE, ret); | ||
| 603 | + } | ||
| 604 | + return ret; | ||
| 605 | + } | ||
| 606 | + req->content_type = ct; | ||
| 607 | + } else if (token == __SRS_TOKEN_CONTENT_LENGTH) { | ||
| 608 | + std::string cl; | ||
| 609 | + if ((ret = recv_token_eof(cl)) != ERROR_SUCCESS) { | ||
| 610 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 611 | + srs_error("rtsp: parse %s failed. ret=%d", __SRS_TOKEN_CONTENT_LENGTH, ret); | ||
| 612 | + } | ||
| 613 | + return ret; | ||
| 614 | + } | ||
| 615 | + req->content_length = ::atol(cl.c_str()); | ||
| 314 | } else { | 616 | } else { |
| 315 | // unknown header name, parse util EOF. | 617 | // unknown header name, parse util EOF. |
| 316 | SrsRtspTokenState state = SrsRtspTokenStateNormal; | 618 | SrsRtspTokenState state = SrsRtspTokenStateNormal; |
| @@ -327,7 +629,30 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req) | @@ -327,7 +629,30 @@ int SrsRtspStack::do_recv_message(SrsRtspRequest* req) | ||
| 327 | } | 629 | } |
| 328 | } | 630 | } |
| 329 | 631 | ||
| 330 | - // parse body. | 632 | + // parse rdp body. |
| 633 | + long consumed = 0; | ||
| 634 | + while (consumed < req->content_length) { | ||
| 635 | + if (!req->sdp) { | ||
| 636 | + req->sdp = new SrsRtspSdp(); | ||
| 637 | + } | ||
| 638 | + | ||
| 639 | + int nb_token = 0; | ||
| 640 | + std::string token; | ||
| 641 | + if ((ret = recv_token_util_eof(token, &nb_token)) != ERROR_SUCCESS) { | ||
| 642 | + if (!srs_is_client_gracefully_close(ret)) { | ||
| 643 | + srs_error("rtsp: parse sdp token failed. ret=%d", ret); | ||
| 644 | + } | ||
| 645 | + return ret; | ||
| 646 | + } | ||
| 647 | + consumed += nb_token; | ||
| 648 | + | ||
| 649 | + if ((ret = req->sdp->parse(token)) != ERROR_SUCCESS) { | ||
| 650 | + srs_error("rtsp: sdp parse token failed, token=%s. ret=%d", token.c_str(), ret); | ||
| 651 | + return ret; | ||
| 652 | + } | ||
| 653 | + srs_info("rtsp: %s", token.c_str()); | ||
| 654 | + } | ||
| 655 | + srs_info("rtsp: sdp parsed, size=%d", consumed); | ||
| 331 | 656 | ||
| 332 | return ret; | 657 | return ret; |
| 333 | } | 658 | } |
| @@ -382,14 +707,14 @@ int SrsRtspStack::recv_token_eof(std::string& token) | @@ -382,14 +707,14 @@ int SrsRtspStack::recv_token_eof(std::string& token) | ||
| 382 | return ret; | 707 | return ret; |
| 383 | } | 708 | } |
| 384 | 709 | ||
| 385 | -int SrsRtspStack::recv_token_util_eof(std::string& token) | 710 | +int SrsRtspStack::recv_token_util_eof(std::string& token, int* pconsumed) |
| 386 | { | 711 | { |
| 387 | int ret = ERROR_SUCCESS; | 712 | int ret = ERROR_SUCCESS; |
| 388 | 713 | ||
| 389 | SrsRtspTokenState state; | 714 | SrsRtspTokenState state; |
| 390 | 715 | ||
| 391 | // use 0x00 as ignore the normal token flag. | 716 | // use 0x00 as ignore the normal token flag. |
| 392 | - if ((ret = recv_token(token, state, 0x00)) != ERROR_SUCCESS) { | 717 | + if ((ret = recv_token(token, state, 0x00, pconsumed)) != ERROR_SUCCESS) { |
| 393 | if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) { | 718 | if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) { |
| 394 | return ret; | 719 | return ret; |
| 395 | } | 720 | } |
| @@ -408,7 +733,7 @@ int SrsRtspStack::recv_token_util_eof(std::string& token) | @@ -408,7 +733,7 @@ int SrsRtspStack::recv_token_util_eof(std::string& token) | ||
| 408 | return ret; | 733 | return ret; |
| 409 | } | 734 | } |
| 410 | 735 | ||
| 411 | -int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch) | 736 | +int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch, int* pconsumed) |
| 412 | { | 737 | { |
| 413 | int ret = ERROR_SUCCESS; | 738 | int ret = ERROR_SUCCESS; |
| 414 | 739 | ||
| @@ -474,6 +799,9 @@ int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char | @@ -474,6 +799,9 @@ int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char | ||
| 474 | // consume the token bytes. | 799 | // consume the token bytes. |
| 475 | srs_assert(p - start); | 800 | srs_assert(p - start); |
| 476 | buf->erase(p - start); | 801 | buf->erase(p - start); |
| 802 | + if (pconsumed) { | ||
| 803 | + *pconsumed = p - start; | ||
| 804 | + } | ||
| 477 | break; | 805 | break; |
| 478 | } | 806 | } |
| 479 | 807 |
| @@ -58,6 +58,8 @@ class ISrsProtocolReaderWriter; | @@ -58,6 +58,8 @@ class ISrsProtocolReaderWriter; | ||
| 58 | // RTSP token | 58 | // RTSP token |
| 59 | #define __SRS_TOKEN_CSEQ "CSeq" | 59 | #define __SRS_TOKEN_CSEQ "CSeq" |
| 60 | #define __SRS_TOKEN_PUBLIC "Public" | 60 | #define __SRS_TOKEN_PUBLIC "Public" |
| 61 | +#define __SRS_TOKEN_CONTENT_TYPE "Content-Type" | ||
| 62 | +#define __SRS_TOKEN_CONTENT_LENGTH "Content-Length" | ||
| 61 | 63 | ||
| 62 | // RTSP methods | 64 | // RTSP methods |
| 63 | #define __SRS_METHOD_OPTIONS "OPTIONS" | 65 | #define __SRS_METHOD_OPTIONS "OPTIONS" |
| @@ -77,6 +79,118 @@ class ISrsProtocolReaderWriter; | @@ -77,6 +79,118 @@ class ISrsProtocolReaderWriter; | ||
| 77 | #define __SRS_VERSION "RTSP/1.0" | 79 | #define __SRS_VERSION "RTSP/1.0" |
| 78 | 80 | ||
| 79 | /** | 81 | /** |
| 82 | +* the rtsp sdp parse state. | ||
| 83 | +*/ | ||
| 84 | +enum SrsRtspSdpState | ||
| 85 | +{ | ||
| 86 | + /** | ||
| 87 | + * other sdp properties. | ||
| 88 | + */ | ||
| 89 | + SrsRtspSdpStateOthers, | ||
| 90 | + /** | ||
| 91 | + * parse sdp audio state. | ||
| 92 | + */ | ||
| 93 | + SrsRtspSdpStateAudio, | ||
| 94 | + /** | ||
| 95 | + * parse sdp video state. | ||
| 96 | + */ | ||
| 97 | + SrsRtspSdpStateVideo, | ||
| 98 | +}; | ||
| 99 | + | ||
| 100 | +/** | ||
| 101 | +* the sdp in announce. | ||
| 102 | +* Appendix C: Use of SDP for RTSP Session Descriptions | ||
| 103 | +* The Session Description Protocol (SDP, RFC 2327 [6]) may be used to | ||
| 104 | +* describe streams or presentations in RTSP. | ||
| 105 | +*/ | ||
| 106 | +class SrsRtspSdp | ||
| 107 | +{ | ||
| 108 | +private: | ||
| 109 | + SrsRtspSdpState state; | ||
| 110 | +public: | ||
| 111 | + /** | ||
| 112 | + * the version of sdp. | ||
| 113 | + */ | ||
| 114 | + std::string version; | ||
| 115 | + /** | ||
| 116 | + * the owner/creator of sdp. | ||
| 117 | + */ | ||
| 118 | + std::string owner_username; | ||
| 119 | + std::string owner_session_id; | ||
| 120 | + std::string owner_session_version; | ||
| 121 | + std::string owner_network_type; | ||
| 122 | + std::string owner_address_type; | ||
| 123 | + std::string owner_address; | ||
| 124 | + /** | ||
| 125 | + * the session name of sdp. | ||
| 126 | + */ | ||
| 127 | + std::string session_name; | ||
| 128 | + /** | ||
| 129 | + * the connection info of sdp. | ||
| 130 | + */ | ||
| 131 | + std::string connection_network_type; | ||
| 132 | + std::string connection_address_type; | ||
| 133 | + std::string connection_address; | ||
| 134 | + /** | ||
| 135 | + * the tool attribute of sdp. | ||
| 136 | + */ | ||
| 137 | + std::string tool; | ||
| 138 | + /** | ||
| 139 | + * the video attribute of sdp. | ||
| 140 | + */ | ||
| 141 | + std::string video_port; | ||
| 142 | + std::string video_protocol; | ||
| 143 | + std::string video_transport_format; | ||
| 144 | + std::string video_bandwidth_kbps; | ||
| 145 | + std::string video_codec; | ||
| 146 | + std::string video_sample_rate; | ||
| 147 | + std::string video_stream_id; | ||
| 148 | + // fmtp | ||
| 149 | + std::string video_packetization_mode; | ||
| 150 | + std::string video_sps; // sequence header: sps. | ||
| 151 | + std::string video_pps; // sequence header: pps. | ||
| 152 | + /** | ||
| 153 | + * the audio attribute of sdp. | ||
| 154 | + */ | ||
| 155 | + std::string audio_port; | ||
| 156 | + std::string audio_protocol; | ||
| 157 | + std::string audio_transport_format; | ||
| 158 | + std::string audio_bandwidth_kbps; | ||
| 159 | + std::string audio_codec; | ||
| 160 | + std::string audio_sample_rate; | ||
| 161 | + std::string audio_channel; | ||
| 162 | + std::string audio_stream_id; | ||
| 163 | + // fmtp | ||
| 164 | + std::string audio_profile_level_id; | ||
| 165 | + std::string audio_mode; | ||
| 166 | + std::string audio_size_length; | ||
| 167 | + std::string audio_index_length; | ||
| 168 | + std::string audio_index_delta_length; | ||
| 169 | + std::string audio_sh; // sequence header. | ||
| 170 | +public: | ||
| 171 | + SrsRtspSdp(); | ||
| 172 | + virtual ~SrsRtspSdp(); | ||
| 173 | +public: | ||
| 174 | + /** | ||
| 175 | + * parse a line of token for sdp. | ||
| 176 | + */ | ||
| 177 | + virtual int parse(std::string token); | ||
| 178 | +private: | ||
| 179 | + /** | ||
| 180 | + * generally, the fmtp is the sequence header for video or audio. | ||
| 181 | + */ | ||
| 182 | + virtual int parse_fmtp_attribute(std::string& attr); | ||
| 183 | + /** | ||
| 184 | + * generally, the control is the stream info for video or audio. | ||
| 185 | + */ | ||
| 186 | + virtual int parse_control_attribute(std::string& attr); | ||
| 187 | + /** | ||
| 188 | + * decode the string by base64. | ||
| 189 | + */ | ||
| 190 | + virtual std::string base64_decode(std::string value); | ||
| 191 | +}; | ||
| 192 | + | ||
| 193 | +/** | ||
| 80 | * the rtsp request message. | 194 | * the rtsp request message. |
| 81 | * 6 Request | 195 | * 6 Request |
| 82 | * A request message from a client to a server or vice versa includes, | 196 | * A request message from a client to a server or vice versa includes, |
| @@ -110,12 +224,33 @@ public: | @@ -110,12 +224,33 @@ public: | ||
| 110 | * number as the original (i.e. the sequence number is not incremented | 224 | * number as the original (i.e. the sequence number is not incremented |
| 111 | * for retransmissions of the same request). | 225 | * for retransmissions of the same request). |
| 112 | */ | 226 | */ |
| 113 | - int seq; | 227 | + long seq; |
| 228 | + /** | ||
| 229 | + * 12.16 Content-Type | ||
| 230 | + * See [H14.18]. Note that the content types suitable for RTSP are | ||
| 231 | + * likely to be restricted in practice to presentation descriptions and | ||
| 232 | + * parameter-value types. | ||
| 233 | + */ | ||
| 234 | + std::string content_type; | ||
| 235 | + /** | ||
| 236 | + * 12.14 Content-Length | ||
| 237 | + * This field contains the length of the content of the method (i.e. | ||
| 238 | + * after the double CRLF following the last header). Unlike HTTP, it | ||
| 239 | + * MUST be included in all messages that carry content beyond the header | ||
| 240 | + * portion of the message. If it is missing, a default value of zero is | ||
| 241 | + * assumed. It is interpreted according to [H14.14]. | ||
| 242 | + */ | ||
| 243 | + long content_length; | ||
| 244 | + /** | ||
| 245 | + * the sdp in announce, NULL for no sdp. | ||
| 246 | + */ | ||
| 247 | + SrsRtspSdp* sdp; | ||
| 114 | public: | 248 | public: |
| 115 | SrsRtspRequest(); | 249 | SrsRtspRequest(); |
| 116 | virtual ~SrsRtspRequest(); | 250 | virtual ~SrsRtspRequest(); |
| 117 | public: | 251 | public: |
| 118 | virtual bool is_options(); | 252 | virtual bool is_options(); |
| 253 | + virtual bool is_announce(); | ||
| 119 | }; | 254 | }; |
| 120 | 255 | ||
| 121 | /** | 256 | /** |
| @@ -159,7 +294,7 @@ public: | @@ -159,7 +294,7 @@ public: | ||
| 159 | * number as the original (i.e. the sequence number is not incremented | 294 | * number as the original (i.e. the sequence number is not incremented |
| 160 | * for retransmissions of the same request). | 295 | * for retransmissions of the same request). |
| 161 | */ | 296 | */ |
| 162 | - int seq; | 297 | + long seq; |
| 163 | public: | 298 | public: |
| 164 | SrsRtspResponse(int cseq); | 299 | SrsRtspResponse(int cseq); |
| 165 | virtual ~SrsRtspResponse(); | 300 | virtual ~SrsRtspResponse(); |
| @@ -283,18 +418,20 @@ private: | @@ -283,18 +418,20 @@ private: | ||
| 283 | virtual int recv_token_eof(std::string& token); | 418 | virtual int recv_token_eof(std::string& token); |
| 284 | /** | 419 | /** |
| 285 | * read the token util got eof, for example, to read the response status Reason-Phrase | 420 | * read the token util got eof, for example, to read the response status Reason-Phrase |
| 421 | + * @param pconsumed, output the token parsed length. NULL to ignore. | ||
| 286 | */ | 422 | */ |
| 287 | - virtual int recv_token_util_eof(std::string& token); | 423 | + virtual int recv_token_util_eof(std::string& token, int* pconsumed = NULL); |
| 288 | /** | 424 | /** |
| 289 | * read a token from io, split by SP, endswith CRLF: | 425 | * read a token from io, split by SP, endswith CRLF: |
| 290 | * token1 SP token2 SP ... tokenN CRLF | 426 | * token1 SP token2 SP ... tokenN CRLF |
| 427 | + * @param token, output the read token. | ||
| 428 | + * @param state, output the token parse state. | ||
| 291 | * @param normal_ch, the char to indicates the normal token. | 429 | * @param normal_ch, the char to indicates the normal token. |
| 292 | * the SP use to indicates the normal token, @see __SRS_RTSP_SP | 430 | * the SP use to indicates the normal token, @see __SRS_RTSP_SP |
| 293 | * the 0x00 use to ignore normal token flag. @see recv_token_util_eof | 431 | * the 0x00 use to ignore normal token flag. @see recv_token_util_eof |
| 294 | - * @param token, output the read token. | ||
| 295 | - * @param state, output the token parse state. | 432 | + * @param pconsumed, output the token parsed length. NULL to ignore. |
| 296 | */ | 433 | */ |
| 297 | - virtual int recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch = __SRS_RTSP_SP); | 434 | + virtual int recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch = __SRS_RTSP_SP, int* pconsumed = NULL); |
| 298 | }; | 435 | }; |
| 299 | 436 | ||
| 300 | #endif | 437 | #endif |
-
请 注册 或 登录 后发表评论