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