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