Module: Mesa
Branch: main
Commit: 1782ab4d8bab0b0e1b57a334b8f802bd821421c0
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=1782ab4d8bab0b0e1b57a334b8f802bd821421c0

Author: Dave Airlie <airl...@redhat.com>
Date:   Mon Oct 16 17:44:59 2023 +1000

util: add a bitstream encoder for video stream headers.

This is based on the d3d12 code, and is mostly a rewrite in C,
these are just some helpers to use for writing h264 and h265
headers for vulkan encode.

Acked-by: Hyunjun Ko <zz...@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25874>

---

 src/util/vl_bitstream.h | 204 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 204 insertions(+)

diff --git a/src/util/vl_bitstream.h b/src/util/vl_bitstream.h
new file mode 100644
index 00000000000..11574830818
--- /dev/null
+++ b/src/util/vl_bitstream.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2023 Red Hat
+ * SPDX-License-Identifier: MIT
+ *
+ * This is a C rewrite of pieces of the d3d12 frontend which is:
+ * Copyright © Microsoft Corporation
+ */
+#ifndef VL_BITSTREAM_H
+#define VL_BITSTREAM_H
+
+struct vl_bitstream_encoder {
+   uint8_t *bits;
+   uint32_t bits_buffer_size;
+   uint32_t offset;
+
+   uint32_t enc_buffer;
+
+   int32_t bits_to_go;
+   bool prevent_start_code;
+
+   bool internal_buffer;
+   bool overflow;
+};
+
+#define VL_BITSTREAM_MAX_BUFFER 256
+
+static inline void
+vl_bitstream_encoder_clear(struct vl_bitstream_encoder *enc,
+                           void *buffer_base,
+                           size_t buffer_offset,
+                           size_t buffer_limit)
+{
+   memset(enc, 0, sizeof(*enc));
+   enc->bits_to_go = 32;
+
+   if (!buffer_base) {
+      enc->bits = malloc(VL_BITSTREAM_MAX_BUFFER);
+      enc->bits_buffer_size = VL_BITSTREAM_MAX_BUFFER;
+      enc->internal_buffer = true;
+   } else {
+      enc->bits = (uint8_t *)buffer_base + buffer_offset;
+      enc->bits_buffer_size = buffer_limit;
+   }
+}
+
+static inline void
+vl_bitstream_encoder_free(struct vl_bitstream_encoder *enc)
+{
+   if (enc->internal_buffer)
+      free(enc->bits);
+}
+
+static inline int
+vl_bitstream_get_num_bits_for_byte_align(struct vl_bitstream_encoder *enc)
+{
+   return enc->bits_to_go & 7;
+}
+
+static inline int
+vl_bitstream_get_byte_count(struct vl_bitstream_encoder *enc)
+{
+   return enc->offset + ((32 - enc->bits_to_go) >> 3);
+}
+
+static inline bool
+vl_bitstream_is_byte_aligned(struct vl_bitstream_encoder *enc)
+{
+   if (enc->overflow)
+      enc->bits_to_go = 32;
+   return !(enc->bits_to_go & 7);
+}
+
+static inline void
+vl_bitstream_write_byte_start_code(struct vl_bitstream_encoder *enc, uint8_t 
val)
+{
+   int offset = enc->offset;
+   uint8_t *buffer = enc->bits + enc->offset;
+   if (enc->prevent_start_code && enc->offset > 1) {
+      if (((val & 0xfc) | buffer[-2] | buffer[-1]) == 0) {
+         *buffer++ = 3;
+         offset++;
+      }
+   }
+
+   *buffer = val;
+   offset++;
+   enc->offset = offset;
+}
+
+static inline bool
+vl_bitstream_verify_buffer(struct vl_bitstream_encoder *enc, uint32_t 
bytes_to_write)
+{
+   if (enc->overflow)
+      return false;
+
+   if (enc->offset + bytes_to_write > enc->bits_buffer_size) {
+      enc->overflow = true;
+      return false;
+   }
+   return true;
+}
+
+static inline void
+vl_bitstream_flush(struct vl_bitstream_encoder *enc)
+{
+   ASSERTED bool is_aligned = vl_bitstream_is_byte_aligned(enc);
+   assert (is_aligned);
+
+   uint32_t temp = (uint32_t)(32 - enc->bits_to_go);
+
+   if (!vl_bitstream_verify_buffer(enc, temp >> 3)) {
+      return;
+   }
+
+   while (temp > 0) {
+      vl_bitstream_write_byte_start_code(enc, (uint8_t)(enc->enc_buffer >> 
24));
+      enc->enc_buffer <<= 8;
+      temp -= 8;
+   }
+
+   enc->bits_to_go = 32;
+   enc->enc_buffer = 0;
+}
+
+static inline void
+vl_bitstream_put_bits(struct vl_bitstream_encoder *enc, int bits_count, 
uint32_t bits_val)
+{
+   if (bits_count < enc->bits_to_go) {
+      enc->enc_buffer |= (bits_val << (enc->bits_to_go - bits_count));
+      enc->bits_to_go -= bits_count;
+   } else if (vl_bitstream_verify_buffer(enc, 4)) {
+      int left_over_bits = bits_count - enc->bits_to_go;
+      enc->enc_buffer |= (bits_val >> left_over_bits);
+
+      {
+         uint8_t *temp = (uint8_t *)&enc->enc_buffer;
+         vl_bitstream_write_byte_start_code(enc, *(temp + 3));
+         vl_bitstream_write_byte_start_code(enc, *(temp + 2));
+         vl_bitstream_write_byte_start_code(enc, *(temp + 1));
+         vl_bitstream_write_byte_start_code(enc, *temp);
+      }
+
+      enc->enc_buffer = 0;
+      enc->bits_to_go = 32 - left_over_bits;
+
+      if (left_over_bits > 0)
+         enc->enc_buffer = (bits_val << (32 - left_over_bits));
+   }
+}
+
+static inline int
+vl_bitstream_get_exp_golomb0_code_len(uint32_t val)
+{
+   int len = 0;
+   val++;
+
+   if (val >= 0x10000) {
+      val >>= 16;
+      len += 16;
+   }
+   if (val >= 0x100) {
+      val >>= 8;
+      len += 8;
+   }
+   assert(val < 256);
+
+   return len + util_logbase2(val);
+}
+
+static inline void
+vl_bitstream_exp_golomb_ue(struct vl_bitstream_encoder *enc, uint32_t val)
+{
+   if (val != UINT32_MAX) {
+      int len = vl_bitstream_get_exp_golomb0_code_len(val);
+      vl_bitstream_put_bits(enc, (len << 1) + 1, val + 1);
+   } else {
+      vl_bitstream_put_bits(enc, 32, 0);
+      vl_bitstream_put_bits(enc, 1, 1);
+      vl_bitstream_put_bits(enc, 32, 1);
+   }
+}
+
+static inline void
+vl_bitstream_exp_golomb_se(struct vl_bitstream_encoder *enc, uint32_t val)
+{
+   if (val > 0)
+      vl_bitstream_exp_golomb_ue(enc, (val << 1) - 1);
+   else
+      vl_bitstream_exp_golomb_ue(enc, ((-val) << 1) - (val == INT_MIN));
+}
+
+static inline void
+vl_bitstream_rbsp_trailing(struct vl_bitstream_encoder *enc)
+{
+   vl_bitstream_put_bits(enc, 1, 1);
+   int left = vl_bitstream_get_num_bits_for_byte_align(enc);
+
+   if (left)
+      vl_bitstream_put_bits(enc, left, 0);
+
+   ASSERTED bool is_aligned = vl_bitstream_is_byte_aligned(enc);
+   assert(is_aligned);
+}
+#endif

Reply via email to