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 int32_t *offsetForRefFrame = new int32_t[numRefFramesInPicOrderCntCycle];
289 if (offsetForRefFrame == nullptr) {
290 for (int32_t i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
291 GetSe(buf, nLen, cursor);
292 }
293 } else {
294 for (int32_t i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
295 offsetForRefFrame[i] = GetSe(buf, nLen, cursor);
296 }
297 }
298
299 delete[] offsetForRefFrame;
300 }
301 // max_num_ref_frames =
302 GetUe(buf, nLen, cursor);
303 // gaps_in_frame_num_value_allowed_flag =
304 GetU(1, buf, cursor);
305 int32_t picWidthMinMbsMinus1 = GetUe(buf, nLen, cursor);
306 int32_t picHeightInMapUnitsMinus1 = GetUe(buf, nLen, cursor);
307
308 width = (picWidthMinMbsMinus1 + 1) * 16; // 16:fixed size
309 height = (picHeightInMapUnitsMinus1 + 1) * 16; // 16:fixed size
310
311 int32_t frameMbsOnlyFlag = GetU(1, buf, cursor);
312 if (!frameMbsOnlyFlag) {
313 // mb_adaptive_frame_field_flag
314 GetU(1, buf, cursor);
315 }
316
317 // direct_8x8_inference_flag
318 GetU(1, buf, cursor);
319 int32_t frameCroppingFlag = GetU(1, buf, cursor);
320 if (frameCroppingFlag) {
321 int32_t frameCropLeftOffset = GetUe(buf, nLen, cursor);
322 int32_t frameCropRightOffset = GetUe(buf, nLen, cursor);
323 int32_t frameCropTopOffset = GetUe(buf, nLen, cursor);
324 int32_t frameCropBottomOffset = GetUe(buf, nLen, cursor);
325
326 int32_t cropUnitX = 2; // 2:fixed size
327 int32_t cropUnitY = 2 * (2 - frameMbsOnlyFlag); // 2:fixed size
328 width -= cropUnitX * (frameCropLeftOffset + frameCropRightOffset);
329 height -= cropUnitY * (frameCropTopOffset + frameCropBottomOffset);
330 }
331
332 return {width, height};
333 }
334
ParseSpsPps()335 bool MediaDescription::ParseSpsPps()
336 {
337 for (auto &a : attributes_) {
338 auto index = a.find("sprop-parameter-sets=");
339 if (index != std::string::npos) {
340 std::string sps_pps = a.substr(index + 21); // 21:fixed size
341
342 index = sps_pps.find(',');
343 if (index != std::string::npos) {
344 auto spsBase64 = sps_pps.substr(0, index);
345 auto ppsBase64 = sps_pps.substr(index + 1);
346
347 uint8_t *spsBuffer = (uint8_t *)malloc(spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
348 memset_s(spsBuffer, spsBase64.size() * 3 / 4 + 1, 0,
349 spsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
350 uint32_t spsLength = Base64::Decode(spsBase64.c_str(), spsBase64.size(), spsBuffer);
351 sps_.reserve(spsLength);
352 for (uint32_t i = 0; i < spsLength; ++i) {
353 sps_.push_back(spsBuffer[i]);
354 }
355
356 uint8_t *ppsBuffer = (uint8_t *)malloc(ppsBase64.size() * 3 / 4 + 1); // 3:fixed size, 4:fixed size
357 memset_s(ppsBuffer, ppsBase64.size() * 3 / 4 + 1, 0, ppsBase64.size() * 3 / 4 + 1);
358 uint32_t ppsLength = Base64::Decode(ppsBase64.c_str(), ppsBase64.size(), ppsBuffer);
359 sps_.reserve(ppsLength);
360 for (uint32_t i = 0; i < ppsLength; ++i) {
361 pps_.push_back(ppsBuffer[i]);
362 }
363 }
364 }
365 }
366
367 return true;
368 }
369
GetAudioSamplingRate() const370 int32_t MediaDescription::GetAudioSamplingRate() const
371 {
372 if (media_.mediaType != "audio") {
373 return 0;
374 }
375 std::string rtpMap = GetRtpMap();
376 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
377 std::smatch sm;
378 if (!std::regex_search(rtpMap, sm, pattern)) {
379 return false;
380 }
381
382 return atoi(sm[3].str().c_str()); // 3:fixed size
383 }
384
GetAudioChannels() const385 int32_t MediaDescription::GetAudioChannels() const
386 {
387 if (media_.mediaType != "audio") {
388 return 0;
389 }
390 std::string rtpMap = GetRtpMap();
391 std::regex pattern("([0-9]+) ([a-zA-Z0-9-]+)/([0-9]+)/([1-9]{1})");
392 std::smatch sm;
393 if (!std::regex_search(rtpMap, sm, pattern)) {
394 return false;
395 }
396
397 return atoi(sm[4].str().c_str()); // 4:fixed size
398 }
399
GetAudioConfig() const400 std::string MediaDescription::GetAudioConfig() const
401 {
402 if (media_.mediaType != "audio") {
403 return {};
404 }
405
406 for (auto &a : attributes_) {
407 auto index = a.find("config=");
408 if (index != std::string::npos) {
409 std::string config = a.substr(index + 7); // 7:fixed size
410 auto semicolon = config.find(';');
411 if (semicolon != std::string::npos) {
412 config = config.substr(0, semicolon);
413 }
414
415 return config;
416 }
417 }
418
419 return {};
420 }
421
Parse(const std::string & sdpStr)422 bool RtspSdp::Parse(const std::string &sdpStr)
423 {
424 auto bodyVec = RtspCommon::Split(sdpStr, RTSP_CRLF);
425 std::list<std::string> lines;
426 for (auto &item : bodyVec) {
427 if (!item.empty()) {
428 lines.emplace_back(item);
429 }
430 }
431
432 return Parse(lines);
433 }
434
Parse(const std::list<std::string> & sdpLines)435 bool RtspSdp::Parse(const std::list<std::string> &sdpLines)
436 {
437 std::shared_ptr<MediaDescription> track = nullptr;
438
439 for (auto &line : sdpLines) {
440 if (line.size() < 3 || line[1] != '=') { // 3:fixed size
441 continue;
442 }
443
444 char key = line[0];
445 std::string value = line.substr(2); // 2:fixed size
446 switch (key) {
447 case 'v':
448 session_.version = atoi(value.c_str());
449 break;
450 case 'o':
451 session_.origin.Parse(value);
452 break;
453 case 's':
454 session_.name = value;
455 break;
456 case 'i':
457 if (!track) {
458 session_.info = value;
459 } else {
460 track->title_ = value;
461 }
462 break;
463 case 'u':
464 session_.uri = value;
465 break;
466 case 'e':
467 session_.email = value;
468 break;
469 case 'p':
470 session_.phone = value;
471 break;
472 case 't': {
473 std::regex match("([0-9]+) ([0-9]+)");
474 std::smatch sm;
475 if (std::regex_search(value, sm, match)) {
476 session_.time.time.first = (uint64_t)atol(sm[1].str().c_str());
477 session_.time.time.second = (uint64_t)atol(sm[2].str().c_str()); // 2:fixed size
478 }
479 break;
480 }
481 case 'r':
482 session_.time.repeat.push_back(value);
483 break;
484 case 'z':
485 session_.time.zone = value;
486 break;
487 case 'a':
488 if (!track) {
489 session_.attributes.push_back(value);
490 } else {
491 track->attributes_.push_back(value);
492 }
493 break;
494 case 'm': {
495 auto mediaTrack = std::make_shared<MediaDescription>();
496 mediaTrack->media_.Parse(value);
497 media_.emplace_back(mediaTrack);
498 track = media_[media_.size() - 1];
499 break;
500 }
501 case 'c': {
502 if (!track) {
503 session_.connection = value;
504 } else {
505 track->connection_ = value;
506 }
507 break;
508 }
509 case 'b': {
510 if (!track) {
511 session_.bandwidth.push_back(value);
512 } else {
513 track->bandwidth_.push_back(value);
514 }
515 break;
516 }
517 default:
518 break;
519 }
520 }
521
522 return true;
523 }
524
GetVideoTrack()525 std::shared_ptr<MediaDescription> RtspSdp::GetVideoTrack()
526 {
527 for (auto &track : media_) {
528 if (track->media_.mediaType == "video") {
529 return track;
530 }
531 }
532
533 return nullptr;
534 }
535
GetAudioTrack()536 std::shared_ptr<MediaDescription> RtspSdp::GetAudioTrack()
537 {
538 for (auto &track : media_) {
539 if (track->media_.mediaType == "audio") {
540 return track;
541 }
542 }
543
544 return nullptr;
545 }
546 } // namespace Sharing
547 } // namespace OHOS