1/*
2 * Copyright (C) 2023 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 "videodec_sample.h"
19#include "native_avcapability.h"
20using namespace OHOS;
21using namespace OHOS::Media;
22using namespace std;
23namespace {
24constexpr int64_t NANOS_IN_SECOND = 1000000000L;
25constexpr int64_t NANOS_IN_MICRO = 1000L;
26constexpr int32_t EIGHT = 8;
27constexpr int32_t SIXTEEN = 16;
28constexpr int32_t TWENTY_FOUR = 24;
29constexpr uint8_t H264_NALU_TYPE = 0x1f;
30constexpr uint32_t START_CODE_SIZE = 4;
31constexpr uint8_t START_CODE[START_CODE_SIZE] = {0, 0, 0, 1};
32constexpr uint8_t SEI = 6;
33constexpr uint8_t SPS = 7;
34constexpr uint8_t PPS = 8;
35
36VDecFuzzSample *g_decSample = nullptr;
37bool g_fuzzError = false;
38void clearIntqueue(std::queue<uint32_t> &q)
39{
40    std::queue<uint32_t> empty;
41    swap(empty, q);
42}
43
44void clearBufferqueue(std::queue<OH_AVCodecBufferAttr> &q)
45{
46    std::queue<OH_AVCodecBufferAttr> empty;
47    swap(empty, q);
48}
49
50void clearAvBufferQueue(std::queue<OH_AVMemory *> &q)
51{
52    std::queue<OH_AVMemory *> empty;
53    swap(empty, q);
54}
55} // namespace
56
57class TestConsumerListener : public IBufferConsumerListener {
58public:
59    TestConsumerListener(sptr<Surface> cs) : cs(cs) {};
60    ~TestConsumerListener() {}
61    void OnBufferAvailable() override
62    {
63        sptr<SurfaceBuffer> buffer;
64        int32_t flushFence;
65        cs->AcquireBuffer(buffer, flushFence, timestamp, damage);
66
67        cs->ReleaseBuffer(buffer, -1);
68    }
69
70private:
71    int64_t timestamp = 0;
72    Rect damage = {};
73    sptr<Surface> cs {nullptr};
74};
75
76VDecFuzzSample::~VDecFuzzSample()
77{
78    if (nativeWindow) {
79        OH_NativeWindow_DestroyNativeWindow(nativeWindow);
80        nativeWindow = nullptr;
81    }
82    Stop();
83    Release();
84}
85
86void VdecError(OH_AVCodec *codec, int32_t errorCode, void *userData)
87{
88    cout << "Error errorCode=" << errorCode << endl;
89}
90
91void VdecFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
92{
93    int32_t currentWidth = 0;
94    int32_t currentHeight = 0;
95    OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, &currentWidth);
96    OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &currentHeight);
97    g_decSample->defaultWidth = currentWidth;
98    g_decSample->defaultHeight = currentHeight;
99}
100
101void VdecInputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData)
102{
103    VDecSignal *signal = static_cast<VDecSignal *>(userData);
104    unique_lock<mutex> lock(signal->inMutex_);
105    signal->inIdxQueue_.push(index);
106    signal->inBufferQueue_.push(data);
107    signal->inCond_.notify_all();
108}
109
110void VdecOutputDataReady(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr,
111                         void *userData)
112{
113    if (g_decSample->isSurfMode) {
114        OH_VideoDecoder_RenderOutputData(codec, index);
115    } else {
116        OH_VideoDecoder_FreeOutputData(codec, index);
117    }
118}
119
120int64_t VDecFuzzSample::GetSystemTimeUs()
121{
122    struct timespec now;
123    (void)clock_gettime(CLOCK_BOOTTIME, &now);
124    int64_t nanoTime = static_cast<int64_t>(now.tv_sec) * NANOS_IN_SECOND + now.tv_nsec;
125    return nanoTime / NANOS_IN_MICRO;
126}
127
128int32_t VDecFuzzSample::ConfigureVideoDecoder()
129{
130    OH_AVFormat *format = OH_AVFormat_Create();
131    if (format == nullptr) {
132        cout << "Fatal: Failed to create format" << endl;
133        return AV_ERR_UNKNOWN;
134    }
135    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, defaultWidth);
136    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, defaultHeight);
137    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, defaultRotation);
138    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, defaultPixelFormat);
139    int ret = OH_VideoDecoder_Configure(vdec_, format);
140    OH_AVFormat_Destroy(format);
141    if (isSurfMode) {
142        cs = Surface::CreateSurfaceAsConsumer();
143        sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
144        cs->RegisterConsumerListener(listener);
145        auto p = cs->GetProducer();
146        ps = Surface::CreateSurfaceAsProducer(p);
147        nativeWindow = CreateNativeWindowFromSurface(&ps);
148        OH_VideoDecoder_SetSurface(vdec_, nativeWindow);
149    }
150    return ret;
151}
152
153int32_t VDecFuzzSample::RunVideoDec()
154{
155    int err = CreateVideoDecoder();
156    if (err != AV_ERR_OK) {
157        cout << "Failed to create video decoder" << endl;
158        return err;
159    }
160
161    err = ConfigureVideoDecoder();
162    if (err != AV_ERR_OK) {
163        cout << "Failed to configure video decoder" << endl;
164        Release();
165        return err;
166    }
167
168    err = SetVideoDecoderCallback();
169    if (err != AV_ERR_OK) {
170        cout << "Failed to setCallback" << endl;
171        Release();
172        return err;
173    }
174
175    err = StartVideoDecoder();
176    if (err != AV_ERR_OK) {
177        cout << "Failed to start video decoder" << endl;
178        Release();
179        return err;
180    }
181    return err;
182}
183
184int32_t VDecFuzzSample::SetVideoDecoderCallback()
185{
186    signal_ = new VDecSignal();
187    if (signal_ == nullptr) {
188        cout << "Failed to new VDecSignal" << endl;
189        return AV_ERR_UNKNOWN;
190    }
191
192    cb_.onError = VdecError;
193    cb_.onStreamChanged = VdecFormatChanged;
194    cb_.onNeedInputData = VdecInputDataReady;
195    cb_.onNeedOutputData = VdecOutputDataReady;
196    return OH_VideoDecoder_SetCallback(vdec_, cb_, static_cast<void *>(signal_));
197}
198
199void VDecFuzzSample::ReleaseInFile()
200{
201    if (inFile_ != nullptr) {
202        if (inFile_->is_open()) {
203            inFile_->close();
204        }
205        inFile_.reset();
206        inFile_ = nullptr;
207    }
208}
209
210void VDecFuzzSample::StopInLoop()
211{
212    if (inputLoop_ != nullptr && inputLoop_->joinable()) {
213        unique_lock<mutex> lock(signal_->inMutex_);
214        clearIntqueue(signal_->inIdxQueue_);
215        signal_->inCond_.notify_all();
216        lock.unlock();
217
218        inputLoop_->join();
219        inputLoop_.reset();
220    }
221}
222
223int32_t VDecFuzzSample::StartVideoDecoder()
224{
225    int ret = OH_VideoDecoder_Start(vdec_);
226    if (ret != AV_ERR_OK) {
227        cout << "Failed to start codec" << endl;
228        return ret;
229    }
230    isRunning_.store(true);
231    inFile_ = make_unique<ifstream>();
232    if (inFile_ == nullptr) {
233        isRunning_.store(false);
234        (void)OH_VideoDecoder_Stop(vdec_);
235        return AV_ERR_UNKNOWN;
236    }
237    inFile_->open(inpDir, ios::in | ios::binary);
238    if (!inFile_->is_open()) {
239        cout << "failed open file " << endl;
240        isRunning_.store(false);
241        (void)OH_VideoDecoder_Stop(vdec_);
242        inFile_->close();
243        inFile_.reset();
244        inFile_ = nullptr;
245        return AV_ERR_UNKNOWN;
246    }
247
248    inputLoop_ = make_unique<thread>(&VDecFuzzSample::InputFuncAVCC, this);
249    if (inputLoop_ == nullptr) {
250        cout << "Failed to create input loop" << endl;
251        isRunning_.store(false);
252        (void)OH_VideoDecoder_Stop(vdec_);
253        ReleaseInFile();
254        return AV_ERR_UNKNOWN;
255    }
256    return AV_ERR_OK;
257}
258
259int32_t VDecFuzzSample::CreateVideoDecoder()
260{
261    OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false, HARDWARE);
262    string codecName = OH_AVCapability_GetName(cap);
263    vdec_ = OH_VideoDecoder_CreateByName("aabbcc");
264    if (vdec_) {
265        OH_VideoDecoder_Destroy(vdec_);
266        vdec_ = nullptr;
267    }
268    OH_AVCodec *tmpDec = OH_VideoDecoder_CreateByMime("aabbcc");
269    if (tmpDec) {
270        OH_VideoDecoder_Destroy(tmpDec);
271        tmpDec = nullptr;
272    }
273    tmpDec = OH_VideoDecoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC);
274    if (tmpDec) {
275        OH_VideoDecoder_Destroy(tmpDec);
276        tmpDec = nullptr;
277    }
278    vdec_ = OH_VideoDecoder_CreateByName(codecName.c_str());
279    g_decSample = this;
280    return vdec_ == nullptr ? AV_ERR_UNKNOWN : AV_ERR_OK;
281}
282
283void VDecFuzzSample::WaitForEOS()
284{
285    if (inputLoop_ && inputLoop_->joinable()) {
286        inputLoop_->join();
287    }
288}
289
290void VDecFuzzSample::CopyStartCode(uint8_t *frameBuffer, uint32_t bufferSize, OH_AVCodecBufferAttr &attr)
291{
292    switch (frameBuffer[START_CODE_SIZE] & H264_NALU_TYPE) {
293        case SPS:
294        case PPS:
295        case SEI:
296            if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
297                cout << "Fatal: memory copy failed" << endl;
298            }
299            attr.pts = GetSystemTimeUs();
300            attr.size = bufferSize + START_CODE_SIZE;
301            attr.offset = 0;
302            attr.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
303            break;
304        default: {
305            if (memcpy_s(frameBuffer, bufferSize + START_CODE_SIZE, START_CODE, START_CODE_SIZE) != EOK) {
306                cout << "Fatal: memory copy failed" << endl;
307            }
308            attr.pts = GetSystemTimeUs();
309            attr.size = bufferSize + START_CODE_SIZE;
310            attr.offset = 0;
311            attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
312        }
313    }
314}
315
316int32_t VDecFuzzSample::ReadData(uint32_t index, OH_AVMemory *buffer)
317{
318    uint8_t ch[4] = {};
319    (void)inFile_->read(reinterpret_cast<char *>(ch), START_CODE_SIZE);
320    if (inFile_->eof()) {
321        SetEOS(index);
322        return 1;
323    }
324    uint32_t bufferSize = static_cast<uint32_t>(((ch[3] & 0xFF)) | ((ch[2] & 0xFF) << EIGHT) |
325    ((ch[1] & 0xFF) << SIXTEEN) | ((ch[0] & 0xFF) << TWENTY_FOUR));
326
327    return SendData(bufferSize, index, buffer);
328}
329
330uint32_t VDecFuzzSample::SendData(uint32_t bufferSize, uint32_t index, OH_AVMemory *buffer)
331{
332    OH_AVCodecBufferAttr attr;
333    uint8_t *frameBuffer = new uint8_t[bufferSize + START_CODE_SIZE];
334    (void)inFile_->read(reinterpret_cast<char *>(frameBuffer + START_CODE_SIZE), bufferSize);
335    CopyStartCode(frameBuffer, bufferSize, attr);
336    int32_t size = OH_AVMemory_GetSize(buffer);
337    if (size < attr.size) {
338        delete[] frameBuffer;
339        isRunning_.store(false);
340        return 1;
341    }
342    uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
343    if (memcpy_s(bufferAddr, size, frameBuffer, attr.size) != EOK) {
344        delete[] frameBuffer;
345        isRunning_.store(false);
346        return 1;
347    }
348    delete[] frameBuffer;
349    int32_t ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
350    if (ret != AV_ERR_OK) {
351        errCount++;
352    }
353    frameCount_++;
354    if (inFile_->eof()) {
355        isRunning_.store(false);
356    }
357    return 0;
358}
359
360void VDecFuzzSample::InputFuncAVCC()
361{
362    frameCount_ = 1;
363    errCount = 0;
364    while (true) {
365        if (!isRunning_.load()) {
366            break;
367        }
368        unique_lock<mutex> lock(signal_->inMutex_);
369        signal_->inCond_.wait(lock, [this]() {
370            if (!isRunning_.load()) {
371                cout << "quit signal" << endl;
372                return true;
373            }
374            return signal_->inIdxQueue_.size() > 0;
375        });
376        if (!isRunning_.load()) {
377            break;
378        }
379        uint32_t index = signal_->inIdxQueue_.front();
380        auto buffer = signal_->inBufferQueue_.front();
381        signal_->inIdxQueue_.pop();
382        signal_->inBufferQueue_.pop();
383        lock.unlock();
384        if (!inFile_->eof()) {
385            int ret = ReadData(index, buffer);
386            if (ret == 1) {
387                break;
388            }
389        }
390    }
391}
392
393OH_AVErrCode VDecFuzzSample::InputFuncFUZZ(const uint8_t *data, size_t size)
394{
395    uint32_t index;
396    unique_lock<mutex> lock(signal_->inMutex_);
397    signal_->inCond_.wait(lock, [this]() {
398        if (!isRunning_.load() && g_fuzzError) {
399            return true;
400        }
401        return signal_->inIdxQueue_.size() > 0;
402    });
403    if (g_fuzzError)
404        return AV_ERR_TIMEOUT;
405    index = signal_->inIdxQueue_.front();
406    auto buffer = signal_->inBufferQueue_.front();
407    lock.unlock();
408    int32_t bufferSize = OH_AVMemory_GetSize(buffer);
409    uint8_t *bufferAddr = OH_AVMemory_GetAddr(buffer);
410
411    if (memcpy_s(bufferAddr, bufferSize, data, size) != EOK) {
412        cout << "Fatal: memcpy fail" << endl;
413        return AV_ERR_NO_MEMORY;
414    }
415    OH_AVCodecBufferAttr attr;
416    attr.pts = GetSystemTimeUs();
417    attr.size = bufferSize;
418    attr.offset = 0;
419    attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
420    OH_AVErrCode ret = OH_VideoDecoder_PushInputData(vdec_, index, attr);
421    signal_->inIdxQueue_.pop();
422    signal_->inBufferQueue_.pop();
423    return ret;
424}
425
426void VDecFuzzSample::SetEOS(uint32_t index)
427{
428    OH_AVCodecBufferAttr attr;
429    attr.pts = 0;
430    attr.size = 0;
431    attr.offset = 0;
432    attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
433    int32_t res = OH_VideoDecoder_PushInputData(vdec_, index, attr);
434    cout << "OH_VideoDecoder_PushInputData    EOS   res: " << res << endl;
435}
436
437int32_t VDecFuzzSample::Flush()
438{
439    unique_lock<mutex> inLock(signal_->inMutex_);
440    clearIntqueue(signal_->inIdxQueue_);
441    signal_->inCond_.notify_all();
442    inLock.unlock();
443    unique_lock<mutex> outLock(signal_->outMutex_);
444    clearIntqueue(signal_->outIdxQueue_);
445    clearBufferqueue(signal_->attrQueue_);
446    signal_->outCond_.notify_all();
447    outLock.unlock();
448    isRunning_.store(false);
449    return OH_VideoDecoder_Flush(vdec_);
450}
451
452int32_t VDecFuzzSample::Reset()
453{
454    isRunning_.store(false);
455    StopInLoop();
456    ReleaseInFile();
457    return OH_VideoDecoder_Reset(vdec_);
458}
459
460int32_t VDecFuzzSample::Release()
461{
462    int ret = 0;
463    if (vdec_ != nullptr) {
464        ret = OH_VideoDecoder_Destroy(vdec_);
465        vdec_ = nullptr;
466    }
467
468    if (signal_ != nullptr) {
469        clearAvBufferQueue(signal_->inBufferQueue_);
470        delete signal_;
471        signal_ = nullptr;
472    }
473    return ret;
474}
475
476int32_t VDecFuzzSample::Stop()
477{
478    StopInLoop();
479    clearIntqueue(signal_->outIdxQueue_);
480    clearBufferqueue(signal_->attrQueue_);
481    ReleaseInFile();
482    return OH_VideoDecoder_Stop(vdec_);
483}
484
485int32_t VDecFuzzSample::Start()
486{
487    int32_t ret = OH_VideoDecoder_Start(vdec_);
488    if (ret == AV_ERR_OK) {
489        isRunning_.store(true);
490    }
491    return ret;
492}
493
494void VDecFuzzSample::SetParameter(int32_t data)
495{
496    OH_AVFormat *format = OH_AVFormat_Create();
497    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, data);
498    (void)OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, data);
499    OH_VideoDecoder_SetParameter(vdec_, format);
500    OH_AVFormat_Destroy(format);
501}