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 <chrono>
18 #include <fstream>
19 #include <functional>
20 #include <getopt.h>
21 #include <istream>
22 #include <netinet/in.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <thread>
28 #include <unistd.h>
29 #include "frame/frame.h"
30 #include "frame/h264_frame.h"
31 #include "rtp_def.h"
32 #include "rtp_factory.h"
33
34 using namespace OHOS::Sharing;
35
36 int gType = -1; // 0 for aac, 1 for h264
37 char *gFileName = nullptr;
38 char *gIP = nullptr;
39 int gPort = 1234;
40
41 int sampling_frequency_table[13] = {96000, 88200, 64000, 48000, 44100, 32000, 24000,
42 22050, 16000, 12000, 11025, 8000, 7350};
43
ShowUsage(char * exe)44 void ShowUsage(char *exe)
45 {
46 printf("Usage:%s -t <type> -f <file> -o <destination host ip> -p <destination host port>", exe);
47 printf("\t-t 0: AAC, 1: H264, 2: G.711");
48 printf("\t-f local file name");
49 printf("\t-o destination host ip, such as 192.168.1.100");
50 printf("\t-p destination host port, default 1234");
51 }
52
ParseParam(int argc,char * argv[])53 int ParseParam(int argc, char *argv[])
54 {
55 int ret;
56
57 while ((ret = getopt(argc, argv, ":t:f:o:p:")) != -1) {
58 switch (ret) {
59 case ('t'):
60 gType = atoi(optarg);
61 break;
62 case ('f'):
63 gFileName = optarg;
64 break;
65 case ('o'):
66 gIP = optarg;
67 break;
68 case ('p'):
69 gPort = atoi(optarg);
70 break;
71 case ':':
72 printf("option [-%c] requires an argument", static_cast<char>(optopt));
73 break;
74 case '?':
75 printf("unknown option: %c", static_cast<char>(optopt));
76 break;
77 default:
78 break;
79 }
80 }
81
82 if ((gType > 2 || gType < 0) || gFileName == nullptr || gIP == nullptr) {
83 printf("param error");
84 ShowUsage(argv[0]);
85 return -1;
86 }
87 return 0;
88 }
89
SendRTP(const char * data,int size)90 int SendRTP(const char *data, int size)
91 {
92 static int socketFd = 0;
93 static struct sockaddr_in destHostAddr;
94
95 if (socketFd <= 0) {
96 socketFd = socket(AF_INET, SOCK_DGRAM, 0);
97 if (socketFd < 0) {
98 perror("socket ");
99 return -1;
100 }
101
102 destHostAddr.sin_family = AF_INET;
103 destHostAddr.sin_port = htons(gPort);
104 inet_aton(gIP, &destHostAddr.sin_addr);
105 printf("init UDP socket (%d) ok", socketFd);
106 }
107
108 ssize_t num = sendto(socketFd, data, size, 0, (struct sockaddr *)&destHostAddr, sizeof(destHostAddr));
109 if (num != size) {
110 perror("sendto error:");
111 return -2;
112 }
113 printf("send data (size: %d) success.", size);
114 return 0;
115 }
116
FindNextNal(const uint8_t * start,const uint8_t * end)117 const uint8_t *FindNextNal(const uint8_t *start, const uint8_t *end)
118 {
119 // there is two kind of nal head. four byte 0x00000001 or three byte 0x000001
120 while (start <= end - 3) {
121 if (start[0] == 0x00 && start[1] == 0x00 && start[2] == 0x01) {
122 return start;
123 }
124 if (start[0] == 0x00 && start[1] == 0x00 && start[2] == 0x00 && start[3] == 0x01) {
125 return start;
126 }
127 start++;
128 }
129
130 return end;
131 }
132
FindH264Frame(const uint8_t * start,const uint8_t * end)133 std::pair<const uint8_t *, int> FindH264Frame(const uint8_t *start, const uint8_t *end)
134 {
135 const uint8_t *frame = FindNextNal(start, end);
136 if (frame >= end) {
137 return std::pair<const uint8_t *, int>{nullptr, 0};
138 }
139 const uint8_t *next = FindNextNal(frame + 3, end);
140 return std::pair<const uint8_t *, int>{frame, next - frame};
141 }
142
ReadH264File(const std::function<void (const char * buf,int len)> & cb)143 int ReadH264File(const std::function<void(const char *buf, int len)> &cb)
144 {
145 std::fstream infile(gFileName, std::ios::in | std::ios_base::binary);
146 if (!infile.is_open()) {
147 printf("failed to open file");
148 return -1;
149 }
150
151 infile.seekg(0, std::ios::end);
152 int size = infile.tellg();
153 infile.seekg(0, std::ios::beg);
154
155 char *content = new char[size];
156 infile.read(content, size);
157 printf("size %d", size);
158 infile.close();
159
160 uint8_t *begin = (uint8_t *)content;
161 int i = 0;
162 std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
163 std::chrono::microseconds interval = std::chrono::microseconds(1000000 / 24);
164
165 while (begin < (uint8_t *)content + size) {
166 std::pair<const uint8_t *, int> res = FindH264Frame(begin, (uint8_t *)content + size);
167
168 printf("h264 frame [%d] %p length %d", i, res.first, res.second);
169 if (res.second == 0)
170 break;
171
172 begin = (uint8_t *)res.first + res.second;
173
174 // skip sei/sps/pps frame
175 const unsigned char *p = res.first;
176 p = *(p + 2) == 0x01 ? p + 3 : p + 4;
177 if ((p[0] & 0x1f) != 0x06 && (p[0] & 0x1f) != 0x07 && (p[0] & 0x1f) != 0x08) {
178 std::this_thread::sleep_until(start + interval * ++i);
179 }
180
181 cb((const char *)res.first, res.second);
182 }
183 return 0;
184 }
185
FindAACFrame(uint8_t * begin,uint8_t * end)186 std::pair<const uint8_t *, int> FindAACFrame(uint8_t *begin, uint8_t *end)
187 {
188 const uint8_t *p = begin;
189 int length = 0;
190 while (p <= (end - 7)) {
191 if ((p[0] & 0xff) == 0xff && (p[1] & 0xf0) == 0xf0) {
192 printf("is aac header");
193 length = static_cast<int>(
194 (((p[3] & 0x03) << 0x11) | ((p[4] & 0xff) << 0x3) | ((p[5] & 0xe0) >> 0x5))); // get AAC length
195 if (p + length <= end) {
196 break;
197 }
198 }
199 p++;
200 }
201
202 return std::pair<const uint8_t *, int>{p, length};
203 }
204
ReadAacFile(const std::function<void (const char * buf,int len)> & cb)205 int ReadAacFile(const std::function<void(const char *buf, int len)> &cb)
206 {
207 std::fstream infile(gFileName, std::ios::in | std::ios_base::binary);
208 if (!infile.is_open()) {
209 printf("failed to open file");
210 return -1;
211 }
212
213 infile.seekg(0, std::ios::end);
214 int size = infile.tellg();
215 infile.seekg(0, std::ios::beg);
216
217 char *content = new char[size];
218 infile.read(content, size);
219 printf("size %d", size);
220 infile.close();
221
222 uint8_t *begin = (uint8_t *)content;
223 int i = 0;
224 std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
225 int sample_rate = 0;
226
227 std::chrono::microseconds interval;
228
229 while (begin < (uint8_t *)content + size) {
230 std::pair<const uint8_t *, int> res = FindAACFrame(begin, (uint8_t *)content + size);
231 i++;
232 printf("aac frame [%d] %p length %d", i, res.first, res.second);
233 if (res.second == 0)
234 break;
235 if (sample_rate == 0) {
236 int index = int((((char *)res.first)[2] & 0x3c) >> 2);
237 sample_rate = sampling_frequency_table[index];
238 interval = std::chrono::microseconds(1024 * 1000000 / sample_rate);
239 }
240
241 begin = (uint8_t *)res.first + res.second;
242
243 std::this_thread::sleep_until(start + interval * i);
244 cb((const char *)res.first, res.second);
245 }
246 return 0;
247 }
248
ReadG711File(int channels,const std::function<void (const char * buf,int len)> & cb)249 int ReadG711File(int channels, const std::function<void(const char *buf, int len)> &cb)
250 {
251 std::fstream infile(gFileName, std::ios::in | std::ios_base::binary);
252 if (!infile.is_open()) {
253 printf("failed to open file");
254 return -1;
255 }
256
257 infile.seekg(0, std::ios::end);
258 int size = infile.tellg();
259 infile.seekg(0, std::ios::beg);
260
261 char *content = new char[size];
262 infile.read(content, size);
263 printf("size %d", size);
264 infile.close();
265
266 uint8_t *begin = (uint8_t *)content;
267 int i = 0;
268 std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
269 std::chrono::microseconds interval = std::chrono::milliseconds(20); // 20 ms
270 int packSize = 160 * channels;
271 while (begin < (uint8_t *)content + size) {
272 std::this_thread::sleep_until(start + interval * i++);
273 cb((const char *)begin, packSize);
274 begin = begin + packSize;
275 }
276
277 return 0;
278 }
279
main(int argc,char * argv[])280 int main(int argc, char *argv[])
281 {
282 if (ParseParam(argc, argv) != 0) {
283 return -1;
284 }
285 printf("%s -t %d -f %s -o %s -p %d", argv[0], gType, gFileName, gIP, gPort);
286
287 if (gType == 0) {
288 auto aacPack = RtpFactory::CreateRtpPack(4568712, 1400, 48000, 97, RtpPayloadStream::MPEG4_GENERIC);
289
290 aacPack->SetOnRtpPack([=](const RtpPacket::Ptr &rtp) {
291 printf("rtp packed seq: %d, timestamp: %d, size: %d", rtp->GetSeq(), rtp->GetStamp(), rtp->Size());
292 SendRTP((char *)rtp->Data(), rtp->Size());
293 });
294
295 ReadAacFile([=](const char *buf, int len) {
296 printf("aac frame %p length %d", buf, len);
297 static int index = 0;
298 auto frame = FrameImpl::Create();
299 frame->codecId_ = CODEC_AAC;
300 frame->Assign((char *)buf, len);
301 frame->prefixSize_ = 7;
302 frame->dts_ = (index++ * 1024) / (48000 / 1000); // 48kHz
303 aacPack->InputFrame(frame);
304 });
305 } else if (gType == 1) {
306 auto avcPack = RtpFactory::CreateRtpPack(4568713, 1400, 90000, 96, RtpPayloadStream::H264);
307
308 avcPack->SetOnRtpPack([=](const RtpPacket::Ptr &rtp) {
309 printf("rtp packed seq: %d, timestamp: %d, size: %d", rtp->GetSeq(), rtp->GetStamp(), rtp->Size());
310 SendRTP((char *)rtp->Data(), rtp->Size());
311 });
312
313 ReadH264File([=](const char *buf, int len) {
314 printf("h264 frame %p length %d", buf, len);
315 for (size_t i = 0; i < 10; i++) {
316 printf("%02x ", buf[i]);
317 }
318 printf("");
319
320 static int index = 0;
321 uint32_t ts = index++ * 1000 / 24;
322 Frame::Ptr frame = std::make_shared<H264Frame>((uint8_t *)buf, (size_t)len, ts, ts, PrefixSize(buf, len));
323 avcPack->InputFrame(frame);
324 });
325 } else if (gType == 2) {
326 auto g711Pack = RtpFactory::CreateRtpPack(4568713, 1400, 8000, 97, RtpPayloadStream::PCMA, 2);
327
328 g711Pack->SetOnRtpPack([=](const RtpPacket::Ptr &rtp) {
329 printf("rtp packed seq: %d, timestamp: %d, size: %d", rtp->GetSeq(), rtp->GetStamp(), rtp->Size());
330 SendRTP((char *)rtp->Data(), rtp->Size());
331 });
332
333 ReadG711File(2, [=](const char *buf, int len) {
334 printf("g711 frame %p length %d", buf, len);
335 static int index = 0;
336 auto frame = FrameImpl::Create();
337 frame->codecId_ = CODEC_G711A;
338 frame->Assign((char *)buf, len);
339 frame->prefixSize_ = 0;
340 frame->dts_ = (index++ * 160) / 8; // 8kHz: i * 160 * 1000 / sampleRate
341
342 g711Pack->InputFrame(frame);
343 });
344 }
345
346 return 0;
347 }