summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorposciak@chromium.org <posciak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-25 07:08:01 +0000
committerposciak@chromium.org <posciak@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-25 07:08:01 +0000
commit9a6ea10bec70ccaa31a105fa9d628988923cce53 (patch)
tree5775239e9207e39c3e12eacde6717c498d814e11 /media
parent4e5e52894edb28ea88fa76f2ac5d38b6fd2258aa (diff)
downloadchromium_src-9a6ea10bec70ccaa31a105fa9d628988923cce53.zip
chromium_src-9a6ea10bec70ccaa31a105fa9d628988923cce53.tar.gz
chromium_src-9a6ea10bec70ccaa31a105fa9d628988923cce53.tar.bz2
Add VaapiVideoEncodeAccelerator for HW-accelerated video encode.
Add an implementation of VideoEncodeAccelerator utilizing VA-API for hardware encode on Intel-based ChromeOS platforms. BUG=378962 TEST=video_encode_accelerator_unittest Review URL: https://codereview.chromium.org/333253002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@279650 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/h264_bitstream_buffer.cc152
-rw-r--r--media/filters/h264_bitstream_buffer.h120
-rw-r--r--media/filters/h264_bitstream_buffer_unittest.cc55
-rw-r--r--media/filters/h264_parser.cc6
-rw-r--r--media/filters/h264_parser.h39
-rw-r--r--media/media.gyp12
6 files changed, 379 insertions, 5 deletions
diff --git a/media/filters/h264_bitstream_buffer.cc b/media/filters/h264_bitstream_buffer.cc
new file mode 100644
index 0000000..48463a5
--- /dev/null
+++ b/media/filters/h264_bitstream_buffer.cc
@@ -0,0 +1,152 @@
+// Copyright 2014 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 "media/filters/h264_bitstream_buffer.h"
+
+#include "base/sys_byteorder.h"
+
+namespace media {
+
+H264BitstreamBuffer::H264BitstreamBuffer() : data_(NULL) {
+ Reset();
+}
+
+H264BitstreamBuffer::~H264BitstreamBuffer() {
+ free(data_);
+ data_ = NULL;
+}
+
+void H264BitstreamBuffer::Reset() {
+ free(data_);
+ data_ = NULL;
+
+ capacity_ = 0;
+ pos_ = 0;
+ reg_ = 0;
+
+ Grow();
+
+ bits_left_in_reg_ = kRegBitSize;
+}
+
+void H264BitstreamBuffer::Grow() {
+ data_ = static_cast<uint8*>(realloc(data_, capacity_ + kGrowBytes));
+ CHECK(data_) << "Failed growing the buffer";
+ capacity_ += kGrowBytes;
+}
+
+void H264BitstreamBuffer::FlushReg() {
+ // Flush all bytes that have at least one bit cached, but not more
+ // (on Flush(), reg_ may not be full).
+ size_t bits_in_reg = kRegBitSize - bits_left_in_reg_;
+ if (bits_in_reg == 0)
+ return;
+
+ size_t bytes_in_reg = (bits_in_reg + 7) / 8;
+ reg_ <<= (kRegBitSize - bits_in_reg);
+
+ // Convert to MSB and append as such to the stream.
+ reg_ = base::HostToNet64(reg_);
+
+ // Make sure we have enough space. Grow() will CHECK() on allocation failure.
+ if (pos_ + bytes_in_reg < capacity_)
+ Grow();
+
+ memcpy(data_ + pos_, &reg_, bytes_in_reg);
+ pos_ += bytes_in_reg;
+
+ reg_ = 0;
+ bits_left_in_reg_ = kRegBitSize;
+}
+
+void H264BitstreamBuffer::AppendU64(size_t num_bits, uint64 val) {
+ CHECK_LE(num_bits, kRegBitSize);
+
+ while (num_bits > 0) {
+ if (bits_left_in_reg_ == 0)
+ FlushReg();
+
+ uint64 bits_to_write =
+ num_bits > bits_left_in_reg_ ? bits_left_in_reg_ : num_bits;
+ uint64 val_to_write = (val >> (num_bits - bits_to_write));
+ if (bits_to_write < 64)
+ val_to_write &= ((1ull << bits_to_write) - 1);
+ reg_ <<= bits_to_write;
+ reg_ |= val_to_write;
+ num_bits -= bits_to_write;
+ bits_left_in_reg_ -= bits_to_write;
+ }
+}
+
+void H264BitstreamBuffer::AppendBool(bool val) {
+ if (bits_left_in_reg_ == 0)
+ FlushReg();
+
+ reg_ <<= 1;
+ reg_ |= (static_cast<uint64>(val) & 1);
+ --bits_left_in_reg_;
+}
+
+void H264BitstreamBuffer::AppendSE(int val) {
+ if (val > 0)
+ AppendUE(val * 2 - 1);
+ else
+ AppendUE(-val * 2);
+}
+
+void H264BitstreamBuffer::AppendUE(unsigned int val) {
+ size_t num_zeros = 0;
+ unsigned int v = val + 1;
+
+ while (v > 1) {
+ v >>= 1;
+ ++num_zeros;
+ }
+
+ AppendBits(num_zeros, 0);
+ AppendBits(num_zeros + 1, val + 1);
+}
+
+#define DCHECK_FINISHED() \
+ DCHECK_EQ(bits_left_in_reg_, kRegBitSize) << "Pending bits not yet written " \
+ "to the buffer, call " \
+ "FinishNALU() first."
+
+void H264BitstreamBuffer::BeginNALU(H264NALU::Type nalu_type, int nal_ref_idc) {
+ DCHECK_FINISHED();
+
+ DCHECK_LE(nalu_type, H264NALU::kEOStream);
+ DCHECK_GE(nal_ref_idc, 0);
+ DCHECK_LE(nal_ref_idc, 3);
+
+ AppendBits(32, 0x00000001);
+ AppendBits(1, 0); // forbidden_zero_bit
+ AppendBits(2, nal_ref_idc);
+ AppendBits(5, nalu_type);
+}
+
+void H264BitstreamBuffer::FinishNALU() {
+ // RBSP stop one bit.
+ AppendBits(1, 1);
+
+ // Byte-alignment zero bits.
+ AppendBits(bits_left_in_reg_ % 8, 0);
+
+ if (bits_left_in_reg_ != kRegBitSize)
+ FlushReg();
+}
+
+size_t H264BitstreamBuffer::BytesInBuffer() {
+ DCHECK_FINISHED();
+ return pos_;
+}
+
+uint8* H264BitstreamBuffer::data() {
+ DCHECK(data_);
+ DCHECK_FINISHED();
+
+ return data_;
+}
+
+} // namespace media
diff --git a/media/filters/h264_bitstream_buffer.h b/media/filters/h264_bitstream_buffer.h
new file mode 100644
index 0000000..4b0511d
--- /dev/null
+++ b/media/filters/h264_bitstream_buffer.h
@@ -0,0 +1,120 @@
+// Copyright 2014 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.
+//
+// This file contains an implementation of a H264BitstreamBuffer class for
+// constructing raw bitstream buffers containing NAL units in
+// H.264 Annex-B stream format.
+// See H.264 spec Annex B and chapter 7for more details.
+
+#ifndef MEDIA_FILTERS_H264_BITSTREAM_BUFFER_H_
+#define MEDIA_FILTERS_H264_BITSTREAM_BUFFER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "media/base/media_export.h"
+#include "media/base/video_frame.h"
+#include "media/filters/h264_parser.h"
+
+namespace media {
+
+// Holds one or more NALUs as a raw bitstream buffer in H.264 Annex-B format.
+// Note that this class currently does NOT insert emulation prevention
+// three-byte sequences (spec 7.3.1).
+class MEDIA_EXPORT H264BitstreamBuffer {
+ public:
+ H264BitstreamBuffer();
+ ~H264BitstreamBuffer();
+
+ // Discard all data and reset the buffer for reuse.
+ void Reset();
+
+ // Append |num_bits| bits to the stream from |val|.
+ // |val| is interpreted in the host endianness.
+ template <typename T>
+ void AppendBits(size_t num_bits, T val) {
+ AppendU64(num_bits, static_cast<uint64>(val));
+ }
+
+ void AppendBits(size_t num_bits, bool val) {
+ DCHECK_EQ(num_bits, 1ul);
+ AppendBool(val);
+ }
+
+ // Append a one-bit bool/flag value |val| to the stream.
+ void AppendBool(bool val);
+
+ // Append a signed value in |val| in Exp-Golomb code.
+ void AppendSE(int val);
+
+ // Append an unsigned value in |val| in Exp-Golomb code.
+ void AppendUE(unsigned int val);
+
+ // Start a new NALU of type |nalu_type| and with given |nal_ref_idc|
+ // (see spec). Note, that until FinishNALU() is called, some of the bits
+ // may not be flushed into the buffer and the data will not be correctly
+ // aligned with trailing bits.
+ void BeginNALU(H264NALU::Type nalu_type, int nal_ref_idc);
+
+ // Finish current NALU. This will flush any cached bits and correctly align
+ // the buffer with RBSP trailing bits. This MUST be called for the stream
+ // returned by data() to be correct.
+ void FinishNALU();
+
+ // Return number of full bytes in the stream. Note that FinishNALU() has to
+ // be called to flush cached bits, or the return value will not include them.
+ size_t BytesInBuffer();
+
+ // Return a pointer to the stream. FinishNALU() must be called before
+ // accessing the stream, otherwise some bits may still be cached and not
+ // in the buffer.
+ uint8* data();
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(H264BitstreamBufferAppendBitsTest,
+ AppendAndVerifyBits);
+
+ // Allocate additional memory (kGrowBytes bytes) for the buffer.
+ void Grow();
+
+ // Append |num_bits| bits from U64 value |val| (in host endianness).
+ void AppendU64(size_t num_bits, uint64 val);
+
+ // Flush any cached bits in the reg with byte granularity, i.e. enough
+ // bytes to flush all pending bits, but not more.
+ void FlushReg();
+
+ typedef uint64 RegType;
+ enum {
+ // Sizes of reg_.
+ kRegByteSize = sizeof(RegType),
+ kRegBitSize = kRegByteSize * 8,
+ // Amount of bytes to grow the buffer by when we run out of
+ // previously-allocated memory for it.
+ kGrowBytes = 4096,
+ };
+
+ COMPILE_ASSERT(kGrowBytes >= kRegByteSize,
+ kGrowBytes_must_be_larger_than_kRegByteSize);
+
+ // Unused bits left in reg_.
+ size_t bits_left_in_reg_;
+
+ // Cache for appended bits. Bits are flushed to data_ with kRegByteSize
+ // granularity, i.e. when reg_ becomes full, or when an explicit FlushReg()
+ // is called.
+ RegType reg_;
+
+ // Current capacity of data_, in bytes.
+ size_t capacity_;
+
+ // Current byte offset in data_ (points to the start of unwritten bits).
+ size_t pos_;
+
+ // Buffer for stream data.
+ uint8* data_;
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_H264_BITSTREAM_BUFFER_H_
diff --git a/media/filters/h264_bitstream_buffer_unittest.cc b/media/filters/h264_bitstream_buffer_unittest.cc
new file mode 100644
index 0000000..3775829
--- /dev/null
+++ b/media/filters/h264_bitstream_buffer_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright 2014 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 "media/filters/h264_bitstream_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+namespace {
+const uint64 kTestPattern = 0xfedcba0987654321;
+}
+
+class H264BitstreamBufferAppendBitsTest
+ : public ::testing::TestWithParam<size_t> {};
+
+// TODO(posciak): More tests!
+
+TEST_P(H264BitstreamBufferAppendBitsTest, AppendAndVerifyBits) {
+ H264BitstreamBuffer b;
+ uint64 num_bits = GetParam();
+ // TODO(posciak): Tests for >64 bits.
+ ASSERT_LE(num_bits, 64u);
+ uint64 num_bytes = (num_bits + 7) / 8;
+
+ b.AppendBits(num_bits, kTestPattern);
+ b.FlushReg();
+
+ EXPECT_EQ(b.BytesInBuffer(), num_bytes);
+
+ uint8* ptr = b.data();
+ uint64 got = 0;
+ uint64 expected = kTestPattern;
+
+ if (num_bits < 64)
+ expected &= ((1ull << num_bits) - 1);
+
+ while (num_bits > 8) {
+ got |= (*ptr & 0xff);
+ num_bits -= 8;
+ got <<= (num_bits > 8 ? 8 : num_bits);
+ ptr++;
+ }
+ if (num_bits > 0) {
+ uint64 temp = (*ptr & 0xff);
+ temp >>= (8 - num_bits);
+ got |= temp;
+ }
+ EXPECT_EQ(got, expected) << std::hex << "0x" << got << " vs 0x" << expected;
+}
+
+INSTANTIATE_TEST_CASE_P(AppendNumBits,
+ H264BitstreamBufferAppendBitsTest,
+ ::testing::Range(1ul, 65ul));
+} // namespace media
diff --git a/media/filters/h264_parser.cc b/media/filters/h264_parser.cc
index 4cdc695..ee21ab8 100644
--- a/media/filters/h264_parser.cc
+++ b/media/filters/h264_parser.cc
@@ -106,10 +106,6 @@ H264SEIMessage::H264SEIMessage() {
} \
} while (0)
-enum AspectRatioIdc {
- kExtendedSar = 255,
-};
-
// ISO 14496 part 10
// VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
static const int kTableSarWidth[] = {
@@ -608,7 +604,7 @@ H264Parser::Result H264Parser::ParseVUIParameters(H264SPS* sps) {
if (aspect_ratio_info_present_flag) {
int aspect_ratio_idc;
READ_BITS_OR_RETURN(8, &aspect_ratio_idc);
- if (aspect_ratio_idc == kExtendedSar) {
+ if (aspect_ratio_idc == H264SPS::kExtendedSar) {
READ_BITS_OR_RETURN(16, &sps->sar_width);
READ_BITS_OR_RETURN(16, &sps->sar_height);
} else {
diff --git a/media/filters/h264_parser.h b/media/filters/h264_parser.h
index 3a60dce..45020af 100644
--- a/media/filters/h264_parser.h
+++ b/media/filters/h264_parser.h
@@ -63,6 +63,26 @@ enum {
struct MEDIA_EXPORT H264SPS {
H264SPS();
+ enum H264ProfileIDC {
+ kProfileIDCBaseline = 66,
+ kProfileIDCConstrainedBaseline = kProfileIDCBaseline,
+ kProfileIDCMain = 77,
+ kProfileIDCHigh = 100,
+ };
+
+ enum AspectRatioIdc {
+ kExtendedSar = 255,
+ };
+
+ enum {
+ // Constants for HRD parameters (spec ch. E.2.2).
+ kBitRateScaleConstantTerm = 6, // Equation E-37.
+ kCPBSizeScaleConstantTerm = 4, // Equation E-38.
+ kDefaultInitialCPBRemovalDelayLength = 24,
+ kDefaultDPBOutputDelayLength = 24,
+ kDefaultTimeOffsetLength = 24,
+ };
+
int profile_idc;
bool constraint_set0_flag;
bool constraint_set1_flag;
@@ -111,6 +131,25 @@ struct MEDIA_EXPORT H264SPS {
bool bitstream_restriction_flag;
int max_num_reorder_frames;
int max_dec_frame_buffering;
+ bool timing_info_present_flag;
+ int num_units_in_tick;
+ int time_scale;
+ bool fixed_frame_rate_flag;
+
+ // TODO(posciak): actually parse these instead of ParseAndIgnoreHRDParameters.
+ bool nal_hrd_parameters_present_flag;
+ int cpb_cnt_minus1;
+ int bit_rate_scale;
+ int cpb_size_scale;
+ int bit_rate_value_minus1[32];
+ int cpb_size_value_minus1[32];
+ bool cbr_flag[32];
+ int initial_cpb_removal_delay_length_minus_1;
+ int cpb_removal_delay_length_minus1;
+ int dpb_output_delay_length_minus1;
+ int time_offset_length;
+
+ bool low_delay_hrd_flag;
int chroma_array_type;
};
diff --git a/media/media.gyp b/media/media.gyp
index 7a38a4f..1b3987a 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -659,6 +659,13 @@
'formats/webm/chromeos/webm_encoder.h',
],
}],
+ # For VaapiVideoEncodeAccelerator.
+ ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
+ 'sources': [
+ 'filters/h264_bitstream_buffer.cc',
+ 'filters/h264_bitstream_buffer.h',
+ ],
+ }],
['OS!="ios"', {
'dependencies': [
'../third_party/libyuv/libyuv.gyp:libyuv',
@@ -1223,6 +1230,11 @@
}],
],
}],
+ ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
+ 'sources': [
+ 'filters/h264_bitstream_buffer_unittest.cc',
+ ],
+ }],
['use_alsa==0', {
'sources!': [
'audio/alsa/alsa_output_unittest.cc',