• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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