1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rtsp_sdp.h"
17 #include <cmath>
18 #include <securec.h>
19 #include "common/common_macro.h"
20 #include "rtsp_common.h"
21 #include "utils/base64.h"
22
23 namespace OHOS {
24 namespace Sharing {
Parse(const std::string &origin)25 bool SessionOrigin::Parse(const std::string &origin)
26 {
27 std::regex pattern("([a-zA-Z0-9-]+) ([a-zA-Z0-9-]+) ([a-zA-Z0-9-]+) (IN) (IP4|IP6) ([0-9a-f.:]+)");
28 std::smatch sm;
29 if (!std::regex_search(origin, sm, pattern)) {
30 return false;
31 }
32
33 username = sm[1].str();
34 sessionId = sm[2].str(); // 2:byte offset
35 sessionVersion = atoi(sm[3].str().c_str()); // 3:byte offset
36 netType = sm[4].str(); // 4:byte offset
37 addrType = sm[5].str(); // 5:byte offset
38 unicastAddr = sm[6].str(); // 6:byte offset
39 return true;
40 }
41
Parse(const std::string &mediaLine)42 bool MediaLine::Parse(const std::string &mediaLine)
43 {
44 std::regex pattern("^(video|audio|text|application|message) ([0-9]+)(/[0-9]+)? "
45 "(udp|RTP/AVP|RTP/SAVP|RTP/SAVPF) ([0-9]+)");
46 std::smatch sm;
47 if (!std::regex_search(mediaLine, sm, pattern)) {
48 return false;
49 }
50 if (sm.size() != 6) { // 6:fixed length
51 return false;
52 }
53 mediaType = sm[1].str();
54 port = atoi(sm[2].str().c_str()); // 2:byte offset
55 protoType = sm[4].str(); // 4:byte offset
56 fmt = atoi(sm[5].str().c_str()); // 5:byte offset
57 return true;
58 }
59
GetTrackId() const60 std::string MediaDescription::GetTrackId() const
61 {
62 for (auto &a : attributes_) {
63 auto index = a.find("control:");
64 if (index != std::string::npos) {
65 return a.substr(8); // 8:fixed length
66 }
67 }
68
69 return {};
70 }
71
GetRtpMap() const72 std::string MediaDescription::GetRtpMap() const
73 {
74 for (auto &a : attributes_) {
75 auto index = a.find("rtpmap:");
76 if (index != std::string::npos) {
77 return a.substr(7); // 7:fixed length
78 }
79 }
80
81 return {};
82 }
83
GetVideoSps()84 std::vector<uint8_t> MediaDescription::GetVideoSps()
85 {
86 if (media_.mediaType != "video") {
87 return {};
88 }
89
90 if (sps_.empty()) {
91 ParseSpsPps();
92 }
93
94 return sps_;
95 }
96
GetVideoPps()97 std::vector<uint8_t> MediaDescription::GetVideoPps()
98 {
99 if (media_.mediaType != "video") {
100 return {};
101 }
102
103 if (pps_.empty()) {
104 ParseSpsPps();
105 }
106
107 return pps_;
108 }
109
GetUe(const uint8_t *buf, uint32_t nLen, uint32_t &pos)110 int32_t MediaDescription::GetUe(const uint8_t *buf, uint32_t nLen, uint32_t &pos)
111 {
112 RETURN_INVALID_IF_NULL(buf);
113 uint32_t nZeroNum = 0;
114 while (pos < nLen * 8) { // 8:unit
115 if (buf[pos / 8] & (0x80 >> (pos % 8))) { // 8:unit
116 break;
117 }
118 nZeroNum++;
119 pos++;
120 }
121 pos++;
122
123 uint64_t dwRet = 0;
124 for (uint32_t i = 0; i < nZeroNum; i++) {
125 dwRet <<= 1;
126 if (buf[pos / 8] & (0x80 >> (pos % 8))) { // 8:unit
127 dwRet += 1;
128 }
129 pos++;
130 }
131
132 return (int32_t)((1 << nZeroNum) - 1 + dwRet);
133 }
134
GetSe(uint8_t *buf, uint32_t nLen, uint32_t &pos)135 int32_t MediaDescription::GetSe(uint8_t *buf, uint32_t nLen, uint32_t &pos)
136 {
137 RETURN_INVALID_IF_NULL(buf);
138 int32_t UeVal = GetUe(buf, nLen, pos);
139 double k = UeVal;
140 int32_t nValue = ceil(k / 2); // 2:unit
141 if (UeVal % 2 == 0) {
142 nValue = -nValue;
143 }
144
145 return nValue;
146 }
147
GetU(uint8_t bitCount, const uint8_t *buf, uint32_t &pos)148 int32_t MediaDescription::GetU(uint8_t bitCount, const uint8_t *buf, uint32_t &pos)
149 {
150 RETURN_INVALID_IF_NULL(buf);
151 int32_t value = 0;
152 for (uint32_t i = 0; i < bitCount; i++) {
153 value <<= 1;
154 if (buf[pos / 8] & (0x80 >> (pos % 8))) { // 8:unit
155 value += 1;
156 }
157 pos++;
158 }
159
160 return value;
161 }
162
ExtractNaluRbsp(uint8_t *buf, uint32_t *bufSize)163 void MediaDescription::ExtractNaluRbsp(uint8_t *buf, uint32_t *bufSize)
164 {
165 RETURN_IF_NULL(buf);
166 RETURN_IF_NULL(bufSize);
167 uint8_t *tmpPtr = buf;
168 uint32_t tmpBufSize = *bufSize;
169 for (uint32_t i = 0; i < (tmpBufSize - 2); i++) { // 2:unit
170 if (!tmpPtr[i] && !tmpPtr[i + 1] && tmpPtr[i + 2] == 3) { // 2:unit, 3:unit
171 for (uint32_t j = i + 2; j < tmpBufSize - 1; j++) { // 2:unit
172 tmpPtr[j] = tmpPtr[j + 1];
173 }
174 (*bufSize)--;
175 }
176 }
177 }
178
GetVideoSize()179 std::pair<int32_t, int32_t> MediaDescription::GetVideoSize()
180 {
181 auto sps = GetVideoSps();
182 int32_t width = 0;
183 int32_t height = 0;
184 uint8_t *buf = sps.data();
185 uint32_t nLen = sps.size();
186 uint32_t cursor = 0;
187 if (sps.size() < 10) { // 10:fixed length
188 return {width, height};
189 }
190
191 ExtractNaluRbsp(buf, &nLen);
192 // forbidden_zero_bit
193 GetU(1, buf, cursor);
194 // nal_ref_idc
195 GetU(2, buf, cursor); // 2:fixed size
196 int32_t nalUnitType = GetU(5, buf, cursor); // 5:fixed size
197 if (nalUnitType != 7) { // 7:fixed size
198 return {width, height};
199 }
200
201 int32_t profileIdc = GetU(8, buf, cursor); // 8:fixed size
202 // constraint_set0_flag
203 GetU(1, buf, cursor);
204 // constraint_set1_flag
205 GetU(1, buf, cursor);
206 // constraint_set2_flag
207 GetU(1, buf, cursor);
208 // constraint_set3_flag
209 GetU(1, buf, cursor);
210 // constraint_set4_flag
211 GetU(1, buf, cursor);
212
213 // constraint_set5_flag
214 GetU(1, buf, cursor);
215 // reserved_zero_2bits
216 GetU(2, buf, cursor); // 2:fixed size
217 // level_idc
218 GetU(8, buf, cursor); // 8:fixed size
219 // seq_parameter_set_id
220 GetUe(buf, nLen, cursor);
221
222 if (profileIdc == 100 // 100:profile
223 || profileIdc == 110 // 110:profile
224 || profileIdc == 122 // 122:profile
225 || profileIdc == 244 // 244:profile
226 || profileIdc == 44 // 44:profile
227 || profileIdc == 83 // 83:profile
228 || profileIdc == 86 // 86:profile
229 || profileIdc == 118 // 118:profile
230 || profileIdc == 128 // 128:profile
231 || profileIdc == 138 // 138:profile
232 || profileIdc == 139 // 139:profile
233 || profileIdc == 134 // 134:profile
234 || profileIdc == 135) { // 135:profile
235 int32_t chromaFormatIdc = GetUe(buf, nLen, cursor);
236 if (chromaFormatIdc == 3) { // 3:format
237 // separate_colour_plane_flag
238 GetU(1, buf, cursor);
239 }
240 // bit_depth_luma_minus8
241 GetUe(buf, nLen, cursor);
242 // bit_depth_chroma_minus8
243 GetUe(buf, nLen, cursor);
244 // qpprime_y_zero_transform_bypass_flag
245 GetU(1, buf, cursor);
246 int32_t seqScalingMatrixPresentFlag = GetU(1, buf, cursor);
247
248 int32_t seqScalingListPresentFlag[12]; // 12:fixed size
249 if (seqScalingMatrixPresentFlag) {
250 int32_t lastScale = 8; // 8:fixed size
251 int32_t nextScale = 8; // 8:fixed size
252 int32_t sizeOfScalingList;
253 for (int32_t i = 0; i < ((chromaFormatIdc != 3) ? 8 : 12); i++) { // 3:format, 8:fixed size, 12:fixed size
254 seqScalingListPresentFlag[i] = GetU(1, buf, cursor);
255 if (seqScalingListPresentFlag[i]) {
256 lastScale = 8; // 8:fixed size
257 nextScale = 8; // 8:fixed size
258 sizeOfScalingList = i < 6 ? 16 : 64; // 6:fixed size, 16:fixed size, 64:fixed size
259 for (int32_t j = 0; j < sizeOfScalingList; j++) {
260 if (nextScale != 0) {
261 int32_t deltaScale = GetSe(buf, nLen, cursor);
262 nextScale = (lastScale + deltaScale) & 0xff;
263 }
264 lastScale = nextScale == 0 ? lastScale : nextScale;
265 }
266 }
267 }
268 }
269 }
270 // log2_max_frame_num_minus4
271 GetUe(buf, nLen, cursor);
272 int32_t picOrderCntType = GetUe(buf, nLen, cursor);
273 if (picOrderCntType == 0) {
274 // log2_max_pic_order_cnt_lsb_minus4
275 GetUe(buf, nLen, cursor);
276 } else if (picOrderCntType == 1) {
277 // delta_pic_order_always_zero_flag
278 GetU(1, buf, cursor);
279 // offset_for_non_ref_pic
280 GetSe(buf, nLen, cursor);
281 // offset_for_top_to_bottom_field
282 GetSe(buf, nLen, cursor);
283 int32_t numRefFramesInPicOrderCntCycle = GetUe(buf, nLen, cursor);
284 if (numRefFramesInPicOrderCntCycle == 0 || numRefFramesInPicOrderCntCycle < 0) {
285 return {width, height};
286 }
287 int32_t *offsetForRefFrame = new int32_t[numRefFramesInPicOrderCntCycle];
288 if (offsetForRefFrame == nullptr) {
289 for (int32_t i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
290 GetSe(buf, nLen, cursor);
291 }
292 } else {
293 for (int32_t i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
294 offsetForRefFrame[i] = GetSe(buf, nLen, cursor);
295 }
296 }
297
298 delete[] offsetForRefFrame;
299 }
300 // max_num_ref_frames =
301 GetUe(buf, nLen, cursor);
302 // gaps_in_frame_num_value_allowed_flag =
303 GetU(1, buf, cursor);
304 int32_t picWidthMinMbsMinus1 = GetUe(buf, nLen, cursor);
305 int32_t picHeightInMapUnitsMinus1 = GetUe(buf, nLen, cursor);
306
307 width = (picWidthMinMbsMinus1 + 1) * 16; // 16:fixed size
308 height = (picHeightInMapUnitsMinus1 + 1) * 16; // 16:fixed size
309
310 int32_t frameMbsOnlyFlag = GetU(1, buf, cursor);
311 if (!frameMbsOnlyFlag) {
312 // mb_adaptive_frame_field_flag
313 GetU(1, buf, cursor);
314 }
315
316 // direct_8x8_inference_flag
317 GetU(1, buf, cursor);
318 int32_t frameCroppingFlag = GetU(1, buf, cursor);
319 if (frameCroppingFlag) {
320 int32_t frameCropLeftOffset = GetUe(buf, nLen, cursor);
321 int32_t frameCropRightOffset = GetUe(buf, nLen, cursor);
322 int32_t frameCropTopOffset = GetUe(buf, nLen, cursor);
323 int32_t frameCropBottomOffset = GetUe(buf, nLen, cursor);
324
325 int32_t cropUnitX = 2; // 2:fixed size
326 int32_t cropUnitY = 2 * (2 - frameMbsOnlyFlag); // 2:fixed size
327 width -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset);
328 height -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset);
329 }
330
331 return {width, height};
332 }
333
334 bool MediaDescription::ParseSpsPps()
335 {
336 for (auto &a : attributes_) {
337 auto index = a.find("sprop-parameter-sets=");
338 if (index != std::string::npos) {
339 std::string sps_pps = a.substr(index + 21); // 21:fixed size
340
341 index = sps_pps.find(',');
342 if (index != std::string::npos) {
343 auto spsBase64 = sps_pps.substr(0, index);
344 auto ppsBase64 = sps_pps.substr(index + 1);
345
346 uint8_t *spsBuffer = (uint8_t *)malloc(spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
347 memset_s(spsBuffer, spsBase64.size() * 3 / 4 + 1, 0,
348 spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
349 uint32_t spsLength = Base64::Decode(spsBase64.c_str(), spsBase64.size(), spsBuffer);
350 sps_.reserve(spsLength);
351 for (uint32_t i = 0; i < spsLength; ++i) {
352 sps_.push_back(spsBuffer[i]);
353 }
354
355 uint8_t *ppsBuffer = (uint8_t *)malloc(ppsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
356 memset_s(ppsBuffer, ppsBase64.size() * 3 / 4 + 1, 0, ppsBase64.size() * 3 / 4 + 1);
357 uint32_t ppsLength = Base64::Decode(ppsBase64.c_str(), ppsBase64.size(), ppsBuffer);
358 sps_.reserve(ppsLength);
359 for (uint32_t i = 0; i < ppsLength; ++i) {
360 pps_.push_back(ppsBuffer[i]);
361 }
362 }
363 }
364 }
365
366 return true;
367 }
368
369 int32_t MediaDescription::GetAudioSamplingRate() const
370 {
371 if (media_.mediaType != "audio") {
372 return 0;
373 }
374 std::string rtpMap = GetRtpMap();
375 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
376 std::smatch sm;
377 if (!std::regex_search(rtpMap, sm, pattern)) {
378 return false;
379 }
380
381 return atoi(sm[3].str().c_str()); // 3:fixed size
382 }
383
384 int32_t MediaDescription::GetAudioChannels() const
385 {
386 if (media_.mediaType != "audio") {
387 return 0;
388 }
389 std::string rtpMap = GetRtpMap();
390 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
391 std::smatch sm;
392 if (!std::regex_search(rtpMap, sm, pattern)) {
393 return false;
394 }
395
396 return atoi(sm[4].str().c_str()); // 4:fixed size
397 }
398
399 std::string MediaDescription::GetAudioConfig() const
400 {
401 if (media_.mediaType != "audio") {
402 return {};
403 }
404
405 for (auto &a : attributes_) {
406 auto index = a.find("config=");
407 if (index != std::string::npos) {
408 std::string config = a.substr(index + 7); // 7:fixed size
409 auto semicolon = config.find(';');
410 if (semicolon != std::string::npos) {
411 config = config.substr(0, semicolon);
412 }
413
414 return config;
415 }
416 }
417
418 return {};
419 }
420
421 bool RtspSdp::Parse(const std::string &sdpStr)
422 {
423 auto bodyVec = RtspCommon::Split(sdpStr, RTSP_CRLF);
424 std::list<std::string> lines;
425 for (auto &item : bodyVec) {
426 if (!item.empty()) {
427 lines.emplace_back(item);
428 }
429 }
430
431 return Parse(lines);
432 }
433
434 bool RtspSdp::Parse(const std::list<std::string> &sdpLines)
435 {
436 std::shared_ptr<MediaDescription> track = nullptr;
437
438 for (auto &line : sdpLines) {
439 if (line.size() < 3 || line[1] != '=') { // 3:fixed size
440 continue;
441 }
442
443 char key = line[0];
444 std::string value = line.substr(2); // 2:fixed size
445 switch (key) {
446 case 'v':
447 session_.version = atoi(value.c_str());
448 break;
449 case 'o':
450 session_.origin.Parse(value);
451 break;
452 case 's':
453 session_.name = value;
454 break;
455 case 'i':
456 if (!track) {
457 session_.info = value;
458 } else {
459 track->title_ = value;
460 }
461 break;
462 case 'u':
463 session_.uri = value;
464 break;
465 case 'e':
466 session_.email = value;
467 break;
468 case 'p':
469 session_.phone = value;
470 break;
471 case 't': {
472 std::regex match("([0-9]+) ([0-9]+)");
473 std::smatch sm;
474 if (std::regex_search(value, sm, match)) {
475 session_.time.time.first = atol(sm[1].str().c_str());
476 session_.time.time.second = atol(sm[2].str().c_str()); // 2:fixed size
477 }
478 break;
479 }
480 case 'r':
481 session_.time.repeat.push_back(value);
482 break;
483 case 'z':
484 session_.time.zone = value;
485 break;
486 case 'a':
487 if (!track) {
488 session_.attributes.push_back(value);
489 } else {
490 track->attributes_.push_back(value);
491 }
492 break;
493 case 'm': {
494 auto mediaTrack = std::make_shared<MediaDescription>();
495 mediaTrack->media_.Parse(value);
496 media_.emplace_back(mediaTrack);
497 track = media_[media_.size() - 1];
498 break;
499 }
500 case 'c': {
501 if (!track) {
502 session_.connection = value;
503 } else {
504 track->connection_ = value;
505 }
506 break;
507 }
508 case 'b': {
509 if (!track) {
510 session_.bandwidth.push_back(value);
511 } else {
512 track->bandwidth_.push_back(value);
513 }
514 break;
515 }
516 default:
517 break;
518 }
519 }
520
521 return true;
522 }
523
524 std::shared_ptr<MediaDescription> RtspSdp::GetVideoTrack()
525 {
526 for (auto &track : media_) {
527 if (track->media_.mediaType == "video") {
528 return track;
529 }
530 }
531
532 return nullptr;
533 }
534
535 std::shared_ptr<MediaDescription> RtspSdp::GetAudioTrack()
536 {
537 for (auto &track : media_) {
538 if (track->media_.mediaType == "audio") {
539 return track;
540 }
541 }
542
543 return nullptr;
544 }
545 } // namespace Sharing
546 } // namespace OHOS