1 /*
2 * Copyright (c) 2025 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 #include <arpa/inet.h>
16 #include <sys/time.h>
17 #include <utility>
18 #include "hevcserverdec_sample.h"
19 #include <iostream>
20 #include "hevc_decoder_api.h"
21 #include "window.h"
22 #include "window_manager.h"
23 #include "window_option.h"
24 using namespace OHOS;
25 using namespace OHOS::Media;
26 using namespace OHOS::MediaAVCodec;
27 using namespace OHOS::MediaAVCodec::Codec;
28 using namespace std;
29 namespace {
30 constexpr int32_t EIGHT = 8;
31 constexpr int32_t SIXTEEN = 16;
32 constexpr int32_t TWENTY_FOUR = 24;
33 constexpr uint8_t SEI = 6;
34 constexpr uint8_t SPS = 7;
35 constexpr uint8_t PPS = 8;
36 constexpr uint32_t START_CODE_SIZE = 4;
37 constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
38 constexpr uint8_t H265_NALU_TYPE = 0x1f;
39 constexpr int64_t NANOS_IN_SECOND = 1000000000L;
40 constexpr int64_t NANOS_IN_MICRO = 1000L;
41 constexpr int32_t MAX_SEND_FRAMES = 10;
42 typedef enum OH_AVCodecBufferFlags {
43 AVCODEC_BUFFER_FLAGS_NONE = 0,
44 /* Indicates that the Buffer is an End-of-Stream frame */
45 AVCODEC_BUFFER_FLAGS_EOS = 1 << 0,
46 /* Indicates that the Buffer contains keyframes */
47 AVCODEC_BUFFER_FLAGS_SYNC_FRAME = 1 << 1,
48 /* Indicates that the data contained in the Buffer is only part of a frame */
49 AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME = 1 << 2,
50 /* Indicates that the Buffer contains Codec-Specific-Data */
51 AVCODEC_BUFFER_FLAGS_CODEC_DATA = 1 << 3,
52 /* Flag is used to discard packets which are required to maintain valid decoder state but are not required */
53 AVCODEC_BUFFER_FLAGS_DISCARD = 1 << 4,
54 /* Flag is used to indicate packets that contain frames that can be discarded by the decoder */
55 AVCODEC_BUFFER_FLAGS_DISPOSABLE = 1 << 5,
56 } OH_AVCodecBufferFlags;
57
clearIntqueue(std::queue<uint32_t> & q)58 void clearIntqueue(std::queue<uint32_t> &q)
59 {
60 std::queue<uint32_t> empty;
61 swap(empty, q);
62 }
63 } // namespace
64
GetSystemTimeUs()65 int64_t VDecServerSample::GetSystemTimeUs()
66 {
67 struct timespec now;
68 (void)clock_gettime(CLOCK_BOOTTIME, &now);
69 int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
70 return nanoTime / NANOS_IN_MICRO;
71 }
72
OnError(AVCodecErrorType errorType,int32_t errorCode)73 void VDecServerSample::CallBack::OnError(AVCodecErrorType errorType, int32_t errorCode)
74 {
75 tester->Flush();
76 tester->Reset();
77 }
78
79
OnOutputFormatChanged(const Format & format)80 void VDecServerSample::CallBack::OnOutputFormatChanged(const Format &format)
81 {
82 tester->GetOutputFormat();
83 }
84
85
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)86 void VDecServerSample::CallBack::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
87 {
88 unique_lock<mutex> lock(tester->signal_->inMutex_);
89 tester->signal_->inIdxQueue_.push(index);
90 tester->signal_->inBufferQueue_.push(buffer);
91 tester->signal_->inCond_.notify_all();
92 }
93
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)94 void VDecServerSample::CallBack::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
95 {
96 if (buffer->flag_ == AVCODEC_BUFFER_FLAGS_EOS) {
97 tester->isEOS_.store(true);
98 tester->signal_->endCond_.notify_all();
99 cout << " get eos output " << endl;
100 }
101 tester->codec_->ReleaseOutputBuffer(index);
102 }
103
~VDecServerSample()104 VDecServerSample::~VDecServerSample()
105 {
106 if (codec_ != nullptr) {
107 codec_->Stop();
108 codec_->Release();
109 HevcDecoder *codec = reinterpret_cast<HevcDecoder*>(codec_.get());
110 codec->DecStrongRef(codec);
111 }
112 }
113
ConfigServerDecoder()114 int32_t VDecServerSample::ConfigServerDecoder()
115 {
116 Format fmt;
117 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, defaultWidth);
118 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, defaultHeight);
119 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, defaultPixelFormat);
120 fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, defaultFrameRate);
121 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, defaultRotation);
122 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, ScalingMode::SCALING_MODE_SCALE_TO_WINDOW);
123 return codec_->Configure(fmt);
124 }
125
SetCallback()126 int32_t VDecServerSample::SetCallback()
127 {
128 shared_ptr<CallBack> cb = make_shared<CallBack>(this);
129 return codec_->SetCallback(cb);
130 }
131
SetOutputSurface()132 int32_t VDecServerSample::SetOutputSurface()
133 {
134 auto cs = Surface::CreateSurfaceAsConsumer();
135 cs_vector.push_back(cs);
136 sptr<IBufferConsumerListener> listener = new ConsumerListener(cs);
137 cs->RegisterConsumerListener(listener);
138 auto p = cs->GetProducer();
139 auto ps = Surface::CreateSurfaceAsProducer(p);
140 ps_vector.push_back(ps);
141 return codec_->SetOutputSurface(ps);
142 }
143
InitDecoder()144 int32_t VDecServerSample::InitDecoder()
145 {
146 int32_t err = ConfigServerDecoder();
147 if (err != AVCS_ERR_OK) {
148 cout << "ConfigServerDecoder failed" << endl;
149 return err;
150 }
151 err = SetCallback();
152 if (err != AVCS_ERR_OK) {
153 cout << "SetCallback failed" << endl;
154 return err;
155 }
156 if (isSurfMode) {
157 err = SetOutputSurface();
158 if (err != AVCS_ERR_OK) {
159 cout << "SetOutputSurface failed" << endl;
160 return err;
161 }
162 }
163 return err;
164 }
165
RunVideoServerDecoder()166 void VDecServerSample::RunVideoServerDecoder()
167 {
168 signal_ = std::make_shared<VDecSignal>();
169 if (signal_ == nullptr) {
170 return;
171 }
172 CreateHevcDecoderByName("OH.Media.Codec.Decoder.Video.HEVC", codec_);
173 if (codec_ == nullptr) {
174 cout << "Create failed" << endl;
175 return;
176 }
177 int32_t err = InitDecoder();
178 if (err != AVCS_ERR_OK) {
179 cout << "Init decoder failed" << endl;
180 return;
181 }
182 err = codec_->Start();
183 if (err != AVCS_ERR_OK) {
184 cout << "Start failed" << endl;
185 return;
186 }
187 isRunning_.store(true);
188 inFile_ = make_unique<ifstream>();
189 if (inFile_ == nullptr) {
190 Stop();
191 return;
192 }
193 inFile_->open(inpDir, ios::in | ios::binary);
194 if (!inFile_->is_open()) {
195 cout << "open input file failed" << endl;
196 Stop();
197 inFile_->close();
198 inFile_.reset();
199 inFile_ = nullptr;
200 return;
201 }
202 inputLoop_ = make_unique<thread>(&VDecServerSample::InputFunc, this);
203 if (inputLoop_ == nullptr) {
204 cout << "Failed to create input loop" << endl;
205 isRunning_.store(false);
206 Stop();
207 ReleaseInFile();
208 return;
209 }
210 if (isSurfMode) {
211 err = SetOutputSurface();
212 if (err != AVCS_ERR_OK) {
213 cout << "SetOutputSurface failed" << endl;
214 }
215 }
216 }
217
WaitForEos()218 void VDecServerSample::WaitForEos()
219 {
220 if (inputLoop_ && inputLoop_->joinable()) {
221 inputLoop_->join();
222 }
223 }
224
GetOutputFormat()225 void VDecServerSample::GetOutputFormat()
226 {
227 Format fmt;
228 int32_t err = codec_->GetOutputFormat(fmt);
229 if (err != AVCS_ERR_OK) {
230 cout << "GetOutputFormat fail" << endl;
231 isRunning_.store(false);
232 signal_->inCond_.notify_all();
233 signal_->endCond_.notify_all();
234 }
235 }
236
Flush()237 void VDecServerSample::Flush()
238 {
239 int32_t err = codec_->Flush();
240 if (err != AVCS_ERR_OK) {
241 cout << "Flush fail" << endl;
242 isRunning_.store(false);
243 signal_->inCond_.notify_all();
244 signal_->endCond_.notify_all();
245 }
246 }
247
Reset()248 void VDecServerSample::Reset()
249 {
250 int32_t err = codec_->Reset();
251 if (err != AVCS_ERR_OK) {
252 cout << "Reset fail" << endl;
253 isRunning_.store(false);
254 signal_->inCond_.notify_all();
255 signal_->endCond_.notify_all();
256 }
257 }
258
Stop()259 void VDecServerSample::Stop()
260 {
261 StopInloop();
262 ReleaseInFile();
263 int32_t err = codec_->Stop();
264 if (err != AVCS_ERR_OK) {
265 cout << "Stop fail" << endl;
266 isRunning_.store(false);
267 signal_->inCond_.notify_all();
268 signal_->endCond_.notify_all();
269 }
270 }
271
SetEOS(uint32_t index,std::shared_ptr<AVBuffer> buffer)272 void VDecServerSample::SetEOS(uint32_t index, std::shared_ptr<AVBuffer> buffer)
273 {
274 buffer->pts_ = GetSystemTimeUs();
275 buffer->flag_ = AVCODEC_BUFFER_FLAGS_EOS;
276 int32_t res = codec_->QueueInputBuffer(index);
277 cout << "OH_VideoDecoder_PushInputData EOS res:" << res << endl;
278 unique_lock<mutex> lock(signal_->outMutex_);
279 signal_->endCond_.wait(lock, [this]() {
280 if (!isRunning_.load()) {
281 cout << "quit signal" << endl;
282 return true;
283 }
284 return isEOS_.load();
285 });
286 }
287
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,std::shared_ptr<AVBuffer> buffer)288 void VDecServerSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, std::shared_ptr<AVBuffer> buffer)
289 {
290 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
291 cout << "Fatal: memory copy failed" << endl;
292 }
293 buffer->pts_ = GetSystemTimeUs();
294 buffer->memory_->SetSize(bufferSize + START_CODE_SIZE);
295 buffer->memory_->SetOffset(0);
296 switch (frameBuffer[START_CODE_SIZE] & H265_NALU_TYPE) {
297 case SPS:
298 case PPS:
299 case SEI:
300 buffer->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
301 break;
302 default: {
303 buffer->flag_ = AVCODEC_BUFFER_FLAGS_NONE;
304 }
305 }
306 }
307
ReadData(uint32_t index,std::shared_ptr<AVBuffer> buffer)308 int32_t VDecServerSample::ReadData(uint32_t index, std::shared_ptr<AVBuffer> buffer)
309 {
310 uint8_t ch[4] = {};
311 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
312 if (repeatRun && inFile_->eof()) {
313 inFile_->clear();
314 inFile_->seekg(0, ios::beg);
315 cout << "repeat" << endl;
316 return 0;
317 } else if (inFile_->eof()) {
318 SetEOS(index, buffer);
319 return 1;
320 }
321 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
322 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
323 return SendData(bufferSize, index, buffer);
324 }
325
SendData(uint32_t bufferSize,uint32_t index,std::shared_ptr<AVBuffer> buffer)326 int32_t VDecServerSample::SendData(uint32_t bufferSize, uint32_t index, std::shared_ptr<AVBuffer> buffer)
327 {
328 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
329 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
330 int32_t size = buffer->memory_->GetCapacity();
331 CopyStartCode(frameBuffer, bufferSize, buffer);
332 if (size < (bufferSize + START_CODE_SIZE)) {
333 delete[] frameBuffer;
334 cout << "ERROR:AVMemory not enough, buffer size " << (bufferSize + START_CODE_SIZE) <<\
335 " AVMemory Size " << size << endl;
336 isRunning_.store(false);
337 return 1;
338 }
339 uint8_t *bufferAddr = buffer->memory_->GetAddr();
340 if (memcpy_s(bufferAddr, size, frameBuffer, bufferSize + START_CODE_SIZE) != EOK) {
341 delete[] frameBuffer;
342 cout << "Fatal: memcpy fail" << endl;
343 isRunning_.store(false);
344 return 1;
345 }
346 delete[] frameBuffer;
347 int32_t ret = codec_->QueueInputBuffer(index);
348 if (ret != AV_ERR_OK) {
349 errCount++;
350 cout << "push input data failed, error:" << ret << endl;
351 }
352 frameCount_ = frameCount_ + 1;
353 if (inFile_->eof()) {
354 isRunning_.store(false);
355 }
356 return 0;
357 }
358
InputFunc()359 void VDecServerSample::InputFunc()
360 {
361 frameCount_ = 1;
362 errCount = 0;
363 while (sendFrameIndex < MAX_SEND_FRAMES) {
364 if (!isRunning_.load()) {
365 break;
366 }
367 unique_lock<mutex> lock(signal_->inMutex_);
368 signal_->inCond_.wait(lock, [this]() {
369 if (!isRunning_.load()) {
370 cout << "quit signal" << endl;
371 return true;
372 }
373 return signal_->inIdxQueue_.size() > 0;
374 });
375 if (!isRunning_.load()) {
376 break;
377 }
378 uint32_t index = signal_->inIdxQueue_.front();
379 auto buffer = signal_->inBufferQueue_.front();
380 signal_->inIdxQueue_.pop();
381 signal_->inBufferQueue_.pop();
382 lock.unlock();
383 if (!inFile_->eof()) {
384 int ret = ReadData(index, buffer);
385 if (ret == 1) {
386 break;
387 }
388 }
389 sendFrameIndex++;
390 }
391 }
392
NotifyMemoryRecycle()393 void VDecServerSample::NotifyMemoryRecycle()
394 {
395 int32_t err = codec_->NotifyMemoryRecycle();
396 if (err != AVCS_ERR_OK) {
397 cout << "NotifyMemoryRecycle fail" << endl;
398 isRunning_.store(false);
399 signal_->inCond_.notify_all();
400 signal_->endCond_.notify_all();
401 }
402 }
403
NotifyMemoryWriteBack()404 void VDecServerSample::NotifyMemoryWriteBack()
405 {
406 int32_t err = codec_->NotifyMemoryWriteBack();
407 if (err != AVCS_ERR_OK) {
408 cout << "NotifyMemoryWriteBack fail" << endl;
409 isRunning_.store(false);
410 signal_->inCond_.notify_all();
411 signal_->endCond_.notify_all();
412 }
413 }
414
StopInloop()415 void VDecServerSample::StopInloop()
416 {
417 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
418 unique_lock<mutex> lock(signal_->inMutex_);
419 clearIntqueue(signal_->inIdxQueue_);
420 signal_->inCond_.notify_all();
421 isEOS_.store(true);
422 signal_->endCond_.notify_all();
423 lock.unlock();
424
425 inputLoop_->join();
426 inputLoop_.reset();
427 }
428 }
429
ReleaseInFile()430 void VDecServerSample::ReleaseInFile()
431 {
432 if (inFile_ != nullptr) {
433 if (inFile_->is_open()) {
434 inFile_->close();
435 }
436 inFile_.reset();
437 inFile_ = nullptr;
438 }
439 }