• 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 <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 }