From 499474a76dcbea441dbb57730aa57c42fd9c9817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 14 Feb 2024 15:49:43 +0200 Subject: [PATCH] Revert "rtpvp8pay: Use GstBitReader instead of dboolhuff implementation from libvpx" This reverts commit b730e7a1b28ce4bcea90fbff7c5293fa2c0a76b2. Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3300 Part-of: --- .../gst/rtp/dboolhuff.LICENSE | 29 ++++ .../gst-plugins-good/gst/rtp/dboolhuff.c | 74 +++++++++ .../gst-plugins-good/gst/rtp/dboolhuff.h | 155 ++++++++++++++++++ .../gst-plugins-good/gst/rtp/gstrtpvp8pay.c | 76 +++------ .../gst-plugins-good/gst/rtp/meson.build | 1 + 5 files changed, 284 insertions(+), 51 deletions(-) create mode 100644 subprojects/gst-plugins-good/gst/rtp/dboolhuff.LICENSE create mode 100644 subprojects/gst-plugins-good/gst/rtp/dboolhuff.c create mode 100644 subprojects/gst-plugins-good/gst/rtp/dboolhuff.h diff --git a/subprojects/gst-plugins-good/gst/rtp/dboolhuff.LICENSE b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.LICENSE new file mode 100644 index 0000000000..83e4e6f6d7 --- /dev/null +++ b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/subprojects/gst-plugins-good/gst/rtp/dboolhuff.c b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.c new file mode 100644 index 0000000000..118bd0b978 --- /dev/null +++ b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the dboolhuff.LICENSE file in this directory. + * See the libvpx original distribution for more information, + * including patent information, and author information. + */ + + +#include "dboolhuff.h" + +#ifdef _MSC_VER +__declspec (align (16)) + const unsigned char vp8_norm[256] = { +#else +const unsigned char vp8_norm[256] __attribute__((aligned (16))) = { +#endif + 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int +vp8dx_start_decode (BOOL_DECODER * br, + const unsigned char *source, unsigned int source_sz) +{ + br->user_buffer_end = source + source_sz; + br->user_buffer = source; + br->value = 0; + br->count = -8; + br->range = 255; + + if (source_sz && !source) + return 1; + + /* Populate the buffer */ + vp8dx_bool_decoder_fill (br); + + return 0; +} + + +void +vp8dx_bool_decoder_fill (BOOL_DECODER * br) +{ + const unsigned char *bufptr; + const unsigned char *bufend; + VP8_BD_VALUE value; + int count; + bufend = br->user_buffer_end; + bufptr = br->user_buffer; + value = br->value; + count = br->count; + + VP8DX_BOOL_DECODER_FILL (count, value, bufptr, bufend); + + br->user_buffer = bufptr; + br->value = value; + br->count = count; +} diff --git a/subprojects/gst-plugins-good/gst/rtp/dboolhuff.h b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.h new file mode 100644 index 0000000000..e0a45a2236 --- /dev/null +++ b/subprojects/gst-plugins-good/gst/rtp/dboolhuff.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2010 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the dboolhuff.LICENSE file in this directory. + * See the libvpx original distribution for more information, + * including patent information, and author information. + */ + + +#ifndef DBOOLHUFF_H +#define DBOOLHUFF_H +#include +#include +#include + +typedef size_t VP8_BD_VALUE; + +# define VP8_BD_VALUE_SIZE ((int)sizeof(VP8_BD_VALUE)*CHAR_BIT) +/*This is meant to be a large, positive constant that can still be efficiently + loaded as an immediate (on platforms like ARM, for example). + Even relatively modest values like 100 would work fine.*/ +# define VP8_LOTS_OF_BITS (0x40000000) + +typedef struct +{ + const unsigned char *user_buffer_end; + const unsigned char *user_buffer; + VP8_BD_VALUE value; + int count; + unsigned int range; +} BOOL_DECODER; + +#ifdef _MSC_VER +__declspec(align(16)) extern const unsigned char vp8_norm[256]; +#else +extern const unsigned char vp8_norm[256] __attribute__((aligned(16))); +#endif + +int vp8dx_start_decode(BOOL_DECODER *br, + const unsigned char *source, + unsigned int source_sz); + +void vp8dx_bool_decoder_fill(BOOL_DECODER *br); + +/*The refill loop is used in several places, so define it in a macro to make + sure they're all consistent. + An inline function would be cleaner, but has a significant penalty, because + multiple BOOL_DECODER fields must be modified, and the compiler is not smart + enough to eliminate the stores to those fields and the subsequent reloads + from them when inlining the function.*/ +#define VP8DX_BOOL_DECODER_FILL(_count,_value,_bufptr,_bufend) \ + do \ + { \ + int shift = VP8_BD_VALUE_SIZE - 8 - ((_count) + 8); \ + int loop_end, x; \ + size_t bits_left = ((_bufend)-(_bufptr))*CHAR_BIT; \ + \ + x = shift + CHAR_BIT - bits_left; \ + loop_end = 0; \ + if(x >= 0) \ + { \ + (_count) += VP8_LOTS_OF_BITS; \ + loop_end = x; \ + if(!bits_left) break; \ + } \ + while(shift >= loop_end) \ + { \ + (_count) += CHAR_BIT; \ + (_value) |= (VP8_BD_VALUE)*(_bufptr)++ << shift; \ + shift -= CHAR_BIT; \ + } \ + } \ + while(0) \ + + +static int vp8dx_decode_bool(BOOL_DECODER *br, int probability) { + unsigned int bit = 0; + VP8_BD_VALUE value; + unsigned int split; + VP8_BD_VALUE bigsplit; + int count; + unsigned int range; + + split = 1 + (((br->range - 1) * probability) >> 8); + + if(br->count < 0) + vp8dx_bool_decoder_fill(br); + + value = br->value; + count = br->count; + + bigsplit = (VP8_BD_VALUE)split << (VP8_BD_VALUE_SIZE - 8); + + range = split; + + if (value >= bigsplit) + { + range = br->range - split; + value = value - bigsplit; + bit = 1; + } + + { + register unsigned int shift = vp8_norm[range]; + range <<= shift; + value <<= shift; + count -= shift; + } + br->value = value; + br->count = count; + br->range = range; + + return bit; +} + +static G_GNUC_UNUSED int vp8_decode_value(BOOL_DECODER *br, int bits) +{ + int z = 0; + int bit; + + for (bit = bits - 1; bit >= 0; bit--) + { + z |= (vp8dx_decode_bool(br, 0x80) << bit); + } + + return z; +} + +static G_GNUC_UNUSED int vp8dx_bool_error(BOOL_DECODER *br) +{ + /* Check if we have reached the end of the buffer. + * + * Variable 'count' stores the number of bits in the 'value' buffer, minus + * 8. The top byte is part of the algorithm, and the remainder is buffered + * to be shifted into it. So if count == 8, the top 16 bits of 'value' are + * occupied, 8 for the algorithm and 8 in the buffer. + * + * When reading a byte from the user's buffer, count is filled with 8 and + * one byte is filled into the value buffer. When we reach the end of the + * data, count is additionally filled with VP8_LOTS_OF_BITS. So when + * count == VP8_LOTS_OF_BITS - 1, the user's data has been exhausted. + */ + if ((br->count > VP8_BD_VALUE_SIZE) && (br->count < VP8_LOTS_OF_BITS)) + { + /* We have tried to decode bits after the end of + * stream was encountered. + */ + return 1; + } + + /* No error. */ + return 0; +} +#endif diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtpvp8pay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtpvp8pay.c index 8664b1d548..af055a148a 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtpvp8pay.c +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtpvp8pay.c @@ -32,6 +32,7 @@ #include #include #include "gstrtpelements.h" +#include "dboolhuff.h" #include "gstrtpvp8pay.h" #include "gstrtputils.h" @@ -282,6 +283,7 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer, guint8 tmp8 = 0; guint8 partitions; guint offset; + BOOL_DECODER bc; guint8 *pdata; if (G_UNLIKELY (buffer_size < 3)) @@ -330,57 +332,35 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer, } offset = keyframe ? 10 : 3; - - /* Everything below is actually using some form of arithmetic coding, but as - * all the bits we're interested in are encoded with 50:50 probability - * they're written out as they are and we can just continue using the bit - * reader here */ + vp8dx_start_decode (&bc, data + offset, size - offset); if (keyframe) { /* color space (1 bit) and clamping type (1 bit) */ - if (!gst_bit_reader_skip (&reader, 2)) - goto error; + vp8dx_decode_bool (&bc, 0x80); + vp8dx_decode_bool (&bc, 0x80); } /* segmentation_enabled */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - - if (tmp8) { - guint8 update_mb_segmentation_map; - guint8 update_segment_feature_data; - - if (!gst_bit_reader_get_bits_uint8 (&reader, &update_mb_segmentation_map, - 1)) - goto error; - - if (!gst_bit_reader_get_bits_uint8 (&reader, &update_segment_feature_data, - 1)) - goto error; + if (vp8dx_decode_bool (&bc, 0x80)) { + guint8 update_mb_segmentation_map = vp8dx_decode_bool (&bc, 0x80); + guint8 update_segment_feature_data = vp8dx_decode_bool (&bc, 0x80); if (update_segment_feature_data) { /* skip segment feature mode */ - if (!gst_bit_reader_skip (&reader, 1)) - goto error; + vp8dx_decode_bool (&bc, 0x80); /* quantizer update */ for (i = 0; i < 4; i++) { /* skip flagged quantizer value (7 bits) and sign (1 bit) */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (tmp8) - if (!gst_bit_reader_skip (&reader, 8)) - goto error; + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 8); } /* loop filter update */ for (i = 0; i < 4; i++) { /* skip flagged lf update value (6 bits) and sign (1 bit) */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (tmp8) - if (!gst_bit_reader_skip (&reader, 7)) - goto error; + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 7); } } @@ -388,44 +368,38 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer, /* segment prob update */ for (i = 0; i < 3; i++) { /* skip flagged segment prob */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (!gst_bit_reader_skip (&reader, 8)) - goto error; + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 8); } } } /* skip filter type (1 bit), loop filter level (6 bits) and * sharpness level (3 bits) */ - if (!gst_bit_reader_skip (&reader, 1 + 6 + 3)) - goto error; + vp8_decode_value (&bc, 1); + vp8_decode_value (&bc, 6); + vp8_decode_value (&bc, 3); /* loop_filter_adj_enabled */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (tmp8) { + if (vp8dx_decode_bool (&bc, 0x80)) { /* delta update */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (tmp8) { + if (vp8dx_decode_bool (&bc, 0x80)) { for (i = 0; i < 8; i++) { /* 8 updates, 1 bit indicate whether there is one and if follow by a * 7 bit update */ - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 1)) - goto error; - if (tmp8) - if (!gst_bit_reader_skip (&reader, 7)) - goto error; + if (vp8dx_decode_bool (&bc, 0x80)) + vp8_decode_value (&bc, 7); } } } - if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 2)) + if (vp8dx_bool_error (&bc)) goto error; + tmp8 = vp8_decode_value (&bc, 2); + partitions = 1 << tmp8; /* Check if things are still sensible */ diff --git a/subprojects/gst-plugins-good/gst/rtp/meson.build b/subprojects/gst-plugins-good/gst/rtp/meson.build index ff62067675..000b91d7ef 100644 --- a/subprojects/gst-plugins-good/gst/rtp/meson.build +++ b/subprojects/gst-plugins-good/gst/rtp/meson.build @@ -1,4 +1,5 @@ rtp_sources = [ + 'dboolhuff.c', 'fnv1hash.c', 'gstbuffermemory.c', 'gstrtpelement.c',