shithub: libvpx

Download patch

ref: 8a5cb084e6e40ba0f6e979843a599bae85a24812
parent: 48b2d902624530cc9c49e9104c8a81af88693622
author: angiebird <angiebird@google.com>
date: Thu Jan 23 09:56:01 EST 2020

Add coded_frame to EncodeFrameResults

This coded_frame represents the raw coded image.

Change-Id: Iea439da2f9e84c4507b082d77ebaac49bfd74fff

--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -7102,10 +7102,6 @@
 #endif  // CONFIG_NON_GREEDY_MV
 }
 
-static void init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
-  encode_frame_result->show_idx = -1;  // Actual encoding doesn't happen.
-}
-
 #if !CONFIG_REALTIME_ONLY
 #if CONFIG_RATE_CTRL
 static void copy_frame_counts(const FRAME_COUNTS *input_counts,
@@ -7224,6 +7220,34 @@
     }
   }
 }
+
+static void yv12_buffer_to_image_buffer(const YV12_BUFFER_CONFIG *yv12_buffer,
+                                        IMAGE_BUFFER *image_buffer) {
+  const uint8_t *src_buf_ls[3] = { yv12_buffer->y_buffer, yv12_buffer->u_buffer,
+                                   yv12_buffer->v_buffer };
+  const int src_stride_ls[3] = { yv12_buffer->y_stride, yv12_buffer->uv_stride,
+                                 yv12_buffer->uv_stride };
+  const int w_ls[3] = { yv12_buffer->y_crop_width, yv12_buffer->uv_crop_width,
+                        yv12_buffer->uv_crop_width };
+  const int h_ls[3] = { yv12_buffer->y_crop_height, yv12_buffer->uv_crop_height,
+                        yv12_buffer->uv_crop_height };
+  int plane;
+  for (plane = 0; plane < 3; ++plane) {
+    const int src_stride = src_stride_ls[plane];
+    const int w = w_ls[plane];
+    const int h = h_ls[plane];
+    const uint8_t *src_buf = src_buf_ls[plane];
+    uint8_t *dst_buf = image_buffer->plane_buffer[plane];
+    int r;
+    assert(image_buffer->plane_width[plane] == w);
+    assert(image_buffer->plane_height[plane] == h);
+    for (r = 0; r < h; ++r) {
+      memcpy(dst_buf, src_buf, sizeof(*src_buf) * w);
+      src_buf += src_stride;
+      dst_buf += w;
+    }
+  }
+}
 #endif  // CONFIG_RATE_CTRL
 
 static void update_encode_frame_result(
@@ -7249,6 +7273,9 @@
   encode_frame_result->sse = psnr.sse[0];
   copy_frame_counts(counts, &encode_frame_result->frame_counts);
   encode_frame_result->partition_info = partition_info;
+  if (encode_frame_result->coded_frame.allocated) {
+    yv12_buffer_to_image_buffer(coded_frame, &encode_frame_result->coded_frame);
+  }
 #else   // CONFIG_RATE_CTRL
   (void)bit_depth;
   (void)input_bit_depth;
@@ -7262,6 +7289,14 @@
 }
 #endif  // !CONFIG_REALTIME_ONLY
 
+void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result) {
+  encode_frame_result->show_idx = -1;  // Actual encoding doesn't happen.
+#if CONFIG_RATE_CTRL
+  vp9_zero(encode_frame_result->coded_frame);
+  encode_frame_result->coded_frame.allocated = 0;
+#endif  // CONFIG_RATE_CTRL
+}
+
 int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
                             size_t *size, uint8_t *dest, int64_t *time_stamp,
                             int64_t *time_end, int flush,
@@ -7277,7 +7312,6 @@
   int arf_src_index;
   const int gf_group_index = cpi->twopass.gf_group.index;
   int i;
-  init_encode_frame_result(encode_frame_result);
 
   if (is_one_pass_cbr_svc(cpi)) {
     vp9_one_pass_cbr_svc_start_layer(cpi);
@@ -7515,6 +7549,7 @@
 
   cpi->td.mb.fp_src_pred = 0;
 #if CONFIG_REALTIME_ONLY
+  (void)encode_frame_result;
   if (cpi->use_svc) {
     SvcEncode(cpi, size, dest, frame_flags);
   } else {
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -913,6 +913,14 @@
   vpx_free(cpi->motion_vector_info);
   cpi->motion_vector_info = NULL;
 }
+
+// This is the c-version counter part of ImageBuffer
+typedef struct IMAGE_BUFFER {
+  int allocated;
+  int plane_width[3];
+  int plane_height[3];
+  uint8_t *plane_buffer[3];
+} IMAGE_BUFFER;
 #endif  // CONFIG_RATE_CTRL
 
 typedef struct ENCODE_FRAME_RESULT {
@@ -924,9 +932,12 @@
   FRAME_COUNTS frame_counts;
   const PARTITION_INFO *partition_info;
   const MOTION_VECTOR_INFO *motion_vector_info;
+  IMAGE_BUFFER coded_frame;
 #endif  // CONFIG_RATE_CTRL
   int quantize_index;
 } ENCODE_FRAME_RESULT;
+
+void vp9_init_encode_frame_result(ENCODE_FRAME_RESULT *encode_frame_result);
 
 void vp9_initialize_enc(void);
 
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -21,6 +21,37 @@
 
 namespace vp9 {
 
+static int get_plane_height(vpx_img_fmt_t img_fmt, int frame_height,
+                            int plane) {
+  assert(plane < 3);
+  if (plane == 0) {
+    return frame_height;
+  }
+  switch (img_fmt) {
+    case VPX_IMG_FMT_I420:
+    case VPX_IMG_FMT_I440:
+    case VPX_IMG_FMT_YV12:
+    case VPX_IMG_FMT_I42016:
+    case VPX_IMG_FMT_I44016: return (frame_height + 1) >> 1;
+    default: return frame_height;
+  }
+}
+
+static int get_plane_width(vpx_img_fmt_t img_fmt, int frame_width, int plane) {
+  assert(plane < 3);
+  if (plane == 0) {
+    return frame_width;
+  }
+  switch (img_fmt) {
+    case VPX_IMG_FMT_I420:
+    case VPX_IMG_FMT_YV12:
+    case VPX_IMG_FMT_I422:
+    case VPX_IMG_FMT_I42016:
+    case VPX_IMG_FMT_I42216: return (frame_width + 1) >> 1;
+    default: return frame_width;
+  }
+}
+
 // TODO(angiebird): Merge this function with vpx_img_plane_width()
 static int img_plane_width(const vpx_image_t *img, int plane) {
   if (plane > 0 && img->x_chroma_shift > 0)
@@ -339,6 +370,70 @@
   }
 }
 
+void output_image_buffer(const ImageBuffer &image_buffer, std::FILE *out_file) {
+  for (int plane = 0; plane < 3; ++plane) {
+    const int w = image_buffer.plane_width[plane];
+    const int h = image_buffer.plane_height[plane];
+    const uint8_t *buf = image_buffer.plane_buffer[plane].get();
+    fprintf(out_file, "%d %d\n", h, w);
+    for (int i = 0; i < w * h; ++i) {
+      fprintf(out_file, "%d ", (int)buf[i]);
+    }
+    fprintf(out_file, "\n");
+  }
+}
+
+static bool init_image_buffer(ImageBuffer *image_buffer, int frame_width,
+                              int frame_height, vpx_img_fmt_t img_fmt) {
+  for (int plane = 0; plane < 3; ++plane) {
+    const int w = get_plane_width(img_fmt, frame_width, plane);
+    const int h = get_plane_height(img_fmt, frame_height, plane);
+    image_buffer->plane_width[plane] = w;
+    image_buffer->plane_height[plane] = h;
+    image_buffer->plane_buffer[plane].reset(new (std::nothrow) uint8_t[w * h]);
+    if (image_buffer->plane_buffer[plane].get() == nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void ImageBuffer_to_IMAGE_BUFFER(const ImageBuffer &image_buffer,
+                                        IMAGE_BUFFER *image_buffer_c) {
+  image_buffer_c->allocated = 1;
+  for (int plane = 0; plane < 3; ++plane) {
+    image_buffer_c->plane_width[plane] = image_buffer.plane_width[plane];
+    image_buffer_c->plane_height[plane] = image_buffer.plane_height[plane];
+    image_buffer_c->plane_buffer[plane] =
+        image_buffer.plane_buffer[plane].get();
+  }
+}
+
+static size_t get_max_coding_data_byte_size(int frame_width, int frame_height) {
+  return frame_width * frame_height * 3;
+}
+
+static bool init_encode_frame_result(EncodeFrameResult *encode_frame_result,
+                                     int frame_width, int frame_height,
+                                     vpx_img_fmt_t img_fmt) {
+  const size_t max_coding_data_byte_size =
+      get_max_coding_data_byte_size(frame_width, frame_height);
+
+  encode_frame_result->coding_data.reset(
+      new (std::nothrow) uint8_t[max_coding_data_byte_size]);
+
+  encode_frame_result->num_rows_4x4 = get_num_unit_4x4(frame_width);
+  encode_frame_result->num_cols_4x4 = get_num_unit_4x4(frame_height);
+  encode_frame_result->partition_info.resize(encode_frame_result->num_rows_4x4 *
+                                             encode_frame_result->num_cols_4x4);
+
+  if (encode_frame_result->coding_data.get() == nullptr) {
+    return false;
+  }
+  return init_image_buffer(&encode_frame_result->coded_frame, frame_width,
+                           frame_height, img_fmt);
+}
+
 static void update_encode_frame_result(
     EncodeFrameResult *encode_frame_result,
     const ENCODE_FRAME_RESULT *encode_frame_info) {
@@ -426,8 +521,6 @@
   impl_ptr_ = std::unique_ptr<EncodeImpl>(new EncodeImpl());
   frame_width_ = frame_width;
   frame_height_ = frame_height;
-  num_rows_4x4_ = get_num_unit_4x4(frame_width);
-  num_cols_4x4_ = get_num_unit_4x4(frame_height);
   frame_rate_num_ = frame_rate_num;
   frame_rate_den_ = frame_rate_den;
   target_bitrate_ = target_bitrate;
@@ -473,6 +566,7 @@
         size_t size;
         unsigned int frame_flags = 0;
         ENCODE_FRAME_RESULT encode_frame_info;
+        vp9_init_encode_frame_result(&encode_frame_info);
         // TODO(angiebird): Call vp9_first_pass directly
         vp9_get_compressed_data(cpi, &frame_flags, &size, NULL, &time_stamp,
                                 &time_end, flush, &encode_frame_info);
@@ -585,32 +679,44 @@
       break;
     }
   }
-  assert(encode_frame_result->coding_data.get() == nullptr);
-  const size_t max_coding_data_byte_size = frame_width_ * frame_height_ * 3;
-  encode_frame_result->coding_data = std::move(
-      std::unique_ptr<uint8_t[]>(new uint8_t[max_coding_data_byte_size]));
-  encode_frame_result->num_rows_4x4 = num_rows_4x4_;
-  encode_frame_result->num_cols_4x4 = num_cols_4x4_;
-  encode_frame_result->partition_info.resize(num_rows_4x4_ * num_cols_4x4_);
-  int64_t time_stamp;
-  int64_t time_end;
-  int flush = 1;  // Make vp9_get_compressed_data encode a frame
-  unsigned int frame_flags = 0;
-  ENCODE_FRAME_RESULT encode_frame_info;
-  vp9_get_compressed_data(cpi, &frame_flags,
-                          &encode_frame_result->coding_data_byte_size,
-                          encode_frame_result->coding_data.get(), &time_stamp,
-                          &time_end, flush, &encode_frame_info);
-  // vp9_get_compressed_data is expected to encode a frame every time, so the
-  // data size should be greater than zero.
-  assert(encode_frame_result->coding_data_byte_size > 0);
-  assert(encode_frame_result->coding_data_byte_size <
-         max_coding_data_byte_size);
 
-  update_encode_frame_result(encode_frame_result, &encode_frame_info);
-  IncreaseGroupOfPictureIndex(&group_of_picture_);
-  if (IsGroupOfPictureFinished(group_of_picture_)) {
-    UpdateGroupOfPicture(impl_ptr_->cpi, &group_of_picture_);
+  if (init_encode_frame_result(encode_frame_result, frame_width_, frame_height_,
+                               impl_ptr_->img_fmt)) {
+    int64_t time_stamp;
+    int64_t time_end;
+    int flush = 1;  // Make vp9_get_compressed_data encode a frame
+    unsigned int frame_flags = 0;
+    ENCODE_FRAME_RESULT encode_frame_info;
+    vp9_init_encode_frame_result(&encode_frame_info);
+    ImageBuffer_to_IMAGE_BUFFER(encode_frame_result->coded_frame,
+                                &encode_frame_info.coded_frame);
+    vp9_get_compressed_data(cpi, &frame_flags,
+                            &encode_frame_result->coding_data_byte_size,
+                            encode_frame_result->coding_data.get(), &time_stamp,
+                            &time_end, flush, &encode_frame_info);
+    // vp9_get_compressed_data is expected to encode a frame every time, so the
+    // data size should be greater than zero.
+    if (encode_frame_result->coding_data_byte_size <= 0) {
+      fprintf(stderr, "Coding data size <= 0\n");
+      abort();
+    }
+    const size_t max_coding_data_byte_size =
+        get_max_coding_data_byte_size(frame_width_, frame_height_);
+    if (encode_frame_result->coding_data_byte_size >
+        max_coding_data_byte_size) {
+      fprintf(stderr, "Coding data size exceeds the maximum.\n");
+      abort();
+    }
+
+    update_encode_frame_result(encode_frame_result, &encode_frame_info);
+    IncreaseGroupOfPictureIndex(&group_of_picture_);
+    if (IsGroupOfPictureFinished(group_of_picture_)) {
+      UpdateGroupOfPicture(impl_ptr_->cpi, &group_of_picture_);
+    }
+  } else {
+    // TODO(angiebird): Clean up encode_frame_result.
+    fprintf(stderr, "init_encode_frame_result() failed.\n");
+    this->EndEncode();
   }
 }
 
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -130,6 +130,17 @@
   NewMotionVectorContextCounts mv;
 };
 
+struct ImageBuffer {
+  // The image data is stored in raster order,
+  // i.e. image[plane][r][c] =
+  // plane_buffer[plane][r * plane_width[plane] + plane_height[plane]].
+  std::unique_ptr<unsigned char[]> plane_buffer[3];
+  int plane_width[3];
+  int plane_height[3];
+};
+
+void output_image_buffer(const ImageBuffer &image_buffer, std::FILE *out_file);
+
 struct EncodeFrameResult {
   int show_idx;
   FrameType frame_type;
@@ -164,6 +175,7 @@
   // Horizontal next: |column_start| + |width|,
   // Vertical next: |row_start| + |height|.
   std::vector<PartitionInfo> partition_info;
+  ImageBuffer coded_frame;
 };
 
 struct GroupOfPicture {
@@ -252,8 +264,6 @@
 
   int frame_width_;   // frame width in pixels.
   int frame_height_;  // frame height in pixels.
-  int num_rows_4x4_;  // number of row units, in size of 4.
-  int num_cols_4x4_;  // number of column units, in size of 4.
   int frame_rate_num_;
   int frame_rate_den_;
   int target_bitrate_;
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -1205,8 +1205,9 @@
       // compute first pass stats
       if (img) {
         int ret;
-        ENCODE_FRAME_RESULT encode_frame_result;
         vpx_codec_cx_pkt_t fps_pkt;
+        ENCODE_FRAME_RESULT encode_frame_result;
+        vp9_init_encode_frame_result(&encode_frame_result);
         // TODO(angiebird): Call vp9_first_pass directly
         ret = vp9_get_compressed_data(cpi, &lib_flags, &size, cx_data,
                                       &dst_time_stamp, &dst_end_time_stamp,
@@ -1229,6 +1230,7 @@
 #endif  // !CONFIG_REALTIME_ONLY
     } else {
       ENCODE_FRAME_RESULT encode_frame_result;
+      vp9_init_encode_frame_result(&encode_frame_result);
       while (cx_data_sz >= ctx->cx_data_sz / 2 &&
              -1 != vp9_get_compressed_data(cpi, &lib_flags, &size, cx_data,
                                            &dst_time_stamp, &dst_end_time_stamp,