Revert "rtpvp8pay: Use GstBitReader instead of dboolhuff implementation from libvpx"

This reverts commit b730e7a1b2.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3300

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6116>
This commit is contained in:
Sebastian Dröge 2024-02-14 15:49:43 +02:00 committed by GStreamer Marge Bot
parent d98c922995
commit 499474a76d
5 changed files with 284 additions and 51 deletions

View file

@ -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.

View file

@ -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;
}

View file

@ -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 <stddef.h>
#include <limits.h>
#include <glib.h>
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

View file

@ -32,6 +32,7 @@
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/video/video.h>
#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 */

View file

@ -1,4 +1,5 @@
rtp_sources = [
'dboolhuff.c',
'fnv1hash.c',
'gstbuffermemory.c',
'gstrtpelement.c',