shithub: libvpx

Download patch

ref: 7460798ba5666e25258a05f1dc7ad462cb3f1b19
parent: 612104bb8dd3b40a635deebaca445f00aa069220
author: Ronald S. Bultje <[email protected]>
date: Wed Sep 30 12:42:59 EDT 2015

vp10: use superframe marker index/size mechanism for tile size.

See issue 1042. Should provide slight bitstream savings in most cases
where tiles are being used.

Change-Id: Ie2808cf8ef30b3efe50804396900c4d63a3fa026

--- a/vp10/common/onyxc_int.h
+++ b/vp10/common/onyxc_int.h
@@ -279,6 +279,7 @@
   int error_resilient_mode;
 
   int log2_tile_cols, log2_tile_rows;
+  int tile_sz_mag;
   int byte_alignment;
   int skip_loop_filter;
 
--- a/vp10/decoder/decodeframe.c
+++ b/vp10/decoder/decodeframe.c
@@ -1370,6 +1370,15 @@
   cm->log2_tile_rows = vpx_rb_read_bit(rb);
   if (cm->log2_tile_rows)
     cm->log2_tile_rows += vpx_rb_read_bit(rb);
+
+#if CONFIG_MISC_FIXES
+  // tile size magnitude
+  if (cm->log2_tile_rows > 0 || cm->log2_tile_cols > 0) {
+    cm->tile_sz_mag = vpx_rb_read_literal(rb, 2);
+  }
+#else
+  cm->tile_sz_mag = 3;
+#endif
 }
 
 typedef struct TileBuffer {
@@ -1378,10 +1387,27 @@
   int col;  // only used with multi-threaded decoding
 } TileBuffer;
 
+static int mem_get_varsize(const uint8_t *data, const int mag) {
+  switch (mag) {
+    case 0:
+      return data[0];
+    case 1:
+      return mem_get_le16(data);
+    case 2:
+      return mem_get_le24(data);
+    case 3:
+      return mem_get_le32(data);
+  }
+
+  assert("Invalid tile size marker value" && 0);
+
+  return -1;
+}
+
 // Reads the next tile returning its size and adjusting '*data' accordingly
 // based on 'is_last'.
 static void get_tile_buffer(const uint8_t *const data_end,
-                            int is_last,
+                            const int tile_sz_mag, int is_last,
                             struct vpx_internal_error_info *error_info,
                             const uint8_t **data,
                             vpx_decrypt_cb decrypt_cb, void *decrypt_state,
@@ -1395,12 +1421,12 @@
 
     if (decrypt_cb) {
       uint8_t be_data[4];
-      decrypt_cb(decrypt_state, *data, be_data, 4);
-      size = mem_get_be32(be_data);
+      decrypt_cb(decrypt_state, *data, be_data, tile_sz_mag + 1);
+      size = mem_get_varsize(be_data, tile_sz_mag);
     } else {
-      size = mem_get_be32(*data);
+      size = mem_get_varsize(*data, tile_sz_mag);
     }
-    *data += 4;
+    *data += tile_sz_mag + 1;
 
     if (size > (size_t)(data_end - *data))
       vpx_internal_error(error_info, VPX_CODEC_CORRUPT_FRAME,
@@ -1426,7 +1452,8 @@
       const int is_last = (r == tile_rows - 1) && (c == tile_cols - 1);
       TileBuffer *const buf = &tile_buffers[r][c];
       buf->col = c;
-      get_tile_buffer(data_end, is_last, &pbi->common.error, &data,
+      get_tile_buffer(data_end, pbi->common.tile_sz_mag,
+                      is_last, &pbi->common.error, &data,
                       pbi->decrypt_cb, pbi->decrypt_state, buf);
     }
   }
--- a/vp10/encoder/bitstream.c
+++ b/vp10/encoder/bitstream.c
@@ -940,7 +940,8 @@
   }
 }
 
-static size_t encode_tiles(VP10_COMP *cpi, uint8_t *data_ptr) {
+static size_t encode_tiles(VP10_COMP *cpi, uint8_t *data_ptr,
+                           unsigned int *max_tile_sz) {
   VP10_COMMON *const cm = &cpi->common;
   vpx_writer residual_bc;
   int tile_row, tile_col;
@@ -948,6 +949,7 @@
   size_t total_size = 0;
   const int tile_cols = 1 << cm->log2_tile_cols;
   const int tile_rows = 1 << cm->log2_tile_rows;
+  unsigned int max_tile = 0;
 
   memset(cm->above_seg_context, 0,
          sizeof(*cm->above_seg_context) * mi_cols_aligned_to_sb(cm->mi_cols));
@@ -971,7 +973,8 @@
       vpx_stop_encode(&residual_bc);
       if (tile_col < tile_cols - 1 || tile_row < tile_rows - 1) {
         // size of this tile
-        mem_put_be32(data_ptr + total_size, residual_bc.pos);
+        mem_put_le32(data_ptr + total_size, residual_bc.pos);
+        max_tile = max_tile > residual_bc.pos ? max_tile : residual_bc.pos;
         total_size += 4;
       }
 
@@ -978,6 +981,7 @@
       total_size += residual_bc.pos;
     }
   }
+  *max_tile_sz = max_tile;
 
   return total_size;
 }
@@ -1278,15 +1282,62 @@
   return header_bc.pos;
 }
 
-void vp10_pack_bitstream(VP10_COMP *cpi, uint8_t *dest, size_t *size) {
+#if CONFIG_MISC_FIXES
+static int remux_tiles(uint8_t *dest, const int sz,
+                       const int n_tiles, const int mag) {
+  int rpos = 0, wpos = 0, n;
+
+  for (n = 0; n < n_tiles; n++) {
+    int tile_sz;
+
+    if (n == n_tiles - 1) {
+      tile_sz = sz - rpos;
+    } else {
+      tile_sz = mem_get_le32(&dest[rpos]);
+      rpos += 4;
+      switch (mag) {
+        case 0:
+          dest[wpos] = tile_sz;
+          break;
+        case 1:
+          mem_put_le16(&dest[wpos], tile_sz);
+          break;
+        case 2:
+          mem_put_le24(&dest[wpos], tile_sz);
+          break;
+        case 3:  // remuxing should only happen if mag < 3
+        default:
+          assert("Invalid value for tile size magnitude" && 0);
+      }
+      wpos += mag + 1;
+    }
+
+    memmove(&dest[wpos], &dest[rpos], tile_sz);
+    wpos += tile_sz;
+    rpos += tile_sz;
+  }
+
+  assert(rpos > wpos);
+  assert(rpos == sz);
+
+  return wpos;
+}
+#endif
+
+void vp10_pack_bitstream(VP10_COMP *const cpi, uint8_t *dest, size_t *size) {
+  VP10_COMMON *const cm = &cpi->common;
   uint8_t *data = dest;
   size_t first_part_size, uncompressed_hdr_size;
   struct vpx_write_bit_buffer wb = {data, 0};
   struct vpx_write_bit_buffer saved_wb;
+  unsigned int max_tile, data_sz;
+  const int n_log2_tiles = cm->log2_tile_rows + cm->log2_tile_cols;
+  const int have_tiles = n_log2_tiles > 0;
 
   write_uncompressed_header(cpi, &wb);
   saved_wb = wb;
-  vpx_wb_write_literal(&wb, 0, 16);  // don't know in advance first part. size
+  // don't know in advance first part. size
+  vpx_wb_write_literal(&wb, 0, 16 + have_tiles * 2);
 
   uncompressed_hdr_size = vpx_wb_bytes_written(&wb);
   data += uncompressed_hdr_size;
@@ -1295,10 +1346,32 @@
 
   first_part_size = write_compressed_header(cpi, data);
   data += first_part_size;
+
+  data_sz = encode_tiles(cpi, data, &max_tile);
+#if CONFIG_MISC_FIXES
+  if (max_tile > 0) {
+    int mag;
+    unsigned int mask;
+
+    // Choose the (tile size) magnitude
+    for (mag = 0, mask = 0xff; mag < 4; mag++) {
+      if (max_tile <= mask)
+        break;
+      mask <<= 8;
+      mask |= 0xff;
+    }
+    assert(n_log2_tiles > 0);
+    vpx_wb_write_literal(&saved_wb, mag, 2);
+    if (mag < 3)
+      data_sz = remux_tiles(data, data_sz, 1 << n_log2_tiles, mag);
+  } else {
+    assert(n_log2_tiles == 0);
+  }
+#endif
+  data += data_sz;
+
   // TODO(jbb): Figure out what to do if first_part_size > 16 bits.
   vpx_wb_write_literal(&saved_wb, (int)first_part_size, 16);
-
-  data += encode_tiles(cpi, data);
 
   *size = data - dest;
 }