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