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