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 SEND_MAX_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;
147 Media::Meta codecInfo;
148 int32_t instanceid = 0;
149 codecInfo.SetData("av_codec_event_info_instance_id", instanceid);
150 err = codec_->Init(codecInfo);
151 if (err != AVCS_ERR_OK) {
152 cout << "decoder Init failed!" << endl;
153 return err;
154 }
155 err = ConfigServerDecoder();
156 if (err != AVCS_ERR_OK) {
157 cout << "ConfigServerDecoder failed" << endl;
158 return err;
159 }
160 err = SetCallback();
161 if (err != AVCS_ERR_OK) {
162 cout << "SetCallback failed" << endl;
163 return err;
164 }
165 signal_ = std::make_shared<VDecSignal>();
166 if (signal_ == nullptr) {
167 cout << "Failed to new VDecSignal" << endl;
168 err = AVCS_ERR_NO_MEMORY;
169 return err;
170 }
171 if (isSurfMode) {
172 err = SetOutputSurface();
173 if (err != AVCS_ERR_OK) {
174 cout << "SetOutputSurface failed" << endl;
175 return err;
176 }
177 }
178 return err;
179 }
180
RunVideoServerDecoder()181 void VDecServerSample::RunVideoServerDecoder()
182 {
183 CreateHevcDecoderByName("OH.Media.Codec.Decoder.Video.HEVC", codec_);
184 if (codec_ == nullptr) {
185 cout << "Create failed" << endl;
186 return;
187 }
188 int32_t err = InitDecoder();
189 if (err != AVCS_ERR_OK) {
190 cout << "Init decoder failed" << endl;
191 return;
192 }
193 err = codec_->Start();
194 if (err != AVCS_ERR_OK) {
195 cout << "Start failed" << endl;
196 return;
197 }
198 isRunning_.store(true);
199 inFile_ = make_unique<ifstream>();
200 if (inFile_ == nullptr) {
201 Stop();
202 return;
203 }
204 inFile_->open(inpDir, ios::in | ios::binary);
205 if (!inFile_->is_open()) {
206 cout << "open input file failed" << endl;
207 Stop();
208 inFile_->close();
209 inFile_.reset();
210 inFile_ = nullptr;
211 return;
212 }
213 inputLoop_ = make_unique<thread>(&VDecServerSample::InputFunc, this);
214 if (inputLoop_ == nullptr) {
215 cout << "Failed to create input loop" << endl;
216 isRunning_.store(false);
217 Stop();
218 ReleaseInFile();
219 return;
220 }
221 if (isSurfMode) {
222 err = SetOutputSurface();
223 if (err != AVCS_ERR_OK) {
224 cout << "SetOutputSurface failed" << endl;
225 }
226 }
227 }
228
WaitForEos()229 void VDecServerSample::WaitForEos()
230 {
231 if (inputLoop_ && inputLoop_->joinable()) {
232 inputLoop_->join();
233 }
234 }
235
GetOutputFormat()236 void VDecServerSample::GetOutputFormat()
237 {
238 Format fmt;
239 int32_t err = codec_->GetOutputFormat(fmt);
240 if (err != AVCS_ERR_OK) {
241 cout << "GetOutputFormat fail" << endl;
242 isRunning_.store(false);
243 signal_->inCond_.notify_all();
244 signal_->endCond_.notify_all();
245 }
246 }
247
Flush()248 void VDecServerSample::Flush()
249 {
250 int32_t err = codec_->Flush();
251 if (err != AVCS_ERR_OK) {
252 cout << "Flush fail" << endl;
253 isRunning_.store(false);
254 signal_->inCond_.notify_all();
255 signal_->endCond_.notify_all();
256 }
257 }
258
Reset()259 void VDecServerSample::Reset()
260 {
261 int32_t err = codec_->Reset();
262 if (err != AVCS_ERR_OK) {
263 cout << "Reset fail" << endl;
264 isRunning_.store(false);
265 signal_->inCond_.notify_all();
266 signal_->endCond_.notify_all();
267 }
268 }
269
Stop()270 void VDecServerSample::Stop()
271 {
272 StopInloop();
273 ReleaseInFile();
274 int32_t err = codec_->Stop();
275 if (err != AVCS_ERR_OK) {
276 cout << "Stop fail" << endl;
277 isRunning_.store(false);
278 signal_->inCond_.notify_all();
279 signal_->endCond_.notify_all();
280 }
281 }
282
SetEOS(uint32_t index,std::shared_ptr<AVBuffer> buffer)283 void VDecServerSample::SetEOS(uint32_t index, std::shared_ptr<AVBuffer> buffer)
284 {
285 buffer->pts_ = GetSystemTimeUs();
286 buffer->flag_ = AVCODEC_BUFFER_FLAGS_EOS;
287 int32_t res = codec_->QueueInputBuffer(index);
288 cout << "OH_VideoDecoder_PushInputData EOS res:" << res << endl;
289 unique_lock<mutex> lock(signal_->outMutex_);
290 signal_->endCond_.wait(lock, [this]() {
291 if (!isRunning_.load()) {
292 cout << "quit signal" << endl;
293 return true;
294 }
295 return isEOS_.load();
296 });
297 }
298
CopyStartCode(uint8_t * frameBuffer,uint32_t bufferSize,std::shared_ptr<AVBuffer> buffer)299 void VDecServerSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, std::shared_ptr<AVBuffer> buffer)
300 {
301 if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
302 cout << "Fatal: memory copy failed" << endl;
303 }
304 buffer->pts_ = GetSystemTimeUs();
305 buffer->memory_->SetSize(bufferSize + START_CODE_SIZE);
306 buffer->memory_->SetOffset(0);
307 switch (frameBuffer[START_CODE_SIZE] & H265_NALU_TYPE) {
308 case SPS:
309 case PPS:
310 case SEI:
311 buffer->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
312 break;
313 default: {
314 buffer->flag_ = AVCODEC_BUFFER_FLAGS_NONE;
315 }
316 }
317 }
318
ReadData(uint32_t index,std::shared_ptr<AVBuffer> buffer)319 int32_t VDecServerSample::ReadData(uint32_t index, std::shared_ptr<AVBuffer> buffer)
320 {
321 uint8_t ch[4] = {};
322 (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
323 if (repeatRun && inFile_->eof()) {
324 inFile_->clear();
325 inFile_->seekg(0, ios::beg);
326 cout << "repeat" << endl;
327 return 0;
328 } else if (inFile_->eof()) {
329 SetEOS(index, buffer);
330 return 1;
331 }
332 uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
333 ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
334 return SendData(bufferSize, index, buffer);
335 }
336
SendData(uint32_t bufferSize,uint32_t index,std::shared_ptr<AVBuffer> buffer)337 int32_t VDecServerSample::SendData(uint32_t bufferSize, uint32_t index, std::shared_ptr<AVBuffer> buffer)
338 {
339 uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
340 (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
341 int32_t size = buffer->memory_->GetCapacity();
342 CopyStartCode(frameBuffer, bufferSize, buffer);
343 if (size < (bufferSize + START_CODE_SIZE)) {
344 delete[] frameBuffer;
345 cout << "ERROR:AVMemory not enough, buffer size " << (bufferSize + START_CODE_SIZE) <<\
346 " AVMemory Size " << size << endl;
347 isRunning_.store(false);
348 return 1;
349 }
350 uint8_t *bufferAddr = buffer->memory_->GetAddr();
351 if (memcpy_s(bufferAddr, size, frameBuffer, bufferSize + START_CODE_SIZE) != EOK) {
352 delete[] frameBuffer;
353 cout << "Fatal: memcpy fail" << endl;
354 isRunning_.store(false);
355 return 1;
356 }
357 delete[] frameBuffer;
358 int32_t ret = codec_->QueueInputBuffer(index);
359 if (ret != AV_ERR_OK) {
360 errCount++;
361 cout << "push input data failed, error:" << ret << endl;
362 }
363 frameCount_ = frameCount_ + 1;
364 if (inFile_->eof()) {
365 isRunning_.store(false);
366 }
367 return 0;
368 }
369
InputFunc()370 void VDecServerSample::InputFunc()
371 {
372 frameCount_ = 1;
373 errCount = 0;
374 while (sendFrameIndex < SEND_MAX_FRAMES) {
375 if (!isRunning_.load()) {
376 break;
377 }
378 unique_lock<mutex> lock(signal_->inMutex_);
379 signal_->inCond_.wait(lock, [this]() {
380 if (!isRunning_.load()) {
381 cout << "quit signal" << endl;
382 return true;
383 }
384 return signal_->inIdxQueue_.size() > 0;
385 });
386 if (!isRunning_.load()) {
387 break;
388 }
389 uint32_t index = signal_->inIdxQueue_.front();
390 auto buffer = signal_->inBufferQueue_.front();
391 signal_->inIdxQueue_.pop();
392 signal_->inBufferQueue_.pop();
393 lock.unlock();
394 if (!inFile_->eof()) {
395 int ret = ReadData(index, buffer);
396 if (ret == 1) {
397 break;
398 }
399 }
400 sendFrameIndex++;
401 }
402 }
403
StopInloop()404 void VDecServerSample::StopInloop()
405 {
406 if (inputLoop_ != nullptr && inputLoop_->joinable()) {
407 unique_lock<mutex> lock(signal_->inMutex_);
408 clearIntqueue(signal_->inIdxQueue_);
409 signal_->inCond_.notify_all();
410 isEOS_.store(true);
411 signal_->endCond_.notify_all();
412 lock.unlock();
413
414 inputLoop_->join();
415 inputLoop_.reset();
416 }
417 }
418
ReleaseInFile()419 void VDecServerSample::ReleaseInFile()
420 {
421 if (inFile_ != nullptr) {
422 if (inFile_->is_open()) {
423 inFile_->close();
424 }
425 inFile_.reset();
426 inFile_ = nullptr;
427 }
428 }