/* Copyright 2017 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef HAL_USB_CACHED_FRAME_H_
#define HAL_USB_CACHED_FRAME_H_

#include <memory>

#include <camera/CameraMetadata.h>

#include "arc/image_processor.h"

namespace arc {

// CachedFrame contains a source FrameBuffer and a cached, converted
// FrameBuffer. The incoming frames would be converted to YU12, the default
// format of libyuv, to allow convenient processing.
class CachedFrame {
 public:
  CachedFrame();
  ~CachedFrame();

  // SetSource() doesn't take ownership of |frame|. The caller can only release
  // |frame| after calling UnsetSource(). SetSource() immediately converts
  // incoming frame into YU12. Return non-zero values if it encounters errors.
  // If |rotate_degree| is 90 or 270, |frame| will be cropped, rotated by the
  // specified amount and scaled.
  // If |rotate_degree| is -1, |frame| will not be cropped, rotated, and scaled.
  // This function will return an error if |rotate_degree| is not -1, 90, or
  // 270.
  int SetSource(const FrameBuffer* frame, int rotate_degree);
  void UnsetSource();

  uint8_t* GetSourceBuffer() const;
  size_t GetSourceDataSize() const;
  uint32_t GetSourceFourCC() const;
  uint8_t* GetCachedBuffer() const;
  uint32_t GetCachedFourCC() const;

  uint32_t GetWidth() const;
  uint32_t GetHeight() const;

  // Calculate the output buffer size when converting to the specified pixel
  // format. |fourcc| is defined as V4L2_PIX_FMT_* in linux/videodev2.h. Return
  // 0 on error.
  size_t GetConvertedSize(int fourcc) const;

  // Caller should fill everything except |data_size| and |fd| of |out_frame|.
  // The function will do format conversion and scale to fit |out_frame|
  // requirement.
  // If |video_hack| is true, it outputs YU12 when |hal_pixel_format| is YV12
  // (swapping U/V planes). Caller should fill |fourcc|, |data|, and
  // Return non-zero error code on failure; return 0 on success.
  int Convert(const android::CameraMetadata& metadata, FrameBuffer* out_frame,
              bool video_hack = false);

 private:
  int ConvertToYU12();
  // When we have a landscape mounted camera and the current camera activity is
  // portrait, the frames shown in the activity would be stretched. Therefore,
  // we want to simulate a native portrait camera. That's why we want to crop,
  // rotate |rotate_degree| clockwise and scale the frame. HAL would not change
  // CameraInfo.orientation. Instead, framework would fake the
  // CameraInfo.orientation. Framework would then tell HAL how much the frame
  // needs to rotate clockwise by |rotate_degree|.
  int CropRotateScale(int rotate_degree);

  const FrameBuffer* source_frame_;
  // const V4L2FrameBuffer* source_frame_;

  // Temporary buffer for cropped and rotated results.
  std::unique_ptr<uint8_t[]> cropped_buffer_;
  size_t cropped_buffer_capacity_;

  // Cache YU12 decoded results.
  std::unique_ptr<AllocatedFrameBuffer> yu12_frame_;

  // Temporary buffer for scaled results.
  std::unique_ptr<AllocatedFrameBuffer> scaled_frame_;
};

}  // namespace arc

#endif  // HAL_USB_CACHED_FRAME_H_