Commit 10fea49b authored by Tom Finegan's avatar Tom Finegan

Add LEB128 encode/decode/tests.

BUG=aomedia:1125

Change-Id: I383c752cdd010001e8226ca510097ef693e486bb
parent 696a7c80
......@@ -146,7 +146,8 @@ set(AOM_SOURCES
"${AOM_ROOT}/aom/src/aom_codec.c"
"${AOM_ROOT}/aom/src/aom_decoder.c"
"${AOM_ROOT}/aom/src/aom_encoder.c"
"${AOM_ROOT}/aom/src/aom_image.c")
"${AOM_ROOT}/aom/src/aom_image.c"
"${AOM_ROOT}/aom/src/aom_integer.c")
set(AOM_COMMON_APP_UTIL_SOURCES
"${AOM_ROOT}/args.c"
......
......@@ -39,4 +39,5 @@ API_SRCS-yes += aom_codec.h
API_SRCS-yes += aom_codec.mk
API_SRCS-yes += aom_frame_buffer.h
API_SRCS-yes += aom_image.h
API_SRCS-yes += src/aom_integer.c
API_SRCS-yes += aom_integer.h
......@@ -75,4 +75,28 @@ typedef size_t uintptr_t;
#define NELEMENTS(x) (int)(sizeof(x) / sizeof(x[0]))
#if defined(__cplusplus)
extern "C" {
#endif // __cplusplus
// Returns size of uint32_t when encoded using LEB128.
size_t aom_uleb_size_in_bytes(uint32_t value);
// Returns decoded LEB128 value.
void aom_uleb_decode(const uint8_t *buffer, size_t available, uint32_t *value);
// Encodes LEB128 integer. Returns 0 when successful, and -1 upon failure.
int aom_uleb_encode(uint32_t value, size_t available, uint8_t *coded_value,
size_t *coded_size);
// Encodes LEB128 integer to size specified. Returns 0 when successful, and -1
// upon failure.
int aom_uleb_encode_fixed_size(uint32_t value, size_t available,
size_t pad_to_size, uint8_t *coded_value,
size_t *coded_size);
#if defined(__cplusplus)
} // extern "C"
#endif // __cplusplus
#endif // AOM_AOM_INTEGER_H_
......@@ -16,3 +16,7 @@ text aom_img_plane_width
text aom_img_plane_height
text aom_img_set_rect
text aom_img_wrap
text aom_uleb_decode
text aom_uleb_encode
text aom_uleb_encode_fixed_size
text aom_uleb_size_in_bytes
/*
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "aom/aom_integer.h"
static const size_t kMaximumLeb128Size = 4;
static const size_t kMaximumLeb128Value = 0xFFFFFFF; // 2^28 - 1
static const uint8_t kLeb128ByteMask = 0x7f; // Binary: 01111111
static const uint8_t kLeb128PadByte = 0x80; // Binary: 10000000
size_t aom_uleb_size_in_bytes(uint32_t value) {
size_t size = 0;
do {
++size;
} while ((value >>= 7) != 0);
return size;
}
void aom_uleb_decode(const uint8_t *buffer, size_t available, uint32_t *value) {
if (buffer && value) {
for (size_t i = 0; i < kMaximumLeb128Size && i < available; ++i) {
const uint8_t decoded_byte = *(buffer + i) & kLeb128ByteMask;
*value |= decoded_byte << (i * 7);
}
}
}
int aom_uleb_encode(uint32_t value, size_t available, uint8_t *coded_value,
size_t *coded_size) {
const size_t leb_size = aom_uleb_size_in_bytes(value);
if (value > kMaximumLeb128Value || leb_size > kMaximumLeb128Size ||
leb_size > available || !coded_value || !coded_size) {
return -1;
}
for (size_t i = 0; i < leb_size; ++i) {
uint8_t byte = value & 0x7f;
value >>= 7;
if (value != 0) byte |= 0x80; // Signal that more bytes follow.
*(coded_value + i) = byte;
}
*coded_size = leb_size;
return 0;
}
int aom_uleb_encode_fixed_size(uint32_t value, size_t available,
size_t pad_to_size, uint8_t *coded_value,
size_t *coded_size) {
if (!coded_value || !coded_size || available < pad_to_size ||
aom_uleb_encode(value, available, coded_value, coded_size) != 0) {
return -1;
}
if (pad_to_size != *coded_size) {
if (*coded_size < pad_to_size) {
const size_t num_pad_bytes = pad_to_size - *coded_size;
for (size_t i = 0; i < num_pad_bytes; ++i) {
const size_t offset = *coded_size + i;
*(coded_value + offset) = kLeb128PadByte;
}
*coded_size += num_pad_bytes;
}
}
return 0;
}
/*
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <stdint.h>
#include "aom/aom_integer.h"
#include "gtest/gtest.h"
namespace {
const uint32_t kSizeTestNumValues = 6;
const uint32_t kSizeTestExpectedSizes[kSizeTestNumValues] = {
1, 1, 2, 3, 4, 5
};
const uint32_t kSizeTestInputs[kSizeTestNumValues] = {
0, 0x7f, 0x3fff, 0x1fffff, 0xffffff, 0x10000000
};
} // namespace
TEST(AomLeb128, DecodeTest) {
const size_t num_leb128_bytes = 3;
const uint8_t leb128_bytes[num_leb128_bytes] = { 0xE5, 0x8E, 0x26 };
const uint32_t expected_value = 0x98765; // 624485
uint32_t value = 0;
aom_uleb_decode(&leb128_bytes[0], num_leb128_bytes, &value);
ASSERT_EQ(expected_value, value);
}
TEST(AomLeb128, EncodeTest) {
const uint32_t test_value = 0x98765; // 624485
const uint32_t expected_value = 0x00E58E26;
const size_t kWriteBufferSize = 4;
uint8_t write_buffer[kWriteBufferSize] = { 0 };
size_t bytes_written = 0;
ASSERT_EQ(aom_uleb_encode(test_value, kWriteBufferSize, &write_buffer[0],
&bytes_written),
0);
ASSERT_EQ(bytes_written, 3u);
uint32_t encoded_value = 0;
for (size_t i = 0; i < bytes_written; ++i) {
const int shift = (bytes_written - 1 - i) * 8;
encoded_value |= write_buffer[i] << shift;
}
ASSERT_EQ(expected_value, encoded_value);
}
TEST(AomLeb128, EncDecTest) {
const uint32_t value = 0x98765; // 624485
const size_t kWriteBufferSize = 4;
uint8_t write_buffer[kWriteBufferSize] = { 0 };
size_t bytes_written = 0;
ASSERT_EQ(aom_uleb_encode(value, kWriteBufferSize, &write_buffer[0],
&bytes_written),
0);
ASSERT_EQ(bytes_written, 3u);
uint32_t decoded_value = 0;
aom_uleb_decode(&write_buffer[0], bytes_written, &decoded_value);
ASSERT_EQ(value, decoded_value);
}
TEST(AomLeb128, FixedSizeEncodeTest) {
const uint32_t test_value = 0x0;
const uint32_t expected_value = 0x00808080;
const size_t kWriteBufferSize = 4;
uint8_t write_buffer[kWriteBufferSize] = { 0 };
size_t bytes_written = 0;
ASSERT_EQ(0, aom_uleb_encode_fixed_size(test_value, kWriteBufferSize,
kWriteBufferSize, &write_buffer[0],
&bytes_written));
ASSERT_EQ(kWriteBufferSize, bytes_written);
uint32_t encoded_value = 0;
for (size_t i = 0; i < bytes_written; ++i) {
const int shift = (bytes_written - 1 - i) * 8;
encoded_value |= write_buffer[i] << shift;
}
ASSERT_EQ(expected_value, encoded_value);
}
TEST(AomLeb128, FixedSizeEncDecTest) {
const uint32_t value = 0x1;
const size_t kWriteBufferSize = 4;
uint8_t write_buffer[kWriteBufferSize] = { 0 };
size_t bytes_written = 0;
ASSERT_EQ(
aom_uleb_encode_fixed_size(value, kWriteBufferSize, kWriteBufferSize,
&write_buffer[0], &bytes_written),
0);
ASSERT_EQ(bytes_written, 4u);
uint32_t decoded_value = 0;
aom_uleb_decode(&write_buffer[0], bytes_written, &decoded_value);
ASSERT_EQ(value, decoded_value);
}
TEST(AomLeb128, SizeTest) {
for (size_t i = 0; i < kSizeTestNumValues; ++i) {
ASSERT_EQ(kSizeTestExpectedSizes[i],
aom_uleb_size_in_bytes(kSizeTestInputs[i]));
}
}
......@@ -24,6 +24,7 @@ set(AOM_UNIT_TEST_WRAPPER_SOURCES
set(AOM_UNIT_TEST_COMMON_SOURCES
"${AOM_ROOT}/test/acm_random.h"
"${AOM_ROOT}/test/aom_integer_test.cc"
"${AOM_ROOT}/test/clear_system_state.h"
"${AOM_ROOT}/test/codec_factory.h"
"${AOM_ROOT}/test/decode_test_driver.cc"
......
......@@ -10,6 +10,7 @@
##
LIBAOM_TEST_SRCS-yes += acm_random.h
LIBAOM_TEST_SRCS-yes += aom_integer_test.cc
LIBAOM_TEST_SRCS-yes += clear_system_state.h
LIBAOM_TEST_SRCS-yes += codec_factory.h
LIBAOM_TEST_SRCS-yes += md5_helper.h
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment