• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }