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 <functional>
18 #include <getopt.h>
19 #include <netinet/in.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <unistd.h>
26 #include "rtp_def.h"
27 #include "rtp_factory.h"
28
29 using namespace OHOS::Sharing;
30
31 int gType = -1; // 0 for aac, 1 for h264, 2 for g711, 3 for mpegts
32 char *gFileName = nullptr;
33 char *gAudioFileName = nullptr;
34 int gPort = 1234;
35 FILE *gFd = nullptr;
36 FILE *gAudioFd = nullptr;
37
38 #define BUFF_SIZE 10240
39
ShowUsage(char * exe)40 void ShowUsage(char *exe)
41 {
42 printf("Usage:\n%s -t <type> -p <listening port> -o <file to save data>\n", exe);
43 printf("\t-t 0: AAC, 1: H264, 2: G711, 3: mpegts\n");
44 printf("\t-p local listening port, default 1234\n");
45 printf("\t-o file to save data OR video data in ts/ps demux stream, such as 123.h264, 234.aac\n");
46 printf("\t-a file to save audio data in ts/ps demux stream, such as 234.aac\n");
47 }
48
ParseParam(int argc,char * argv[])49 int ParseParam(int argc, char *argv[])
50 {
51 int ret;
52 while ((ret = getopt(argc, argv, ":t:p:o:a:")) != -1) {
53 switch (ret) {
54 case ('t'):
55 gType = atoi(optarg);
56 break;
57 case ('p'):
58 gPort = atoi(optarg);
59 break;
60 case ('o'):
61 gFileName = optarg;
62 break;
63 case ('a'):
64 gAudioFileName = optarg;
65 break;
66 case ':':
67 printf("option [-%c] requires an argument", static_cast<char>(optopt));
68 break;
69 case '?':
70 printf("unknown option: %c", static_cast<char>(optopt));
71 break;
72 default:
73 break;
74 }
75 }
76
77 if ((gType < 0 || gType > 3) || gFileName == nullptr) {
78 printf("param error\n");
79 ShowUsage(argv[0]);
80 return -1;
81 }
82 return 0;
83 }
84
RecvUDP(const std::function<void (const char * buf,int len)> & cb)85 int RecvUDP(const std::function<void(const char *buf, int len)> &cb)
86 {
87 int servSocket, nbytes;
88 struct sockaddr_in servAddr, cliAddr;
89 int addrLen = sizeof(cliAddr);
90 char buffer[BUFF_SIZE];
91
92 if ((servSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
93 perror("socket err");
94 return -1;
95 }
96
97 bzero(&servAddr, sizeof(servAddr));
98
99 servAddr.sin_family = AF_INET;
100 servAddr.sin_port = htons(gPort);
101 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
102
103 if (bind(servSocket, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0) {
104 perror("bind err");
105 return -1;
106 }
107
108 while (1) {
109 if ((nbytes = recvfrom(servSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliAddr,
110 (socklen_t *)&addrLen)) < 0) {
111 perror("recvfrom err");
112 return -1;
113 }
114
115 printf("\nRecv data(size:%d) From %s:%d\n", nbytes, inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
116
117 cb(buffer, nbytes);
118 memset(buffer, 0, BUFF_SIZE);
119 }
120 }
121
HandleSignal(int sig)122 void HandleSignal(int sig)
123 {
124 if (gFd != nullptr) {
125 fclose(gFd);
126 }
127
128 if (gAudioFd != nullptr) {
129 fclose(gAudioFd);
130 }
131 printf("Catch Ctrl+C,\nsave '%s' success\nexit success.\n", gFileName);
132 exit(0);
133 }
134
main(int argc,char * argv[])135 int main(int argc, char *argv[])
136 {
137 if (ParseParam(argc, argv) != 0) {
138 return -1;
139 }
140 printf("%s -t %d -p %d -o %s -a %s\n", argv[0], gType, gPort, gFileName, gAudioFileName);
141
142 // Catch Ctrl+C signal
143 signal(SIGINT, HandleSignal);
144 if (gFileName != nullptr) {
145 gFd = fopen(gFileName, "wb");
146 }
147 if (gAudioFileName) {
148 gAudioFd = fopen(gAudioFileName, "wb");
149 }
150 if (gType == 1) {
151 auto h264unPack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{96, 90000, RtpPayloadStream::H264});
152 h264unPack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
153 if (frame->GetTrackType() == TRACK_VIDEO) {
154 printf("h264 data: len: %d dts: %d\n", frame->Size(), frame->Dts());
155 auto data = frame->Data();
156 auto bytes = frame->Size();
157 for (size_t i = 0; i < 16 && i < bytes; i++) {
158 printf("%02x ", data[i] & 0xff);
159 }
160 printf("\n");
161 fwrite(frame->Data(), frame->Size(), 1, gFd); // save .h264 file
162 }
163 });
164
165 RecvUDP([h264unPack](const char *buf, int len) {
166 // print data (12B RTP header + 12B Payload)
167 for (size_t i = 0; i < 24 && i < len; i++) {
168 printf("%02x ", buf[i] & 0xff);
169 if (i == 11) {
170 printf("\n");
171 }
172 }
173 printf("\n");
174 h264unPack->ParseRtp(buf, len);
175 });
176
177 } else if (gType == 0) {
178 auto extra = std::make_shared<AACExtra>();
179 extra->aacConfig_ = "1210";
180 auto aacunPack =
181 RtpFactory::CreateRtpUnpack(RtpPlaylodParam{97, 44100, RtpPayloadStream::MPEG4_GENERIC, extra});
182 aacunPack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
183 printf("SetOnRtpUnpack\n");
184 if (frame->GetTrackType() == TRACK_AUDIO) {
185 printf("aac data: len: %d dts: %d\n", frame->Size(), frame->Dts());
186 auto data = frame->Data();
187 auto bytes = frame->Size();
188 for (size_t i = 0; i < 16 && i < bytes; i++) {
189 printf("%02x ", data[i] & 0xff);
190 }
191 printf("\n");
192 fwrite(frame->Data(), frame->Size(), 1, gFd); // save .aac file
193 }
194 });
195
196 RecvUDP([aacunPack](const char *buf, int len) {
197 // print data (12B RTP header + 12B Payload)
198 for (size_t i = 0; i < 24 && i < len; i++) {
199 printf("%02x ", buf[i] & 0xff);
200 if (i == 11) {
201 printf("\n");
202 }
203 }
204 printf("\n");
205 aacunPack->ParseRtp(buf, len);
206 });
207 } else if (gType == 2) {
208 auto g711Unpack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{97, 8000, RtpPayloadStream::PCMA});
209 g711Unpack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
210 printf("SetOnRtpUnpack\n");
211 if (frame->GetTrackType() == TRACK_AUDIO) {
212 printf("g711 data: len: %d dts: %d\n", frame->Size(), frame->Dts());
213 auto data = frame->Data();
214 auto bytes = frame->Size();
215 for (size_t i = 0; i < 16 && i < bytes; i++) {
216 printf("%02x ", data[i] & 0xff);
217 }
218 printf("\n");
219 fwrite(frame->Data(), frame->Size(), 1, gFd); // save .pcma file
220 }
221 });
222
223 RecvUDP([g711Unpack](const char *buf, int len) {
224 // print data (12B RTP header + 12B Payload)
225 for (size_t i = 0; i < 24 && i < len; i++) {
226 printf("%02x ", buf[i] & 0xff);
227 if (i == 11) {
228 printf("\n");
229 }
230 }
231 printf("\n");
232 g711Unpack->ParseRtp(buf, len);
233 });
234 } else if (gType == 3) {
235 auto tsUnpack = RtpFactory::CreateRtpUnpack(RtpPlaylodParam{33, 90000, RtpPayloadStream::MPEG2_TS});
236 tsUnpack->SetOnRtpUnpack([=](uint32_t ssrc, const Frame::Ptr &frame) {
237 printf("mpegts OnRtpUnpack in TrackType = %d size=%d dts=%d\n", frame->GetTrackType(), frame->Size(),
238 frame->Dts());
239 printf("ts data: len: %d dts: %d\n", frame->Size(), frame->Dts());
240 auto data = frame->Data();
241 auto bytes = frame->Size();
242 for (size_t i = 0; i < 16 && i < bytes; i++) {
243 printf("%02x ", data[i] & 0xff);
244 }
245 printf("\n");
246 if (frame->GetTrackType() == TRACK_VIDEO) {
247 fwrite(frame->Data(), frame->Size(), 1, gFd); // save .h264 file
248 } else if (frame->GetTrackType() == TRACK_AUDIO) {
249 fwrite(frame->Data(), frame->Size(), 1, gAudioFd);
250 }
251 });
252
253 RecvUDP([tsUnpack](const char *buf, int len) {
254 // print data (12B RTP header + 12B Payload)
255 for (size_t i = 0; i < 24 && i < len; i++) {
256 printf("%02x ", buf[i] & 0xff);
257 if (i == 11) {
258 printf("\n");
259 }
260 }
261 printf("\n");
262 tsUnpack->ParseRtp(buf, len);
263 });
264 }
265
266 return 0;
267 }