1 /*
2  * Copyright (c) 2020-2021 Huawei Device 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 "test_play_file_h265.h"
17 
18 #include "codec_interface.h"
19 #include "securec.h"
20 
21 #include <chrono>
22 #include <iostream>
23 #include <thread>
24 
25 using namespace std;
26 
Display(CODEC_HANDLETYPE decoderHdl)27 void PlayManager::Display(CODEC_HANDLETYPE decoderHdl)
28 {
29     OutputInfo outInfo = {};
30     CodecBufferInfo outBuf = {};
31     outInfo.bufferCnt = 1;
32     outInfo.buffers = &outBuf;
33     constexpr uint32_t timeoutMs = 100; // timeout:100ms
34     int32_t ret = CodecDequeueOutput(decoderHdl, timeoutMs, nullptr, &outInfo);
35     if (ret == CODEC_ERR_FRAME_BUF_EMPTY) {
36         DEMO_LOG("CodecDequeueOutput deque empty.(ret=%d)", ret);
37         return;
38     } else if (ret != 0) {
39         DEMO_LOG("CodecDequeueOutput error.(ret=%d)", ret);
40         return;
41     }
42 
43     ret = Write2VideoDevice(outInfo);
44     if (ret != 0) {
45         DEMO_LOG("Write video device failed.");
46     }
47 
48     frameCnt_++;
49     ret = CodecQueueOutput(decoderHdl, &outInfo, timeoutMs, -1);
50     if (ret != 0) {
51         DEMO_LOG("CodecQueueOutput failed.(ret=%d)", ret);
52         return;
53     }
54 }
55 
PlayManager()56 PlayManager::PlayManager()
57 {
58     InitVideoOutput();
59 }
60 
~PlayManager()61 PlayManager::~PlayManager()
62 {
63     DeinitVideoOutput();
64 }
65 
InitVideoOutput()66 int32_t PlayManager::InitVideoOutput()
67 {
68     int32_t ret = HalPlayerSysInit();
69     if (ret != 0) {
70         DEMO_LOG("hal system init failed.");
71         return DEMO_ERR;
72     }
73 
74     ret = HalPlayerVoInit(&voHdl_);
75     if (ret != 0) {
76         DEMO_LOG("video output init failed.");
77         return DEMO_ERR;
78     }
79 
80     ret = HalStartVideoOutput(voHdl_);
81     if (ret != 0) {
82         DEMO_LOG("video output start failed.");
83         return DEMO_ERR;
84     }
85 
86     return DEMO_OK;
87 }
88 
DeinitVideoOutput()89 int32_t PlayManager::DeinitVideoOutput()
90 {
91     int32_t ret = HalStopVideoOutput(voHdl_);
92     if (ret != 0) {
93         DEMO_LOG("video output start failed.");
94         return DEMO_ERR;
95     }
96 
97     HalPlayerVoDeinit(voHdl_);
98 
99     return DEMO_OK;
100 }
101 
Write2VideoDevice(OutputInfo & outputInfo)102 int32_t PlayManager::Write2VideoDevice(OutputInfo &outputInfo)
103 {
104     int32_t x = 200;
105     int32_t y = 200;
106     int32_t w = 960;
107     int32_t h = 540;
108 
109     HalVideoOutputAttr voAttr = {x, y, w, h, 0};
110     int32_t ret = HalConfigVideoOutput(voHdl_, voAttr);
111     if (ret != 0) {
112         DEMO_LOG("HalConfigVideoOutput failed.");
113         return DEMO_ERR;
114     }
115 
116     ret = HalWriteVo(voHdl_, outputInfo.vendorPrivate);
117     if (ret != 0) {
118         DEMO_LOG("HalWriteVo failed.");
119         return DEMO_ERR;
120     }
121 
122     return DEMO_OK;
123 }
124 
DecodeManager()125 DecodeManager::DecodeManager()
126 {
127     DecoderCreate();
128 }
129 
~DecodeManager()130 DecodeManager::~DecodeManager()
131 {
132     DecoderDestroy();
133 }
134 
DecoderCreate()135 int32_t DecodeManager::DecoderCreate()
136 {
137     int index = 0;
138     Param param[PARAM_MAX_NUM];
139     AvCodecMime mime = MEDIA_MIMETYPE_VIDEO_HEVC;
140     param[index].key = KEY_MIMETYPE;
141     param[index].val = (void *)&mime;
142     param[index].size = sizeof(AvCodecMime);
143     index++;
144     uint32_t width = 1920;
145     param[index].key = KEY_WIDTH;
146     param[index].val = (void *)&width;
147     param[index].size = sizeof(uint32_t);
148     index++;
149     uint32_t height = 1080;
150     param[index].key = KEY_HEIGHT;
151     param[index].val = (void *)&height;
152     param[index].size = sizeof(uint32_t);
153     index++;
154     uint32_t bufSize = 0;
155     param[index].key = KEY_BUFFERSIZE;
156     param[index].val = (void *)&bufSize;
157     param[index].size = sizeof(uint32_t);
158     index++;
159     CodecType domain = VIDEO_DECODER;
160     param[index].key = KEY_CODEC_TYPE;
161     param[index].val = (void *)&domain;
162     param[index].size = sizeof(CodecType);
163     index++;
164 
165     int32_t ret = CodecInit();
166     if (ret != 0) {
167         DEMO_LOG("Codec init failed.(ret=%d)", ret);
168         return DEMO_ERR;
169     }
170 
171     ret = CodecCreate("codec.avc.soft.decoder", param, index, &decoderHdl_);
172     if (ret != 0) {
173         DEMO_LOG("Codec create failed.(ret=%d)", ret);
174         return DEMO_ERR;
175     }
176 
177     ret = CodecStart(decoderHdl_);
178     if (ret != 0) {
179         DEMO_LOG("Codec start failed.(ret=%d)", ret);
180         return DEMO_ERR;
181     }
182 
183     return DEMO_OK;
184 }
185 
DecoderDestroy()186 void DecodeManager::DecoderDestroy()
187 {
188     CodecStop(decoderHdl_);
189     CodecDestroy(decoderHdl_);
190 }
191 
DecodePack(uint8_t * addr,uint32_t len,uint64_t timeStampUs)192 int32_t DecodeManager::DecodePack(uint8_t *addr, uint32_t len, uint64_t timeStampUs)
193 {
194     InputInfo inputData = {};
195     CodecBufferInfo inBufInfo = {};
196     uint32_t timeoutMs = 100; // 100ms timeout
197     int32_t ret = CodecDequeInput(decoderHdl_, timeoutMs, &inputData);
198     if (ret != 0) {
199         DEMO_LOG("CodecDequeInput error.(ret=%d)", ret);
200         return DEMO_ERR;
201     }
202 
203     inBufInfo.addr = addr;
204     inBufInfo.length = len;
205 
206     inputData.bufferCnt = 1;
207     inputData.buffers = &inBufInfo;
208     inputData.pts = timeStampUs;
209     inputData.flag = 0;
210     while ((ret = CodecQueueInput(decoderHdl_, &inputData, timeoutMs)) == CODEC_ERR_STREAM_BUF_FULL) {
211         this_thread::sleep_for(chrono::milliseconds(timeoutMs));
212     }
213     if (ret != 0) {
214         DEMO_LOG("CodecQueueInput error.(ret=%d)", ret);
215         return DEMO_ERR;
216     }
217     frameCnt_++;
218     return DEMO_OK;
219 }
220 
ReadH265File(ifstream & file,char * buf,int32_t len)221 static int32_t ReadH265File(ifstream &file, char *buf, int32_t len)
222 {
223     file.read(buf, len);
224     if (file) {
225         return len;
226     } else {
227         return file.gcount();
228     }
229 }
230 
GetNal(const uint8_t * bsData,int32_t dataSize,int32_t * startCodeSize,int32_t * nalSize)231 static int32_t GetNal(const uint8_t *bsData, int32_t dataSize, int32_t *startCodeSize, int32_t *nalSize)
232 {
233     int32_t curNalOffset = 0;
234     int32_t nextNalOffset = 0;
235     int32_t offset;
236     uint8_t byte0 = 0;
237     uint8_t byte1 = 1;
238     uint8_t offset1 = 1;
239     uint8_t offset2 = 2;
240     uint8_t offset3 = 3;
241 
242     for (offset = 0; offset < dataSize; offset++) {
243         if ((bsData[offset] == byte0) && (bsData[offset + offset1] == byte0) && (bsData[offset + offset2] == byte1)) {
244             *startCodeSize = 3; // h265 start frame length: 3->001
245             curNalOffset = offset;
246             break;
247         } else if ((bsData[offset] == byte0) && (bsData[offset + offset1] == byte0) &&
248                    (bsData[offset + offset2] == byte0) && (bsData[offset + offset3] == byte1)) {
249             *startCodeSize = 4; // h265 start frame length: 4->0001
250             curNalOffset = offset;
251             break;
252         }
253     }
254 
255     if (offset == dataSize) {
256         return -1;
257     }
258 
259     for (offset = curNalOffset + offset3; offset < dataSize; offset++) {
260         if ((bsData[offset] == byte0) && (bsData[offset + offset1] == byte0) && (bsData[offset + offset2] == byte1)) {
261             nextNalOffset = offset;
262             break;
263         } else if ((bsData[offset] == byte0) && (bsData[offset + offset1] == byte0) &&
264                    (bsData[offset + offset2] == byte0) && (bsData[offset + offset3] == 0x01)) {
265             nextNalOffset = offset;
266             break;
267         }
268     }
269 
270     if (offset == dataSize) {
271         *nalSize = dataSize - curNalOffset;
272     } else {
273         *nalSize = nextNalOffset - curNalOffset;
274     }
275 
276     return curNalOffset;
277 }
278 
DisplayThrd(PlayManager * playMng,CODEC_HANDLETYPE decoderHdl,bool * stop,uint32_t timeStep)279 static void DisplayThrd(PlayManager *playMng, CODEC_HANDLETYPE decoderHdl, bool *stop, uint32_t timeStep)
280 {
281     while (!(*stop)) {
282         this_thread::sleep_for(chrono::microseconds(timeStep));
283         playMng->Display(decoderHdl);
284     }
285     DEMO_LOG("play end.");
286 }
287 
main()288 int main()
289 {
290     DEMO_LOG("Demo begin");
291 
292     PlayManager playMng;
293     DEMO_LOG("Init video output succeed.");
294 
295     DecodeManager decodeMng;
296     CODEC_HANDLETYPE decoderHdl = decodeMng.GetHdl();
297     DEMO_LOG("Init decoder succeed.");
298 
299     cout << "Type in file path:";
300     string fileName;
301     getline(cin, fileName);
302     if (fileName.empty()) {
303         fileName.assign("/tmp/1080P.h265");
304     }
305     ifstream file(fileName, ios::binary | ios::ate);
306     if (!file) {
307         DEMO_LOG("Openfile %s failed.", fileName.c_str());
308         return 0;
309     }
310     int32_t fileSize = file.tellg();
311     file.seekg(0, file.beg);
312     DEMO_LOG("Open file succeed.(size=%d)", fileSize);
313 
314     constexpr uint32_t bufSize = 1024 * 1024;
315     uint8_t *buf = (uint8_t *)malloc(bufSize);
316     if (buf == nullptr) {
317         DEMO_LOG("Memory not enough.");
318         return 0;
319     }
320 
321     constexpr uint32_t timeStep = 33333; // 33333us, 30fps
322     bool displayStop = false;
323     thread displayThrd(DisplayThrd, &playMng, decoderHdl, &displayStop, timeStep);
324     uint64_t timeStamp = 0;
325     int32_t bufLen = 0;
326     while (file) {
327         bufLen += ReadH265File(file, static_cast<char *>(buf + bufLen), bufSize - bufLen);
328 
329         int32_t frameSize;
330         int32_t codeSize;
331         int32_t offset = 0;
332         offset = GetNal(buf, bufLen, &codeSize, &frameSize);
333         if (offset < 0) {
334             DEMO_LOG("Get nal frame failed.");
335             break;
336         }
337         int32_t ret = decodeMng.DecodePack(buf + offset, frameSize, timeStamp);
338         timeStamp += timeStep;
339         int result = memmove_s(buf, bufSize, buf + offset + frameSize, bufLen - offset - frameSize);
340         if (result != 0) {
341             DEMO_LOG("memmove_s failed.");
342             break;
343         }
344         bufLen = bufLen - offset - frameSize;
345         if (ret != DEMO_OK) {
346             DEMO_LOG("Decode one frame failed.");
347             continue;
348         }
349     }
350     while (playMng.GetCnt() != decodeMng.GetCnt()) {
351         this_thread::sleep_for(chrono::seconds(1)); // sleep 1s
352     }
353     displayStop = true;
354     displayThrd.join();
355     if (buf != nullptr) {
356         free(buf);
357     }
358 
359     DEMO_LOG("Demo end");
360 }
361