From 3c45feac210a72043449f5b1e7d92281e67b318f Mon Sep 17 00:00:00 2001 From: Ansersion Date: Mon, 22 Feb 2016 17:00:26 +0800 Subject: [PATCH] Add 'PayloadType' check to make it compatible with SDP media without 'time rate' --- .gitignore | 1 + gtest/test_suit_rtspClient_parseSDP.cpp | 54 +++++++++++++++++++++++- gtest/test_suit_tmp.cpp | 34 ++++++--------- myRtspClient/MediaSession.cpp | 54 ++++++++++++++++++++++++ myRtspClient/include/MediaSession.h | 6 ++- myRtspClient/rtspClient.cpp | 20 ++++++++- third_party/jrtplib-3.9.1/CMakeLists.txt | 3 +- 7 files changed, 146 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index a911752..f3800d5 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ CoreDumpTest.sh example/recv_video_and_audio_example example/test_audio_recv.mp3 example/test_video_recv.h264 +test.txt diff --git a/gtest/test_suit_rtspClient_parseSDP.cpp b/gtest/test_suit_rtspClient_parseSDP.cpp index 6411ec7..5eeba3a 100644 --- a/gtest/test_suit_rtspClient_parseSDP.cpp +++ b/gtest/test_suit_rtspClient_parseSDP.cpp @@ -50,7 +50,7 @@ TEST(rtspClient, RtspClient_ParseSDP_InvalidInput) EXPECT_EQ(MediaSessionMap.empty(), true); } -TEST(rtspClient, RtspClient_ParseSDP_RegularInput) +TEST(rtspClient, RtspClient_ParseSDP_1_RegularInput) { string SDP("\ RTSP/1.0 200 OK\r\n\ @@ -104,11 +104,63 @@ TEST(rtspClient, RtspClient_ParseSDP_RegularInput) EXPECT_EQ(true, MediaSessionMap["audio"].TimeRate == 90000); EXPECT_EQ(true, MediaSessionMap["audio"].ControlURI == "rtsp://127.0.0.1:554/ansersion/trackID=0"); + EXPECT_EQ(1, MediaSessionMap["audio"].PayloadType.size()); + for(vector::iterator it = MediaSessionMap["audio"].PayloadType.begin(); it != MediaSessionMap["audio"].PayloadType.end(); it++) { + EXPECT_EQ(14, *it); + } + EXPECT_EQ(true, MediaSessionMap["video"].MediaType == "video"); EXPECT_EQ(true, MediaSessionMap["video"].EncodeType == "H264"); EXPECT_EQ(true, MediaSessionMap["video"].Protocol == "RTP/AVP"); EXPECT_EQ(true, MediaSessionMap["video"].TimeRate == 90000); EXPECT_EQ(true, MediaSessionMap["video"].ControlURI == "rtsp://127.0.0.1:554/ansersion/trackID=1"); EXPECT_EQ(true, MediaSessionMap["video"].Packetization == 1); + + EXPECT_EQ(1, MediaSessionMap["audio"].PayloadType.size()); + for(vector::iterator it = MediaSessionMap["video"].PayloadType.begin(); it != MediaSessionMap["video"].PayloadType.end(); it++) { + EXPECT_EQ(96, *it); + } } +TEST(rtspClient, RtspClient_ParseSDP_2_RegularInput) +{ + string SDP("\ + v=0\r\n\ + o=- 1456130741857568 1 IN IP4 192.168.1.162\r\n\ + s=Session streamed by testOnDemandRTSPServer\r\n\ + i=mp3AudioTest\r\n\ + t=0 0\r\n\ + a=tool:LIVE555 Streaming Media v2015.12.22\r\n\ + a=type:broadcast\r\n\ + a=control:*\r\n\ + a=range:npt=0-163.524\r\n\ + a=x-qt-text-nam:Session streamed by testOnDemandRTSPServer\r\n\ + a=x-qt-text-inf:mp3AudioTest\r\n\ + m=audio 0 RTP/AVP 14\r\n\ + c=IN IP4 0.0.0.0\r\n\ + b=AS:128\r\n\ + a=control:track1\r\n"); + + RtspClient Client; + Client.ParseSDP(SDP); + // multimap SDPInfo = Client.GetSDPInfo(); + // typedef multimap::iterator It_type; + // pair p = SDPInfo.equal_range("s"); + // It_type It = p.first; + map MediaSessionMap = Client.GetMediaSessions(); + + // EXPECT_EQ(true, It->second == "Unnamed"); + // EXPECT_EQ(SDPInfo.count("a"), 10); + // EXPECT_EQ(SDPInfo.count("m"), 2); + // EXPECT_EQ(SDPInfo.count("v"), 1); + // EXPECT_EQ(SDPInfo.count("x"), 0); + + EXPECT_EQ(true, MediaSessionMap["audio"].MediaType == "audio"); + EXPECT_EQ(true, MediaSessionMap["audio"].Protocol == "RTP/AVP"); + EXPECT_EQ(true, MediaSessionMap["audio"].TimeRate == 90000); + + EXPECT_EQ(1, MediaSessionMap["audio"].PayloadType.size()); + for(vector::iterator it = MediaSessionMap["audio"].PayloadType.begin(); it != MediaSessionMap["audio"].PayloadType.end(); it++) { + EXPECT_EQ(14, *it); + } +} diff --git a/gtest/test_suit_tmp.cpp b/gtest/test_suit_tmp.cpp index bd2c527..e85ca16 100644 --- a/gtest/test_suit_tmp.cpp +++ b/gtest/test_suit_tmp.cpp @@ -26,32 +26,26 @@ #include "myRegex.h" #include "rtspClient.h" #include "MediaSession.h" -// #include "myRtpSession.h" -// using namespace std; -// using namespace jrtplib; +using namespace std; +// #include "myRtpSession.h" -// TEST(rtspClient, TMP_TEST) +// TEST(myRegex, Regex_InvalidInput) // { +// MyRegex Regex; // -// MediaSession Ms; -// Ms.RTPPort = 20020; -// Ms.TimeRate = 8000; +// // char str[] = "audio 0 RTP/AVP 14 16 18\r\n"; +// char str[] = "audio 0 RTP/AVP 14\r\n"; +// char pattern[] = "([a-zA-Z]+) +([0-9/]+) +([A-Za-z/]+) +\\b([0-9]+)\\b"; +// list group; +// bool IgnoreCase = true; // -// MyRTPSession Mrs; -// if(!Mrs.MyRTP_SetUp(&Ms)) { -// printf("Msr Setup Error"); -// return; -// } // -// uint8_t buf[4192]; -// size_t size = 0; -// int num = 100; +// EXPECT_EQ(Regex.Regex(str, pattern, &group, IgnoreCase), MyRegex::REGEX_SUCCESS); // -// for (int i = 1 ; i <= num ; i++) -// { -// Mrs.GetMyRTPData(buf, &size); -// printf("size: %lu\n", size); +// int i = 0; +// for(list::iterator it = group.begin(); it != group.end(); it++) { +// i++; +// cout << i << ": " << *it << endl; // } -// EXPECT_EQ(true, true); // } diff --git a/myRtspClient/MediaSession.cpp b/myRtspClient/MediaSession.cpp index bd88ae2..72e6f77 100644 --- a/myRtspClient/MediaSession.cpp +++ b/myRtspClient/MediaSession.cpp @@ -16,10 +16,45 @@ #include "MediaSession.h" #include "myRtpSession.h" #include "nalu_types.h" +#include + +using std::vector; #define MEDIA_SESSION_OK 1 #define MEDIA_SESSION_ERROR 0 +/* + Refer to RTP PayloadType list + "0" means that the item is reserved + */ +int PT2TimeRateMap[] = +{ + 8000, + 0, + 0, + 8000, + 8000, + 8000, + 16000, + 8000, + 8000, + 8000, + 44100, + 44100, + 8000, + 8000, + 90000, + 8000, + 11025, + 22050, + 8000, + 0, + 0, + 0, + 0, + 0 +}; + MediaSession::MediaSession(): MediaType(""), Protocol(""), @@ -88,3 +123,22 @@ uint8_t * MediaSession::GetMediaPacket(uint8_t * buf, size_t * size, unsigned lo if(!RTPInterface) return NULL; return RTPInterface->GetMyRTPPacket(buf, size, timeout); } + +int MediaSession::MediaInfoCheck() +{ + // Check "PayloadType" + if(PayloadType.size() == 0) { + printf("WARNING: invalid PayloadType\n"); + return -1; + } + for(vector::iterator it = PayloadType.begin(); it != PayloadType.end(); it++) { + if(*it < 0) { + printf("WARNING: invalid PayloadType\n"); + return -1; + } + } + if(TimeRate <= 0) { + TimeRate = PT2TimeRateMap[*(PayloadType.begin())]; // FIXME: only use the first PayloadType + printf("MediaInfoCheck: %d\n", TimeRate); + } +} diff --git a/myRtspClient/include/MediaSession.h b/myRtspClient/include/MediaSession.h index d635574..c9242b7 100644 --- a/myRtspClient/include/MediaSession.h +++ b/myRtspClient/include/MediaSession.h @@ -32,7 +32,7 @@ class StreamParameters // ###2015-01-11### // { public: /* For general media session */ - unsigned int PayloadNum; + unsigned int PayloadType; std::string EncodeType; unsigned int TimeRate; @@ -68,12 +68,14 @@ class MediaSession * */ uint8_t * GetMediaPacket(uint8_t * buf, size_t * size, unsigned long timeout_ms = TIMEOUT_MICROSECONDS); + int MediaInfoCheck(); + public: std::string MediaType; std::vector Ports; // RTP and RTCP ports, -1 indicate none. ###2015-01-11### // std::string Protocol; - std::vector PayloadNum; // ###2015-01-11### // + std::vector PayloadType; // ###2015-01-11### // std::string EncodeType; unsigned int TimeRate; // std::map StreamParams; diff --git a/myRtspClient/rtspClient.cpp b/myRtspClient/rtspClient.cpp index d5812a6..0ee587d 100644 --- a/myRtspClient/rtspClient.cpp +++ b/myRtspClient/rtspClient.cpp @@ -470,18 +470,30 @@ int RtspClient::ParseSDP(string SDP) if(Key == "s") CollectMediaInfo = false; if(!CollectMediaInfo) continue; - if(Key == "m") { - string PatternTmp("([a-zA-Z]+) +.+ +(.+) +.*"); + if(Key == "m") { + /* Pattern: (MediaType) +(Ports) +(Protocol) +(PayloadType)" + Example: "(audio) (0) (RTP/AVP) (14)" + */ + // string PatternTmp("([a-zA-Z]+) +.+ +(.+) +.*"); + string PatternTmp("([a-zA-Z]+) +([0-9/]+) +([A-Za-z/]+) +\\b([0-9]+)\\b"); if(!Regex.Regex(Value.c_str(), PatternTmp.c_str(), &Group)) { continue; } Group.pop_front(); CurrentMediaSession.assign(Group.front()); Group.pop_front(); + Group.pop_front(); // FIXME: Ports are ignored string Protocol(Group.front()); + Group.pop_front(); + int PayloadTypeTmp = -1; + stringstream ssPayloadType; + ssPayloadType << Group.front(); + ssPayloadType >> PayloadTypeTmp; + MediaSession NewMediaSession; NewMediaSession.MediaType.assign(CurrentMediaSession); NewMediaSession.Protocol.assign(Protocol); + NewMediaSession.PayloadType.push_back(PayloadTypeTmp); (*MediaSessionMap)[CurrentMediaSession] = NewMediaSession; } @@ -536,6 +548,10 @@ int RtspClient::ParseSDP(string SDP) } } } + + for(map::iterator it = MediaSessionMap->begin(); it != MediaSessionMap->end(); it++) { + it->second.MediaInfoCheck(); + } return Result; } diff --git a/third_party/jrtplib-3.9.1/CMakeLists.txt b/third_party/jrtplib-3.9.1/CMakeLists.txt index 4bfcf4a..bd83aa7 100755 --- a/third_party/jrtplib-3.9.1/CMakeLists.txt +++ b/third_party/jrtplib-3.9.1/CMakeLists.txt @@ -24,7 +24,8 @@ include(CheckCXXSourceCompiles) include(TestBigEndian) include(${PROJECT_SOURCE_DIR}/cmake/Macros.cmake) -find_package(JThread) +# Uncomment the following to enable JThread probing +# find_package(JThread) set(JRTPLIB_LINK_LIBS "") set(JRTPLIB_INTERNAL_INCLUDES "")