Subsampling aware allocs and bitstream
authorJohn Koleszar <jkoleszar@google.com>
Mon, 6 May 2013 22:52:06 +0000 (15:52 -0700)
committerJohn Koleszar <jkoleszar@google.com>
Fri, 10 May 2013 00:50:12 +0000 (17:50 -0700)
Make framebuffer allocations according to the chroma subsamping
factors in use. A bit is placed in the raw part of the frame header for
each of the two subsampling factors. This will be moved in a future
commit to make them part of the TBD feature set bits, probably only set
on keyframes, etc.

Change-Id: I59ed38d3a3c0d4af3c7c277617de28d04a001853

17 files changed:
vp9/common/vp9_alloccommon.c
vp9/common/vp9_blockd.h
vp9/common/vp9_mbpitch.c
vp9/common/vp9_onyxc_int.h
vp9/common/vp9_postproc.c
vp9/decoder/vp9_decodframe.c
vp9/encoder/vp9_bitstream.c
vp9/encoder/vp9_encodeframe.c
vp9/encoder/vp9_firstpass.c
vp9/encoder/vp9_lookahead.c
vp9/encoder/vp9_lookahead.h
vp9/encoder/vp9_onyx_if.c
vp9/vp9_cx_iface.c
vp9/vp9_iface_common.h
vpx_scale/generic/yv12config.c
vpx_scale/yv12config.h
vpxdec.c

index a4120c2..ec81fbd 100644 (file)
@@ -52,10 +52,10 @@ void vp9_free_frame_buffers(VP9_COMMON *oci) {
   int i;
 
   for (i = 0; i < NUM_YV12_BUFFERS; i++)
-    vp8_yv12_de_alloc_frame_buffer(&oci->yv12_fb[i]);
+    vp9_free_frame_buffer(&oci->yv12_fb[i]);
 
-  vp8_yv12_de_alloc_frame_buffer(&oci->temp_scale_frame);
-  vp8_yv12_de_alloc_frame_buffer(&oci->post_proc_buffer);
+  vp9_free_frame_buffer(&oci->temp_scale_frame);
+  vp9_free_frame_buffer(&oci->post_proc_buffer);
 
   vpx_free(oci->mip);
   vpx_free(oci->prev_mip);
@@ -80,8 +80,9 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) {
 
   for (i = 0; i < NUM_YV12_BUFFERS; i++) {
     oci->fb_idx_ref_cnt[i] = 0;
-    if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height,
-                                    VP9BORDERINPIXELS) < 0) {
+    if (vp9_alloc_frame_buffer(&oci->yv12_fb[i], width, height,
+                               oci->subsampling_x, oci->subsampling_y,
+                               VP9BORDERINPIXELS) < 0) {
       vp9_free_frame_buffers(oci);
       return 1;
     }
@@ -98,14 +99,16 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) {
     oci->fb_idx_ref_cnt[i] = 1;
   }
 
-  if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16,
-                                  VP9BORDERINPIXELS) < 0) {
+  if (vp9_alloc_frame_buffer(&oci->temp_scale_frame, width, 16,
+                             oci->subsampling_x, oci->subsampling_y,
+                             VP9BORDERINPIXELS) < 0) {
     vp9_free_frame_buffers(oci);
     return 1;
   }
 
-  if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height,
-                                  VP9BORDERINPIXELS) < 0) {
+  if (vp9_alloc_frame_buffer(&oci->post_proc_buffer, width, height,
+                             oci->subsampling_x, oci->subsampling_y,
+                             VP9BORDERINPIXELS) < 0) {
     vp9_free_frame_buffers(oci);
     return 1;
   }
index b621b0f..ab9e28d 100644 (file)
@@ -692,7 +692,8 @@ static TX_TYPE get_tx_type_16x16(const MACROBLOCKD *xd, int ib) {
   return tx_type;
 }
 
-void vp9_setup_block_dptrs(MACROBLOCKD *xd);
+void vp9_setup_block_dptrs(MACROBLOCKD *xd,
+                           int subsampling_x, int subsampling_y);
 
 static TX_SIZE get_uv_tx_size(const MACROBLOCKD *xd) {
   MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi;
index 8c05a34..d9f892b 100644 (file)
 
 #include "vp9/common/vp9_blockd.h"
 
-void vp9_setup_block_dptrs(MACROBLOCKD *mb) {
+void vp9_setup_block_dptrs(MACROBLOCKD *mb,
+                           int subsampling_x, int subsampling_y) {
   int i;
 
   for (i = 0; i < MAX_MB_PLANE; i++) {
     mb->plane[i].plane_type = i ? PLANE_TYPE_UV : PLANE_TYPE_Y_WITH_DC;
-    mb->plane[i].subsampling_x = !!i;
-    mb->plane[i].subsampling_y = !!i;
+    mb->plane[i].subsampling_x = i ? subsampling_x : 0;
+    mb->plane[i].subsampling_y = i ? subsampling_y : 0;
   }
 }
index 9f0c712..3e8bb15 100644 (file)
@@ -132,6 +132,12 @@ typedef struct VP9Common {
   int last_width;
   int last_height;
 
+  // TODO(jkoleszar): this implies chroma ss right now, but could vary per
+  // plane. Revisit as part of the future change to YV12_BUFFER_CONFIG to
+  // support additional planes.
+  int subsampling_x;
+  int subsampling_y;
+
   YUV_TYPE clr_type;
   CLAMP_TYPE  clamp_type;
 
index f93b74c..f81690a 100644 (file)
@@ -631,13 +631,7 @@ int vp9_post_proc_frame(VP9_COMMON *oci, YV12_BUFFER_CONFIG *dest,
 
   if (!flags) {
     *dest = *oci->frame_to_show;
-
-    /* handle problem with extending borders */
-    dest->y_width = oci->width;
-    dest->y_height = oci->height;
-    dest->uv_height = dest->y_height / 2;
     return 0;
-
   }
 
 #if ARCH_X86||ARCH_X86_64
index 54e06f5..4be3677 100644 (file)
@@ -929,6 +929,8 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) {
     pc->version = (data[0] >> 1) & 7;
     pc->show_frame = (data[0] >> 4) & 1;
     scaling_active = (data[0] >> 5) & 1;
+    pc->subsampling_x = (data[0] >> 6) & 1;
+    pc->subsampling_y = (data[0] >> 7) & 1;
     first_partition_size = read_le16(data + 1);
 
     if (!read_is_valid(data, first_partition_size, data_end))
@@ -961,8 +963,9 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) {
   init_frame(pbi);
 
   // Reset the frame pointers to the current frame size
-  vp8_yv12_realloc_frame_buffer(new_fb, pc->width, pc->height,
-                                VP9BORDERINPIXELS);
+  vp9_realloc_frame_buffer(new_fb, pc->width, pc->height,
+                           pc->subsampling_x, pc->subsampling_y,
+                           VP9BORDERINPIXELS);
 
   if (vp9_reader_init(&header_bc, data, first_partition_size))
     vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
@@ -1073,7 +1076,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) {
     CHECK_MEM_ERROR(pc->last_frame_seg_map,
                     vpx_calloc((pc->mi_rows * pc->mi_cols), 1));
 
-  vp9_setup_block_dptrs(xd);
+  vp9_setup_block_dptrs(xd, pc->subsampling_x, pc->subsampling_y);
 
   // clear out the coeff buffer
   for (i = 0; i < MAX_MB_PLANE; ++i)
index 20154d8..da0bb21 100644 (file)
@@ -1805,6 +1805,8 @@ void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, unsigned long *size) {
     int scaling = (pc->width != pc->display_width ||
                    pc->height != pc->display_height);
     int v = (oh.first_partition_length_in_bytes << 8) |
+            (pc->subsampling_y << 7) |
+            (pc->subsampling_x << 6) |
             (scaling << 5) |
             (oh.show_frame << 4) |
             (oh.version << 1) |
index 49e8cce..418f60e 100644 (file)
@@ -1423,7 +1423,7 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) {
 
   vp9_build_block_offsets(x);
 
-  vp9_setup_block_dptrs(&x->e_mbd);
+  vp9_setup_block_dptrs(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
 
   xd->mode_info_context->mbmi.mode = DC_PRED;
   xd->mode_info_context->mbmi.uv_mode = DC_PRED;
index 1e25a00..ff0725f 100644 (file)
@@ -489,7 +489,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
 
   vp9_build_block_offsets(x);
 
-  vp9_setup_block_dptrs(&x->e_mbd);
+  vp9_setup_block_dptrs(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
 
   vp9_frame_init_quantizer(cpi);
 
index a89d254..708fe45 100644 (file)
@@ -46,7 +46,7 @@ void vp9_lookahead_destroy(struct lookahead_ctx *ctx) {
       unsigned int i;
 
       for (i = 0; i < ctx->max_sz; i++)
-        vp8_yv12_de_alloc_frame_buffer(&ctx->buf[i].img);
+        vp9_free_frame_buffer(&ctx->buf[i].img);
       free(ctx->buf);
     }
     free(ctx);
@@ -56,6 +56,8 @@ void vp9_lookahead_destroy(struct lookahead_ctx *ctx) {
 
 struct lookahead_ctx * vp9_lookahead_init(unsigned int width,
                                           unsigned int height,
+                                          unsigned int subsampling_x,
+                                          unsigned int subsampling_y,
                                           unsigned int depth) {
   struct lookahead_ctx *ctx = NULL;
 
@@ -71,8 +73,9 @@ struct lookahead_ctx * vp9_lookahead_init(unsigned int width,
     if (!ctx->buf)
       goto bail;
     for (i = 0; i < depth; i++)
-      if (vp8_yv12_alloc_frame_buffer(&ctx->buf[i].img,
-                                      width, height, VP9BORDERINPIXELS))
+      if (vp9_alloc_frame_buffer(&ctx->buf[i].img,
+                                 width, height, subsampling_x, subsampling_y,
+                                 VP9BORDERINPIXELS))
         goto bail;
   }
   return ctx;
index 2406618..81baa2c 100644 (file)
@@ -31,6 +31,8 @@ struct lookahead_ctx;
  */
 struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
                                          unsigned int height,
+                                         unsigned int subsampling_x,
+                                         unsigned int subsampling_y,
                                          unsigned int depth);
 
 
index 782816f..58f8fdb 100644 (file)
@@ -313,9 +313,9 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
 
   vp9_free_frame_buffers(&cpi->common);
 
-  vp8_yv12_de_alloc_frame_buffer(&cpi->last_frame_uf);
-  vp8_yv12_de_alloc_frame_buffer(&cpi->scaled_source);
-  vp8_yv12_de_alloc_frame_buffer(&cpi->alt_ref_buffer);
+  vp9_free_frame_buffer(&cpi->last_frame_uf);
+  vp9_free_frame_buffer(&cpi->scaled_source);
+  vp9_free_frame_buffer(&cpi->alt_ref_buffer);
   vp9_lookahead_destroy(cpi->lookahead);
 
   vpx_free(cpi->tok);
@@ -835,15 +835,19 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
 }
 
 static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
+  VP9_COMMON *cm = &cpi->common;
+
   cpi->lookahead = vp9_lookahead_init(cpi->oxcf.width, cpi->oxcf.height,
+                                      cm->subsampling_x, cm->subsampling_y,
                                       cpi->oxcf.lag_in_frames);
   if (!cpi->lookahead)
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate lag buffers");
 
-  if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer,
-                                  cpi->oxcf.width, cpi->oxcf.height,
-                                  VP9BORDERINPIXELS))
+  if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
+                               cpi->oxcf.width, cpi->oxcf.height,
+                               cm->subsampling_x, cm->subsampling_y,
+                               VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate altref buffer");
 }
@@ -873,13 +877,17 @@ void vp9_alloc_compressor_data(VP9_COMP *cpi) {
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate partition data");
 
-  if (vp8_yv12_alloc_frame_buffer(&cpi->last_frame_uf,
-                                  cm->width, cm->height, VP9BORDERINPIXELS))
+  if (vp9_alloc_frame_buffer(&cpi->last_frame_uf,
+                             cm->width, cm->height,
+                             cm->subsampling_x, cm->subsampling_y,
+                             VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate last frame buffer");
 
-  if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source,
-                                  cm->width, cm->height, VP9BORDERINPIXELS))
+  if (vp9_alloc_frame_buffer(&cpi->scaled_source,
+                             cm->width, cm->height,
+                             cm->subsampling_x, cm->subsampling_y,
+                             VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate scaled source buffer");
 
@@ -914,13 +922,17 @@ static void update_frame_size(VP9_COMP *cpi) {
   vp9_update_frame_size(cm);
 
   // Update size of buffers local to this frame
-  if (vp8_yv12_realloc_frame_buffer(&cpi->last_frame_uf,
-                                    cm->width, cm->height, VP9BORDERINPIXELS))
+  if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
+                               cm->width, cm->height,
+                               cm->subsampling_x, cm->subsampling_y,
+                               VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to reallocate last frame buffer");
 
-  if (vp8_yv12_realloc_frame_buffer(&cpi->scaled_source,
-                                    cm->width, cm->height, VP9BORDERINPIXELS))
+  if (vp9_realloc_frame_buffer(&cpi->scaled_source,
+                               cm->width, cm->height,
+                               cm->subsampling_x, cm->subsampling_y,
+                               VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to reallocate scaled source buffer");
 
@@ -1032,6 +1044,9 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
 
   cm->width = oxcf->width;
   cm->height = oxcf->height;
+  cm->subsampling_x = 0;
+  cm->subsampling_y = 0;
+  vp9_alloc_compressor_data(cpi);
 
   // change includes all joint functionality
   vp9_change_config(ptr, oxcf);
@@ -1196,17 +1211,13 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
 
   cm->sharpness_level = cpi->oxcf.Sharpness;
 
-  // Increasing the size of the frame beyond the first seen frame, or some
-  // otherwise signalled maximum size, is not supported.
-  // TODO(jkoleszar): exit gracefully.
-  if (!cpi->initial_width) {
-    alloc_raw_frame_buffers(cpi);
-    vp9_alloc_compressor_data(cpi);
-    cpi->initial_width = cm->width;
-    cpi->initial_height = cm->height;
+  if (cpi->initial_width) {
+    // Increasing the size of the frame beyond the first seen frame, or some
+    // otherwise signalled maximum size, is not supported.
+    // TODO(jkoleszar): exit gracefully.
+    assert(cm->width <= cpi->initial_width);
+    assert(cm->height <= cpi->initial_height);
   }
-  assert(cm->width <= cpi->initial_width);
-  assert(cm->height <= cpi->initial_height);
   update_frame_size(cpi);
 
   if (cpi->oxcf.fixed_q >= 0) {
@@ -2492,9 +2503,10 @@ static void scale_references(VP9_COMP *cpi) {
         ref->y_crop_height != cm->height) {
       int new_fb = get_free_fb(cm);
 
-      vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[new_fb],
-                                    cm->width, cm->height,
-                                    VP9BORDERINPIXELS);
+      vp9_realloc_frame_buffer(&cm->yv12_fb[new_fb],
+                               cm->width, cm->height,
+                               cm->subsampling_x, cm->subsampling_y,
+                               VP9BORDERINPIXELS);
       scale_and_extend_frame(ref, &cm->yv12_fb[new_fb]);
       cpi->scaled_ref_idx[i] = new_fb;
     } else {
@@ -3579,6 +3591,15 @@ int vp9_receive_raw_frame(VP9_PTR ptr, unsigned int frame_flags,
   struct vpx_usec_timer  timer;
   int                    res = 0;
 
+  if (!cpi->initial_width) {
+    // TODO(jkoleszar): Support 1/4 subsampling?
+    cm->subsampling_x = sd->uv_width < sd->y_width;
+    cm->subsampling_y = sd->uv_height < sd->y_height;
+    alloc_raw_frame_buffers(cpi);
+
+    cpi->initial_width = cm->width;
+    cpi->initial_height = cm->height;
+  }
   vpx_usec_timer_start(&timer);
   if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags,
                          cpi->active_map_enabled ? cpi->active_map : NULL))
@@ -3843,9 +3864,10 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
   cm->frame_flags = *frame_flags;
 
   // Reset the frame pointers to the current frame size
-  vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[cm->new_fb_idx],
-                                cm->width, cm->height,
-                                VP9BORDERINPIXELS);
+  vp9_realloc_frame_buffer(&cm->yv12_fb[cm->new_fb_idx],
+                           cm->width, cm->height,
+                           cm->subsampling_x, cm->subsampling_y,
+                           VP9BORDERINPIXELS);
 
   // Calculate scaling factors for each of the 3 available references
   for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i) {
index 1d95eed..45609da 100644 (file)
@@ -211,11 +211,12 @@ static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
   switch (img->fmt) {
     case VPX_IMG_FMT_YV12:
     case VPX_IMG_FMT_I420:
-    case VPX_IMG_FMT_VPXI420:
-    case VPX_IMG_FMT_VPXYV12:
+    case VPX_IMG_FMT_I422:
+    case VPX_IMG_FMT_I444:
       break;
     default:
-      ERROR("Invalid image format. Only YV12 and I420 images are supported");
+      ERROR("Invalid image format. Only YV12, I420, I422, I444 images are "
+            "supported.");
   }
 
   if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h))
@@ -553,14 +554,17 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
   yv12->y_crop_height = img->d_h;
   yv12->y_width  = img->d_w;
   yv12->y_height = img->d_h;
-  yv12->uv_width = (1 + yv12->y_width) / 2;
-  yv12->uv_height = (1 + yv12->y_height) / 2;
+
+  yv12->uv_width = img->x_chroma_shift == 1 ? (1 + yv12->y_width) / 2
+                                            : yv12->y_width;
+  yv12->uv_height = img->y_chroma_shift == 1 ? (1 + yv12->y_height) / 2
+                                             : yv12->y_height;
 
   yv12->y_stride = img->stride[VPX_PLANE_Y];
   yv12->uv_stride = img->stride[VPX_PLANE_U];
 
   yv12->border  = (img->stride[VPX_PLANE_Y] - img->w) / 2;
-  yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 || img->fmt == VPX_IMG_FMT_VPXYV12); // REG_YUV = 0
+  yv12->clrtype = REG_YUV;
   return res;
 }
 
@@ -940,39 +944,7 @@ static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx) {
   }
 
   if (0 == vp9_get_preview_raw_frame(ctx->cpi, &sd, &flags)) {
-
-    /*
-    vpx_img_wrap(&ctx->preview_img, VPX_IMG_FMT_YV12,
-        sd.y_width + 2*VP9BORDERINPIXELS,
-        sd.y_height + 2*VP9BORDERINPIXELS,
-        1,
-        sd.buffer_alloc);
-    vpx_img_set_rect(&ctx->preview_img,
-        VP9BORDERINPIXELS, VP9BORDERINPIXELS,
-        sd.y_width, sd.y_height);
-        */
-
-    ctx->preview_img.bps = 12;
-    ctx->preview_img.planes[VPX_PLANE_Y] = sd.y_buffer;
-    ctx->preview_img.planes[VPX_PLANE_U] = sd.u_buffer;
-    ctx->preview_img.planes[VPX_PLANE_V] = sd.v_buffer;
-
-    if (sd.clrtype == REG_YUV)
-      ctx->preview_img.fmt = VPX_IMG_FMT_I420;
-    else
-      ctx->preview_img.fmt = VPX_IMG_FMT_VPXI420;
-
-    ctx->preview_img.x_chroma_shift = 1;
-    ctx->preview_img.y_chroma_shift = 1;
-
-    ctx->preview_img.d_w = sd.y_width;
-    ctx->preview_img.d_h = sd.y_height;
-    ctx->preview_img.stride[VPX_PLANE_Y] = sd.y_stride;
-    ctx->preview_img.stride[VPX_PLANE_U] = sd.uv_stride;
-    ctx->preview_img.stride[VPX_PLANE_V] = sd.uv_stride;
-    ctx->preview_img.w   = sd.y_width;
-    ctx->preview_img.h   = sd.y_height;
-
+    yuvconfig2image(&ctx->preview_img, &sd, NULL);
     return &ctx->preview_img;
   } else
     return NULL;
index 87d7ca6..96de5f5 100644 (file)
@@ -16,13 +16,24 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG  *yv12,
     * the Y, U, and V planes, nor other alignment adjustments that
     * might be representable by a YV12_BUFFER_CONFIG, so we just
     * initialize all the fields.*/
-  img->fmt = yv12->clrtype == REG_YUV ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420;
+  int bps = 12;
+  if (yv12->uv_height == yv12->y_height) {
+    if (yv12->uv_width == yv12->y_width) {
+      img->fmt = VPX_IMG_FMT_I444;
+      bps = 24;
+    } else {
+      img->fmt = VPX_IMG_FMT_I422;
+      bps = 16;
+    }
+  } else {
+    img->fmt = VPX_IMG_FMT_I420;
+  }
   img->w = yv12->y_stride;
   img->h = multiple16(yv12->y_height + 2 * VP9BORDERINPIXELS);
-  img->d_w = yv12->y_width;
-  img->d_h = yv12->y_height;
-  img->x_chroma_shift = 1;
-  img->y_chroma_shift = 1;
+  img->d_w = yv12->y_crop_width;
+  img->d_h = yv12->y_crop_height;
+  img->x_chroma_shift = yv12->uv_width < yv12->y_width;
+  img->y_chroma_shift = yv12->uv_height < yv12->y_height;
   img->planes[VPX_PLANE_Y] = yv12->y_buffer;
   img->planes[VPX_PLANE_U] = yv12->u_buffer;
   img->planes[VPX_PLANE_V] = yv12->v_buffer;
@@ -31,7 +42,7 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG  *yv12,
   img->stride[VPX_PLANE_U] = yv12->uv_stride;
   img->stride[VPX_PLANE_V] = yv12->uv_stride;
   img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
-  img->bps = 12;
+  img->bps = bps;
   img->user_priv = user_priv;
   img->img_data = yv12->buffer_alloc;
   img->img_data_owner = 0;
index fc7f828..cd66f00 100644 (file)
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-
+#include "./vpx_config.h"
 #include "vpx_scale/yv12config.h"
 #include "vpx_mem/vpx_mem.h"
 
@@ -97,3 +97,89 @@ int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
   }
   return -2;
 }
+
+#if CONFIG_VP9
+// TODO(jkoleszar): Maybe replace this with struct vpx_image
+
+int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
+  if (ybf) {
+    vpx_free(ybf->buffer_alloc);
+
+    /* buffer_alloc isn't accessed by most functions.  Rather y_buffer,
+      u_buffer and v_buffer point to buffer_alloc and are used.  Clear out
+      all of this so that a freed pointer isn't inadvertently used */
+    vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG));
+  } else {
+    return -1;
+  }
+
+  return 0;
+}
+
+int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+                             int width, int height,
+                             int ss_x, int ss_y, int border) {
+  if (ybf) {
+    const int aligned_width = (width + 15) & ~15;
+    const int aligned_height = (height + 15) & ~15;
+    const int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
+    const int yplane_size = (aligned_height + 2 * border) * y_stride;
+    const int uv_width = aligned_width >> ss_x;
+    const int uv_height = aligned_height >> ss_y;
+    const int uv_stride = y_stride >> ss_x;
+    const int uv_border_w = border >> ss_x;
+    const int uv_border_h = border >> ss_y;
+    const int uvplane_size = (uv_height + 2 * uv_border_h) * uv_stride;
+    const int frame_size = yplane_size + 2 * uvplane_size;
+
+    if (!ybf->buffer_alloc) {
+      ybf->buffer_alloc = vpx_memalign(32, frame_size);
+      ybf->buffer_alloc_sz = frame_size;
+    }
+
+    if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size)
+      return -1;
+
+    /* Only support allocating buffers that have a border that's a multiple
+     * of 32. The border restriction is required to get 16-byte alignment of
+     * the start of the chroma rows without intoducing an arbitrary gap
+     * between planes, which would break the semantics of things like
+     * vpx_img_set_rect(). */
+    if (border & 0x1f)
+      return -3;
+
+    ybf->y_crop_width = width;
+    ybf->y_crop_height = height;
+    ybf->y_width  = aligned_width;
+    ybf->y_height = aligned_height;
+    ybf->y_stride = y_stride;
+
+    ybf->uv_width = uv_width;
+    ybf->uv_height = uv_height;
+    ybf->uv_stride = uv_stride;
+
+    ybf->border = border;
+    ybf->frame_size = frame_size;
+
+    ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
+    ybf->u_buffer = ybf->buffer_alloc + yplane_size +
+                    (uv_border_h * uv_stride) + uv_border_w;
+    ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size +
+                    (uv_border_h * uv_stride) + uv_border_w;
+
+    ybf->corrupted = 0; /* assume not currupted by errors */
+    return 0;
+  }
+  return -2;
+}
+
+int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+                           int width, int height,
+                           int ss_x, int ss_y, int border) {
+  if (ybf) {
+    vp9_free_frame_buffer(ybf);
+    return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border);
+  }
+  return -2;
+}
+#endif
index 22df399..85396c0 100644 (file)
@@ -72,6 +72,14 @@ extern "C" {
                                     int width, int height, int border);
   int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf);
 
+  int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+                             int width, int height, int ss_x, int ss_y,
+                             int border);
+  int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+                               int width, int height, int ss_x, int ss_y,
+                               int border);
+  int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
+
 #ifdef __cplusplus
 }
 #endif
index 41c654f..811d41b 100644 (file)
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -12,6 +12,7 @@
 /* This is a simple program that reads ivf files and decodes them
  * using the new interface. Decoded frames are output as YV12 raw.
  */
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -890,6 +891,7 @@ int main(int argc, const char **argv_) {
 
   if (use_y4m && !noblit) {
     char buffer[128];
+
     if (!single_file) {
       fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
               " try --i420 or --yv12.\n");
@@ -907,8 +909,8 @@ int main(int argc, const char **argv_) {
     /*Note: We can't output an aspect ratio here because IVF doesn't
        store one, and neither does VP8.
       That will have to wait until these tools support WebM natively.*/
-    sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n",
-            "420jpeg", width, height, fps_num, fps_den, 'p');
+    snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ",
+             width, height, fps_num, fps_den, 'p');
     out_put(out, (unsigned char *)buffer,
             (unsigned int)strlen(buffer), do_md5);
   }
@@ -1023,6 +1025,17 @@ int main(int argc, const char **argv_) {
       show_progress(frame_in, frame_out, dx_time);
 
     if (!noblit) {
+      if (frame_out == 1 && use_y4m) {
+        /* Write out the color format to terminate the header line */
+        const char *color =
+            img->fmt == VPX_IMG_FMT_444A ? "C444alpha\n" :
+            img->fmt == VPX_IMG_FMT_I444 ? "C444\n" :
+            img->fmt == VPX_IMG_FMT_I422 ? "C422\n" :
+            "C420jpeg\n";
+
+        out_put(out, (const unsigned char*)color, strlen(color), do_md5);
+      }
+
       if (do_scale) {
         if (img && frame_out == 1) {
           stream_w = img->d_w;
@@ -1031,6 +1044,7 @@ int main(int argc, const char **argv_) {
                                      stream_w, stream_h, 16);
         }
         if (img && (img->d_w != stream_w || img->d_h != stream_h)) {
+          assert(img->fmt == VPX_IMG_FMT_I420);
           I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
                     img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
                     img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
@@ -1051,6 +1065,12 @@ int main(int argc, const char **argv_) {
         unsigned int y;
         char out_fn[PATH_MAX];
         uint8_t *buf;
+        unsigned int c_w =
+            img->x_chroma_shift ? (1 + img->d_w) >> img->x_chroma_shift
+                                : img->d_w;
+        unsigned int c_h =
+            img->y_chroma_shift ? (1 + img->d_h) >> img->y_chroma_shift
+                                : img->d_h;
 
         if (!single_file) {
           size_t len = sizeof(out_fn) - 1;
@@ -1071,15 +1091,15 @@ int main(int argc, const char **argv_) {
 
         buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U];
 
-        for (y = 0; y < (1 + img->d_h) / 2; y++) {
-          out_put(out, buf, (1 + img->d_w) / 2, do_md5);
+        for (y = 0; y < c_h; y++) {
+          out_put(out, buf, c_w, do_md5);
           buf += img->stride[VPX_PLANE_U];
         }
 
         buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V];
 
-        for (y = 0; y < (1 + img->d_h) / 2; y++) {
-          out_put(out, buf, (1 + img->d_w) / 2, do_md5);
+        for (y = 0; y < c_h; y++) {
+          out_put(out, buf, c_w, do_md5);
           buf += img->stride[VPX_PLANE_V];
         }