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 = (uint32_t)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 uint32_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 int32_t valueint = (int32_t)value;
160
161 return valueint;
162 }
163
ExtractNaluRbsp(uint8_t * buf,uint32_t * bufSize)164 void MediaDescription::ExtractNaluRbsp(uint8_t *buf, uint32_t *bufSize)
165 {
166 RETURN_IF_NULL(buf);
167 RETURN_IF_NULL(bufSize);
168 uint8_t *tmpPtr = buf;
169 uint32_t tmpBufSize = *bufSize;
170 for (uint32_t i = 0; (i + 2) < tmpBufSize; i++) { // 2:unit
171 if (!tmpPtr[i] && !tmpPtr[i + 1] && tmpPtr[i + 2] == 3) { // 2:unit, 3:unit
172 for (uint32_t j = i + 2; j < tmpBufSize - 1; j++) { // 2:unit
173 tmpPtr[j] = tmpPtr[j + 1];
174 }
175 (*bufSize)--;
176 }
177 }
178 }
179
GetVideoSize()180 std::pair<int32_t, int32_t> MediaDescription::GetVideoSize()
181 {
182 auto sps = GetVideoSps();
183 int32_t width = 0;
184 int32_t height = 0;
185 uint8_t *buf = sps.data();
186 uint32_t nLen = sps.size();
187 uint32_t cursor = 0;
188 if (sps.size() < 10) { // 10:fixed length
189 return {width, height};
190 }
191
192 ExtractNaluRbsp(buf, &nLen);
193 // forbidden_zero_bit
194 GetU(1, buf, cursor);
195 // nal_ref_idc
196 GetU(2, buf, cursor); // 2:fixed size
197 int32_t nalUnitType = GetU(5, buf, cursor); // 5:fixed size
198 if (nalUnitType != 7) { // 7:fixed size
199 return {width, height};
200 }
201
202 int32_t profileIdc = GetU(8, buf, cursor); // 8:fixed size
203 // constraint_set0_flag
204 GetU(1, buf, cursor);
205 // constraint_set1_flag
206 GetU(1, buf, cursor);
207 // constraint_set2_flag
208 GetU(1, buf, cursor);
209 // constraint_set3_flag
210 GetU(1, buf, cursor);
211 // constraint_set4_flag
212 GetU(1, buf, cursor);
213
214 // constraint_set5_flag
215 GetU(1, buf, cursor);
216 // reserved_zero_2bits
217 GetU(2, buf, cursor); // 2:fixed size
218 // level_idc
219 GetU(8, buf, cursor); // 8:fixed size
220 // seq_parameter_set_id
221 GetUe(buf, nLen, cursor);
222
223 if (profileIdc == 100 // 100:profile
224 || profileIdc == 110 // 110:profile
225 || profileIdc == 122 // 122:profile
226 || profileIdc == 244 // 244:profile
227 || profileIdc == 44 // 44:profile
228 || profileIdc == 83 // 83:profile
229 || profileIdc == 86 // 86:profile
230 || profileIdc == 118 // 118:profile
231 || profileIdc == 128 // 128:profile
232 || profileIdc == 138 // 138:profile
233 || profileIdc == 139 // 139:profile
234 || profileIdc == 134 // 134:profile
235 || profileIdc == 135) { // 135:profile
236 int32_t chromaFormatIdc = GetUe(buf, nLen, cursor);
237 if (chromaFormatIdc == 3) { // 3:format
238 // separate_colour_plane_flag
239 GetU(1, buf, cursor);
240 }
241 // bit_depth_luma_minus8
242 GetUe(buf, nLen, cursor);
243 // bit_depth_chroma_minus8
244 GetUe(buf, nLen, cursor);
245 // qpprime_y_zero_transform_bypass_flag
246 GetU(1, buf, cursor);
247 int32_t seqScalingMatrixPresentFlag = GetU(1, buf, cursor);
248
249 int32_t seqScalingListPresentFlag[12]; // 12:fixed size
250 if (seqScalingMatrixPresentFlag) {
251 int32_t lastScale = 8; // 8:fixed size
252 int32_t nextScale = 8; // 8:fixed size
253 int32_t sizeOfScalingList;
254 for (int32_t i = 0; i < ((chromaFormatIdc != 3) ? 8 : 12); i++) { // 3:format, 8:fixed size, 12:fixed size
255 seqScalingListPresentFlag[i] = GetU(1, buf, cursor);
256 if (seqScalingListPresentFlag[i]) {
257 lastScale = 8; // 8:fixed size
258 nextScale = 8; // 8:fixed size
259 sizeOfScalingList = i < 6 ? 16 : 64; // 6:fixed size, 16:fixed size, 64:fixed size
260 for (int32_t j = 0; j < sizeOfScalingList; j++) {
261 if (nextScale != 0) {
262 int32_t deltaScale = GetSe(buf, nLen, cursor);
263 nextScale = (uint32_t)(lastScale + deltaScale) & 0xff;
264 }
265 lastScale = nextScale == 0 ? lastScale : nextScale;
266 }
267 }
268 }
269 }
270 }
271 // log2_max_frame_num_minus4
272 GetUe(buf, nLen, cursor);
273 int32_t picOrderCntType = GetUe(buf, nLen, cursor);
274 if (picOrderCntType == 0) {
275 // log2_max_pic_order_cnt_lsb_minus4
276 GetUe(buf, nLen, cursor);
277 } else if (picOrderCntType == 1) {
278 // delta_pic_order_always_zero_flag
279 GetU(1, buf, cursor);
280 // offset_for_non_ref_pic
281 GetSe(buf, nLen, cursor);
282 // offset_for_top_to_bottom_field
283 GetSe(buf, nLen, cursor);
284 int32_t numRefFramesInPicOrderCntCycle = GetUe(buf, nLen, cursor);
285 if (numRefFramesInPicOrderCntCycle == 0 || numRefFramesInPicOrderCntCycle < 0) {
286 return {width, height};
287 }
288 uint32_t index = static_cast<uint32_t>(numRefFramesInPicOrderCntCycle);
289 int32_t *offsetForRefFrame = new int32_t[index];
290 if (offsetForRefFrame == nullptr) {
291 for (uint32_t i = 0; i < index; i++) {
292 GetSe(buf, nLen, cursor);
293 }
294 } else {
295 for (uint32_t i = 0; i < index; i++) {
296 offsetForRefFrame[i] = GetSe(buf, nLen, cursor);
297 }
298 }
299
300 delete[] offsetForRefFrame;
301 }
302 // max_num_ref_frames =
303 GetUe(buf, nLen, cursor);
304 // gaps_in_frame_num_value_allowed_flag =
305 GetU(1, buf, cursor);
306 int32_t picWidthMinMbsMinus1 = GetUe(buf, nLen, cursor);
307 int32_t picHeightInMapUnitsMinus1 = GetUe(buf, nLen, cursor);
308
309 width = (picWidthMinMbsMinus1 + 1) * 16; // 16:fixed size
310 height = (picHeightInMapUnitsMinus1 + 1) * 16; // 16:fixed size
311
312 int32_t frameMbsOnlyFlag = GetU(1, buf, cursor);
313 if (!frameMbsOnlyFlag) {
314 // mb_adaptive_frame_field_flag
315 GetU(1, buf, cursor);
316 }
317
318 // direct_8x8_inference_flag
319 GetU(1, buf, cursor);
320 int32_t frameCroppingFlag = GetU(1, buf, cursor);
321 if (frameCroppingFlag) {
322 int32_t frameCropLeftOffset = GetUe(buf, nLen, cursor);
323 int32_t frameCropRightOffset = GetUe(buf, nLen, cursor);
324 int32_t frameCropTopOffset = GetUe(buf, nLen, cursor);
325 int32_t frameCropBottomOffset = GetUe(buf, nLen, cursor);
326
327 int32_t cropUnitX = 2; // 2:fixed size
328 int32_t cropUnitY = 2 * (2 - frameMbsOnlyFlag); // 2:fixed size
329 width -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset);
330 height -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset);
331 }
332
333 return {width, height};
334 }
335
ParseSpsPps()336 bool MediaDescription::ParseSpsPps()
337 {
338 for (auto &a : attributes_) {
339 auto index = a.find("sprop-parameter-sets=");
340 if (index != std::string::npos) {
341 std::string sps_pps = a.substr(index + 21); // 21:fixed size
342
343 index = sps_pps.find(',');
344 if (index != std::string::npos) {
345 auto spsBase64 = sps_pps.substr(0, index);
346 auto ppsBase64 = sps_pps.substr(index + 1);
347
348 uint8_t *spsBuffer = (uint8_t *)malloc(spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
349 (void)memset_s(spsBuffer, spsBase64.size() * 3 / 4 + 1, 0,
350 spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
351 uint32_t spsLength = Base64::Decode(spsBase64.c_str(), spsBase64.size(), spsBuffer);
352 sps_.reserve(spsLength);
353 for (uint32_t i = 0; i < spsLength; ++i) {
354 sps_.push_back(spsBuffer[i]);
355 }
356
357 uint8_t *ppsBuffer = (uint8_t *)malloc(ppsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
358 (void)memset_s(ppsBuffer, ppsBase64.size() * 3 / 4 + 1, 0, ppsBase64.size() * 3 / 4 + 1);
359 uint32_t ppsLength = Base64::Decode(ppsBase64.c_str(), ppsBase64.size(), ppsBuffer);
360 sps_.reserve(ppsLength);
361 for (uint32_t i = 0; i < ppsLength; ++i) {
362 pps_.push_back(ppsBuffer[i]);
363 }
364 }
365 }
366 }
367
368 return true;
369 }
370
GetAudioSamplingRate() const371 int32_t MediaDescription::GetAudioSamplingRate() const
372 {
373 if (media_.mediaType != "audio") {
374 return 0;
375 }
376 std::string rtpMap = GetRtpMap();
377 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
378 std::smatch sm;
379 if (!std::regex_search(rtpMap, sm, pattern)) {
380 return false;
381 }
382
383 return atoi(sm[3].str().c_str()); // 3:fixed size
384 }
385
GetAudioChannels() const386 int32_t MediaDescription::GetAudioChannels() const
387 {
388 if (media_.mediaType != "audio") {
389 return 0;
390 }
391 std::string rtpMap = GetRtpMap();
392 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
393 std::smatch sm;
394 if (!std::regex_search(rtpMap, sm, pattern)) {
395 return false;
396 }
397
398 return atoi(sm[4].str().c_str()); // 4:fixed size
399 }
400
GetAudioConfig() const401 std::string MediaDescription::GetAudioConfig() const
402 {
403 if (media_.mediaType != "audio") {
404 return {};
405 }
406
407 for (auto &a : attributes_) {
408 auto index = a.find("config=");
409 if (index != std::string::npos) {
410 std::string config = a.substr(index + 7); // 7:fixed size
411 auto semicolon = config.find(';');
412 if (semicolon != std::string::npos) {
413 config = config.substr(0, semicolon);
414 }
415
416 return config;
417 }
418 }
419
420 return {};
421 }
422
Parse(const std::string & sdpStr)423 bool RtspSdp::Parse(const std::string &sdpStr)
424 {
425 auto bodyVec = RtspCommon::Split(sdpStr, RTSP_CRLF);
426 std::list<std::string> lines;
427 for (auto &item : bodyVec) {
428 if (!item.empty()) {
429 lines.emplace_back(item);
430 }
431 }
432
433 return Parse(lines);
434 }
435
Parse(const std::list<std::string> & sdpLines)436 bool RtspSdp::Parse(const std::list<std::string> &sdpLines)
437 {
438 std::shared_ptr<MediaDescription> track = nullptr;
439
440 for (auto &line : sdpLines) {
441 if (line.size() < 3 || line[1] != '=') { // 3:fixed size
442 continue;
443 }
444
445 char key = line[0];
446 std::string value = line.substr(2); // 2:fixed size
447 switch (key) {
448 case 'v':
449 session_.version = atoi(value.c_str());
450 break;
451 case 'o':
452 session_.origin.Parse(value);
453 break;
454 case 's':
455 session_.name = value;
456 break;
457 case 'i':
458 if (!track) {
459 session_.info = value;
460 } else {
461 track->title_ = value;
462 }
463 break;
464 case 'u':
465 session_.uri = value;
466 break;
467 case 'e':
468 session_.email = value;
469 break;
470 case 'p':
471 session_.phone = value;
472 break;
473 case 't': {
474 std::regex match("([0-9]+) ([0-9]+)");
475 std::smatch sm;
476 if (std::regex_search(value, sm, match)) {
477 session_.time.time.first = (uint64_t)atol(sm[1].str().c_str());
478 session_.time.time.second = (uint64_t)atol(sm[2].str().c_str()); // 2:fixed size
479 }
480 break;
481 }
482 case 'r':
483 session_.time.repeat.push_back(value);
484 break;
485 case 'z':
486 session_.time.zone = value;
487 break;
488 case 'a':
489 if (!track) {
490 session_.attributes.push_back(value);
491 } else {
492 track->attributes_.push_back(value);
493 }
494 break;
495 case 'm': {
496 auto mediaTrack = std::make_shared<MediaDescription>();
497 mediaTrack->media_.Parse(value);
498 media_.emplace_back(mediaTrack);
499 track = media_[media_.size() - 1];
500 break;
501 }
502 case 'c': {
503 if (!track) {
504 session_.connection = value;
505 } else {
506 track->connection_ = value;
507 }
508 break;
509 }
510 case 'b': {
511 if (!track) {
512 session_.bandwidth.push_back(value);
513 } else {
514 track->bandwidth_.push_back(value);
515 }
516 break;
517 }
518 default:
519 break;
520 }
521 }
522
523 return true;
524 }
525
GetVideoTrack()526 std::shared_ptr<MediaDescription> RtspSdp::GetVideoTrack()
527 {
528 for (auto &track : media_) {
529 if (track->media_.mediaType == "video") {
530 return track;
531 }
532 }
533
534 return nullptr;
535 }
536
GetAudioTrack()537 std::shared_ptr<MediaDescription> RtspSdp::GetAudioTrack()
538 {
539 for (auto &track : media_) {
540 if (track->media_.mediaType == "audio") {
541 return track;
542 }
543 }
544
545 return nullptr;
546 }
547 } // namespace Sharing
548 } // namespace OHOS