Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1257)

Unified Diff: content/common/gpu/media/h264_parser.cc

Issue 9814001: Add VAVDA, the VAAPI Video Decode Accelerator for Intel CPUs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/common/gpu/media/h264_parser.cc
diff --git a/content/common/gpu/media/h264_parser.cc b/content/common/gpu/media/h264_parser.cc
new file mode 100644
index 0000000000000000000000000000000000000000..817edb71b501dc8adab8c58aebe977a3cb4d690a
--- /dev/null
+++ b/content/common/gpu/media/h264_parser.cc
@@ -0,0 +1,1198 @@
+// 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.
+
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Not part of this CL?
+#include "h264_parser.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+
+#include <fstream>
+H264BitReader::H264BitReader()
+ : data_(NULL),
+ bytes_left_(0),
+ curr_byte_(0),
+ bits_in_curr_byte_(0)
+{}
+
+H264BitReader::~H264BitReader() {}
+
+bool H264BitReader::Initialize(uint8* data, size_t size) {
+ DCHECK(data);
+
+ if (size < 1)
+ return false;
+
+ data_ = data;
+ bytes_left_ = size;
+ bits_in_curr_byte_ = 0;
+ // for detecting emulation-prevention three-byte sequences
+ prev_two_bytes_ = 0xffff;
+
+ return true;
+}
+
+bool 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) {
+ // skip
+ ++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_++;
+ --bytes_left_;
+ bits_in_curr_byte_ = 8;
+
+ prev_two_bytes_ = (prev_two_bytes_ << 8) | curr_byte_;
+
+ return true;
+}
+
+bool H264BitReader::ReadBits(int num_bits, uint32 *out) {
+ int bits_left = num_bits;
+ *out = 0;
+ DCHECK(num_bits <= 32);
+
+ while (bits_in_curr_byte_ < bits_left) {
+ // Take all that's left in current byte
+ // shift to make space for the rest
+ *out = (curr_byte_ << (num_bits - bits_in_curr_byte_));
+ bits_left -= bits_in_curr_byte_;
+
+ if (!UpdateCurrByte())
+ return false;
+ }
+
+ *out |= (curr_byte_ >> (bits_in_curr_byte_ - bits_left));
+ *out &= ((1 << num_bits) - 1);
+ bits_in_curr_byte_ -= bits_left;
+
+ return true;
+}
+
+bool H264BitReader::MoreRBSPData() {
+ // make sure we have more bits if we are at 0 bits in current byte
+ // if updating current byte fails, we don't have more data anyway
+ if (bits_in_curr_byte_ == 0)
+ if (!UpdateCurrByte())
+ return false;
+
+ // not on last byte?
+ if (bytes_left_ > 0)
+ return true;
+
+ // last byte, look for stop bit; if there is one, and there are still
+ // preceding bits in front of it the byte before it, we have more data
+ // if the last bit == 1 we find is our current bit, no more data
+ for (int i = 0; i < bits_in_curr_byte_ - 1; ++i) {
+ if ((curr_byte_ >> i) & 0x01)
+ return true;
+ }
+
+ return false;
+}
+
+#define read_bits_or_return(num_bits, out) \
+do { \
+ uint32 out32; \
+ if (!br_.ReadBits(num_bits, &out32)) { \
+ LOG(INFO) << "Error in stream: unexpected end of data"; \
+ DLOG(INFO) << "While trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ *out = out32; \
+} while(0)
+
+#define read_ue_or_return(out) \
+do { \
+ uint32 out32; \
+ if (ReadUE(&out32) != kOk) { \
+ LOG(INFO) << "Error in stream: invalid stream"; \
+ DLOG(INFO) << "While trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ *out = out32; \
+} while(0)
+
+#define read_se_or_return(out) \
+do { \
+ int32 out32; \
+ if (ReadSE(&out32) != kOk) { \
+ LOG(INFO) << "Error in stream: invalid stream"; \
+ DLOG(INFO) << "While trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ *out = out32; \
+} while(0)
+
+#define range_in_or_return(val, low, high) \
+do { \
+ if ((val) < (low) || (val) > (high)) { \
+ LOG(INFO) << "Error in stream: invalid value"; \
+ DLOG(INFO) << "Expected " #val " to be in range " \
+ << "[" << (low) << ":" << (high) << "]" \
+ << "found " << (val) << " instead"; \
+ return kInvalidStream; \
+ } \
+} while(0)
+
+#define true_or_return(a) \
+do { \
+ if (!(a)) { \
+ LOG(INFO) << "Error in stream: invalid value"; \
+ DLOG(INFO) << "Expected " << #a; \
+ return kInvalidStream; \
+ } \
+} while(0)
+
+
+H264Parser::H264Parser() {
+ Reset();
+}
+
+H264Parser::~H264Parser() {
+ STLDeleteContainerPairSecondPointers(active_SPSes_.begin(),
+ active_SPSes_.end());
+ STLDeleteContainerPairSecondPointers(active_PPSes_.begin(),
+ active_PPSes_.end());
+}
+
+void H264Parser::Reset() {
+ /*STLDeleteContainerPairSecondPointers(active_SPSes_.begin(),
+ active_SPSes_.end());
+ active_SPSes_.clear();
+
+ STLDeleteContainerPairSecondPointers(active_PPSes_.begin(),
+ active_PPSes_.end());
+ active_PPSes_.clear();*/
+ bytes_left_ = 0;
+ stream_ = NULL;
+}
+
+void H264Parser::SetStream(uint8* stream, size_t stream_size) {
+ DCHECK(stream);
+ DCHECK(stream_size > 0);
+
+ stream_ = stream;
+ bytes_left_ = stream_size;
+}
+
+H264PPS* H264Parser::GetPPS(uint8 pps_id) {
+ PPSById::iterator it = active_PPSes_.find(pps_id);
+ if (it == active_PPSes_.end())
+ return NULL;
+
+ return it->second;
+}
+
+H264SPS* H264Parser::GetSPS(uint8 sps_id) {
+ SPSById::iterator it = active_SPSes_.find(sps_id);
+ if (it == active_SPSes_.end())
+ return NULL;
+
+ return it->second;
+}
+
+static inline bool IsStartCode(uint8* data) {
+ DCHECK(data);
+ return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
+}
+
+// Find offset from start of data to next NALU start code
+// and size of found start code (3 or 4 bytes)
+static bool FindStartCode(uint8* data, size_t data_size,
+ size_t* offset,
+ size_t *start_code_size) {
+ int bytes_left = data_size;
+
+ while (bytes_left > 3) {
+
+ if (IsStartCode(data)) {
+ // found three-byte start code, set pointers at its beginning
+ *offset = data_size - bytes_left;
+ *start_code_size = 3;
+
+ // if there is a zero byte before this start code,
+ // then it's actually a four-byte start code, so backtrack one byte
+ if (*offset > 0 && *(data - 1) == 0x00) {
+ --(*offset);
+ ++(*start_code_size);
+ }
+
+ return true;
+ }
+
+ ++data;
+ --bytes_left;
+ }
+
+ // end of data
+ return false;
+}
+
+// Find the next NALU in stream, returning its start offset without the start
+// code (i.e. at the beginning of NALU data).
+// Size will include trailing zero bits, and will be from start offset to
+// before the start code of the next NALU (or end of stream).
+static bool LocateNalu(uint8* stream, size_t stream_size,
+ size_t* nalu_start_off, size_t* nalu_size) {
+ size_t start_code_size;
+ *nalu_start_off = 0;
+
+ // find start code of the next NALU
+ if (!FindStartCode(stream, stream_size, nalu_start_off, &start_code_size)) {
+ DVLOG(4) << "Could not find start code, end of stream?";
+ return false;
+ }
+
+ // discard its start code
+ *nalu_start_off += start_code_size;
+ // move the stream to the beginning of it (skip the start code)
+ stream_size -= *nalu_start_off;
+ stream += *nalu_start_off;
+
+ // Find the start code of next NALU; if successful, NALU size is the number
+ // of bytes from after previous start code to before this one;
+ // if next start code is not found, it is still a valid NALU if there
+ // are still some bytes left after the first start code.
+ // nalu_size is the offset to the next start code
+ if (!FindStartCode(stream, stream_size, nalu_size, &start_code_size)) {
+ // end of stream (no next NALU), but still valid NALU if any bytes left
+ *nalu_size = stream_size;
+ if (*nalu_size < 1) {
+ DVLOG(3) << "End of stream";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+H264Parser::Result H264Parser::ReadUE(uint32* val) {
+ int num_bits = -1;
+ uint8 bit;
+ uint32 rest;
+
+ // Count the number of contiguous zero bits
+ do {
+ read_bits_or_return(1, &bit);
+ num_bits++;
+ } while (bit == 0);
+
+ if (num_bits > 32)
+ return kInvalidStream;
+
+ // calculate exp-Golomb code value
+ *val = (1 << num_bits) - 1;
+
+ if (num_bits > 0) {
+ read_bits_or_return(num_bits, &rest);
+ *val += rest;
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ReadSE(int32* val) {
+ uint32 ue;
+ Result res;
+
+ // see Chapter 9 in the spec
+ res = ReadUE(&ue);
+ if (res != kOk)
+ return res;
+
+ if (ue % 2 == 0)
+ *val = -(ue / 2);
+ else
+ *val = ue / 2 + 1;
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseNextNalu(H264NALU *nalu) {
+ uint8 data;
+ size_t off_to_nalu_start;
+
+ DCHECK(stream_);
+
+ if (!LocateNalu(stream_, bytes_left_, &off_to_nalu_start, &nalu->size)) {
+ DVLOG(4) << "Could not find next NALU, bytes left in stream: "
+ << bytes_left_;
+ return kEOStream;
+ }
+
+ nalu->data = stream_ + off_to_nalu_start;
+ // initialize bit reader at the start of found NALU
+ br_.Initialize(nalu->data, nalu->size);
+ DVLOG(4) << "Looking for NALU, Stream bytes left: " << bytes_left_
+ << " off to next nalu: " << off_to_nalu_start;
+
+ // move parser state to after this NALU, so next time ParseNextNalu
+ // is called we will effectively be skipping it
+ // other parsing functions will use the bit reader for parsing
+ stream_ += off_to_nalu_start + nalu->size;
+ bytes_left_ -= off_to_nalu_start + nalu->size;
+
+ // read NALU header
+ // skip the forbidden_zero_bit, but check for it
+ read_bits_or_return(1, &data);
+ true_or_return(data == 0);
+
+ read_bits_or_return(2, &nalu->nal_ref_idc);
+ read_bits_or_return(5, &nalu->nal_unit_type);
+ true_or_return(nalu->nal_unit_type < 31);
+
+ DVLOG(4) << "Nalu type: " << (int)nalu->nal_unit_type
+ << " at: " << (void*)nalu->data << " size: " << nalu->size
+ << " ref: " << (int)nalu->nal_ref_idc;
+
+ return kOk;
+}
+
+// Default scaling lists (as per spec)
+static const uint8 default_4x4_intra[16] = {
+ 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, };
+
+static const uint8 default_4x4_inter[16] = {
+ 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, };
+
+static const uint8 default_8x8_intra[64] = {
+ 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23,
+ 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27,
+ 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31,
+ 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, };
+
+static const uint8 default_8x8_inter[64] = {
+ 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21,
+ 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24,
+ 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27,
+ 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, };
+
+static inline void DefaultScalingList4x4(int i, uint8 scaling_list4x4[][16]) {
+ DCHECK(i < 6);
+
+ if (i < 3)
+ memcpy(scaling_list4x4[i], default_4x4_intra, sizeof(default_4x4_intra));
+ else if (i < 6)
+ memcpy(scaling_list4x4[i], default_4x4_inter, sizeof(default_4x4_inter));
+}
+
+static inline void DefaultScalingList8x8(int i, uint8 scaling_list8x8[][64]) {
+ DCHECK(i < 6);
+
+ if (i % 2 == 0)
+ memcpy(scaling_list8x8[i], default_8x8_intra, sizeof(default_8x8_intra));
+ else
+ memcpy(scaling_list8x8[i], default_8x8_inter, sizeof(default_8x8_inter));
+}
+
+static void FallbackScalingList4x4(int i,
+ const uint8 default_scaling_list_intra[],
+ const uint8 default_scaling_list_inter[],
+ uint8 scaling_list4x4[][16]) {
+ switch (i) {
+ case 0:
+ memcpy(scaling_list4x4[i], default_scaling_list_intra,
+ sizeof(default_scaling_list_intra));
+ break;
+
+ case 1:
+ memcpy(scaling_list4x4[i], scaling_list4x4[0],
+ sizeof(scaling_list4x4[0]));
+ break;
+
+ case 2:
+ memcpy(scaling_list4x4[i], scaling_list4x4[1],
+ sizeof(scaling_list4x4[1]));
+ break;
+
+ case 3:
+ memcpy(scaling_list4x4[i], default_scaling_list_inter,
+ sizeof(default_scaling_list_inter));
+ break;
+
+ case 4:
+ memcpy(scaling_list4x4[i], scaling_list4x4[3],
+ sizeof(scaling_list4x4[3]));
+ break;
+
+ case 5:
+ memcpy(scaling_list4x4[i], scaling_list4x4[4],
+ sizeof(scaling_list4x4[4]));
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+static void FallbackScalingList8x8(int i,
+ const uint8 default_scaling_list_intra[],
+ const uint8 default_scaling_list_inter[],
+ uint8 scaling_list8x8[][64]) {
+ switch (i) {
+ case 0:
+ memcpy(scaling_list8x8[i], default_scaling_list_intra,
+ sizeof(default_scaling_list_intra));
+ break;
+
+ case 1:
+ memcpy(scaling_list8x8[i], default_scaling_list_inter,
+ sizeof(default_scaling_list_inter));
+ break;
+
+ case 2:
+ memcpy(scaling_list8x8[i], scaling_list8x8[0],
+ sizeof(scaling_list8x8[0]));
+ break;
+
+ case 3:
+ memcpy(scaling_list8x8[i], scaling_list8x8[1],
+ sizeof(scaling_list8x8[1]));
+ break;
+
+ case 4:
+ memcpy(scaling_list8x8[i], scaling_list8x8[2],
+ sizeof(scaling_list8x8[2]));
+ break;
+
+ case 5:
+ memcpy(scaling_list8x8[i], scaling_list8x8[3],
+ sizeof(scaling_list8x8[3]));
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+H264Parser::Result H264Parser::ScalingList(uint8* scaling_list, int size,
+ bool* use_default) {
+ // see chapter 7.3.2.1.1.1
+ uint8 last_scale = 8;
+ uint8 next_scale = 8;
+ int32 delta_scale;
+
+ *use_default = false;
+
+ // TODO check if we need to scan in zigzag pattern for the driver
+ for (int j = 0; j < size; ++j) {
+ if (next_scale != 0) {
+ read_se_or_return(&delta_scale);
+ next_scale = (last_scale + delta_scale) & 0xff;
+
+ if (j == 0 && next_scale == 0) {
+ *use_default = true;
+ return kOk;
+ }
+ }
+
+ scaling_list[j] = (next_scale == 0) ? last_scale : next_scale;
+ last_scale = scaling_list[j];
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseSPSScalingLists(H264SPS* sps) {
+ // see 7.4.2.1.1
+ bool seq_scaling_list_present_flag;
+ bool use_default;
+ Result res;
+
+ // parse scaling_list4x4
+ for (int i = 0; i < 6; ++i) {
+ read_bits_or_return(1, &seq_scaling_list_present_flag);
+
+ if (seq_scaling_list_present_flag) {
+ res = ScalingList(sps->scaling_list4x4[i],
+ sizeof(sps->scaling_list4x4[i]),
+ &use_default);
+ if (res != kOk)
+ return res;
+
+ if (use_default)
+ DefaultScalingList4x4(i, sps->scaling_list4x4);
+
+ } else {
+ FallbackScalingList4x4(i, default_4x4_intra, default_4x4_inter,
+ sps->scaling_list4x4);
+ }
+ }
+
+ // parse scaling_list8x8
+ for (int i = 0; i < (sps->chroma_format_idc != 3) ? 2 : 6; ++i) {
+ read_bits_or_return(1, &seq_scaling_list_present_flag);
+
+ if (seq_scaling_list_present_flag) {
+ res = ScalingList(sps->scaling_list8x8[i],
+ sizeof(sps->scaling_list8x8[i]),
+ &use_default);
+ if (res != kOk)
+ return res;
+
+ if (use_default)
+ DefaultScalingList8x8(i, sps->scaling_list8x8);
+
+ } else {
+ FallbackScalingList8x8(i, default_8x8_intra, default_8x8_inter,
+ sps->scaling_list8x8);
+ }
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParsePPSScalingLists(H264SPS* sps,
+ H264PPS* pps) {
+ // see 7.4.2.2
+ bool pic_scaling_list_present_flag;
+ bool use_default;
+ Result res;
+
+ for (int i = 0; i < 6; ++i) {
+ read_bits_or_return(1, &pic_scaling_list_present_flag);
+
+ if (pic_scaling_list_present_flag) {
+ res = ScalingList(pps->scaling_list4x4[i],
+ sizeof(pps->scaling_list4x4[i]),
+ &use_default);
+ if (res != kOk)
+ return res;
+
+ if (use_default) // check SPS scaling flag?
+ DefaultScalingList4x4(i, pps->scaling_list4x4);
+
+ } else {
+ if (sps->seq_scaling_matrix_present_flag) {
+ // table 7-2 fallback rule A
+ FallbackScalingList4x4(i, default_4x4_intra, default_4x4_inter,
+ pps->scaling_list4x4);
+ } else {
+ // table 7-2 fallback rule B
+ FallbackScalingList4x4(i, sps->scaling_list4x4[0],
+ sps->scaling_list4x4[3], pps->scaling_list4x4);
+ }
+ }
+ }
+
+ if (pps->transform_8x8_mode_flag) {
+ for (int i = 0; i < (sps->chroma_format_idc != 3) ? 2 : 6; ++i) {
+ read_bits_or_return(1, &pic_scaling_list_present_flag);
+
+ if (pic_scaling_list_present_flag) {
+ res = ScalingList(pps->scaling_list8x8[i],
+ sizeof(pps->scaling_list8x8[i]),
+ &use_default);
+ if (res != kOk)
+ return res;
+
+ if (use_default)
+ DefaultScalingList8x8(i, pps->scaling_list8x8);
+
+ } else {
+ if (sps->seq_scaling_matrix_present_flag) {
+ // table 7-2 fallback rule A
+ FallbackScalingList8x8(i, default_8x8_intra,
+ default_8x8_inter, pps->scaling_list8x8);
+ } else {
+ // table 7-2 fallback rule B
+ FallbackScalingList8x8(i, sps->scaling_list8x8[0],
+ sps->scaling_list8x8[1], pps->scaling_list8x8);
+ }
+ }
+ }
+ }
+ return kOk;
+}
+
+static void FillDefaultSeqScalingLists(H264SPS* sps) {
+ // assumes uint8s in arrays
+ memset(sps->scaling_list4x4, 16, sizeof(sps->scaling_list4x4));
+ memset(sps->scaling_list8x8, 16, sizeof(sps->scaling_list8x8));
+}
+
+H264Parser::Result H264Parser::ParseSPS(int* sps_id) {
+ // see 7.4.2.1
+ uint8 data;
+ Result res;
+
+ *sps_id = -1;
+
+ scoped_ptr<H264SPS> sps(new H264SPS);
+ CHECK(sps != NULL);
+ memset(sps.get(), 0, sizeof(H264SPS));
+
+ read_bits_or_return(8, &sps->profile_idc);
+ // skip constraint_setx_flag and reserved flags
+ read_bits_or_return(8, &data);
+ read_bits_or_return(8, &sps->level_idc);
+ read_ue_or_return(&sps->seq_parameter_set_id);
+ true_or_return(sps->seq_parameter_set_id < 32);
+
+ if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+ sps->profile_idc == 122 || sps->profile_idc == 244 ||
+ sps->profile_idc == 44 || sps->profile_idc == 83 ||
+ sps->profile_idc == 86 || sps->profile_idc == 118 ||
+ sps->profile_idc == 128) {
+ read_ue_or_return(&sps->chroma_format_idc);
+ true_or_return(sps->chroma_format_idc < 4);
+
+ if (sps->chroma_format_idc == 3)
+ read_bits_or_return(1, &sps->separate_colour_plane_flag);
+
+ if (sps->separate_colour_plane_flag)
+ sps->chroma_array_type = 0;
+ else
+ sps->chroma_array_type = sps->chroma_format_idc;
+
+ read_ue_or_return(&sps->bit_depth_luma_minus8);
+ true_or_return(sps->bit_depth_luma_minus8 < 7);
+
+ read_ue_or_return(&sps->bit_depth_chroma_minus8);
+ true_or_return(sps->bit_depth_chroma_minus8 < 7);
+
+ read_bits_or_return(1, &sps->qpprime_y_zero_transform_bypass_flag);
+ read_bits_or_return(1, &sps->seq_scaling_matrix_present_flag);
+
+ if (sps->seq_scaling_matrix_present_flag) {
+ DVLOG(4) << "Scaling matrix present";
+ res = ParseSPSScalingLists(sps.get());
+ if (res != kOk)
+ return res;
+ } else {
+ FillDefaultSeqScalingLists(sps.get());
+ }
+ }
+
+ read_ue_or_return(&sps->log2_max_frame_num_minus4);
+ true_or_return(sps->log2_max_frame_num_minus4 < 13);
+
+ read_ue_or_return(&sps->pic_order_cnt_type);
+ true_or_return(sps->pic_order_cnt_type < 3);
+
+ if (sps->pic_order_cnt_type == 0) {
+ read_ue_or_return(&sps->log2_max_pic_order_cnt_lsb_minus4);
+ true_or_return(sps->log2_max_pic_order_cnt_lsb_minus4 < 13);
+ } else if (sps->pic_order_cnt_type == 1) {
+ read_bits_or_return(1, &sps->delta_pic_order_always_zero_flag);
+ read_se_or_return(&sps->offset_for_non_ref_pic);
+ read_se_or_return(&sps->offset_for_top_to_bottom_field);
+ read_ue_or_return(&sps->num_ref_frames_in_pic_order_cnt_cycle);
+ for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i)
+ read_se_or_return(&sps->offset_for_ref_frame[i]);
+ }
+
+ read_ue_or_return(&sps->max_num_ref_frames);
+ read_bits_or_return(1, &sps->gaps_in_frame_num_value_allowed_flag);
+
+ if (sps->gaps_in_frame_num_value_allowed_flag)
+ return kUnsupportedStream;
+
+ read_ue_or_return(&sps->pic_width_in_mbs_minus1);
+ read_ue_or_return(&sps->pic_height_in_map_units_minus1);
+
+ read_bits_or_return(1, &sps->frame_mbs_only_flag);
+ if (!sps->frame_mbs_only_flag)
+ read_bits_or_return(1, &sps->mb_adaptive_frame_field_flag);
+
+ read_bits_or_return(1, &sps->direct_8x8_inference_flag);
+
+ read_bits_or_return(1, &sps->frame_cropping_flag);
+ if (sps->frame_cropping_flag) {
+ read_ue_or_return(&sps->frame_crop_left_offset);
+ read_ue_or_return(&sps->frame_crop_right_offset);
+ read_ue_or_return(&sps->frame_crop_top_offset);
+ read_ue_or_return(&sps->frame_crop_bottom_offset);
+ }
+
+ read_bits_or_return(1, &sps->vui_parameters_present_flag);
+ if (sps->vui_parameters_present_flag) {
+ DLOG(INFO) << "VUI parameters present in SPS, ignoring";
+ }
+
+ // If an SPS with the same id already exists, replace it
+ SPSById::iterator it = active_SPSes_.find(sps->seq_parameter_set_id);
+ if (it != active_SPSes_.end()) {
+ delete it->second;
+ active_SPSes_.erase(it);
+ }
+
+ *sps_id = sps->seq_parameter_set_id;
+ active_SPSes_[sps->seq_parameter_set_id] = sps.release();
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParsePPS(int* pps_id) {
+ // see 7.4.2.2
+ H264SPS* sps;
+ Result res;
+
+ *pps_id = -1;
+
+ scoped_ptr<H264PPS> pps(new H264PPS);
+ CHECK(pps != NULL);
+ memset(pps.get(), 0, sizeof(H264PPS));
+
+ read_ue_or_return(&pps->pic_parameter_set_id);
+ read_ue_or_return(&pps->seq_parameter_set_id);
+ true_or_return(pps->seq_parameter_set_id < 32);
+
+ sps = GetSPS(pps->seq_parameter_set_id);
+ true_or_return(sps != NULL);
+
+ read_bits_or_return(1, &pps->entropy_coding_mode_flag);
+ read_bits_or_return(1, &pps->bottom_field_pic_order_in_frame_present_flag);
+
+ read_ue_or_return(&pps->num_slice_groups_minus1);
+ if (pps->num_slice_groups_minus1 > 1) {
+ DLOG(INFO) << "Slice groups not supported";
+ return kUnsupportedStream;
+ }
+
+ read_ue_or_return(&pps->num_ref_idx_l0_default_active_minus1);
+ true_or_return(pps->num_ref_idx_l0_default_active_minus1 < 32);
+
+ read_ue_or_return(&pps->num_ref_idx_l1_default_active_minus1);
+ true_or_return(pps->num_ref_idx_l1_default_active_minus1 < 32);
+
+ read_bits_or_return(1, &pps->weighted_pred_flag);
+ read_bits_or_return(2, &pps->weighted_bipred_idc);
+ true_or_return(pps->weighted_bipred_idc < 3);
+
+ read_se_or_return(&pps->pic_init_qp_minus26);
+ range_in_or_return(pps->pic_init_qp_minus26, -26, 25);
+
+ read_se_or_return(&pps->pic_init_qs_minus26);
+ range_in_or_return(pps->pic_init_qs_minus26, -26, 25);
+
+ read_se_or_return(&pps->chroma_qp_index_offset);
+ range_in_or_return(pps->chroma_qp_index_offset, -12, 12);
+
+ read_bits_or_return(1, &pps->deblocking_filter_control_present_flag);
+ read_bits_or_return(1, &pps->constrained_intra_pred_flag);
+ read_bits_or_return(1, &pps->redundant_pic_cnt_present_flag);
+
+ if (br_.MoreRBSPData()) {
+ read_bits_or_return(1, &pps->transform_8x8_mode_flag);
+ read_bits_or_return(1, &pps->pic_scaling_matrix_present_flag);
+
+ if (pps->pic_scaling_matrix_present_flag) {
+ DVLOG(4) << "Picture scaling matrix present";
+ res = ParsePPSScalingLists(sps, pps.get());
+ if (res != kOk)
+ return res;
+ }
+
+ read_se_or_return(&pps->second_chroma_qp_index_offset);
+ }
+
+ PPSById::iterator it = active_PPSes_.find(pps->pic_parameter_set_id);
+ if (it != active_PPSes_.end()) {
+ delete it->second;
+ active_PPSes_.erase(it);
+ }
+
+ *pps_id = pps->pic_parameter_set_id;
+ // If a PPS with the same id already exists, replace it
+ active_PPSes_[pps->pic_parameter_set_id] = pps.release();
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseRefPicListModification(
+ uint8 num_ref_idx_active_minus1,
+ H264ModificationOfPicNum* ref_list_mods) {
+ H264ModificationOfPicNum *pic_num_mod;
+
+ if (num_ref_idx_active_minus1 >= 32)
+ return kInvalidStream;
+
+ //for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) {
+ for (int i = 0; i < 32; ++i) {
+ pic_num_mod = &ref_list_mods[i];
+ read_ue_or_return(&pic_num_mod->modification_of_pic_nums_idc);
+ true_or_return(pic_num_mod->modification_of_pic_nums_idc < 4);
+
+ switch (pic_num_mod->modification_of_pic_nums_idc) {
+ case 0:
+ case 1:
+ read_ue_or_return(&pic_num_mod->abs_diff_pic_num_minus1);
+ break;
+
+ case 2:
+ read_ue_or_return(&pic_num_mod->long_term_pic_num);
+ break;
+
+ case 3:
+ // per spec, list cannot be empty
+ if (i == 0)
+ return kInvalidStream;
+ return kOk;
+
+ default:
+ return kInvalidStream;
+ }
+ }
+
+ // if we got here, we didn't get loop end marker prematurely,
+ // so make sure it is there
+ uint8 modification_of_pic_nums_idc;
+ read_ue_or_return(&modification_of_pic_nums_idc);
+ true_or_return(modification_of_pic_nums_idc == 3);
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::RefPicListModification(H264SliceHeader* shdr) {
+ Result res;
+
+ if (shdr->slice_type % 5 != 2 && shdr->slice_type % 5 != 4) {
+ read_bits_or_return(1, &shdr->ref_pic_list_modification_flag_l0);
+ if (shdr->ref_pic_list_modification_flag_l0) {
+ res = ParseRefPicListModification(shdr->num_ref_idx_l0_active_minus1,
+ shdr->ref_list_l0_modifications);
+ if (res != kOk)
+ return res;
+ }
+ }
+
+ if (shdr->slice_type % 5 == 1) {
+ read_bits_or_return(1, &shdr->ref_pic_list_modification_flag_l1);
+ if (shdr->ref_pic_list_modification_flag_l1) {
+ res = ParseRefPicListModification(shdr->num_ref_idx_l1_active_minus1,
+ shdr->ref_list_l1_modifications);
+ if (res != kOk)
+ return res;
+ }
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseWeightingFactors(
+ H264WeightingFactors* w_facts,
+ int num_ref_idx_active_minus1,
+ uint8 chroma_array_type,
+ uint8 luma_log2_weight_denom,
+ uint8 chroma_log2_weight_denom) {
+
+ int16 def_luma_weight = 1 << luma_log2_weight_denom;
+ int16 def_chroma_weight = 1 << chroma_log2_weight_denom;
+
+ for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) {
+ read_bits_or_return(1, &w_facts->luma_weight_flag);
+ if (w_facts->luma_weight_flag) {
+ read_se_or_return(&w_facts->luma_weight[i]);
+ range_in_or_return(w_facts->luma_weight[i], -128, 127);
+
+ read_se_or_return(&w_facts->luma_offset[i]);
+ range_in_or_return(w_facts->luma_offset[i], -128, 127);
+ } else {
+ w_facts->luma_weight[i] = def_luma_weight;
+ w_facts->luma_offset[i] = 0;
+ }
+
+ if (chroma_array_type != 0) {
+ read_bits_or_return(1, &w_facts->chroma_weight_flag);
+ if (w_facts->chroma_weight_flag) {
+ for (int j = 0; j < 2; ++j) {
+ read_se_or_return(&w_facts->chroma_weight[i][j]);
+ range_in_or_return(w_facts->chroma_weight[i][j], -128, 127);
+
+ read_se_or_return(&w_facts->chroma_offset[i][j]);
+ range_in_or_return(w_facts->chroma_offset[i][j], -128, 127);
+ }
+ } else {
+ for (int j = 0; j < 2; ++j) {
+ w_facts->chroma_weight[i][j] = def_chroma_weight;
+ w_facts->chroma_offset[i][j] = 0;
+ }
+ }
+ }
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParsePredWeightTable(H264SliceHeader *shdr,
+ H264SPS* sps) {
+ Result res;
+
+ read_ue_or_return(&shdr->luma_log2_weight_denom);
+ true_or_return(shdr->luma_log2_weight_denom < 8);
+
+ if (sps->chroma_array_type != 0)
+ read_ue_or_return(&shdr->chroma_log2_weight_denom);
+ true_or_return(shdr->chroma_log2_weight_denom < 8);
+
+ res = ParseWeightingFactors(&shdr->pred_weight_table_l0,
+ shdr->num_ref_idx_l0_active_minus1,
+ sps->chroma_array_type,
+ shdr->luma_log2_weight_denom,
+ shdr->chroma_log2_weight_denom);
+ if (res != kOk)
+ return res;
+
+ if (shdr->slice_type % 5 == 1) {
+ res = ParseWeightingFactors(&shdr->pred_weight_table_l1,
+ shdr->num_ref_idx_l1_active_minus1,
+ sps->chroma_array_type,
+ shdr->luma_log2_weight_denom,
+ shdr->chroma_log2_weight_denom);
+ if (res != kOk)
+ return res;
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseDecRefPicMarking(H264SliceHeader *shdr) {
+
+ if (shdr->idr_pic_flag) {
+ read_bits_or_return(1, &shdr->no_output_of_prior_pics_flag);
+ read_bits_or_return(1, &shdr->long_term_reference_flag);
+ } else {
+ read_bits_or_return(1, &shdr->adaptive_ref_pic_marking_mode_flag);
+
+ H264DecRefPicMarking* marking;
+ if (shdr->adaptive_ref_pic_marking_mode_flag) {
+ size_t i;
+ for (i = 0; i < arraysize(shdr->ref_pic_marking); ++i) {
+ marking = &shdr->ref_pic_marking[i];
+
+ read_ue_or_return(&marking->memory_mgmnt_control_operation);
+ if (marking->memory_mgmnt_control_operation == 0)
+ break;
+
+ if (marking->memory_mgmnt_control_operation == 1 ||
+ marking->memory_mgmnt_control_operation == 3)
+ read_ue_or_return(&marking->difference_of_pic_nums_minus1);
+
+ if (marking->memory_mgmnt_control_operation == 2)
+ read_ue_or_return(&marking->long_term_pic_num);
+
+ if (marking->memory_mgmnt_control_operation == 3 ||
+ marking->memory_mgmnt_control_operation == 6)
+ read_ue_or_return(&marking->long_term_frame_idx);
+
+ if (marking->memory_mgmnt_control_operation == 4)
+ read_ue_or_return(&marking->max_long_term_frame_idx_plus1);
+
+ if (marking->memory_mgmnt_control_operation > 6)
+ return kInvalidStream;
+ }
+
+ if (i == arraysize(shdr->ref_pic_marking)) {
+ LOG(INFO) << "Ran out of dec ref pic marking fields";
+ return kUnsupportedStream;
+ }
+ }
+ }
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseSliceHeader(H264SliceHeader* shdr,
+ H264NALU* nalu) {
+ // see 7.4.3
+ H264SPS* sps;
+ H264PPS* pps;
+ Result res;
+
+ memset(shdr, 0, sizeof(*shdr));
+
+ shdr->idr_pic_flag = ((nalu->nal_unit_type == 5) ? true : false);
+ shdr->nal_ref_idc = nalu->nal_ref_idc;
+ shdr->nalu_data = nalu->data;
+ shdr->nalu_size = nalu->size;
+
+ read_ue_or_return(&shdr->first_mb_in_slice);
+ read_ue_or_return(&shdr->slice_type);
+ true_or_return(shdr->slice_type < 10);
+
+ read_ue_or_return(&shdr->pic_parameter_set_id);
+
+ pps = GetPPS(shdr->pic_parameter_set_id);
+ true_or_return(pps != NULL);
+
+ sps = GetSPS(pps->seq_parameter_set_id);
+ true_or_return(sps != NULL);
+
+ if (sps->separate_colour_plane_flag) {
+ DLOG(INFO) << "Interlaced streams not supported";
+ return kUnsupportedStream;
+ //read_bits_or_return(2, &shdr->colour_plane_id);
+ //true_or_return(shdr->colour_plane_id < 3);
+ }
+
+ read_bits_or_return(sps->log2_max_frame_num_minus4 + 4,
+ &shdr->frame_num);
+ if (!sps->frame_mbs_only_flag) {
+ read_bits_or_return(1, &shdr->field_pic_flag);
+ if (shdr->field_pic_flag) {
+ DLOG(INFO) << "Interlaced streams not supported";
+ return kUnsupportedStream;
+ //read_bits_or_return(1, &shdr->bottom_field_flag);
+ }
+ }
+
+ if (shdr->idr_pic_flag)
+ read_ue_or_return(&shdr->idr_pic_id);
+
+ if (sps->pic_order_cnt_type == 0) {
+ read_bits_or_return(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
+ &shdr->pic_order_cnt_lsb);
+ if (pps->bottom_field_pic_order_in_frame_present_flag &&
+ !shdr->field_pic_flag)
+ read_se_or_return(&shdr->delta_pic_order_cnt_bottom);
+ }
+
+ if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
+ read_se_or_return(&shdr->delta_pic_order_cnt[0]);
+ if (pps->bottom_field_pic_order_in_frame_present_flag &&
+ !shdr->field_pic_flag)
+ read_se_or_return(&shdr->delta_pic_order_cnt[1]);
+ }
+
+ if (pps->redundant_pic_cnt_present_flag) {
+ read_ue_or_return(&shdr->redundant_pic_cnt);
+ true_or_return(shdr->redundant_pic_cnt < 128);
+ }
+
+ if (IsH264BSlice(shdr))
+ read_bits_or_return(1, &shdr->direct_spatial_mv_pred_flag);
+
+ if (IsH264PSlice(shdr) || IsH264SPSlice(shdr) || IsH264BSlice(shdr)) {
+ read_bits_or_return(1, &shdr->num_ref_idx_active_override_flag);
+ if (shdr->num_ref_idx_active_override_flag) {
+ read_ue_or_return(&shdr->num_ref_idx_l0_active_minus1);
+ if (IsH264BSlice(shdr))
+ read_ue_or_return(&shdr->num_ref_idx_l1_active_minus1);
+ } else {
+ shdr->num_ref_idx_l0_active_minus1 =
+ pps->num_ref_idx_l0_default_active_minus1;
+ shdr->num_ref_idx_l1_active_minus1 =
+ pps->num_ref_idx_l1_default_active_minus1;
+ }
+ }
+ if (shdr->field_pic_flag) {
+ true_or_return(shdr->num_ref_idx_l0_active_minus1 < 32);
+ true_or_return(shdr->num_ref_idx_l1_active_minus1 < 32);
+ } else {
+ true_or_return(shdr->num_ref_idx_l0_active_minus1 < 16);
+ true_or_return(shdr->num_ref_idx_l1_active_minus1 < 16);
+ }
+
+ if (nalu->nal_unit_type == 20) {
+ return kUnsupportedStream;
+ } else {
+ res = RefPicListModification(shdr);
+ if (res != kOk)
+ return res;
+ }
+
+ if ((pps->weighted_pred_flag && (IsH264PSlice(shdr) || IsH264SPSlice(shdr)))
+ || (pps->weighted_bipred_idc == 1 && IsH264BSlice(shdr))) {
+ res = ParsePredWeightTable(shdr, sps);
+ if (res != kOk)
+ return res;
+ }
+
+ if (nalu->nal_ref_idc != 0) {
+ res = ParseDecRefPicMarking(shdr);
+ if (res != kOk)
+ return res;
+ }
+
+ if (pps->entropy_coding_mode_flag &&
+ !IsH264ISlice(shdr) && !IsH264SISlice(shdr)) {
+ read_ue_or_return(&shdr->cabac_init_idc);
+ true_or_return(shdr->cabac_init_idc < 3);
+ }
+
+ read_se_or_return(&shdr->slice_qp_delta);
+
+ if (IsH264SPSlice(shdr) || IsH264SISlice(shdr)) {
+ if (IsH264SPSlice(shdr))
+ read_bits_or_return(1, &shdr->sp_for_switch_flag);
+ read_se_or_return(&shdr->slice_qs_delta);
+ }
+
+ if (pps->deblocking_filter_control_present_flag) {
+ read_ue_or_return(&shdr->disable_deblocking_filter_idc);
+ true_or_return(shdr->disable_deblocking_filter_idc < 3);
+
+ if (shdr->disable_deblocking_filter_idc != 1) {
+ read_se_or_return(&shdr->slice_alpha_c0_offset_div2);
+ range_in_or_return(shdr->slice_alpha_c0_offset_div2, -6, 6);
+
+ read_se_or_return(&shdr->slice_beta_offset_div2);
+ range_in_or_return(shdr->slice_beta_offset_div2, -6, 6);
+ }
+ }
+
+ if (pps->num_slice_groups_minus1 > 0) {
+ // TODO slice groups
+ DLOG(INFO) << "Slice groups not supported";
+ return kUnsupportedStream;
+ }
+
+ shdr->header_bit_size = shdr->nalu_size * 8 - br_.NumBitsLeft();
+
+ return kOk;
+}
+
+H264Parser::Result H264Parser::ParseSEI(H264SEIMessage* sei_msg) {
+ int8 byte;
+
+ memset(sei_msg, 0, sizeof(*sei_msg));
+
+ read_bits_or_return(8, &byte);
+ while (byte == 0xff) {
+ sei_msg->type += 255;
+ read_bits_or_return(8, &byte);
+ }
+ sei_msg->type += byte;
+
+ while (byte == 0xff) {
+ sei_msg->payload_size += 255;
+ read_bits_or_return(8, &byte);
+ }
+ sei_msg->payload_size += byte;
+
+ DVLOG(4) << "Found SEI message type: " << sei_msg->type
+ << " payload size: " << sei_msg->payload_size;
+
+ switch (sei_msg->type) {
+ case kH264SEIRecoveryPoint:
+ read_ue_or_return(&sei_msg->recovery_point.recovery_frame_cnt);
+ read_bits_or_return(1, &sei_msg->recovery_point.exact_match_flag);
+ read_bits_or_return(1, &sei_msg->recovery_point.broken_link_flag);
+ read_bits_or_return(2,
+ &sei_msg->recovery_point.changing_slice_group_idc);
+ break;
+
+ default:
+ DVLOG(4) << "Unsupported SEI message";
+ break;
+ }
+
+ return kOk;
+}
+

Powered by Google App Engine
This is Rietveld 408576698