text: // Copyright 2019 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #define IN_EASYMEDIA_STREAM_CC
  #include "stream.h"
  
  #include <assert.h>
  #include <errno.h>
  
  #include "utils.h"
  
  namespace easymedia {
  
  static size_t local_read(void *ptr, size_t size, size_t nmemb, void *stream) {
    Stream *s = static_cast<Stream *>(stream);
    return s->Read(ptr, size, nmemb);
  }
  
  static size_t local_write(const void *ptr, size_t size, size_t nmemb,
                            void *stream) {
    Stream *s = static_cast<Stream *>(stream);
    return s->Write(ptr, size, nmemb);
  }
  
  static int local_seek(void *stream, int64_t offset, int whence) {
    Stream *s = static_cast<Stream *>(stream);
    return s->Seek(offset, whence);
  }
  
  static long local_tell(void *stream) {
    Stream *s = static_cast<Stream *>(stream);
    return s->Tell();
  }
  
  int local_close(void *stream) {
    Stream *s = static_cast<Stream *>(stream);
    return s->Close();
  }
  
  StreamOperation Stream::c_operations = {
    close : local_close,
    read : local_read,
    write : local_write,
    seek : local_seek,
    tell : local_tell
  };
  
  int Stream::Close() {
    readable = false;
    writeable = false;
    seekable = false;
    return 0;
  }
  
  DEFINE_REFLECTOR(Stream)
  
  // request should equal stream_name
  DEFINE_FACTORY_COMMON_PARSE(Stream)
  
  DEFINE_PART_FINAL_EXPOSE_PRODUCT(Stream, Stream)
  
  bool Stream::ReadImage(void *ptr, const ImageInfo &info) {
    size_t read_size;
    if ((info.pix_fmt != PIX_FMT_FBC0) && (info.pix_fmt != PIX_FMT_FBC2) &&
        (info.width == info.vir_width) && (info.height == info.vir_height)) {
      int num, den;
      GetPixFmtNumDen(info.pix_fmt, num, den);
      read_size = info.width * info.height * num / den;
      if (!read_size)
        return false;
      size_t ret = Read(ptr, 1, read_size);
      if (ret != read_size) {
        // RKMEDIA_LOGI("read ori stream failed, %d != %d\n", ret, read_size);
        return false;
      }
      return true;
    }
    int row = 0;
    uint8_t *buf_y = (uint8_t *)ptr;
    uint8_t *buf_u = buf_y + info.vir_width * info.vir_height;
    // uint8_t *buf_v = buf_u + info.vir_width * info.vir_height / 4;
    switch (info.pix_fmt) {
    case PIX_FMT_NV12:
      for (row = 0; row < info.height; row++) {
        read_size = Read(buf_y + row * info.vir_width, 1, info.width);
        if ((int)read_size != info.width) {
          // RKMEDIA_LOGI("read ori yuv stream luma failed, %d != %d\n",
          // read_size,info.width);
          return false;
        }
      }
      for (row = 0; row < info.height / 2; row++) {
        read_size = Read(buf_u + row * info.vir_width, 1, info.width);
        if ((int)read_size != info.width) {
          // RKMEDIA_LOGI("read ori yuv stream cb failed, %d != %d\n", read_size,
          // info.width);
          return false;
        }
      }
      break;
    case PIX_FMT_FBC0: {
      uint32_t align_w = UPALIGNTO16(info.width);
      uint32_t align_h = UPALIGNTO16(info.height);
      uint32_t header_size = UPALIGNTO(align_w * align_h / 16, 4096);
      uint8_t *buf = (uint8_t *)ptr;
  
      // Read fbc header.
      read_size = Read(buf, 1, header_size);
      if (read_size != header_size)
        return false;
      // Read fbc body.
      buf += header_size;
      read_size = Read(buf, 1, align_w * align_h * 3 / 2);
      if (read_size != align_w * align_h * 3 / 2)
        return false;
    } break;
    case PIX_FMT_FBC2: {
      uint32_t align_w = UPALIGNTO16(info.width);
      uint32_t align_h = UPALIGNTO16(info.height);
      uint32_t header_size = UPALIGNTO(align_w * align_h / 16, 4096);
      uint8_t *buf = (uint8_t *)ptr;
  
      // Read fbc header.
      read_size = Read(buf, 1, header_size);
      if (read_size != header_size)
        return false;
      // Read fbc body.
      buf += header_size;
      read_size = Read(buf, 1, align_w * align_h * 2);
      if (read_size != align_w * align_h * 2)
        return false;
    } break;
    default:
      RKMEDIA_LOGI("TODO: read image fmt %d\n", info.pix_fmt);
      return false;
    }
    return true;
  }
  
  } // namespace easymedia
  