• 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 <arpa/inet.h>
17 #include <condition_variable>
18 #include <functional>
19 #include <getopt.h>
20 #include <memory>
21 #include <mutex>
22 #include <netinet/in.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29 #include "rtp_def.h"
30 #include "rtp_factory.h"
31 #include "rtsp_client.h"
32 #include "sharing_log.h"
33 
34 using namespace OHOS::Sharing;
35 
36 #define RTP_AUDIO_LOCAL_PORT 60000
37 #define RTP_VIDEO_LOCAL_PORT 60002
38 #define BUFF_SIZE            10240
39 
40 FILE *h264File = nullptr;
41 FILE *aacFile = nullptr;
42 
HandleSignal(int sig)43 void HandleSignal(int sig)
44 {
45     if (h264File) {
46         fclose(h264File);
47     }
48 
49     if (aacFile) {
50         fclose(aacFile);
51     }
52 
53     printf("Catch Ctrl+C, exit success.\n");
54     exit(0);
55 }
56 
RecvUDP(int port,const std::function<void (const char * buf,int len)> & cb)57 int RecvUDP(int port, const std::function<void(const char *buf, int len)> &cb)
58 {
59     int servSocket, nbytes;
60     struct sockaddr_in servAddr, cliAddr;
61     int addrLen = sizeof(cliAddr);
62     char buffer[BUFF_SIZE];
63 
64     if ((servSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
65         perror("socket err");
66         return -1;
67     }
68 
69     bzero(&servAddr, sizeof(servAddr));
70 
71     servAddr.sin_family = AF_INET;
72     servAddr.sin_port = htons(port);
73     servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
74 
75     if (bind(servSocket, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
76         perror("bind err");
77         return -1;
78     }
79 
80     while (1) {
81         if ((nbytes = recvfrom(servSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliAddr,
82                                (socklen_t *)&addrLen)) < 0) {
83             perror("recvfrom err");
84             return -1;
85         }
86 
87         printf("\nRecv data(size:%d) From %s:%d\n", nbytes, inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
88 
89         cb(buffer, nbytes);
90         memset(buffer, 0, BUFF_SIZE);
91     }
92 }
93 
RecvSaveH264()94 void RecvSaveH264()
95 {
96     if (!h264File) {
97         time_t t = time(nullptr);
98         std::string file = "RTP_" + std::to_string(t) + ".h264";
99         h264File = fopen(file.c_str(), "wb");
100         if (!h264File) {
101             return;
102         }
103         printf("Save H264 (%s)\n", file.c_str());
104     }
105 
106     auto h264unPack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{96, 90000, RtpPayloadStream::H264});
107     h264unPack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
108         if (frame->GetTrackType() == TRACK_VIDEO) {
109             printf("h264 data: len: %d dts: %d\n", frame->Size(), frame->Dts());
110             auto data = frame->Data();
111             auto bytes = frame->Size();
112             for (size_t i = 0; i < 16 && i < bytes; i++) {
113                 printf("%02x ", data[i] & 0xff);
114             }
115             printf("\nfwrite (len: %d)\n", frame->Size());
116             fwrite(frame->Data(), frame->Size(), 1, h264File); // save .h264 file
117         }
118     });
119 
120     RecvUDP(RTP_VIDEO_LOCAL_PORT, [h264unPack](const char *buf, int len) {
121         // print data (12B RTP header + 12B Payload)
122         for (size_t i = 0; i < 24 && i < len; i++) {
123             printf("%02x ", buf[i] & 0xff);
124             if (i == 11) {
125                 printf("\n");
126             }
127         }
128         printf("\n");
129         h264unPack->ParseRtp(buf, len);
130     });
131 }
132 
main(int argc,char * argv[])133 int main(int argc, char *argv[])
134 {
135     auto rtspClient = std::make_shared<RtspClient>();
136     std::vector<OHOS::Sharing::SdpTrack::Ptr> medias;
137     uint32_t trackIndex = 0;
138     std::mutex mutex;
139     std::condition_variable cvSignal;
140     std::string url(argv[1]);
141 
142     // Catch Ctrl+C cvSignal
143     signal(SIGINT, HandleSignal);
144 
145     rtspClient->SetUrl(url);
146     rtspClient->SetOnRecvRtspPacket([&](const std::string &method, const RtspMessage &rsp) {
147         printf("SetOnRecvRtspPacket method: %s\n", method.c_str());
148         if (method == "OPTIONS") {
149             printf("SetOnRecvRtspPacket OPTIONS");
150             auto err = rtspClient->HandleOptionRsp(rsp);
151             switch (err) {
152                 case RtspRspResult::RSP_UNAUTHED:
153                     rtspClient->SendOption();
154                     break;
155                 case RtspRspResult::RSP_OK:
156                     rtspClient->SendDescribe();
157                     break;
158                 default: {
159                     printf("SetOnRecvRtspPacket ret err");
160                     cvSignal.notify_one();
161                 } break;
162             }
163 
164         } else if (method == "DESCRIBE") {
165             printf("SetOnRecvRtspPacket DESCRIBE");
166             auto err = rtspClient->HandleDescribeRsp(rsp);
167             switch (err) {
168                 case RtspRspResult::RSP_UNAUTHED:
169                     rtspClient->SendDescribe();
170                     break;
171                 case RtspRspResult::RSP_OK: {
172                     auto mediaTemp = rtspClient->GetAllMedia();
173                     for (auto media : mediaTemp) {
174                         medias.emplace_back(media);
175                     }
176                     // set RTP listening port for a/v, may just use one port
177                     rtspClient->SetTransPort(RTP_AUDIO_LOCAL_PORT, TRACK_AUDIO);
178                     rtspClient->SetTransPort(RTP_VIDEO_LOCAL_PORT, TRACK_VIDEO);
179                     rtspClient->SendSetup(trackIndex++);
180 
181                     break;
182                 }
183                 default: {
184                     printf("SetOnRecvRtspPacket ret err");
185                     cvSignal.notify_one();
186                     break;
187                 }
188             }
189         } else if (method == "SETUP") {
190             printf("SetOnRecvRtspPacket SETUP");
191             auto err = rtspClient->HandleSetupRsp(rsp);
192             switch (err) {
193                 case RtspRspResult::RSP_OK:
194                     if (trackIndex < medias.size()) {
195                         rtspClient->SendSetup(trackIndex++);
196                     } else {
197                         rtspClient->SendPlay();
198                         trackIndex = 0;
199                     }
200                     break;
201                 default: {
202                     printf("SetOnRecvRtspPacket ret err");
203                     cvSignal.notify_one();
204                 } break;
205             }
206         } else if (method == "PLAY") {
207             printf("SetOnRecvRtspPacket PLAY");
208             auto err = rtspClient->HandlePlayRsp(rsp);
209             if (err != RtspRspResult::RSP_OK) {
210                 printf("SetOnRecvRtspPacket ret err");
211                 cvSignal.notify_one();
212             }
213 
214             RecvSaveH264();
215 
216             cvSignal.notify_one();
217         }
218     });
219 
220     rtspClient->SetExceptionCb([&](const RtspExceptType except) {
221         printf("OnRtspException err");
222         printf("%s %d\n", __FUNCTION__, __LINE__);
223         cvSignal.notify_one();
224     });
225 
226     rtspClient->SetRtspReadyCb([&]() {
227         printf("%s %d send Option\n", __FUNCTION__, __LINE__);
228         rtspClient->SendOption();
229     });
230 
231     if (!rtspClient->Open()) {
232         printf("OpenRtspClient err");
233         return 0;
234     }
235 
236     std::unique_lock<std::mutex> lk(mutex);
237     cvSignal.wait(lk);
238     return 0;
239 };