summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/common/gpu/media/h264_bit_reader.cc45
-rw-r--r--content/common/gpu/media/h264_bit_reader.h31
-rw-r--r--content/common/gpu/media/h264_bit_reader_unittest.cc68
-rw-r--r--content/common/gpu/media/h264_parser.cc103
-rw-r--r--content/common/gpu/media/h264_parser.h56
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/content_tests.gypi1
7 files changed, 152 insertions, 154 deletions
diff --git a/content/common/gpu/media/h264_bit_reader.cc b/content/common/gpu/media/h264_bit_reader.cc
new file mode 100644
index 0000000..b8d00e1
--- /dev/null
+++ b/content/common/gpu/media/h264_bit_reader.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/h264_bit_reader.h"
+
+namespace content {
+
+H264BitReader::H264BitReader() {
+}
+
+H264BitReader::~H264BitReader() {}
+
+void H264BitReader::UpdateCurrByte() {
+ DCHECK_EQ(num_remaining_bits_in_curr_byte_, 0);
+
+ if (bytes_left_ >= 1) {
+ // Emulation prevention three-byte detection.
+ // If a sequence of 0x000003 is found, skip (ignore) the last byte (0x03).
+ if (*data_ == 0x03 && Tell() >= 16 && data_[-1] == 0 && data_[-2] == 0) {
+ // Detected 0x000003, skip last byte.
+ ++data_;
+ --bytes_left_;
+ position_ += 8;
+ }
+ }
+
+ if (bytes_left_ >= 1) {
+ // Load a new byte and advance pointers.
+ curr_byte_ = *data_;
+ ++data_;
+ --bytes_left_;
+ num_remaining_bits_in_curr_byte_ = 8;
+ }
+
+ // Check if this is the end of RBSP data.
+ if (bytes_left_ == 0) {
+ while (num_remaining_bits_in_curr_byte_ != 0 && !(curr_byte_ & 0x1)) {
+ --num_remaining_bits_in_curr_byte_;
+ curr_byte_ >>= 1;
+ }
+ }
+}
+
+} // namespace content
diff --git a/content/common/gpu/media/h264_bit_reader.h b/content/common/gpu/media/h264_bit_reader.h
new file mode 100644
index 0000000..652c869
--- /dev/null
+++ b/content/common/gpu/media/h264_bit_reader.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_H264_BIT_READER_H_
+#define CONTENT_COMMON_GPU_MEDIA_H264_BIT_READER_H_
+
+#include "base/compiler_specific.h"
+#include "media/base/bit_reader.h"
+
+namespace content {
+
+// A class to provide bit-granularity reading of H.264 streams.
+// This class takes into account H.264 stream-specific constraints, such as
+// skipping emulation-prevention bytes and stop bits. See spec for more
+// details.
+class H264BitReader : public media::BitReader {
+ public:
+ H264BitReader();
+ virtual ~H264BitReader();
+
+ private:
+ // This function handles the H.264 escape sequence and stop bit.
+ virtual void UpdateCurrByte() OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(H264BitReader);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_MEDIA_H264_BIT_READER_H_
diff --git a/content/common/gpu/media/h264_bit_reader_unittest.cc b/content/common/gpu/media/h264_bit_reader_unittest.cc
new file mode 100644
index 0000000..cf90e02
--- /dev/null
+++ b/content/common/gpu/media/h264_bit_reader_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/h264_bit_reader.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::H264BitReader;
+
+TEST(BitReaderTest, H264StreamTest) {
+ // This stream contains an escape sequence. Its last byte only has 4 bits.
+ // 0001 0010 0011 0100 0000 0000 0000 0000 0000 0011 0101 0110 0111 0000
+ uint8 buffer[] = {0x12, 0x34, 0x00, 0x00, 0x03, 0x56, 0x70};
+ H264BitReader reader;
+ uint8 value8;
+ uint32 value32;
+
+ reader.Initialize(buffer, sizeof(buffer));
+ EXPECT_EQ(reader.Tell(), 0);
+ EXPECT_TRUE(reader.ReadBits(4, &value8));
+ EXPECT_EQ(value8, 1u);
+ EXPECT_EQ(reader.Tell(), 4);
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.ReadBits(8, &value8));
+ EXPECT_EQ(value8, 0x23u);
+ EXPECT_EQ(reader.Tell(), 12);
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.ReadBits(24, &value32));
+ EXPECT_EQ(value32, 0x400005u);
+ EXPECT_EQ(reader.Tell(), 44); // Include the skipped escape byte
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.ReadBits(8, &value8));
+ EXPECT_EQ(value8, 0x67u);
+ EXPECT_EQ(reader.Tell(), 52); // Include the skipped escape byte
+ EXPECT_FALSE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.ReadBits(0, &value8));
+ EXPECT_EQ(reader.Tell(), 52); // Include the skipped escape byte
+ EXPECT_FALSE(reader.ReadBits(1, &value8));
+ EXPECT_FALSE(reader.HasMoreData());
+
+ // Do it again using SkipBits
+ reader.Initialize(buffer, sizeof(buffer));
+ EXPECT_EQ(reader.Tell(), 0);
+ EXPECT_TRUE(reader.SkipBits(4));
+ EXPECT_EQ(reader.Tell(), 4);
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.SkipBits(8));
+ EXPECT_EQ(reader.Tell(), 12);
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.SkipBits(24));
+ EXPECT_EQ(reader.Tell(), 44); // Include the skipped escape byte
+ EXPECT_TRUE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.SkipBits(8));
+ EXPECT_EQ(reader.Tell(), 52); // Include the skipped escape byte
+ EXPECT_FALSE(reader.HasMoreData());
+
+ EXPECT_TRUE(reader.SkipBits(0));
+ EXPECT_FALSE(reader.SkipBits(1));
+ EXPECT_FALSE(reader.HasMoreData());
+}
diff --git a/content/common/gpu/media/h264_parser.cc b/content/common/gpu/media/h264_parser.cc
index ace3dab..1452238 100644
--- a/content/common/gpu/media/h264_parser.cc
+++ b/content/common/gpu/media/h264_parser.cc
@@ -50,103 +50,6 @@ H264SEIMessage::H264SEIMessage() {
memset(this, 0, sizeof(*this));
}
-H264Parser::H264BitReader::H264BitReader()
- : data_(NULL),
- bytes_left_(0),
- curr_byte_(0),
- num_remaining_bits_in_curr_byte_(0),
- prev_two_bytes_(0) {
-}
-
-H264Parser::H264BitReader::~H264BitReader() {}
-
-bool H264Parser::H264BitReader::Initialize(const uint8* data, off_t size) {
- DCHECK(data);
-
- if (size < 1)
- return false;
-
- data_ = data;
- bytes_left_ = size;
- num_remaining_bits_in_curr_byte_ = 0;
- // Initially set to 0xffff to accept all initial two-byte sequences.
- prev_two_bytes_ = 0xffff;
-
- return true;
-}
-
-bool H264Parser::H264BitReader::UpdateCurrByte() {
- if (bytes_left_ < 1)
- return false;
-
- // Emulation prevention three-byte detection.
- // If a sequence of 0x000003 is found, skip (ignore) the last byte (0x03).
- if (*data_ == 0x03 && (prev_two_bytes_ & 0xffff) == 0) {
- // Detected 0x000003, skip last byte.
- ++data_;
- --bytes_left_;
- // Need another full three bytes before we can detect the sequence again.
- prev_two_bytes_ = 0xffff;
-
- if (bytes_left_ < 1)
- return false;
- }
-
- // Load a new byte and advance pointers.
- curr_byte_ = *data_++ & 0xff;
- --bytes_left_;
- num_remaining_bits_in_curr_byte_ = 8;
-
- prev_two_bytes_ = (prev_two_bytes_ << 8) | curr_byte_;
-
- return true;
-}
-
-// Read |num_bits| (1 to 31 inclusive) from the stream and return them
-// in |out|, with first bit in the stream as MSB in |out| at position
-// (|num_bits| - 1).
-bool H264Parser::H264BitReader::ReadBits(int num_bits, int *out) {
- int bits_left = num_bits;
- *out = 0;
- DCHECK(num_bits <= 31);
-
- while (num_remaining_bits_in_curr_byte_ < bits_left) {
- // Take all that's left in current byte, shift to make space for the rest.
- *out = (curr_byte_ << (bits_left - num_remaining_bits_in_curr_byte_));
- bits_left -= num_remaining_bits_in_curr_byte_;
-
- if (!UpdateCurrByte())
- return false;
- }
-
- *out |= (curr_byte_ >> (num_remaining_bits_in_curr_byte_ - bits_left));
- *out &= ((1 << num_bits) - 1);
- num_remaining_bits_in_curr_byte_ -= bits_left;
-
- return true;
-}
-
-off_t H264Parser::H264BitReader::NumBitsLeft() {
- return (num_remaining_bits_in_curr_byte_ + bytes_left_ * 8);
-}
-
-bool H264Parser::H264BitReader::HasMoreRBSPData() {
- // Make sure we have more bits, if we are at 0 bits in current byte
- // and updating current byte fails, we don't have more data anyway.
- if (num_remaining_bits_in_curr_byte_ == 0 && !UpdateCurrByte())
- return false;
-
- // On last byte?
- if (bytes_left_)
- return true;
-
- // Last byte, look for stop bit;
- // We have more RBSP data if the last non-zero bit we find is not the
- // first available bit.
- return (curr_byte_ &
- ((1 << (num_remaining_bits_in_curr_byte_ - 1)) - 1)) != 0;
-}
-
#define READ_BITS_OR_RETURN(num_bits, out) \
do { \
int _out; \
@@ -358,7 +261,9 @@ H264Parser::Result H264Parser::AdvanceToNextNALU(H264NALU *nalu) {
nalu->data = stream_ + off_to_nalu_start;
// Initialize bit reader at the start of found NALU.
- if (!br_.Initialize(nalu->data, nalu->size))
+ br_.Initialize(nalu->data, nalu->size);
+
+ if (!br_.HasMoreData())
return kEOStream;
DVLOG(4) << "Looking for NALU, Stream bytes left: " << bytes_left_
@@ -812,7 +717,7 @@ H264Parser::Result H264Parser::ParsePPS(int* pps_id) {
READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag);
READ_BOOL_OR_RETURN(&pps->redundant_pic_cnt_present_flag);
- if (br_.HasMoreRBSPData()) {
+ if (br_.HasMoreData()) {
READ_BOOL_OR_RETURN(&pps->transform_8x8_mode_flag);
READ_BOOL_OR_RETURN(&pps->pic_scaling_matrix_present_flag);
diff --git a/content/common/gpu/media/h264_parser.h b/content/common/gpu/media/h264_parser.h
index ed76f16..e9aea18 100644
--- a/content/common/gpu/media/h264_parser.h
+++ b/content/common/gpu/media/h264_parser.h
@@ -13,6 +13,7 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
+#include "content/common/gpu/media/h264_bit_reader.h"
namespace content {
@@ -301,61 +302,6 @@ class CONTENT_EXPORT H264Parser {
Result ParseSEI(H264SEIMessage* sei_msg);
private:
- // A class to provide bit-granularity reading of H.264 streams.
- // This is not a generic bit reader class, as it takes into account
- // H.264 stream-specific constraints, such as skipping emulation-prevention
- // bytes and stop bits. See spec for more details.
- // TODO(posciak): need separate unittests for this class.
- class H264BitReader {
- public:
- H264BitReader();
- ~H264BitReader();
-
- // Initialize the reader to start reading at |data|, |size| being size
- // of |data| in bytes.
- // Return false on insufficient size of stream..
- // TODO(posciak,fischman): consider replacing Initialize() with
- // heap-allocating and creating bit readers on demand instead.
- bool Initialize(const uint8* data, off_t size);
-
- // Read |num_bits| next bits from stream and return in |*out|, first bit
- // from the stream starting at |num_bits| position in |*out|.
- // |num_bits| may be 1-32, inclusive.
- // Return false if the given number of bits cannot be read (not enough
- // bits in the stream), true otherwise.
- bool ReadBits(int num_bits, int *out);
-
- // Return the number of bits left in the stream.
- off_t NumBitsLeft();
-
- // See the definition of more_rbsp_data() in spec.
- bool HasMoreRBSPData();
-
- private:
- // Advance to the next byte, loading it into curr_byte_.
- // Return false on end of stream.
- bool UpdateCurrByte();
-
- // Pointer to the next unread (not in curr_byte_) byte in the stream.
- const uint8* data_;
-
- // Bytes left in the stream (without the curr_byte_).
- off_t bytes_left_;
-
- // Contents of the current byte; first unread bit starting at position
- // 8 - num_remaining_bits_in_curr_byte_ from MSB.
- int curr_byte_;
-
- // Number of bits remaining in curr_byte_
- int num_remaining_bits_in_curr_byte_;
-
- // Used in emulation prevention three byte detection (see spec).
- // Initially set to 0xffff to accept all initial two-byte sequences.
- int prev_two_bytes_;
-
- DISALLOW_COPY_AND_ASSIGN(H264BitReader);
- };
-
// Exp-Golomb code parsing as specified in chapter 9.1 of the spec.
// Read one unsigned exp-Golomb code from the stream and return in |*val|.
Result ReadUE(int* val);
diff --git a/content/content_common.gypi b/content/content_common.gypi
index cb1860f..ae14818 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -216,6 +216,8 @@
'common/gpu/image_transport_surface_win.cc',
'common/gpu/media/avc_config_record_builder.cc',
'common/gpu/media/avc_config_record_builder.h',
+ 'common/gpu/media/h264_bit_reader.cc',
+ 'common/gpu/media/h264_bit_reader.h',
'common/gpu/media/h264_parser.cc',
'common/gpu/media/h264_parser.h',
'common/gpu/media/mac_video_decode_accelerator.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index eeb3805..ec33b24 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -645,6 +645,7 @@
'../testing/gtest.gyp:gtest',
],
'sources': [
+ 'common/gpu/media/h264_bit_reader_unittest.cc',
'common/gpu/media/h264_parser_unittest.cc',
],
}