| // Copyright 2012 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/media/filters/shell_rbsp_stream.h" |
| |
| #include <list> |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/stringprintf.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media { |
| |
| class ShellRBSPStreamTest : public testing::Test { |
| protected: |
| ShellRBSPStreamTest() {} |
| |
| virtual ~ShellRBSPStreamTest() {} |
| |
| // Given num encode the value in signed exp-golomb syntax and push |
| // the value on the provided bitlist |
| void EncodeSEV(int32 num, std::list<bool>& bits) { |
| bool is_negative = (num < 0); |
| uint32 unum = 0; |
| if (is_negative) { |
| unum = (uint32)(num * -1); |
| } else { |
| unum = (uint32)num; |
| } |
| // multiply unsigned value by 2 |
| unum = unum << 1; |
| // subtract one from the positive values |
| if (!is_negative) { |
| --unum; |
| } |
| // encode the resulting uev |
| EncodeUEV(unum, bits); |
| } |
| |
| // Given num encode the value in unsigned exp-golomb syntax and push |
| // the value on to the provided bitlist |
| void EncodeUEV(uint32 num, std::list<bool>& bits) { |
| // find largest (2^pow) - 1 smaller than num |
| uint32 pow = 31; |
| uint32 base = 0x7fffffff; |
| while (base > num) { |
| pow--; |
| base = base >> 1; |
| } |
| // encoding calls for pow leading zeros, followed by a 1, followed |
| // by pow digits of the input number - ((2^pow) - 1). |
| // we move from MSb to LSb, so start by pushing back the leading 0s |
| for (int i = 0; i < pow; i++) { |
| bits.push_back(false); |
| } |
| // now push the separating one |
| bits.push_back(true); |
| // and now pow bits of the remainder bitfield MSb to LSb |
| uint32 remainder = num - base; |
| for (int i = pow - 1; i >= 0; --i) { |
| bits.push_back((remainder >> i) & 0x01); |
| } |
| } |
| |
| // after building a bitlist in various fun ways call this method to |
| // create a buffer on the heap that can be passed to ShellRBSPStream |
| // for deserialization. |
| scoped_array<uint8> SerializeToBuffer(const std::list<bool>& bitlist, |
| bool add_sequence_bytes, |
| size_t& buffer_size_out) { |
| // start by building a list of bytes, so we can add the |
| // 00 00 => 00 00 03 sequence bytes |
| std::list<uint8> bytelist; |
| uint8 push_byte = 0; |
| uint32 bit_counter = 0; |
| for (std::list<bool>::const_iterator it = bitlist.begin(); |
| it != bitlist.end(); ++it) { |
| bit_counter++; |
| push_byte = push_byte << 1; |
| if (*it) { |
| push_byte |= 1; |
| } |
| if (!(bit_counter % 8)) { |
| bytelist.push_back(push_byte); |
| push_byte = 0; |
| } |
| } |
| // push any remaining bits on as the final byte |
| if (bit_counter % 8) { |
| bytelist.push_back(push_byte << (8 - (bit_counter % 8))); |
| } |
| // if we should add sequence bytes we iterate through the new |
| // byte list looking for 00 00 and inserting a 03 after each. |
| if (add_sequence_bytes) { |
| int num_zeros = 0; |
| for (std::list<uint8>::iterator it = bytelist.begin(); |
| it != bytelist.end(); ++it) { |
| // if we just passed two sequential zeros insert a 03 |
| if (num_zeros == 2) { |
| bytelist.insert(it, 0x03); |
| // reset the counter |
| num_zeros = 0; |
| } |
| if (*it == 0) { |
| ++num_zeros; |
| } else { |
| num_zeros = 0; |
| } |
| } |
| } else { |
| // we will need to detect any naturally ocurring 00 00 03s |
| // and protect them from removal of the 03, by inserting a |
| // second 03 |
| int num_zeros = 0; |
| for (std::list<uint8>::iterator it = bytelist.begin(); |
| it != bytelist.end(); ++it) { |
| if ((num_zeros >= 2) && (*it == 0x03)) { |
| bytelist.insert(it, 0x03); |
| } |
| if (*it == 0) { |
| ++num_zeros; |
| } else { |
| num_zeros = 0; |
| } |
| } |
| } |
| // alright we can make the final output buffer |
| scoped_array<uint8> buf(new uint8[bytelist.size()]); |
| int index = 0; |
| for (std::list<uint8>::iterator it = bytelist.begin(); it != bytelist.end(); |
| it++) { |
| buf[index] = *it; |
| index++; |
| } |
| buffer_size_out = bytelist.size(); |
| return buf.Pass(); |
| } |
| }; |
| |
| TEST_F(ShellRBSPStreamTest, ReadUEV) { |
| std::list<bool> fibbits; |
| // encode first 47 Fibonacci numbers |
| uint32 f_n_minus_2 = 0; |
| EncodeUEV(f_n_minus_2, fibbits); |
| uint32 f_n_minus_1 = 1; |
| EncodeUEV(f_n_minus_1, fibbits); |
| for (int i = 2; i < 47; i++) { |
| uint32 f_n = f_n_minus_1 + f_n_minus_2; |
| EncodeUEV(f_n, fibbits); |
| // update values |
| f_n_minus_2 = f_n_minus_1; |
| f_n_minus_1 = f_n; |
| } |
| // convert to buffer |
| size_t fib_buffer_size = 0; |
| scoped_array<uint8> fib_buffer = |
| SerializeToBuffer(fibbits, true, fib_buffer_size); |
| size_t fib_buffer_no_sequence_size; |
| scoped_array<uint8> fib_buffer_no_sequence = |
| SerializeToBuffer(fibbits, false, fib_buffer_no_sequence_size); |
| ShellRBSPStream fib_stream(fib_buffer.get(), fib_buffer_size); |
| ShellRBSPStream fib_stream_no_sequence(fib_buffer_no_sequence.get(), |
| fib_buffer_no_sequence_size); |
| // deserialize the same sequence from both buffers |
| uint32 uev = 0; |
| uint32 uev_n = 0; |
| f_n_minus_2 = 0; |
| ASSERT_TRUE(fib_stream.ReadUEV(uev)); |
| ASSERT_EQ(uev, f_n_minus_2); |
| ASSERT_TRUE(fib_stream_no_sequence.ReadUEV(uev_n)); |
| ASSERT_EQ(uev_n, f_n_minus_2); |
| |
| f_n_minus_1 = 1; |
| ASSERT_TRUE(fib_stream.ReadUEV(uev)); |
| ASSERT_EQ(uev, f_n_minus_1); |
| ASSERT_TRUE(fib_stream_no_sequence.ReadUEV(uev_n)); |
| ASSERT_EQ(uev_n, f_n_minus_1); |
| |
| for (int i = 2; i < 47; i++) { |
| uint32 f_n = f_n_minus_1 + f_n_minus_2; |
| ASSERT_TRUE(fib_stream.ReadUEV(uev)); |
| ASSERT_EQ(uev, f_n); |
| ASSERT_TRUE(fib_stream_no_sequence.ReadUEV(uev_n)); |
| ASSERT_EQ(uev_n, f_n); |
| f_n_minus_2 = f_n_minus_1; |
| f_n_minus_1 = f_n; |
| } |
| // subsequent call to ReadUEV should fail |
| ASSERT_FALSE(fib_stream.ReadUEV(uev)); |
| ASSERT_FALSE(fib_stream_no_sequence.ReadUEV(uev_n)); |
| } |
| |
| TEST_F(ShellRBSPStreamTest, ReadSEV) { |
| std::list<bool> lucasbits; |
| // encode first 44 Lucas numbers with alternating sign |
| int32 l_n_minus_2 = 1; |
| EncodeSEV(l_n_minus_2, lucasbits); |
| int32 l_n_minus_1 = 2; |
| EncodeSEV(-l_n_minus_1, lucasbits); |
| for (int i = 2; i < 44; ++i) { |
| int32 l_n = l_n_minus_1 + l_n_minus_2; |
| if (i % 2) { |
| EncodeSEV(-l_n, lucasbits); |
| } else { |
| EncodeSEV(l_n, lucasbits); |
| } |
| l_n_minus_2 = l_n_minus_1; |
| l_n_minus_1 = l_n; |
| } |
| // convert to buffers |
| size_t lucas_seq_buffer_size = 0; |
| scoped_array<uint8> lucas_seq_buffer = |
| SerializeToBuffer(lucasbits, true, lucas_seq_buffer_size); |
| size_t lucas_deseq_buffer_size = 0; |
| scoped_array<uint8> lucas_deseq_buffer = |
| SerializeToBuffer(lucasbits, false, lucas_deseq_buffer_size); |
| ShellRBSPStream lucas_seq_stream(lucas_seq_buffer.get(), |
| lucas_seq_buffer_size); |
| ShellRBSPStream lucas_deseq_stream(lucas_deseq_buffer.get(), |
| lucas_deseq_buffer_size); |
| l_n_minus_2 = 1; |
| l_n_minus_1 = 2; |
| int32 sev = 0; |
| int32 sev_n = 0; |
| ASSERT_TRUE(lucas_seq_stream.ReadSEV(sev)); |
| ASSERT_EQ(sev, 1); |
| ASSERT_TRUE(lucas_deseq_stream.ReadSEV(sev_n)); |
| ASSERT_EQ(sev_n, 1); |
| ASSERT_TRUE(lucas_seq_stream.ReadSEV(sev)); |
| ASSERT_EQ(sev, -2); |
| ASSERT_TRUE(lucas_deseq_stream.ReadSEV(sev_n)); |
| ASSERT_EQ(sev_n, -2); |
| for (int i = 2; i < 44; ++i) { |
| int32 l_n = l_n_minus_1 + l_n_minus_2; |
| ASSERT_TRUE(lucas_seq_stream.ReadSEV(sev)); |
| ASSERT_TRUE(lucas_deseq_stream.ReadSEV(sev_n)); |
| if (i % 2) { |
| ASSERT_EQ(-sev, l_n); |
| ASSERT_EQ(-sev_n, l_n); |
| } else { |
| ASSERT_EQ(sev, l_n); |
| ASSERT_EQ(sev_n, l_n); |
| } |
| l_n_minus_2 = l_n_minus_1; |
| l_n_minus_1 = l_n; |
| } |
| // subsequent calls to ReadSEV should fail |
| ASSERT_FALSE(lucas_seq_stream.ReadSEV(sev)); |
| ASSERT_FALSE(lucas_deseq_stream.ReadSEV(sev_n)); |
| } |
| |
| static const uint8 kTestRBSPExpGolombTooBig[] = { |
| // 15 leading zeros, should be fine |
| // 0000000000000001010101010101010 |
| // = 2^15 - 1 + read_bits(010101010101010) |
| // = 32768 - 1 + 10922 = 43689 unsigned, 21845 signed |
| // 0000 0000 0000 0001 0101 0101 0101 010+0 (first 0 of next number) |
| 0x00, 0x01, 0x55, 0x54, |
| // 31 leading zeros, should be fine |
| // 000000000000000000000000000000010000000000000000000000000000001 |
| // = 2^31 - 1 + 1 = 2147483648 unsigned, -1073741824 signed |
| // 0 appended on to last byte |
| // 0000 0000 0000 0000 0000 0000 0000 0010 0000 0000 0000 0000 0000 0000 |
| 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, |
| // 0000 01+00 (first 2 zeros of next number) |
| 0x04, |
| // 32 leading zeros, should not be ok |
| // 00000000000000000000000000000000111111111111111111111111111111111 |
| // = 2^32 - 1 + 2^32 = 2^33 - 1 = 8589934591 |
| // 00 appended on to last byte |
| // 0000 0000 0000 0000 0000 0000 0000 0011 1111 1111 1111 1111 1111 1111 |
| 0x00, 0x00, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, |
| // 1111 111+0 (to complete the byte) |
| 0xfe}; |
| |
| TEST_F(ShellRBSPStreamTest, ReadUEVTooLarge) { |
| // construct a stream from the supplied test data |
| ShellRBSPStream uev_too_big(kTestRBSPExpGolombTooBig, |
| sizeof(kTestRBSPExpGolombTooBig)); |
| // first call should succeed |
| uint32 uev = 0; |
| ASSERT_TRUE(uev_too_big.ReadUEV(uev)); |
| ASSERT_EQ(uev, 43689); |
| // as should the second call |
| ASSERT_TRUE(uev_too_big.ReadUEV(uev)); |
| ASSERT_EQ(uev, 2147483648u); |
| // third should fail |
| ASSERT_FALSE(uev_too_big.ReadUEV(uev)); |
| } |
| |
| TEST_F(ShellRBSPStreamTest, ReadSEVTooLarge) { |
| // construct a stream from the supplied test data |
| ShellRBSPStream sev_too_big(kTestRBSPExpGolombTooBig, |
| sizeof(kTestRBSPExpGolombTooBig)); |
| // first call should succeed |
| int32 sev = 0; |
| ASSERT_TRUE(sev_too_big.ReadSEV(sev)); |
| ASSERT_EQ(sev, 21845); |
| // as should the second call |
| ASSERT_TRUE(sev_too_big.ReadSEV(sev)); |
| ASSERT_EQ(sev, -1073741824); |
| // third should fail |
| ASSERT_FALSE(sev_too_big.ReadSEV(sev)); |
| } |
| |
| TEST_F(ShellRBSPStreamTest, ReadBit) { |
| std::list<bool> padded_ones; |
| // build a bitfield of 1 padded by n zeros, for n in range[0, 1024] |
| for (int i = 0; i < 1024; i++) { |
| for (int j = 0; j < i; j++) { |
| padded_ones.push_back(false); |
| } |
| padded_ones.push_back(true); |
| } |
| // build the buffer with sequence bits and without |
| size_t sequence_buff_size = 0; |
| scoped_array<uint8> sequence_buff = |
| SerializeToBuffer(padded_ones, true, sequence_buff_size); |
| ShellRBSPStream seq_stream(sequence_buff.get(), sequence_buff_size); |
| |
| size_t desequence_buff_size = 0; |
| scoped_array<uint8> desequence_buff = |
| SerializeToBuffer(padded_ones, false, desequence_buff_size); |
| ShellRBSPStream deseq_stream(desequence_buff.get(), desequence_buff_size); |
| for (std::list<bool>::iterator it = padded_ones.begin(); |
| it != padded_ones.end(); ++it) { |
| uint8 bit = 0; |
| ASSERT_TRUE(seq_stream.ReadBit(bit)); |
| ASSERT_EQ(*it, bit); |
| uint8 deseq_bit = 0; |
| ASSERT_TRUE(deseq_stream.ReadBit(deseq_bit)); |
| ASSERT_EQ(*it, deseq_bit); |
| } |
| |
| // there should be less than a byte in the either stream |
| uint8 fail_byte = 0; |
| ASSERT_FALSE(seq_stream.ReadByte(fail_byte)); |
| ASSERT_FALSE(deseq_stream.ReadByte(fail_byte)); |
| } |
| |
| TEST_F(ShellRBSPStreamTest, ReadByte) { |
| // build a field of 16 x (0xaa byte followed by 0 bit) |
| std::list<bool> aa_field; |
| for (int i = 0; i < 16; ++i) { |
| for (int j = 0; j < 8; ++j) { |
| aa_field.push_back(!(j % 2)); |
| } |
| aa_field.push_back(false); |
| } |
| // deseqbuff will be identical due to dense packing of 01 pattern |
| size_t aabuff_size = 0; |
| scoped_array<uint8> aabuff = SerializeToBuffer(aa_field, true, aabuff_size); |
| ShellRBSPStream aa_stream(aabuff.get(), aabuff_size); |
| for (int i = 0; i < 16; ++i) { |
| uint8 aa = 0; |
| ASSERT_TRUE(aa_stream.ReadByte(aa)); |
| ASSERT_EQ(aa, 0xaa); |
| // read the zero separator bit |
| uint8 zero = 0; |
| ASSERT_TRUE(aa_stream.ReadBit(zero)); |
| ASSERT_EQ(zero, 0); |
| } |
| |
| // build a field of 24 x (1 bit, 4 bytes of 0, one 03 byte, 4 bytes of 0) |
| std::list<bool> zero_field; |
| for (int i = 0; i < 24; ++i) { |
| zero_field.push_back(true); |
| for (int j = 0; j < 32; ++j) { |
| zero_field.push_back(false); |
| } |
| zero_field.push_back(false); |
| zero_field.push_back(false); |
| zero_field.push_back(false); |
| zero_field.push_back(false); |
| zero_field.push_back(false); |
| zero_field.push_back(false); |
| zero_field.push_back(true); |
| zero_field.push_back(true); |
| for (int j = 0; j < 32; ++j) { |
| zero_field.push_back(false); |
| } |
| } |
| size_t zseqbuff_size = 0; |
| scoped_array<uint8> zseqbuff = |
| SerializeToBuffer(zero_field, true, zseqbuff_size); |
| ShellRBSPStream zseq_stream(zseqbuff.get(), zseqbuff_size); |
| size_t zdseqbuff_size = 0; |
| scoped_array<uint8> zdseqbuff = |
| SerializeToBuffer(zero_field, false, zdseqbuff_size); |
| ShellRBSPStream zdseq_stream(zdseqbuff.get(), zdseqbuff_size); |
| for (int i = 0; i < 24; ++i) { |
| // read the leading 1 bit |
| uint8 seq_bit = 0; |
| ASSERT_TRUE(zseq_stream.ReadBit(seq_bit)); |
| ASSERT_EQ(seq_bit, 1); |
| uint8 dseq_bit = 0; |
| ASSERT_TRUE(zdseq_stream.ReadBit(dseq_bit)); |
| ASSERT_EQ(dseq_bit, 1); |
| // read 4 zeros |
| uint8 seq_byte = 0; |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| uint8 dseq_byte = 0; |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| // read the 3 |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0x03); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0x03); |
| // read the remaining 4 zeros |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zseq_stream.ReadByte(seq_byte)); |
| ASSERT_EQ(seq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| ASSERT_TRUE(zdseq_stream.ReadByte(dseq_byte)); |
| ASSERT_EQ(dseq_byte, 0); |
| } |
| } |
| |
| TEST_F(ShellRBSPStreamTest, ReadBits) { |
| // test the assertion in the ReadBits comment, as it had a bug :) |
| std::list<bool> seventeen_ones; |
| for (int i = 0; i < 17; ++i) { |
| seventeen_ones.push_back(true); |
| } |
| size_t seventeen_ones_size = 0; |
| scoped_array<uint8> seventeen_ones_buff = |
| SerializeToBuffer(seventeen_ones, false, seventeen_ones_size); |
| ShellRBSPStream seventeen_ones_stream(seventeen_ones_buff.get(), |
| seventeen_ones_size); |
| uint32 seventeen_ones_word = 0; |
| ASSERT_TRUE(seventeen_ones_stream.ReadBits(17, seventeen_ones_word)); |
| ASSERT_EQ(seventeen_ones_word, 0x0001ffff); |
| |
| // serialize all powers of two from 2^0 to 2^31 |
| std::list<bool> pows; |
| for (int i = 0; i < 32; ++i) { |
| pows.push_back(true); |
| for (int j = 0; j < i; ++j) { |
| pows.push_back(false); |
| } |
| } |
| size_t pows_size = 0; |
| scoped_array<uint8> pows_buff = SerializeToBuffer(pows, true, pows_size); |
| ShellRBSPStream pows_stream(pows_buff.get(), pows_size); |
| // ReadBits(0) should succeed and not modify the value of the ref output or |
| // internal bit iterator |
| uint32 dont_touch = 0xfeedfeed; |
| ASSERT_TRUE(pows_stream.ReadBits(0, dont_touch)); |
| ASSERT_EQ(dont_touch, 0xfeedfeed); |
| // compare deserializations |
| for (int i = 0; i < 32; ++i) { |
| uint32 bits = 0; |
| ASSERT_TRUE(pows_stream.ReadBits(i + 1, bits)); |
| ASSERT_EQ(bits, (uint32)(1 << i)); |
| } |
| } |
| |
| TEST_F(ShellRBSPStreamTest, SkipBytes) { |
| // serialize all nine-bit values from zero to 512 |
| std::list<bool> nines; |
| for (int i = 0; i < 512; ++i) { |
| for (int j = 8; j >= 0; --j) { |
| nines.push_back((i >> j) & 1); |
| } |
| } |
| size_t nines_size = 0; |
| scoped_array<uint8> nines_buff = SerializeToBuffer(nines, true, nines_size); |
| size_t nines_deseq_size = 0; |
| scoped_array<uint8> nines_deseq_buff = |
| SerializeToBuffer(nines, false, nines_deseq_size); |
| ShellRBSPStream nines_stream(nines_buff.get(), nines_size); |
| ShellRBSPStream nines_deseq_stream(nines_deseq_buff.get(), nines_deseq_size); |
| // iterate through streams, skipping in one and reading in the other, always |
| // comparing values. |
| for (int i = 0; i < 512; ++i) { |
| if (i % 2) { |
| ASSERT_TRUE(nines_stream.SkipBytes(1)); |
| uint8 bit = 0; |
| ASSERT_TRUE(nines_stream.ReadBit(bit)); |
| uint32 ninebits = 0; |
| ASSERT_TRUE(nines_deseq_stream.ReadBits(9, ninebits)); |
| ASSERT_EQ(ninebits, i); |
| ASSERT_EQ(ninebits & 1, bit); |
| } else { |
| ASSERT_TRUE(nines_deseq_stream.SkipBytes(1)); |
| uint8 bit = 0; |
| ASSERT_TRUE(nines_deseq_stream.ReadBit(bit)); |
| uint32 ninebits = 0; |
| ASSERT_TRUE(nines_stream.ReadBits(9, ninebits)); |
| ASSERT_EQ(ninebits, i); |
| ASSERT_EQ(ninebits & 1, bit); |
| } |
| } |
| // 1 true bit followed by 1 byte with 1, followed by 1 true bit, then 2 bytes |
| // with 2, followed by 1 bit, then 3 bytes with 3, etc up to 256 |
| std::list<bool> run_length; |
| for (int i = 0; i < 256; ++i) { |
| for (int j = 0; j < i; ++j) { |
| for (int k = 7; k >= 0; --k) { |
| run_length.push_back((i >> k) & 1); |
| } |
| } |
| run_length.push_back(true); |
| } |
| size_t run_length_size = 0; |
| scoped_array<uint8> run_length_buff = |
| SerializeToBuffer(run_length, true, run_length_size); |
| size_t run_length_deseq_size = 0; |
| scoped_array<uint8> run_length_deseq_buff = |
| SerializeToBuffer(run_length, false, run_length_deseq_size); |
| ShellRBSPStream run_length_stream(run_length_buff.get(), run_length_size); |
| ShellRBSPStream run_length_deseq_stream(run_length_deseq_buff.get(), |
| run_length_deseq_size); |
| // read first bit, skip first byte from each stream, read next bit |
| uint8 bit = 0; |
| ASSERT_TRUE(run_length_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| bit = 0; |
| ASSERT_TRUE(run_length_deseq_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| ASSERT_TRUE(run_length_stream.SkipBytes(1)); |
| ASSERT_TRUE(run_length_deseq_stream.SkipBytes(1)); |
| bit = 0; |
| ASSERT_TRUE(run_length_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| bit = 0; |
| ASSERT_TRUE(run_length_deseq_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| |
| for (int i = 2; i < 256; ++i) { |
| // read first byte in seq stream, make sure it matches value |
| uint8 byte = 0; |
| ASSERT_TRUE(run_length_stream.ReadByte(byte)); |
| ASSERT_EQ(byte, i); |
| // skip the rest of the byte field |
| ASSERT_TRUE(run_length_stream.SkipBytes(i - 1)); |
| bit = 0; |
| // read the separating one bit |
| ASSERT_TRUE(run_length_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| // read last byte in deseq stream, so skip bytes first |
| ASSERT_TRUE(run_length_deseq_stream.SkipBytes(i - 1)); |
| byte = 0; |
| ASSERT_TRUE(run_length_deseq_stream.ReadByte(byte)); |
| ASSERT_EQ(byte, i); |
| // read the separating one bit |
| bit = 0; |
| ASSERT_TRUE(run_length_deseq_stream.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| } |
| |
| // further skips should fail |
| ASSERT_FALSE(run_length_stream.SkipBytes(1)); |
| ASSERT_FALSE(run_length_deseq_stream.SkipBytes(1)); |
| } |
| |
| TEST_F(ShellRBSPStreamTest, SkipBits) { |
| std::list<bool> one_ohs; |
| // encode one 1, followed by one zero, followed by 2 1s, followed by 2 zeros, |
| // etc |
| for (int i = 1; i <= 64; ++i) { |
| for (int j = 0; j < i; ++j) { |
| one_ohs.push_back(true); |
| } |
| for (int j = 0; j < i; ++j) { |
| one_ohs.push_back(false); |
| } |
| } |
| size_t skip_ones_size = 0; |
| scoped_array<uint8> skip_ones_buff = |
| SerializeToBuffer(one_ohs, true, skip_ones_size); |
| size_t skip_ohs_size = 0; |
| scoped_array<uint8> skip_ohs_buff = |
| SerializeToBuffer(one_ohs, false, skip_ohs_size); |
| ShellRBSPStream skip_ones(skip_ones_buff.get(), skip_ones_size); |
| ShellRBSPStream skip_ohs(skip_ohs_buff.get(), skip_ohs_size); |
| for (int i = 1; i < 64; ++i) { |
| // skip the ones |
| ASSERT_TRUE(skip_ones.SkipBits(i)); |
| // read the ones from the zeros stream |
| for (int j = 0; j < i; ++j) { |
| uint8 bit = 0; |
| ASSERT_TRUE(skip_ohs.ReadBit(bit)); |
| ASSERT_EQ(bit, 1); |
| } |
| // skip the ohs |
| ASSERT_TRUE(skip_ohs.SkipBits(i)); |
| // read the ohs from the ones stream |
| for (int j = 0; j < i; ++j) { |
| uint8 bit = 0; |
| ASSERT_TRUE(skip_ones.ReadBit(bit)); |
| ASSERT_EQ(bit, 0); |
| } |
| } |
| } |
| |
| } // namespace media |