├── Makefile ├── README.md ├── test.cpp ├── LICENSE ├── memory.h ├── version.h ├── memory.cpp ├── bitstream.h ├── cabac.h ├── math.h ├── base.h ├── bitstream.cpp └── cabac.cpp /Makefile: -------------------------------------------------------------------------------- 1 | abac-test: 2 | g++ test.cpp bitstream.cpp cabac.cpp memory.cpp -O3 -o abac-test 3 | debug: 4 | g++ test.cpp bitstream.cpp cabac.cpp memory.cpp -DDEBUG -Wall -g -o abac-test 5 | clean: 6 | rm -f abac-test 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adaptive Arithmetic Coder 2 | Context adaptive binary arithmetic coding, often abbreviated as CABAC, is an essential part of modern video compression. It performs lossless compression of a binary data stream without any prior knowledge of the particular characteristics of the data. These features make it an attractive algorithm for video compression because it is simple, effective and requires no prior (or side band) communication between a client and server. 3 | 4 | This project is a simple implementation of an adaptive binary arithmetic coder that supports block and stream based coding. 5 | 6 | For more information, check out 'Context Adaptive Binary Arithmetic Coding' on my blog at http://www.bertolami.com. 7 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "cabac.h" 3 | #include "math.h" 4 | 5 | using namespace evx; 6 | 7 | uint8 test_kernel(uint8 value) 8 | { 9 | return value % 4; 10 | } 11 | 12 | void test_basic_cabac_rt() 13 | { 14 | entropy_coder coder; 15 | bitstream a((uint32) 512); 16 | bitstream b((uint32) 512); 17 | bitstream c((uint32) 512); 18 | 19 | for (uint8 i = 0; i < 32; ++i) 20 | { 21 | a.write_byte(test_kernel(i)); 22 | } 23 | 24 | uint16 raw_size = a.query_occupancy(); 25 | evx_msg("raw size: %i bits", raw_size); 26 | 27 | if (raw_size != (32 << 3)) 28 | { 29 | evx_err("Failed to write data to the source bitstream."); 30 | return; 31 | } 32 | 33 | coder.encode(&a, &b); 34 | evx_msg("encoded size: %i bits", b.query_occupancy()); 35 | coder.decode(raw_size, &b, &c); 36 | 37 | for (uint8 i = 0; i < c.query_byte_occupancy(); ++i) 38 | { 39 | if (test_kernel(i) != c.query_data()[i]) 40 | { 41 | evx_err("Data integrity check failure."); 42 | return; 43 | } 44 | } 45 | 46 | evx_msg("test completed successfully."); 47 | } 48 | 49 | int main() 50 | { 51 | test_basic_cabac_rt(); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, ramenhut 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2015 Joe Bertolami. All Right Reserved. 5 | // 6 | // math.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EV_MEMORY_H__ 36 | #define __EV_MEMORY_H__ 37 | 38 | #include "base.h" 39 | 40 | namespace evx { 41 | 42 | uint32 aligned_bit_copy(uint8 *dest, uint32 dest_bit_offset, uint8 *source, uint32 source_bit_offset, uint32 copy_bit_count); 43 | 44 | uint32 unaligned_bit_copy(uint8 *dest, uint32 dest_offset, uint8 *source, uint32 source_offset, uint32 copy_bit_count); 45 | 46 | } // namespace evx 47 | 48 | #endif // __EV_MEMORY_H__ -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2015 Joe Bertolami. All Right Reserved. 5 | // 6 | // version.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EVX_VERSION_H__ 36 | #define __EVX_VERSION_H__ 37 | 38 | #define EVX_VERSION_MAJOR 1 // auto-gen, do not modify! 39 | #define EVX_VERSION_MINOR 29 // auto-gen, do not modify! 40 | #define EVX_VERSION_CHANGELIST 30 // auto-gen, do not modify! 41 | 42 | #define EVX_VERSION_WORD(major, minor) ((((major) & 0xFF) << 8) | ((minor) & 0xFF)) 43 | #define EVX_MAJOR_VERSION(x) (((x) >> 8) & 0xFF) 44 | #define EVX_MINOR_VERSION(x) ((x) & 0xFF) 45 | 46 | #endif // __EVX_VERSION_H__ -------------------------------------------------------------------------------- /memory.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "memory.h" 3 | #include "math.h" 4 | 5 | namespace evx { 6 | 7 | uint32 aligned_bit_copy(uint8 *dest, uint32 dest_bit_offset, uint8 *source, uint32 source_bit_offset, uint32 copy_bit_count) 8 | { 9 | if (EVX_PARAM_CHECK) 10 | { 11 | if (!dest || !source || 12 | 0 != (dest_bit_offset % 8) || 13 | 0 != (source_bit_offset % 8) || 14 | 0 == (copy_bit_count >> 3)) 15 | { 16 | evx_post_error(EVX_ERROR_INVALIDARG); 17 | return 0; 18 | } 19 | } 20 | 21 | uint32 dest_byte_offset = dest_bit_offset >> 3; 22 | uint32 source_byte_offset = source_bit_offset >> 3; 23 | uint32 bytes_copied = copy_bit_count >> 3; 24 | 25 | memcpy(dest + dest_byte_offset, source + source_byte_offset, bytes_copied); 26 | 27 | return (bytes_copied << 3); 28 | } 29 | 30 | uint32 unaligned_bit_copy( uint8 *dest, uint32 dest_offset, uint8 *source, uint32 source_offset, uint32 copy_bit_count ) 31 | { 32 | if (EVX_PARAM_CHECK) 33 | { 34 | if (!dest || 0 == copy_bit_count || !source) 35 | { 36 | evx_post_error(EVX_ERROR_INVALIDARG); 37 | return 0; 38 | } 39 | } 40 | 41 | uint32 source_copy_limit = source_offset + copy_bit_count; 42 | 43 | /* Perform an unaligned copy of our data. */ 44 | while (source_offset < source_copy_limit) 45 | { 46 | uint32 target_byte = dest_offset >> 3; 47 | uint8 target_bit = dest_offset % 8; 48 | uint32 source_byte = source_offset >> 3; 49 | uint8 source_bit = source_offset % 8; 50 | uint32 bits_left = source_copy_limit - source_offset; 51 | 52 | /* We traverse our buffer and perform copies in as large of increments as possible. */ 53 | uint8 write_capacity = evx_min2(8 - target_bit, 8 - source_bit); 54 | uint8 write_count = evx_min2(write_capacity, bits_left); 55 | uint8 write_fill_mask = (0x1 << write_count) - 1; 56 | 57 | uint8 *target_data = &(dest[target_byte]); 58 | uint8 *source_data = &(source[source_byte]); 59 | 60 | *target_data = (*target_data & ~(write_fill_mask << target_bit)); 61 | *target_data |= ((*source_data & (write_fill_mask << source_bit)) >> source_bit) << target_bit; 62 | 63 | source_offset += write_count; 64 | dest_offset += write_count; 65 | } 66 | 67 | return copy_bit_count; 68 | } 69 | 70 | } // namespace evx -------------------------------------------------------------------------------- /bitstream.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2015 Joe Bertolami. All Right Reserved. 5 | // 6 | // bitstream.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EVX_BIT_STREAM_H__ 36 | #define __EVX_BIT_STREAM_H__ 37 | 38 | #include "base.h" 39 | 40 | #define EVX_READ_BIT(source, bit) (((source) >> (bit)) & 0x1) 41 | #define EVX_WRITE_BIT(dest, bit, value) (dest) = (((dest) & ~(0x1 << (bit))) | \ 42 | (((value) & 0x1) << (bit))) 43 | namespace evx { 44 | 45 | class bitstream 46 | { 47 | uint32 read_index; 48 | uint32 write_index; 49 | uint32 data_capacity; 50 | uint8 *data_store; 51 | 52 | public: 53 | 54 | bitstream(); 55 | bitstream(uint32 size); 56 | bitstream(void *bytes, uint32 size); 57 | virtual ~bitstream(); 58 | 59 | uint8 *query_data() const; 60 | uint32 query_capacity() const; 61 | uint32 query_occupancy() const; 62 | uint32 query_byte_occupancy() const; 63 | uint32 resize_capacity(uint32 size_in_bits); 64 | 65 | /* seek will only adjust the read index. there is purposely 66 | no way to adjust the write index. */ 67 | evx_status seek(uint32 bit_offset); 68 | evx_status assign(const bitstream &rvalue); 69 | evx_status assign(void *bytes, uint32 size); 70 | 71 | void clear(); 72 | void empty(); 73 | 74 | bool is_empty() const; 75 | bool is_full() const; 76 | 77 | evx_status write_byte(uint8 value); 78 | evx_status write_bit(uint8 value); 79 | evx_status write_bytes(void *data, uint32 byte_count); 80 | evx_status write_bits(void *data, uint32 bit_count); 81 | 82 | evx_status read_byte(void *data); 83 | evx_status read_bit(void *data); 84 | evx_status read_bytes(void *data, uint32 *byte_count); 85 | evx_status read_bits(void *data, uint32 *bit_count); 86 | 87 | private: 88 | 89 | EVX_DISABLE_COPY_AND_ASSIGN(bitstream); 90 | }; 91 | 92 | } // namespace EVX 93 | 94 | #endif // __EVX_BIT_STREAM_H__ 95 | -------------------------------------------------------------------------------- /cabac.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2015 Joe Bertolami. All Right Reserved. 5 | // 6 | // cabac.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EV_CABAC_H__ 36 | #define __EV_CABAC_H__ 37 | 38 | #include "bitstream.h" 39 | 40 | /* 41 | // Entropy Stream Interface 42 | // 43 | // There are two ways to use this interface: 44 | // 45 | // o: Stream coding 46 | // 47 | // To code an entire stream at once, call Encode()/Decode(). This will instruct 48 | // the coder to initialize itself, perform the coding operation, perform a flush 49 | // if necessary, and clear its internal state. 50 | // 51 | // o: Incremental coding 52 | // 53 | // To incrementally code one or more symbols at a time, you must pass FALSE as the 54 | // optional parameter to Encode and Decode. Additionally, you must call FinishEncode() 55 | // after all encode operations are complete, and StartDecode prior to calling the first 56 | // Decode(). This process allows the coder to properly initialize, flush, and reset itself. 57 | */ 58 | 59 | namespace evx { 60 | 61 | class entropy_coder 62 | { 63 | bool adaptive; 64 | uint32 e3_count; 65 | uint32 history[2]; 66 | uint32 value; 67 | 68 | uint32 model; 69 | uint32 low; 70 | uint32 high; 71 | uint32 mid; 72 | 73 | private: 74 | 75 | void resolve_model(); 76 | 77 | evx_status flush_encoder(bitstream *dest); 78 | evx_status flush_inverse_bits(uint8 value, bitstream *dest); 79 | 80 | evx_status encode_symbol(uint8 value); 81 | evx_status decode_symbol(uint32 value, bitstream *dest); 82 | 83 | evx_status resolve_encode_scaling(bitstream *dest); 84 | evx_status resolve_decode_scaling(uint32 *value, bitstream *source, bitstream *dest); 85 | 86 | public: 87 | 88 | entropy_coder(); 89 | explicit entropy_coder(uint32 input_model); 90 | void clear(); 91 | 92 | evx_status encode(bitstream *source, bitstream *dest, bool auto_finish=true); 93 | evx_status decode(uint32 symbol_count, bitstream *source, bitstream *dest, bool auto_start=true); 94 | 95 | evx_status start_decode(bitstream *source); 96 | evx_status finish_encode(bitstream *dest); 97 | 98 | private: 99 | 100 | EVX_DISABLE_COPY_AND_ASSIGN(entropy_coder); 101 | }; 102 | 103 | } // namespace EVX 104 | 105 | #endif // __EVX_CABAC_H__ -------------------------------------------------------------------------------- /math.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2015 Joe Bertolami. All Right Reserved. 5 | // 6 | // math.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EV_MATH_H__ 36 | #define __EV_MATH_H__ 37 | 38 | #include "base.h" 39 | 40 | #define EVX_KB ((uint32) 1024) 41 | #define EVX_MB (EVX_KB * EVX_KB) 42 | #define EVX_GB (EVX_MB * EVX_KB) 43 | 44 | #define EVX_MAX_INT64 (0x7FFFFFFFFFFFFFFF) 45 | #define EVX_MAX_INT32 (0x7FFFFFFF) 46 | #define EVX_MAX_INT16 (0x7FFF) 47 | #define EVX_MAX_INT8 (0x7F) 48 | 49 | #define EVX_MAX_UINT64 (0xFFFFFFFFFFFFFFFF) 50 | #define EVX_MAX_UINT32 (0xFFFFFFFF) 51 | #define EVX_MAX_UINT16 (0xFFFF) 52 | #define EVX_MAX_UINT8 (0xFF) 53 | 54 | #define EVX_MIN_INT64 (-EVX_MAX_INT64 - 1) 55 | #define EVX_MIN_INT32 (-EVX_MAX_INT32 - 1) 56 | #define EVX_MIN_INT16 (-EVX_MAX_INT16 - 1) 57 | #define EVX_MIN_INT8 (-EVX_MAX_INT8 - 1) 58 | 59 | #define evx_min2( a, b ) ((a) < (b) ? (a) : (b)) 60 | #define evx_max2( a, b ) ((a) > (b) ? (a) : (b)) 61 | #define evx_min3( a, b, c ) ((c) < (a) ? ((c) < (b) ? (c) : (b)) : (a) < (b) ? (a) : (b)) 62 | #define evx_max3( a, b, c ) ((c) > (a) ? ((c) > (b) ? (c) : (b)) : (a) > (b) ? (a) : (b)) 63 | 64 | namespace evx { 65 | 66 | const uint8 log2_byte_lut[] = { 67 | 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 68 | 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 69 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 70 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 71 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 72 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 73 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 74 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 75 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 76 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 77 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 78 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 79 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 80 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 81 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 82 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 83 | }; 84 | 85 | inline uint8 log2(uint8 value) 86 | { 87 | return log2_byte_lut[value]; 88 | } 89 | 90 | inline uint8 log2(uint16 value) 91 | { 92 | if (value <= 0xFF) 93 | { 94 | return log2((uint8) value); 95 | } 96 | 97 | return 8 + log2((uint8) (value >> 8)); 98 | } 99 | 100 | inline uint8 log2(uint32 value) 101 | { 102 | if (value <= 0xFFFF) 103 | { 104 | return log2((uint16) value); 105 | } 106 | 107 | return 16 + log2((uint16) (value >> 16)); 108 | } 109 | 110 | inline int8 abs(int8 value) 111 | { 112 | if (value == EVX_MIN_INT8) 113 | return EVX_MAX_INT8; 114 | 115 | return (value < 0 ? -value : value); 116 | } 117 | 118 | inline int16 abs(int16 value) 119 | { 120 | if (value == EVX_MIN_INT16) 121 | return EVX_MAX_INT16; 122 | 123 | return (value < 0 ? -value : value); 124 | } 125 | 126 | inline int32 abs(int32 value) 127 | { 128 | if (value == EVX_MIN_INT32) 129 | return EVX_MAX_INT32; 130 | 131 | return (value < 0 ? -value : value); 132 | } 133 | 134 | inline int16 clip_range(int16 value, int16 min, int16 max) 135 | { 136 | return (value < min ? min : (value > max ? max : value)); 137 | } 138 | 139 | inline uint32 greater_multiple(uint32 value, uint32 multiple) 140 | { 141 | uint32 mod = value % multiple; 142 | 143 | if (0 != mod) 144 | { 145 | value += multiple - mod; 146 | } 147 | 148 | return value; 149 | } 150 | 151 | inline uint32 align(uint32 value, uint32 alignment) 152 | { 153 | return greater_multiple(value, alignment); 154 | } 155 | 156 | } // namespace evx 157 | 158 | #endif // __EV_MATH_H__ -------------------------------------------------------------------------------- /base.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | // 4 | // Copyright (c) 2002-2014 Joe Bertolami. All Right Reserved. 5 | // 6 | // base.h 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are met: 10 | // 11 | // * Redistributions of source code must retain the above copyright notice, this 12 | // list of conditions and the following disclaimer. 13 | // 14 | // * Redistributions in binary form must reproduce the above copyright notice, 15 | // this list of conditions and the following disclaimer in the documentation 16 | // and/or other materials provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Additional Information: 30 | // 31 | // For more information, visit http://www.bertolami.com. 32 | // 33 | */ 34 | 35 | #ifndef __EV_BASE_H__ 36 | #define __EV_BASE_H__ 37 | 38 | /********************************************************************************** 39 | // 40 | // Platform definitions 41 | // 42 | **********************************************************************************/ 43 | 44 | #if defined (_WIN32) || defined (_WIN64) 45 | #include "windows.h" 46 | 47 | #pragma warning (disable : 4244) // conversion, possible loss of data 48 | #pragma warning (disable : 4018) // signed / unsigned mismatch 49 | #pragma warning (disable : 4996) // deprecated interfaces 50 | #pragma warning (disable : 4221) // empty translation unit 51 | #pragma warning (disable : 4273) // inconsistent linkage 52 | 53 | #define EVX_PLATFORM_WINDOWS // building a Windows application 54 | #elif defined (__APPLE__) 55 | #include "TargetConditionals.h" 56 | #include "unistd.h" 57 | #include "sys/types.h" 58 | #include "ctype.h" 59 | 60 | #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 61 | #define EVX_PLATFORM_IOS // building an application for iOS 62 | #elif TARGET_OS_MAC 63 | #define EVX_PLATFORM_MACOSX // building a Mac OSX application 64 | #endif 65 | #elif defined (__linux__) 66 | #include "unistd.h" 67 | #include "stdint.h" 68 | #define EVX_PLATFORM_LINUX // building a Linux application 69 | #else 70 | #error "Unsupported target platform detected." 71 | #endif 72 | 73 | /********************************************************************************** 74 | // 75 | // Debug definitions 76 | // 77 | **********************************************************************************/ 78 | 79 | #if defined (EVX_PLATFORM_WINDOWS) 80 | #ifdef _DEBUG 81 | #define EVX_DEBUG _DEBUG 82 | #elif defined (DEBUG) 83 | #define EVX_DEBUG DEBUG 84 | #endif 85 | #if defined(EVX_DEBUG) && !defined(debug_break) 86 | #define debug_break __debugbreak 87 | #endif 88 | #define __EVX_FUNCTION__ __FUNCTION__ 89 | #elif defined (EVX_PLATFORM_IOS) || defined (EVX_PLATFORM_MACOSX) || defined (EVX_PLATFORM_LINUX) 90 | #ifdef DEBUG 91 | #define EVX_DEBUG DEBUG 92 | #if !defined(debug_break) 93 | #define debug_break() __builtin_trap() 94 | #endif 95 | #endif 96 | #define __EVX_FUNCTION__ __func__ 97 | #endif 98 | 99 | /********************************************************************************** 100 | // 101 | // Standard headers 102 | // 103 | **********************************************************************************/ 104 | 105 | #include "stdio.h" 106 | #include "stdlib.h" 107 | #include "stdarg.h" 108 | #include "string.h" 109 | 110 | /********************************************************************************** 111 | // 112 | // Standard types 113 | // 114 | **********************************************************************************/ 115 | 116 | namespace evx { 117 | 118 | #if defined (EVX_PLATFORM_WINDOWS) 119 | typedef INT64 int64; 120 | typedef INT32 int32; 121 | typedef INT16 int16; 122 | typedef INT8 int8; 123 | 124 | typedef UINT64 uint64; 125 | typedef UINT32 uint32; 126 | typedef UINT16 uint16; 127 | typedef UINT8 uint8; 128 | #elif defined (EVX_PLATFORM_IOS) || defined (EVX_PLATFORM_MACOSX) 129 | typedef int64_t int64; 130 | typedef int32_t int32; 131 | typedef int16_t int16; 132 | typedef int8_t int8; 133 | 134 | typedef u_int64_t uint64; 135 | typedef u_int32_t uint32; 136 | typedef u_int16_t uint16; 137 | typedef u_int8_t uint8; 138 | #elif defined (EVX_PLATFORM_LINUX) 139 | typedef int64_t int64; 140 | typedef int32_t int32; 141 | typedef int16_t int16; 142 | typedef int8_t int8; 143 | 144 | typedef uint64_t uint64; 145 | typedef uint32_t uint32; 146 | typedef uint16_t uint16; 147 | typedef uint8_t uint8; 148 | #endif 149 | 150 | typedef float float32; 151 | typedef double float64; 152 | typedef wchar_t wchar; 153 | 154 | } // namespace evx 155 | 156 | /********************************************************************************** 157 | // 158 | // Status codes 159 | // 160 | **********************************************************************************/ 161 | 162 | namespace evx { typedef uint8 evx_status; } 163 | 164 | #define EVX_SUCCESS (0) 165 | #define EVX_ERROR_INVALIDARG (1) 166 | #define EVX_ERROR_NOTIMPL (2) 167 | #define EVX_ERROR_OUTOFMEMORY (3) 168 | #define EVX_ERROR_UNDEFINED (4) 169 | #define EVX_ERROR_HARDWAREFAIL (5) 170 | #define EVX_ERROR_INVALID_INDEX (6) 171 | #define EVX_ERROR_CAPACITY_LIMIT (7) 172 | #define EVX_ERROR_INVALID_RESOURCE (8) 173 | #define EVX_ERROR_OPERATION_TIMEDOUT (9) 174 | #define EVX_ERROR_EXECUTION_FAILURE (10) 175 | #define EVX_ERROR_PERMISSION_DENIED (11) 176 | #define EVX_ERROR_IO_FAILURE (12) 177 | #define EVX_ERROR_RESOURCE_UNREACHABLE (13) 178 | #define EVX_ERROR_SYSTEM_FAILURE (14) 179 | #define EVX_ERROR_NOT_READY (15) 180 | #define EVX_ERROR_OPERATION_COMPLETED (16) 181 | #define EVX_ERROR_RESOURCE_UNUSED (17) 182 | 183 | /********************************************************************************** 184 | // 185 | // Debug support 186 | // 187 | **********************************************************************************/ 188 | 189 | #ifdef EVX_DEBUG 190 | #define EVX_PARAM_CHECK (1) 191 | #define evx_err(fmt, ...) do { printf("[EVX-ERR] "); \ 192 | printf(fmt, ##__VA_ARGS__); \ 193 | printf("\n"); debug_break(); \ 194 | } while(0) 195 | 196 | #define evx_msg(fmt, ...) do { printf("[EVX-MSG] "); \ 197 | printf(fmt, ##__VA_ARGS__); \ 198 | printf("\n"); \ 199 | } while(0) 200 | #else 201 | #define EVX_PARAM_CHECK (0) 202 | #define evx_err(fmt, ...) 203 | #define evx_msg(fmt, ...) 204 | #endif 205 | 206 | #define EVX_ERROR_CREATE_STRING(x) ((char *) #x) 207 | #define evx_post_error(x) post_error_i(x, EVX_ERROR_CREATE_STRING(x), __EVX_FUNCTION__, (char *) __FILE__, __LINE__) 208 | 209 | namespace evx { 210 | 211 | inline uint32 post_error_i(uint8 error, const char *error_string, const char *function, const char *filename, uint32 line) 212 | { 213 | #ifdef EVX_DEBUG 214 | const char *path = filename; 215 | for (int32 i = (int32) strlen(filename); i >= 0; --i) 216 | { 217 | if (filename[ i ] == '/') 218 | break; 219 | 220 | path = &filename[i]; 221 | } 222 | 223 | evx_err("*** RIP *** %s @ %s in %s:%i", error_string, function, path, line); 224 | #endif 225 | return error; 226 | } 227 | 228 | } // namespace evx 229 | 230 | /********************************************************************************** 231 | // 232 | // Standard helpers 233 | // 234 | **********************************************************************************/ 235 | 236 | #define EVX_DISABLE_COPY_AND_ASSIGN(type) \ 237 | type(const type &rvalue); \ 238 | type &operator = (const type &rvalue); 239 | 240 | #endif // __EV_BASE_H__ 241 | -------------------------------------------------------------------------------- /bitstream.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "bitstream.h" 3 | #include "math.h" 4 | #include "memory.h" 5 | 6 | namespace evx { 7 | 8 | bitstream::bitstream() 9 | { 10 | read_index = 0; 11 | write_index = 0; 12 | data_store = 0; 13 | data_capacity = 0; 14 | } 15 | 16 | bitstream::bitstream(uint32 size) 17 | { 18 | data_store = 0; 19 | 20 | if (size != resize_capacity(size)) 21 | { 22 | evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 23 | } 24 | } 25 | 26 | bitstream::bitstream(void *bytes, uint32 size) 27 | { 28 | data_store = 0; 29 | 30 | if (0 != assign(bytes, size)) 31 | { 32 | evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 33 | } 34 | } 35 | 36 | bitstream::~bitstream() 37 | { 38 | clear(); 39 | } 40 | 41 | uint8 *bitstream::query_data() const 42 | { 43 | return data_store; 44 | } 45 | 46 | uint32 bitstream::query_capacity() const 47 | { 48 | return data_capacity << 3; 49 | } 50 | 51 | uint32 bitstream::query_occupancy() const 52 | { 53 | return write_index - read_index; 54 | } 55 | 56 | uint32 bitstream::query_byte_occupancy() const 57 | { 58 | return align(query_occupancy(), 8) >> 3; 59 | } 60 | 61 | uint32 bitstream::resize_capacity(uint32 size_in_bits) 62 | { 63 | if (EVX_PARAM_CHECK) 64 | { 65 | if (0 == size_in_bits) 66 | { 67 | evx_post_error(EVX_ERROR_INVALIDARG); 68 | return 0; 69 | } 70 | } 71 | 72 | clear(); 73 | 74 | uint32 byte_size = align(size_in_bits, 8) >> 3; 75 | data_store = new uint8[byte_size]; 76 | 77 | if (!data_store) 78 | { 79 | evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 80 | return 0; 81 | } 82 | 83 | data_capacity = byte_size; 84 | return size_in_bits; 85 | } 86 | 87 | evx_status bitstream::seek(uint32 bit_offset) 88 | { 89 | if (bit_offset >= write_index) 90 | { 91 | bit_offset = write_index; 92 | } 93 | 94 | read_index = bit_offset; 95 | return 0; 96 | } 97 | 98 | evx_status bitstream::assign(void *bytes, uint32 size) 99 | { 100 | if (EVX_PARAM_CHECK) 101 | { 102 | if (0 == size || !bytes) 103 | { 104 | return evx_post_error(EVX_ERROR_INVALIDARG); 105 | } 106 | } 107 | 108 | clear(); 109 | 110 | /* Copy the data into our own buffer and adjust our indices. */ 111 | data_store = new uint8[size]; 112 | 113 | if (!data_store) 114 | { 115 | return evx_post_error(EVX_ERROR_OUTOFMEMORY); 116 | } 117 | 118 | memcpy(data_store, bytes, size); 119 | 120 | read_index = 0; 121 | write_index = size << 3; 122 | data_capacity = size; 123 | 124 | return EVX_SUCCESS; 125 | } 126 | 127 | void bitstream::clear() 128 | { 129 | empty(); 130 | 131 | delete [] data_store; 132 | data_store = 0; 133 | data_capacity = 0; 134 | } 135 | 136 | void bitstream::empty() 137 | { 138 | write_index = 0; 139 | read_index = 0; 140 | } 141 | 142 | bool bitstream::is_empty() const 143 | { 144 | return (write_index == read_index); 145 | } 146 | 147 | bool bitstream::is_full() const 148 | { 149 | return (write_index == query_capacity()); 150 | } 151 | 152 | evx_status bitstream::write_byte(uint8 value) 153 | { 154 | if (write_index + 8 > query_capacity()) 155 | { 156 | return EVX_ERROR_CAPACITY_LIMIT; 157 | } 158 | 159 | /* Determine the current byte to write. */ 160 | uint32 dest_byte = write_index >> 3; 161 | uint8 dest_bit = write_index % 8; 162 | 163 | if (0 == dest_bit) 164 | { 165 | /* This is a byte aligned write, so we perform it at byte level. */ 166 | uint8 *data = &(data_store[dest_byte]); 167 | *data = value; 168 | write_index += 8; 169 | } 170 | else 171 | { 172 | /* Slower byte unaligned write. */ 173 | for (uint8 i = 0; i < 8; ++i) 174 | { 175 | write_bit((value >> i) & 0x1); 176 | } 177 | } 178 | 179 | return EVX_SUCCESS; 180 | } 181 | 182 | evx_status bitstream::write_bit(uint8 value) 183 | { 184 | if (write_index + 1 > query_capacity()) 185 | { 186 | return EVX_ERROR_CAPACITY_LIMIT; 187 | } 188 | 189 | /* Determine the current byte to write. */ 190 | uint32 dest_byte = write_index >> 3; 191 | uint8 dest_bit = write_index % 8; 192 | 193 | /* Pull the correct byte from our data store, update it, and then store it. 194 | Note that we do not guarantee that unused buffer memory was zero filled, 195 | thus we safely clear the write bit. */ 196 | uint8 *data = &(data_store[dest_byte]); 197 | *data = ((*data) & ~(0x1 << dest_bit)) | (value & 0x1) << dest_bit; 198 | write_index++; 199 | 200 | return EVX_SUCCESS; 201 | } 202 | 203 | evx_status bitstream::write_bits(void *data, uint32 bit_count) 204 | { 205 | if (EVX_PARAM_CHECK) 206 | { 207 | if (!data || 0 == bit_count) 208 | { 209 | return evx_post_error(EVX_ERROR_INVALIDARG); 210 | } 211 | } 212 | 213 | if (write_index + bit_count > query_capacity()) 214 | { 215 | return EVX_ERROR_CAPACITY_LIMIT; 216 | } 217 | 218 | uint32 bits_copied = 0; 219 | uint8 *source = reinterpret_cast(data); 220 | 221 | if (0 == (write_index % 8) && (bit_count >= 8)) 222 | { 223 | /* We can perform a (partial) fast copy because our source and destination 224 | are byte aligned. We handle any trailing bits below. */ 225 | bits_copied = aligned_bit_copy(data_store, write_index, source, 0, bit_count); 226 | 227 | if (!bits_copied) 228 | { 229 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 230 | } 231 | } 232 | 233 | if (bits_copied < bit_count) 234 | { 235 | /* Perform unaligned copies of our data. */ 236 | bits_copied += unaligned_bit_copy(data_store, 237 | write_index + bits_copied, 238 | source, 239 | bits_copied, 240 | bit_count - bits_copied); 241 | } 242 | 243 | write_index += bits_copied; 244 | 245 | return EVX_SUCCESS; 246 | } 247 | 248 | evx_status bitstream::write_bytes(void *data, uint32 byte_count) 249 | { 250 | return write_bits(data, byte_count << 3); 251 | } 252 | 253 | evx_status bitstream::read_bit(void *data) 254 | { 255 | if (EVX_PARAM_CHECK) 256 | { 257 | if (!data) 258 | { 259 | return evx_post_error(EVX_ERROR_INVALIDARG); 260 | } 261 | } 262 | 263 | if (read_index >= write_index) 264 | { 265 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 266 | } 267 | 268 | /* Determine the current byte to read from. */ 269 | uint32 source_byte = read_index >> 3; 270 | uint8 source_bit = read_index % 8; 271 | uint8 *dest = reinterpret_cast(data); 272 | 273 | /* Pull the correct byte from our data store. Note that we 274 | preserve the high bits of *dest. */ 275 | *dest &= 0xFE; 276 | *dest |= ((data_store[source_byte]) >> source_bit) & 0x1; 277 | read_index++; 278 | 279 | return EVX_SUCCESS; 280 | } 281 | 282 | evx_status bitstream::read_byte(void *data) 283 | { 284 | if (EVX_PARAM_CHECK) 285 | { 286 | if (!data) 287 | { 288 | return evx_post_error(EVX_ERROR_INVALIDARG); 289 | } 290 | } 291 | 292 | if (read_index + 8 > write_index) 293 | { 294 | return EVX_ERROR_INVALID_RESOURCE; 295 | } 296 | 297 | /* Determine the current byte to read from. */ 298 | uint32 source_byte = read_index >> 3; 299 | uint8 source_bit = read_index % 8; 300 | uint8 *dest = reinterpret_cast(data); 301 | 302 | if (0 == (source_bit % 8)) 303 | { 304 | *dest = data_store[source_byte]; 305 | read_index += 8; 306 | } 307 | else 308 | { 309 | /* Slower byte unaligned read. */ 310 | for (uint8 i = 0; i < 8; ++i) 311 | { 312 | uint8 temp = 0; 313 | read_bit(&temp); 314 | *dest = (*dest & ~(0x1 << i)) | (temp << i); 315 | } 316 | } 317 | 318 | return EVX_SUCCESS; 319 | } 320 | 321 | evx_status bitstream::read_bits(void *data, uint32 *bit_count) 322 | { 323 | if (EVX_PARAM_CHECK) 324 | { 325 | if (!data || !bit_count || 0 == *bit_count) 326 | { 327 | return evx_post_error(EVX_ERROR_INVALIDARG); 328 | } 329 | } 330 | 331 | /* We attempt to read *puiBitCount bits and replace it with the number 332 | actually read. */ 333 | if (read_index + (*bit_count) > write_index) 334 | { 335 | (*bit_count) = write_index - read_index; 336 | } 337 | 338 | uint32 bits_copied = 0; 339 | uint8 *dest = reinterpret_cast(data); 340 | 341 | if (0 == (read_index % 8) && ((*bit_count) >= 8 )) 342 | { 343 | /* We can perform a (partial) fast copy because our source and destination 344 | are byte aligned. We handle any trailing bits below. */ 345 | bits_copied = aligned_bit_copy(dest, 0, data_store, read_index, (*bit_count)); 346 | 347 | if (!bits_copied) 348 | { 349 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 350 | } 351 | } 352 | 353 | /* Perform unaligned copies of our data. */ 354 | if (bits_copied < (*bit_count)) 355 | { 356 | bits_copied += unaligned_bit_copy(dest, 357 | bits_copied, 358 | data_store, 359 | read_index + bits_copied, 360 | (*bit_count) - bits_copied); 361 | } 362 | 363 | read_index += bits_copied; 364 | 365 | return EVX_SUCCESS; 366 | } 367 | 368 | evx_status bitstream::read_bytes(void *data, uint32 *byte_count) 369 | { 370 | if (EVX_PARAM_CHECK) 371 | { 372 | if (!byte_count || 0 == *byte_count) 373 | { 374 | return evx_post_error(EVX_ERROR_INVALIDARG); 375 | } 376 | } 377 | 378 | uint32 bit_count = (*byte_count) << 3; 379 | evx_status result = read_bits(data, &bit_count); 380 | (*byte_count) = bit_count >> 3; 381 | 382 | return result; 383 | } 384 | 385 | } // namespace EVX -------------------------------------------------------------------------------- /cabac.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "cabac.h" 3 | #include "math.h" 4 | 5 | #define EVX_ENTROPY_PRECISION (16) 6 | #define EVX_ENTROPY_PRECISION_MAX ((uint32(0x1) << EVX_ENTROPY_PRECISION) - 1) 7 | #define EVX_ENTROPY_PRECISION_MASK ((uint32(0x1) << EVX_ENTROPY_PRECISION) - 1) 8 | #define EVX_ENTROPY_HALF_RANGE ((EVX_ENTROPY_PRECISION_MAX >> 1)) 9 | #define EVX_ENTROPY_QTR_RANGE (EVX_ENTROPY_HALF_RANGE >> 1) 10 | #define EVX_ENTROPY_3QTR_RANGE (3 * EVX_ENTROPY_QTR_RANGE) 11 | #define EVX_ENTROPY_MSB_MASK (uint64(0x1) << (EVX_ENTROPY_PRECISION - 1)) 12 | #define EVX_ENTROPY_SMSB_MASK (EVX_ENTROPY_MSB_MASK >> 1) 13 | 14 | #if (EVX_ENTROPY_PRECISION > 32) 15 | #error "EVX_ENTROPY_PRECISION must be <= 32" 16 | #endif 17 | 18 | namespace evx { 19 | 20 | /* 21 | // ABAC Ranging 22 | // 23 | // + Our range for 0 is [0, mid] (inclusive) 24 | // + Our range for 1 is [mid+1, high] (inclusive) 25 | // 26 | // Thus, when encoding a zero, low should remain the same, high becomes mid. 27 | // When encoding a one, low should be set to mid + 1, high remains the same. 28 | */ 29 | 30 | entropy_coder::entropy_coder() 31 | { 32 | history[0] = 1; 33 | history[1] = 1; 34 | 35 | e3_count = 0; 36 | adaptive = 1; 37 | model = EVX_ENTROPY_HALF_RANGE; 38 | value = 0; 39 | 40 | low = 0; 41 | high = EVX_ENTROPY_PRECISION_MAX; 42 | mid = EVX_ENTROPY_HALF_RANGE; 43 | } 44 | 45 | entropy_coder::entropy_coder(uint32 input_model) 46 | { 47 | history[0] = 0; 48 | history[1] = 0; 49 | 50 | model = input_model; 51 | e3_count = 0; 52 | adaptive = 0; 53 | value = 0; 54 | 55 | low = 0; 56 | high = EVX_ENTROPY_PRECISION_MAX; 57 | mid = model; 58 | } 59 | 60 | void entropy_coder::clear() 61 | { 62 | low = 0; 63 | value = 0; 64 | e3_count = 0; 65 | 66 | if (adaptive) 67 | { 68 | history[0] = 1; 69 | history[1] = 1; 70 | high = EVX_ENTROPY_PRECISION_MAX; 71 | mid = EVX_ENTROPY_HALF_RANGE; 72 | } 73 | else 74 | { 75 | high = EVX_ENTROPY_PRECISION_MAX; 76 | mid = model; 77 | } 78 | } 79 | 80 | void entropy_coder::resolve_model() 81 | { 82 | uint64 mid_range = 0; 83 | uint64 range = high - low; 84 | 85 | if (adaptive) 86 | { 87 | mid_range = range * history[0] / (history[0] + history[1]); 88 | } 89 | else 90 | { 91 | mid_range = range * model / EVX_ENTROPY_PRECISION_MAX; 92 | } 93 | 94 | mid = low + mid_range; 95 | } 96 | 97 | evx_status entropy_coder::encode_symbol(uint8 value) 98 | { 99 | /* We only encode the first 2 GB instances of each symbol. */ 100 | if (history[value] >= (2 * EVX_GB)) 101 | { 102 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 103 | } 104 | 105 | /* Adapt our model with knowledge of our recently processed value. */ 106 | resolve_model(); 107 | 108 | /* Encode our bit. */ 109 | value = value & 0x1; 110 | 111 | if (value) 112 | { 113 | low = mid + 1; 114 | } 115 | else 116 | { 117 | high = mid; 118 | } 119 | 120 | history[value]++; 121 | 122 | return EVX_SUCCESS; 123 | } 124 | 125 | evx_status entropy_coder::decode_symbol(uint32 value, bitstream *dest) 126 | { 127 | if (EVX_PARAM_CHECK) 128 | { 129 | if (!dest) 130 | { 131 | return evx_post_error(EVX_ERROR_INVALIDARG); 132 | } 133 | } 134 | 135 | /* Adapt our model with knowledge of our recently processed value. */ 136 | resolve_model(); 137 | 138 | /* Decode our bit. */ 139 | if (value >= low && value <= mid) 140 | { 141 | high = mid; 142 | history[0]++; 143 | dest->write_bit(0); 144 | } 145 | else if (value > mid && value <= high) 146 | { 147 | low = mid + 1; 148 | history[1]++; 149 | dest->write_bit(1); 150 | } 151 | 152 | return EVX_SUCCESS; 153 | } 154 | 155 | evx_status entropy_coder::flush_inverse_bits(uint8 value, bitstream *dest) 156 | { 157 | if (EVX_PARAM_CHECK) 158 | { 159 | if (!dest) 160 | { 161 | return evx_post_error(EVX_ERROR_INVALIDARG); 162 | } 163 | } 164 | 165 | value = !value; 166 | 167 | for (uint32 i = 0; i < e3_count; ++i) 168 | { 169 | if (EVX_SUCCESS != dest->write_bit(value)) 170 | { 171 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 172 | } 173 | } 174 | 175 | e3_count = 0; 176 | 177 | return EVX_SUCCESS; 178 | } 179 | 180 | evx_status entropy_coder::resolve_encode_scaling(bitstream *dest) 181 | { 182 | if (EVX_PARAM_CHECK) 183 | { 184 | if (!dest) 185 | { 186 | return evx_post_error(EVX_ERROR_INVALIDARG); 187 | } 188 | } 189 | 190 | while (true) 191 | { 192 | if ((high & EVX_ENTROPY_MSB_MASK) == (low & EVX_ENTROPY_MSB_MASK)) 193 | { 194 | /* E1/E2 scaling violation. */ 195 | uint8 msb = (high & EVX_ENTROPY_MSB_MASK) >> (EVX_ENTROPY_PRECISION - 1); 196 | low -= EVX_ENTROPY_HALF_RANGE * msb + msb; 197 | high -= EVX_ENTROPY_HALF_RANGE * msb + msb; 198 | 199 | if (EVX_SUCCESS != dest->write_bit(msb)) 200 | { 201 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 202 | } 203 | 204 | if (EVX_SUCCESS != flush_inverse_bits(msb, dest)) 205 | { 206 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 207 | } 208 | } 209 | else if (high <= EVX_ENTROPY_3QTR_RANGE && low > EVX_ENTROPY_QTR_RANGE) 210 | { 211 | /* E3 scaling violation. */ 212 | high -= EVX_ENTROPY_QTR_RANGE + 1; 213 | low -= EVX_ENTROPY_QTR_RANGE + 1; 214 | e3_count += 1; 215 | } 216 | else 217 | { 218 | break; 219 | } 220 | 221 | high = ((high << 0x1) & EVX_ENTROPY_PRECISION_MAX) | 0x1; 222 | low = ((low << 0x1) & EVX_ENTROPY_PRECISION_MAX) | 0x0; 223 | } 224 | 225 | return EVX_SUCCESS; 226 | } 227 | 228 | evx_status entropy_coder::resolve_decode_scaling(uint32 *value, bitstream *source, bitstream *dest) 229 | { 230 | if (EVX_PARAM_CHECK) 231 | { 232 | if (!value || !source || !dest) 233 | { 234 | return evx_post_error(EVX_ERROR_INVALIDARG); 235 | } 236 | } 237 | 238 | uint8 bit = 0; 239 | 240 | while (true) 241 | { 242 | if (high <= EVX_ENTROPY_HALF_RANGE) 243 | { 244 | /* If our high value is less than half we do nothing (but 245 | prevent the loop from exiting). */ 246 | } 247 | else if (low > EVX_ENTROPY_HALF_RANGE) 248 | { 249 | high -= (EVX_ENTROPY_HALF_RANGE + 1); 250 | low -= (EVX_ENTROPY_HALF_RANGE + 1); 251 | *value -= (EVX_ENTROPY_HALF_RANGE + 1); 252 | } 253 | else if (high <= EVX_ENTROPY_3QTR_RANGE && low > EVX_ENTROPY_QTR_RANGE) 254 | { 255 | /* E3 scaling violation. */ 256 | high -= EVX_ENTROPY_QTR_RANGE + 1; 257 | low -= EVX_ENTROPY_QTR_RANGE + 1; 258 | *value -= EVX_ENTROPY_QTR_RANGE + 1; 259 | } 260 | else 261 | { 262 | break; 263 | } 264 | 265 | if (!source->is_empty()) 266 | { 267 | if (EVX_SUCCESS != source->read_bit(&bit)) 268 | { 269 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 270 | } 271 | } 272 | 273 | high = ((high << 0x1) & EVX_ENTROPY_PRECISION_MAX) | 0x1; 274 | low = ((low << 0x1) & EVX_ENTROPY_PRECISION_MAX) | 0x0; 275 | *value = ((*value << 0x1) & EVX_ENTROPY_PRECISION_MAX) | bit; 276 | } 277 | 278 | return EVX_SUCCESS; 279 | } 280 | 281 | evx_status entropy_coder::flush_encoder(bitstream *dest) 282 | { 283 | if (EVX_PARAM_CHECK) 284 | { 285 | if (!dest) 286 | { 287 | return evx_post_error(EVX_ERROR_INVALIDARG); 288 | } 289 | } 290 | 291 | e3_count++; 292 | 293 | if (low < EVX_ENTROPY_QTR_RANGE) 294 | { 295 | if (EVX_SUCCESS != dest->write_bit(0) || 296 | EVX_SUCCESS != flush_inverse_bits(0, dest)) 297 | { 298 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 299 | } 300 | } 301 | else 302 | { 303 | if (EVX_SUCCESS != dest->write_bit(1) || 304 | EVX_SUCCESS != flush_inverse_bits(1, dest)) 305 | { 306 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 307 | } 308 | } 309 | 310 | clear(); 311 | 312 | return EVX_SUCCESS; 313 | } 314 | 315 | evx_status entropy_coder::encode(bitstream *source, bitstream *dest, bool auto_finish) 316 | { 317 | if (EVX_PARAM_CHECK) 318 | { 319 | if (!source || !dest) 320 | { 321 | return evx_post_error(EVX_ERROR_INVALIDARG); 322 | } 323 | } 324 | 325 | uint8 value = 0; 326 | 327 | while (!source->is_empty()) 328 | { 329 | if (EVX_SUCCESS != source->read_bit(&value) || 330 | EVX_SUCCESS != encode_symbol(value) || 331 | EVX_SUCCESS != resolve_encode_scaling(dest)) 332 | { 333 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 334 | } 335 | } 336 | 337 | if (auto_finish) 338 | { 339 | /* We close out the tab here in order to remain consistent with the decode 340 | behavior. If stream support is required, this will require an update. */ 341 | if (EVX_SUCCESS != flush_encoder(dest)) 342 | { 343 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 344 | } 345 | 346 | clear(); 347 | } 348 | 349 | return EVX_SUCCESS; 350 | } 351 | 352 | evx_status entropy_coder::decode(uint32 symbol_count, bitstream *source, bitstream *dest, bool auto_start) 353 | { 354 | if (EVX_PARAM_CHECK) 355 | { 356 | if (0 == symbol_count || !source || !dest ) 357 | { 358 | return evx_post_error(EVX_ERROR_INVALIDARG); 359 | } 360 | } 361 | 362 | if (auto_start) 363 | { 364 | uint8 bit = 0; 365 | value = 0; 366 | 367 | clear(); 368 | 369 | /* We read in our initial bits with padded tailing zeroes. */ 370 | for (uint32 i = 0; i < EVX_ENTROPY_PRECISION; ++i) 371 | { 372 | if (!source->is_empty()) 373 | { 374 | if (EVX_SUCCESS != source->read_bit(&bit)) 375 | { 376 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 377 | } 378 | } 379 | 380 | value <<= 0x1; 381 | value |= bit; 382 | } 383 | } 384 | 385 | /* Begin decoding the sequence. */ 386 | for (uint32 i = 0; i < symbol_count; ++i) 387 | { 388 | if (EVX_SUCCESS != decode_symbol(value, dest) || 389 | EVX_SUCCESS != resolve_decode_scaling(&value, source, dest)) 390 | { 391 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 392 | } 393 | } 394 | 395 | return EVX_SUCCESS; 396 | } 397 | 398 | evx_status entropy_coder::start_decode(bitstream *source) 399 | { 400 | uint8 bit = 0; 401 | value = 0; 402 | 403 | clear(); 404 | 405 | /* We read in our initial bits with padded tailing zeroes. */ 406 | for (uint32 i = 0; i < EVX_ENTROPY_PRECISION; ++i) 407 | { 408 | if (!source->is_empty()) 409 | { 410 | if (EVX_SUCCESS != source->read_bit(&bit)) 411 | { 412 | return evx_post_error(EVX_ERROR_INVALID_RESOURCE); 413 | } 414 | } 415 | 416 | value <<= 0x1; 417 | value |= bit; 418 | } 419 | 420 | return EVX_SUCCESS; 421 | } 422 | 423 | evx_status entropy_coder::finish_encode(bitstream *dest) 424 | { 425 | if (EVX_SUCCESS != flush_encoder(dest)) 426 | { 427 | return evx_post_error(EVX_ERROR_EXECUTION_FAILURE); 428 | } 429 | 430 | clear(); 431 | 432 | return EVX_SUCCESS; 433 | } 434 | 435 | } // namespace evx --------------------------------------------------------------------------------