• 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 "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