libyuv implements general cvt, resize, crop functions

My idea of implementation is to convert all formats to i420 first, and then perform crop resize and cvt operations.

Get Fourcc code

uint32_t Scaler::GetFOURCC(const Scaler::Buffer *src) {
  uint32_t fourcc = 0;
  
  switch (src->color) {
    case Scaler::ColorFormat::YUV_I420:
      fourcc = libyuv::FourCC::FOURCC_I420;
      break;
    
    case Scaler::ColorFormat::YUV_NV21:
      fourcc = libyuv::FourCC::FOURCC_NV21;
      break;
    
    case Scaler::ColorFormat::YUV_NV12:
      fourcc = libyuv::FourCC::FOURCC_NV12;
      break;
    
    case Scaler::ColorFormat::BGR:
      fourcc = libyuv::FourCC::FOURCC_24BG;
      break;

    case Scaler::ColorFormat::RGB:
      fourcc = libyuv::FourCC::FOURCC_RAW;
      break;
    
    case Scaler::ColorFormat::BGRA:
      fourcc = libyuv::FourCC::FOURCC_ARGB;
      break;
    
    case Scaler::ColorFormat::ARGB:
      fourcc = libyuv::FourCC::FOURCC_BGRA;
      break;
    
    case Scaler::ColorFormat::RGBA:
      fourcc = libyuv::FourCC::FOURCC_ABGR;
      break;

    case Scaler::ColorFormat::ABGR:
      fourcc = libyuv::FourCC::FOURCC_RGBA;
      break;

    default:
      LOG(ERROR) << "libyuv not support this color cvt I420";
      break;
  }
  return fourcc;
}

Process

bool LibyuvProcess(const Scaler::Buffer *src, Scaler::Buffer *dst, const Scaler::Rect *crop) {
  if (!src || !dst) return false;

  if (!crop & amp; & amp; src->width == dst->width & amp; & amp; src->height == dst->height & amp; & amp; src->color == dst- >color) {
    // copy src to dst directly
    bool src_continus = IsBufferContinus_(src);
    bool dst_continus = IsBufferContinus_(dst);
    if (src->color <= Scaler::ColorFormat::YUV_I420) {
      if (src_continus & amp; & amp; dst_continus) {
        memcpy(dst->data[0], src->data[0], src->width * src->height * 3 / 2);
      } else {
        memcpy(dst->data[0], src->data[0], src->width * src->height);
        memcpy(dst->data[1], src->data[1], src->width * src->height / 4);
        memcpy(dst->data[2], src->data[2], src->width * src->height / 4);
      }

    } else if (src->color <= Scaler::ColorFormat::YUV_NV12) {
      if (src_continus & amp; & amp; dst_continus) {
         memcpy(dst->data[0], src->data[0], src->width * src->height * 3 / 2);
      } else {
         memcpy(dst->data[0], src->data[0], src->width * src->height);
         memcpy(dst->data[1], src->data[1], src->width * src->height / 2);
      }

    } else if (src->color <= Scaler::ColorFormat::RGB) {
      memcpy(dst->data[0], src->data[0], src->width * src->height * 3);
      dst->data[1] = dst->data[2] = nullptr;
    } else if (src->color <= Scaler::ColorFormat::ARGB) {
      memcpy(dst->data[0], src->data[0], src->width * src->height * 4);
      dst->data[1] = dst->data[2] = nullptr;
    } else {
      LOG(ERROR) << "scaler, we not realize this color space" << src->color;
      return false;
    }
    for (size_t i = 0; i < 3; i + + ) {
      dst->stride[i] = src->stride[i];
    }
    return true;
  }
  /*
    // TODO after first, "else if" is test, will be move future
    if (src->color == Scaler::ColorFormat::BGR & amp; & amp; dst->color == Scaler::ColorFormat::YUV_NV21) {
      Scaler::LibyuvCvtBGRToNV21_Process(src, dst, crop);
    } else if (src->color == ColorFormat::YUV_NV21 & amp; & amp; dst->color == ColorFormat::YUV_NV21) {
      Scaler::LibyuvResize_NV21(src, dst);
    } else if (src->color == ColorFormat::BGR & amp; & dst->color == ColorFormat::YUV_I420) {
      Scaler::LibyuvCvtBGRtoI420(src, dst);
    } else if (src->color == ColorFormat::YUV_I420 & amp; & amp; dst->color == ColorFormat::YUV_I420) {
      Scaler::LibyuvResize_I420(src, dst);
    }
  */
    uint32_t width = src->width;
    uint32_t height = src->height;
    Scaler::Buffer *src_crop = nullptr;
    Scaler::Buffer *resize_buf = nullptr;
    if (crop != nullptr) {
      width = crop->w;
      height = crop->h;
      if (width == dst->width & amp; & amp; height == dst->height & amp; & amp; src->color == dst->color) {
        if (src->color == Scaler::ColorFormat::YUV_I420) {
          dst->stride[0] = src->width;
          dst->stride[1] = dst->stride[2] = src->width >> 1;
          memcpy(dst->data[0], src->data[0], src->stride[0] * src->height);
          memcpy(dst->data[1], src->data[1], dst->stride[1] * dst->height / 2);
          memcpy(dst->data[1], src->data[1], dst->stride[1] * dst->height / 2);
        } else if (src->color <= ColorFormat::YUV_NV12) {
          dst->stride[0] = dst->stride[1] = src->width;
          memcpy(dst->data[0], src->data[0], src->stride[0] * src->height);
          memcpy(dst->data[1], src->data[1], src->stride[1] * src->height);
        } else if (src->color <= ColorFormat::ARGB) {
          dst->stride[0] = src->stride[0];
          memcpy(dst->data[0], src->data[0], dst->stride[0] * src->height);
        } else {
          LOG(ERROR) << "scaler not support this color space";
        }
        return true;
      } else {
        src_crop = new Scaler::Buffer();
        src_crop->color = Scaler::ColorFormat::YUV_I420;
        src_crop->width = crop->w;
        src_crop->height = crop->h;
        src_crop->stride[0] = src_crop->width;
        src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
        src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
        src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
        src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
        Scaler::LibyuvToI420(src, src_crop, crop);
      }
    }
    

    if (width != dst->width || height != dst->height) {
      resize_buf = new Scaler::Buffer();
      memset(resize_buf, 0, sizeof(Scaler::Buffer));
      resize_buf->color= Scaler::ColorFormat::YUV_I420;
      resize_buf->width = dst->width;
      resize_buf->height = dst->height;
      resize_buf->stride[0] = resize_buf->width;
      resize_buf->stride[1] = resize_buf->stride[2] = resize_buf->width >> 1;
      resize_buf->data[0] = new uint8_t[resize_buf->width * resize_buf->height * 3 / 2];
      resize_buf->data[1] = resize_buf->data[0] + resize_buf->width * resize_buf->height;
      resize_buf->data[2] = resize_buf->data[1] + resize_buf->width * resize_buf->height / 4;

      if (src_crop == nullptr) {
        src_crop = new Scaler::Buffer();
        src_crop->color = Scaler::ColorFormat::YUV_I420;
        src_crop->width = src->width;
        src_crop->height = src->height;
        src_crop->stride[0] = src_crop->width;
        src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
        src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
        src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
        src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
        Scaler::LibyuvToI420(src, src_crop, nullptr);
      }

      libyuv::I420Scale(src_crop->data[0], src_crop->stride[0],
                        src_crop->data[1], src_crop->stride[1],
                        src_crop->data[2], src_crop->stride[2],
                        src_crop->width, src_crop->height,
                        resize_buf->data[0], resize_buf->stride[0],
                        resize_buf->data[1], resize_buf->stride[1],
                        resize_buf->data[2], resize_buf->stride[2],
                        resize_buf->width, resize_buf->height,
                        libyuv::FilterMode::kFilterNone);
    }

    if (dst->color != Scaler::ColorFormat::YUV_I420) {
      // i420 covert to dst->color, output to dst->data
      if (resize_buf != nullptr) {
        Scaler::LibyuvConvertFromI420(resize_buf, dst);
        if (src_crop != nullptr) {
          delete[] src_crop->data[0];
          src_crop->data[0] = nullptr;
          delete src_crop;
          src_crop = nullptr;
        }
        delete[] resize_buf->data[0];
        delete resize_buf;
        resize_buf->data[0] = resize_buf->data[1] = resize_buf->data[2] = nullptr;
        resize_buf = nullptr;
        return true;
      }
      if (src_crop == nullptr) {
        src_crop = new Scaler::Buffer();
        src_crop->color = Scaler::ColorFormat::YUV_I420;
        src_crop->width = src->width;
        src_crop->height = src->height;
        src_crop->stride[0] = src_crop->width;
        src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
        src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
        src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
        src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
        Scaler::LibyuvToI420(src, src_crop, nullptr);
      }
      Scaler::LibyuvConvertFromI420(src_crop, dst);
      if (src_crop != nullptr) {
        delete[] src_crop->data[0];
        delete src_crop;
        src_crop->data[0] = src_crop->data[1] = src_crop->data[2] = nullptr;
        src_crop = nullptr;
      }
      return true;

    } else {
      if (resize_buf != nullptr) {
        memcpy(dst->data[0], resize_buf->data[0], dst->width * dst->height * 3 / 2);
      } else {
        Scaler::LibyuvToI420(src, dst, nullptr);
      }
    }
    if (src_crop != nullptr) {
      delete[] src_crop->data[0];
      src_crop->data[0] = src_crop->data[1] = src_crop->data[2] = nullptr;
      delete src_crop;
      src_crop = nullptr;
    }
    if (resize_buf != nullptr) {
      delete[] resize_buf->data[0];
      resize_buf->data[0] = resize_buf->data[1] = resize_buf->data[2] = nullptr;
      delete resize_buf;
      resize_buf = nullptr;
    }
    return true;
}

Convert to I420

void Scaler::LibyuvToI420(const Buffer *src,
                          Buffer *dst,
                          const Rect *crop) {
  size_t frame_size = 0;
  if (src->color <= Scaler::ColorFormat::YUV_NV12) {
    frame_size = src->stride[0] * src->height * 3 / 2;
  } else if (src->color <= Scaler::ColorFormat::ARGB) {
    frame_size = src->stride[0] * src->height;
  }
  uint32_t fourcc = Scaler::GetFOURCC(src);
  if (crop != nullptr) {
    libyuv::ConvertToI420(src->data[0], frame_size,
                          dst->data[0], dst->stride[0],
                          dst->data[1], dst->stride[1],
                          dst->data[2], dst->stride[2],
                          crop->x, crop->y,
                          src->width, src->height,
                          crop->w, crop->h,
                          libyuv::RotationMode::kRotate0,
                          fourcc);

  } else {
    libyuv::ConvertToI420(src->data[0], frame_size,
                         dst->data[0], dst->stride[0],
                         dst->data[1], dst->stride[1],
                         dst->data[2], dst->stride[2],
                         0, 0,
                         src->width, src->height,
                         dst->width, dst->height,
                         libyuv::RotationMode::kRotate0,
                         fourcc);
  }

}

Convert from I420 to output format

void Scaler::LibyuvConvertFromI420(const Buffer *src,
                                   Buffer *dst) {
  /*
  size_t frame_size = 0;
  if (src->color <= Scaler::ColorFormat::YUV_NV12) {
    frame_size = src->stride[0] * src->height * 3 / 2;
  } else if (src->color <= Scaler::ColorFormat::ARGB) {
    frame_size = src->stride[0] * src->height;
  }
  */
  uint32_t fourcc = Scaler::GetFOURCC(dst);
  libyuv::ConvertFromI420(src->data[0], src->stride[0],
                          src->data[1], src->stride[1],
                          src->data[2], src->stride[2],
                          dst->data[0],dst->stride[0],
                          dst->width, dst->height,
                          fourcc);
}
Because it is converted to i420 intermediate format, the length and width of the picture must be an even number

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Cloud native entry-level skills treeHomepageOverview 15597 people are learning the system