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