On 20.12.2011 19:20, Maarten Lankhorst wrote:
Hey Christian,
On 12/20/2011 02:16 PM, Christian König wrote:
Why do you want to change that anyway?
The search for start codes was especially split out of the VLC stuff, because start
codes start are byte aligned anyway and it doesn't make much sense to search for
them using the slower peekbits& fillbits functions.
Since 4 bytes are loaded at a time and bit aligning is fast enough, it's not that
much slower, the reason I want this is to be able to add support for when the
array size is> 1, currently and even with that patch its not handled, but if a
slice is split between multiple buffers you can at least pick up where you left..
Good argument, but we should complete the patch instead of leaving the
code in a condition where we just bail out with an assertion if the
application happens to not behave as we have planned.
for example with mplayer I have observed that the start code 0x00,0x00,0x01
and the actual value are in separate buffers for some codecs, and for wmv the
following is said:
* Some VC-1 advanced profile streams do not contain slice start codes; again,
* the container format must indicate where picture data begins and ends. In
* this case, pictures are assumed to be progressive and to contain a single
* slice. It is highly recommended that applications detect this condition,
* and add the missing start codes to the bitstream passed to VDPAU. However,
* VDPAU implementations must allow bitstreams with missing start codes, and
* act as if a 0x0000010D (frame) start code had been present.
Since mplayer can chop up the start code and the 0x0d, you'd need a parser to
handle this.
I planned on using vlc to detect the lack of start code.
Well, sounds like a plan to me.
The correct sollution would be to let fillbits return a boolean signaling that
the buffer(s) are depleted.
Maybe, I want to start filling from the next stream if this is the case.
Yeah, take a look at the attachment, that's how I implemented it, but
what todo if we don't have any more inputs?
Currently we load up to three extra bytes and then just continue to
pretend that the stream only contains zeros, well on a second though
that isn't so bad after all.
I played around with it a bit today and it seems that the current
behavior is already the best we can do about it.
Adding an interface definition without an implementation usually only
makes sense when we could have more than one different implementation.
As the TODO says, I want to add support for array_size> 1 still, also next patch
uses this interface, even if I didn't add the support for array_size> 1 yet. If I
don't continuously reset vlc it should work correctly even when a stream has multiple
buffers.
Take a look at the attached patch then, that should do it quite well.
- //assert(vlc->valid_bits>= num_bits);
+ assert(vlc->valid_bits>= num_bits || vl_vlc_bits_left(vlc)< num_bits);
Hui? bits_left is calculation the total number of bits left in the buffer,
while valid_bits is the number of currently loaded bits, so that check is
erroneous.
Yes, but if you are near the end of the stream it is possible that peekbits can
extend beyond it when doing vlc decoding, hence the second check.
This is a special case for peekbits that would otherwise crash unnecessarily
over DCT coefficients, any call that really consumes the bits will still fail.
Ah ok, now I understand your intentions. Well then check for "vlc->data
>= vlc->end" instead, since at the end of the stream even
"vl_vlc_bits_left(vlc)< num_bits" will fail ( at least if everything
goes right), and in the middle of a stream it will succeed in the case
when there is a missing fillbits!
On 20.12.2011 21:08, Lucas Stach wrote:
Hi all!
Just jumping in with regard to the assert.
Am Dienstag, den 20.12.2011, 19:20 +0100 schrieb Maarten Lankhorst:
[snip]
return vlc->buffer>> (64 - num_bits);
}
@@ -130,7 +132,7 @@ vl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
static INLINE void
vl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
{
- //assert(vlc->valid_bits> num_bits);
+ assert(vlc->valid_bits>= num_bits);
Just commenting in all checks isn't such a good idea, since that affect
performance very badly, a define which enables all assertions at once at the
beginning of the file seems the better idea.
Sure.
Please don't define your own semantic for this checks. Assert is only
used in debug builds and there it shouldn't matter how it affects
performance. In release builds assert is typically a no-op and therefore
optimized away, but it could also be used to help the compiler optimize
for the asserted conditions.
Asserts should be never deactivated with code defines.
Those functions are called a couple of million times a second, so even
if the assertion is only tested in debug builds it has quite an effect
on performance, sometimes even masquerading real performance problems.
So my practice was to only uncomment them when I work on that part of
the code. I don't want to change the Assert semantics in any way, just a
simple define enabling certain assertions only under certain conditions
should be sufficient.
Christian.
>From b19139fa4b22dc8eebb9b105dd29c7fee88816e5 Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <m.b.lankho...@gmail.com>
Date: Tue, 20 Dec 2011 12:43:23 +0100
Subject: [PATCH] vl: Only initialize vlc once
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
And add more sanity checks to stream. This shouldn't
break things beyond those that aren't broken already.
v2: also implement multiple inputs for the vlc functions
Signed-off-by: Maarten Lankhorst <m.b.lankho...@gmail.com>
Signed-off-by: Christian König <deathsim...@vodafone.de>
---
src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c | 50 +++++-------
src/gallium/auxiliary/vl/vl_vlc.h | 102 ++++++++++++++++++-----
2 files changed, 101 insertions(+), 51 deletions(-)
diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
index 936cf2c..cf75000 100644
--- a/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
+++ b/src/gallium/auxiliary/vl/vl_mpeg12_bitstream.c
@@ -786,7 +786,7 @@ entry:
}
}
-static INLINE bool
+static INLINE void
decode_slice(struct vl_mpg12_bs *bs)
{
struct pipe_mpeg12_macroblock mb;
@@ -800,20 +800,25 @@ decode_slice(struct vl_mpg12_bs *bs)
mb.blocks = dct_blocks;
reset_predictor(bs);
+ vl_vlc_fillbits(&bs->vlc);
dct_scale = quant_scale[bs->desc.q_scale_type][vl_vlc_get_uimsbf(&bs->vlc, 5)];
- if (vl_vlc_get_uimsbf(&bs->vlc, 1))
+ if (vl_vlc_get_uimsbf(&bs->vlc, 1)) {
+ vl_vlc_fillbits(&bs->vlc);
while (vl_vlc_get_uimsbf(&bs->vlc, 9) & 1)
vl_vlc_fillbits(&bs->vlc);
+ }
vl_vlc_fillbits(&bs->vlc);
+ assert(vl_vlc_bits_left(&bs->vlc) > 23 && vl_vlc_peekbits(&bs->vlc, 23));
do {
int inc = 0;
- while (vl_vlc_peekbits(&bs->vlc, 11) == 15) {
- vl_vlc_eatbits(&bs->vlc, 11);
- vl_vlc_fillbits(&bs->vlc);
- }
+ if (bs->decoder->profile == PIPE_VIDEO_PROFILE_MPEG1)
+ while (vl_vlc_peekbits(&bs->vlc, 11) == 15) {
+ vl_vlc_eatbits(&bs->vlc, 11);
+ vl_vlc_fillbits(&bs->vlc);
+ }
while (vl_vlc_peekbits(&bs->vlc, 11) == 8) {
vl_vlc_eatbits(&bs->vlc, 11);
@@ -928,7 +933,6 @@ decode_slice(struct vl_mpg12_bs *bs)
mb.num_skipped_macroblocks = 0;
bs->decoder->decode_macroblock(bs->decoder, &mb.base, 1);
- return true;
}
void
@@ -959,32 +963,20 @@ void
vl_mpg12_bs_decode(struct vl_mpg12_bs *bs, unsigned num_bytes, const uint8_t *buffer)
{
assert(bs);
- assert(buffer && num_bytes);
- while(num_bytes > 2) {
- if (buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x01 &&
- buffer[3] >= 0x01 && buffer[3] < 0xAF) {
- unsigned consumed;
+ vl_vlc_init(&bs->vlc, 1, (const void * const *)&buffer, &num_bytes);
+ while (vl_vlc_bits_left(&bs->vlc) > 32) {
+ uint32_t code = vl_vlc_peekbits(&bs->vlc, 32);
- buffer += 3;
- num_bytes -= 3;
-
- vl_vlc_init(&bs->vlc, buffer, num_bytes);
-
- if (!decode_slice(bs))
- return;
-
- consumed = num_bytes - vl_vlc_bits_left(&bs->vlc) / 8;
-
- /* crap, this is a bug we have consumed more bytes than left in the buffer */
- assert(consumed <= num_bytes);
-
- num_bytes -= consumed;
- buffer += consumed;
+ if (code >= 0x101 && code <= 0x1AF) {
+ vl_vlc_eatbits(&bs->vlc, 24);
+ decode_slice(bs);
+ vl_vlc_bytealign(&bs->vlc);
} else {
- ++buffer;
- --num_bytes;
+ vl_vlc_eatbits(&bs->vlc, 8);
}
+
+ vl_vlc_fillbits(&bs->vlc);
}
}
diff --git a/src/gallium/auxiliary/vl/vl_vlc.h b/src/gallium/auxiliary/vl/vl_vlc.h
index dc4faed..f961b8b 100644
--- a/src/gallium/auxiliary/vl/vl_vlc.h
+++ b/src/gallium/auxiliary/vl/vl_vlc.h
@@ -35,12 +35,22 @@
#include "util/u_math.h"
#include "util/u_pointer.h"
+#if 0
+ #define VL_VLC_DEBUG_ASSERT(x) assert(x)
+#else
+ #define VL_VLC_DEBUG_ASSERT(x) do { } while(0)
+#endif
+
struct vl_vlc
{
uint64_t buffer;
unsigned valid_bits;
- uint32_t *data;
- uint32_t *end;
+ const uint32_t *data;
+ const uint32_t *end;
+
+ unsigned num_inputs;
+ const void *const *inputs;
+ const unsigned *sizes;
};
struct vl_vlc_entry
@@ -60,6 +70,9 @@ vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_v
{
unsigned i, bits = util_logbase2(dst_size);
+ assert(dst && dst_size);
+ assert(src && src_size);
+
for (i=0;i<dst_size;++i) {
dst[i].length = 0;
dst[i].value = 0;
@@ -72,12 +85,36 @@ vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_v
}
static INLINE void
+vl_vlc_next_input(struct vl_vlc *vlc)
+{
+ const uint8_t* data = vlc->inputs[0];
+ unsigned len = vlc->sizes[0];
+
+ VL_VLC_DEBUG_ASSERT(vlc);
+ VL_VLC_DEBUG_ASSERT(vlc->num_inputs);
+
+ /* align the data pointer */
+ while (pointer_to_uintptr(data) & 3) {
+ vlc->buffer |= (uint64_t)*data << (56 - vlc->valid_bits);
+ ++data;
+ --len;
+ vlc->valid_bits += 8;
+ }
+ vlc->data = (const uint32_t*)data;
+ vlc->end = (const uint32_t*)(data + len);
+
+ --vlc->num_inputs;
+ ++vlc->inputs;
+ ++vlc->sizes;
+}
+
+static INLINE void
vl_vlc_fillbits(struct vl_vlc *vlc)
{
- if (vlc->valid_bits < 32) {
- uint32_t value = *vlc->data;
+ VL_VLC_DEBUG_ASSERT(vlc);
- //assert(vlc->data <= vlc->end);
+ if (vlc->valid_bits < 32 && vlc->data < vlc->end) {
+ uint32_t value = *vlc->data;
#ifndef PIPE_ARCH_BIG_ENDIAN
value = util_bswap32(value);
@@ -86,28 +123,40 @@ vl_vlc_fillbits(struct vl_vlc *vlc)
vlc->buffer |= (uint64_t)value << (32 - vlc->valid_bits);
++vlc->data;
vlc->valid_bits += 32;
+
+ /* if this input is depleted, go to next one */
+ if (vlc->data >= vlc->end && vlc->num_inputs) {
+ unsigned bytes_overdue = ((uint8_t*)vlc->data)-((uint8_t*)vlc->end);
+
+ /* adjust valid bits */
+ vlc->valid_bits -= bytes_overdue * 8;
+
+ /* clear not valid bits */
+ vlc->buffer &= ~((1LL << (64 - vlc->valid_bits)) - 1);
+
+ /* go on to next input */
+ vl_vlc_next_input(vlc);
+
+ /* and retry to fill the buffer */
+ vl_vlc_fillbits(vlc);
+ }
}
}
static INLINE void
-vl_vlc_init(struct vl_vlc *vlc, const uint8_t *data, unsigned len)
+vl_vlc_init(struct vl_vlc *vlc, unsigned num_inputs,
+ const void *const *inputs, const unsigned *sizes)
{
assert(vlc);
- assert(data && len);
+ assert(num_inputs);
vlc->buffer = 0;
vlc->valid_bits = 0;
+ vlc->num_inputs = num_inputs;
+ vlc->inputs = inputs;
+ vlc->sizes = sizes;
- /* align the data pointer */
- while (pointer_to_uintptr(data) & 3) {
- vlc->buffer |= (uint64_t)*data << (56 - vlc->valid_bits);
- ++data;
- --len;
- vlc->valid_bits += 8;
- }
- vlc->data = (uint32_t*)data;
- vlc->end = (uint32_t*)(data + len);
-
+ vl_vlc_next_input(vlc);
vl_vlc_fillbits(vlc);
vl_vlc_fillbits(vlc);
}
@@ -115,22 +164,24 @@ vl_vlc_init(struct vl_vlc *vlc, const uint8_t *data, unsigned len)
static INLINE unsigned
vl_vlc_bits_left(struct vl_vlc *vlc)
{
+ unsigned i;
signed bytes_left = ((uint8_t*)vlc->end)-((uint8_t*)vlc->data);
+ for (i = 0; i < vlc->num_inputs; ++i)
+ bytes_left += vlc->sizes[i];
return bytes_left * 8 + vlc->valid_bits;
}
static INLINE unsigned
vl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
{
- //assert(vlc->valid_bits >= num_bits);
-
+ VL_VLC_DEBUG_ASSERT(vlc->valid_bits >= num_bits || vlc->data >= vlc->end);
return vlc->buffer >> (64 - num_bits);
}
static INLINE void
vl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
{
- //assert(vlc->valid_bits > num_bits);
+ VL_VLC_DEBUG_ASSERT(vlc->valid_bits >= num_bits);
vlc->buffer <<= num_bits;
vlc->valid_bits -= num_bits;
@@ -141,7 +192,7 @@ vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
{
unsigned value;
- //assert(vlc->valid_bits >= num_bits);
+ VL_VLC_DEBUG_ASSERT(vlc->valid_bits >= num_bits);
value = vlc->buffer >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
@@ -154,7 +205,7 @@ vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
{
signed value;
- //assert(vlc->valid_bits >= num_bits);
+ VL_VLC_DEBUG_ASSERT(vlc->valid_bits >= num_bits);
value = ((int64_t)vlc->buffer) >> (64 - num_bits);
vl_vlc_eatbits(vlc, num_bits);
@@ -167,7 +218,14 @@ vl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned n
{
tbl += vl_vlc_peekbits(vlc, num_bits);
vl_vlc_eatbits(vlc, tbl->length);
+ VL_VLC_DEBUG_ASSERT(tbl->length);
return tbl->value;
}
+static INLINE void
+vl_vlc_bytealign(struct vl_vlc *vlc)
+{
+ vl_vlc_eatbits(vlc, vlc->valid_bits & 7);
+}
+
#endif /* vl_vlc_h */
--
1.7.5.4
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev