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