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