• 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 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 }