summaryrefslogtreecommitdiff
path: root/chromium/media/video/h265_parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/video/h265_parser.cc')
-rw-r--r--chromium/media/video/h265_parser.cc1681
1 files changed, 1680 insertions, 1 deletions
diff --git a/chromium/media/video/h265_parser.cc b/chromium/media/video/h265_parser.cc
index 77e83491ce7..7d46b7029fb 100644
--- a/chromium/media/video/h265_parser.cc
+++ b/chromium/media/video/h265_parser.cc
@@ -6,12 +6,115 @@
#include <stddef.h>
+#include <algorithm>
+#include <cmath>
+
+#include "base/bits.h"
#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
#include "media/base/decrypt_config.h"
+#include "media/base/video_codecs.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
namespace media {
+namespace {
+
+// From Table 7-6.
+constexpr int kDefaultScalingListSize1To3Matrix0To2[] = {
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 17, 16, 17, 18,
+ 17, 18, 18, 17, 18, 21, 19, 20, 21, 20, 19, 21, 24, 22, 22, 24,
+ 24, 22, 22, 24, 25, 25, 27, 30, 27, 25, 25, 29, 31, 35, 35, 31,
+ 29, 36, 41, 44, 41, 36, 47, 54, 54, 47, 65, 70, 65, 88, 88, 115,
+};
+constexpr int kDefaultScalingListSize1To3Matrix3To5[] = {
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18,
+ 18, 18, 18, 18, 18, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24,
+ 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 28, 28, 28, 28, 28,
+ 28, 33, 33, 33, 33, 33, 41, 41, 41, 41, 54, 54, 54, 71, 71, 91,
+};
+
+// VUI parameters: Table E-1 "Interpretation of sample aspect ratio indicator"
+constexpr int kTableSarWidth[] = {0, 1, 12, 10, 16, 40, 24, 20, 32,
+ 80, 18, 15, 64, 160, 4, 3, 2};
+constexpr int kTableSarHeight[] = {0, 1, 11, 11, 11, 33, 11, 11, 11,
+ 33, 11, 11, 33, 99, 3, 2, 1};
+static_assert(base::size(kTableSarWidth) == base::size(kTableSarHeight),
+ "sar tables must have the same size");
+
+// Converts [|start|, |end|) range with |encrypted_ranges| into a vector of
+// SubsampleEntry. |encrypted_ranges| must be with in the range defined by
+// |start| and |end|.
+// It is OK to pass in empty |encrypted_ranges|; this will return a vector
+// with single SubsampleEntry with clear_bytes set to the size of the buffer.
+std::vector<SubsampleEntry> EncryptedRangesToSubsampleEntry(
+ const uint8_t* start,
+ const uint8_t* end,
+ const Ranges<const uint8_t*>& encrypted_ranges) {
+ std::vector<SubsampleEntry> subsamples(encrypted_ranges.size());
+ const uint8_t* cur = start;
+ for (size_t i = 0; i < encrypted_ranges.size(); ++i) {
+ const uint8_t* encrypted_start = encrypted_ranges.start(i);
+ DCHECK_GE(encrypted_start, cur)
+ << "Encrypted range started before the current buffer pointer.";
+ subsamples[i].clear_bytes = encrypted_start - cur;
+
+ const uint8_t* encrypted_end = encrypted_ranges.end(i);
+ subsamples[i].cypher_bytes = encrypted_end - encrypted_start;
+
+ cur = encrypted_end;
+ DCHECK_LE(cur, end) << "Encrypted range is outside the buffer range.";
+ }
+
+ // If there is more data in the buffer but not covered by encrypted_ranges,
+ // then it must be in the clear.
+ if (cur < end)
+ subsamples.emplace_back(end - cur, 0);
+
+ return subsamples;
+}
+
+void FillInDefaultScalingListData(H265ScalingListData* scaling_list_data,
+ int size_id,
+ int matrix_id) {
+ if (size_id == 0) {
+ std::fill_n(scaling_list_data->scaling_list_4x4[matrix_id],
+ H265ScalingListData::kScalingListSizeId0Count,
+ H265ScalingListData::kDefaultScalingListSize0Values);
+ return;
+ }
+
+ int* dst;
+ switch (size_id) {
+ case 1:
+ dst = scaling_list_data->scaling_list_8x8[matrix_id];
+ break;
+ case 2:
+ dst = scaling_list_data->scaling_list_16x16[matrix_id];
+ break;
+ case 3:
+ dst = scaling_list_data->scaling_list_32x32[matrix_id];
+ break;
+ }
+ const int* src;
+ if (matrix_id < 3)
+ src = kDefaultScalingListSize1To3Matrix0To2;
+ else
+ src = kDefaultScalingListSize1To3Matrix3To5;
+ memcpy(dst, src,
+ H265ScalingListData::kScalingListSizeId1To3Count * sizeof(*src));
+
+ // These are sixteen because the default for the minus8 values is 8.
+ if (size_id == 2)
+ scaling_list_data->scaling_list_dc_coef_16x16[matrix_id] = 16;
+ else if (size_id == 3)
+ scaling_list_data->scaling_list_dc_coef_32x32[matrix_id] = 16;
+}
+
+} // namespace
+
#define READ_BITS_OR_RETURN(num_bits, out) \
do { \
int _out; \
@@ -23,6 +126,56 @@ namespace media {
*out = _out; \
} while (0)
+#define SKIP_BITS_OR_RETURN(num_bits) \
+ do { \
+ int bits_left = num_bits; \
+ int data; \
+ while (bits_left > 0) { \
+ if (!br_.ReadBits(bits_left > 16 ? 16 : bits_left, &data)) { \
+ DVLOG(1) << "Error in stream: unexpected EOS while trying to skip"; \
+ return kInvalidStream; \
+ } \
+ bits_left -= 16; \
+ } \
+ } while (0)
+
+#define READ_BOOL_OR_RETURN(out) \
+ do { \
+ int _out; \
+ if (!br_.ReadBits(1, &_out)) { \
+ DVLOG(1) \
+ << "Error in stream: unexpected EOS while trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ *out = _out != 0; \
+ } while (0)
+
+#define READ_UE_OR_RETURN(out) \
+ do { \
+ if (ReadUE(out) != kOk) { \
+ DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ } while (0)
+
+#define READ_SE_OR_RETURN(out) \
+ do { \
+ if (ReadSE(out) != kOk) { \
+ DVLOG(1) << "Error in stream: invalid value while trying to read " #out; \
+ return kInvalidStream; \
+ } \
+ } while (0)
+
+#define IN_RANGE_OR_RETURN(val, min, max) \
+ do { \
+ if ((val) < (min) || (val) > (max)) { \
+ DVLOG(1) << "Error in stream: invalid value, expected " #val " to be" \
+ << " in range [" << (min) << ":" << (max) << "]" \
+ << " found " << (val) << " instead"; \
+ return kInvalidStream; \
+ } \
+ } while (0)
+
#define TRUE_OR_RETURN(a) \
do { \
if (!(a)) { \
@@ -32,7 +185,43 @@ namespace media {
} while (0)
H265NALU::H265NALU() {
- memset(this, 0, sizeof(*this));
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265ScalingListData::H265ScalingListData() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265StRefPicSet::H265StRefPicSet() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265SPS::H265SPS() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265ProfileTierLevel::H265ProfileTierLevel() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265VUIParameters::H265VUIParameters() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265PPS::H265PPS() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265RefPicListsModifications::H265RefPicListsModifications() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265PredWeightTable::H265PredWeightTable() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
+}
+
+H265SliceHeader::H265SliceHeader() {
+ memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
}
H265Parser::H265Parser() {
@@ -41,10 +230,87 @@ H265Parser::H265Parser() {
H265Parser::~H265Parser() {}
+int H265ProfileTierLevel::GetMaxLumaPs() const {
+ // From Table A.8 - General tier and level limits.
+ // |general_level_idc| is 30x the actual level.
+ if (general_level_idc <= 30) // level 1
+ return 36864;
+ if (general_level_idc <= 60) // level 2
+ return 122880;
+ if (general_level_idc <= 63) // level 2.1
+ return 245760;
+ if (general_level_idc <= 90) // level 3
+ return 552960;
+ if (general_level_idc <= 93) // level 3.1
+ return 983040;
+ if (general_level_idc <= 123) // level 4, 4.1
+ return 2228224;
+ if (general_level_idc <= 156) // level 5, 5.1, 5.2
+ return 8912896;
+ // level 6, 6.1, 6.2 - beyond that there's no actual limit.
+ return 35651584;
+}
+
+size_t H265ProfileTierLevel::GetDpbMaxPicBuf() const {
+ // From A.4.2 - Profile-specific level limits for the video profiles.
+ // If sps_curr_pic_ref_enabled_flag is required to be zero, than this is 6
+ // otherwise it is 7.
+ return (general_profile_idc >= kProfileIdcMain &&
+ general_profile_idc <= kProfileIdcHighThroughput)
+ ? 6
+ : 7;
+}
+
+gfx::Size H265SPS::GetCodedSize() const {
+ return gfx::Size(pic_width_in_luma_samples, pic_height_in_luma_samples);
+}
+
+gfx::Rect H265SPS::GetVisibleRect() const {
+ // 7.4.3.2.1
+ // These are verified in the parser that they won't overflow.
+ int left = (conf_win_left_offset + vui_parameters.def_disp_win_left_offset) *
+ sub_width_c;
+ int top = (conf_win_top_offset + vui_parameters.def_disp_win_top_offset) *
+ sub_height_c;
+ int right =
+ (conf_win_right_offset + vui_parameters.def_disp_win_right_offset) *
+ sub_width_c;
+ int bottom =
+ (conf_win_bottom_offset + vui_parameters.def_disp_win_bottom_offset) *
+ sub_height_c;
+ return gfx::Rect(left, top, pic_width_in_luma_samples - left - right,
+ pic_height_in_luma_samples - top - bottom);
+}
+
+// From E.3.1 VUI parameters semantics
+VideoColorSpace H265SPS::GetColorSpace() const {
+ if (!vui_parameters.colour_description_present_flag)
+ return VideoColorSpace();
+
+ return VideoColorSpace(
+ vui_parameters.colour_primaries, vui_parameters.transfer_characteristics,
+ vui_parameters.matrix_coeffs,
+ vui_parameters.video_full_range_flag ? gfx::ColorSpace::RangeID::FULL
+ : gfx::ColorSpace::RangeID::LIMITED);
+}
+
+bool H265SliceHeader::IsISlice() const {
+ return slice_type == kSliceTypeI;
+}
+
+bool H265SliceHeader::IsPSlice() const {
+ return slice_type == kSliceTypeP;
+}
+
+bool H265SliceHeader::IsBSlice() const {
+ return slice_type == kSliceTypeB;
+}
+
void H265Parser::Reset() {
stream_ = NULL;
bytes_left_ = 0;
encrypted_ranges_.clear();
+ previous_nalu_range_.clear();
}
void H265Parser::SetStream(const uint8_t* stream, off_t stream_size) {
@@ -61,6 +327,7 @@ void H265Parser::SetEncryptedStream(
stream_ = stream;
bytes_left_ = stream_size;
+ previous_nalu_range_.clear();
encrypted_ranges_.clear();
const uint8_t* start = stream;
@@ -116,6 +383,54 @@ bool H265Parser::LocateNALU(off_t* nalu_size, off_t* start_code_size) {
return true;
}
+H265Parser::Result H265Parser::ReadUE(int* val) {
+ // Count the number of contiguous zero bits.
+ int bit;
+ int num_bits = -1;
+ do {
+ READ_BITS_OR_RETURN(1, &bit);
+ num_bits++;
+ } while (bit == 0);
+
+ if (num_bits > 31)
+ return kInvalidStream;
+
+ // Calculate exp-Golomb code value of size num_bits.
+ // Special case for |num_bits| == 31 to avoid integer overflow. The only
+ // valid representation as an int is 2^31 - 1, so the remaining bits must
+ // be 0 or else the number is too large.
+ *val = (1u << num_bits) - 1u;
+
+ int rest;
+ if (num_bits == 31) {
+ READ_BITS_OR_RETURN(num_bits, &rest);
+ return (rest == 0) ? kOk : kInvalidStream;
+ }
+
+ if (num_bits > 0) {
+ READ_BITS_OR_RETURN(num_bits, &rest);
+ *val += rest;
+ }
+
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ReadSE(int* val) {
+ // See Chapter 9 in the spec.
+ int ue;
+ Result res;
+ res = ReadUE(&ue);
+ if (res != kOk)
+ return res;
+
+ if (ue % 2 == 0)
+ *val = -(ue / 2);
+ else
+ *val = ue / 2 + 1;
+
+ return kOk;
+}
+
H265Parser::Result H265Parser::AdvanceToNextNALU(H265NALU* nalu) {
off_t start_code_size;
off_t nalu_size_with_start_code;
@@ -125,6 +440,7 @@ H265Parser::Result H265Parser::AdvanceToNextNALU(H265NALU* nalu) {
return kEOStream;
}
+ DCHECK(nalu);
nalu->data = stream_ + start_code_size;
nalu->size = nalu_size_with_start_code - start_code_size;
DVLOG(4) << "NALU found: size=" << nalu_size_with_start_code;
@@ -153,6 +469,1369 @@ H265Parser::Result H265Parser::AdvanceToNextNALU(H265NALU* nalu) {
<< " at: " << reinterpret_cast<const void*>(nalu->data)
<< " size: " << nalu->size;
+ previous_nalu_range_.clear();
+ previous_nalu_range_.Add(nalu->data, nalu->data + nalu->size);
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseSPS(int* sps_id) {
+ // 7.4.3.2
+ DVLOG(4) << "Parsing SPS";
+ Result res = kOk;
+
+ DCHECK(sps_id);
+ *sps_id = -1;
+
+ std::unique_ptr<H265SPS> sps = std::make_unique<H265SPS>();
+ SKIP_BITS_OR_RETURN(4); // sps_video_parameter_set_id
+ READ_BITS_OR_RETURN(3, &sps->sps_max_sub_layers_minus1);
+ IN_RANGE_OR_RETURN(sps->sps_max_sub_layers_minus1, 0, 6);
+ SKIP_BITS_OR_RETURN(1); // sps_temporal_id_nesting_flag
+
+ res = ParseProfileTierLevel(true, sps->sps_max_sub_layers_minus1,
+ &sps->profile_tier_level);
+ if (res != kOk)
+ return res;
+
+ READ_UE_OR_RETURN(&sps->sps_seq_parameter_set_id);
+ IN_RANGE_OR_RETURN(sps->sps_seq_parameter_set_id, 0, 15);
+ READ_UE_OR_RETURN(&sps->chroma_format_idc);
+ IN_RANGE_OR_RETURN(sps->chroma_format_idc, 0, 3);
+ if (sps->chroma_format_idc == 3) {
+ READ_BOOL_OR_RETURN(&sps->separate_colour_plane_flag);
+ }
+ sps->chroma_array_type =
+ sps->separate_colour_plane_flag ? 0 : sps->chroma_format_idc;
+ // Table 6-1.
+ if (sps->chroma_format_idc == 1) {
+ sps->sub_width_c = sps->sub_height_c = 2;
+ } else if (sps->chroma_format_idc == 2) {
+ sps->sub_width_c = 2;
+ sps->sub_height_c = 1;
+ } else {
+ sps->sub_width_c = sps->sub_height_c = 1;
+ }
+ READ_UE_OR_RETURN(&sps->pic_width_in_luma_samples);
+ READ_UE_OR_RETURN(&sps->pic_height_in_luma_samples);
+ TRUE_OR_RETURN(sps->pic_width_in_luma_samples != 0);
+ TRUE_OR_RETURN(sps->pic_height_in_luma_samples != 0);
+
+ // Equation A-2: Calculate max_dpb_size.
+ int max_luma_ps = sps->profile_tier_level.GetMaxLumaPs();
+ base::CheckedNumeric<int> pic_size = sps->pic_height_in_luma_samples;
+ pic_size *= sps->pic_width_in_luma_samples;
+ if (!pic_size.IsValid())
+ return kInvalidStream;
+ int pic_size_in_samples_y = pic_size.ValueOrDefault(0);
+ size_t max_dpb_pic_buf = sps->profile_tier_level.GetDpbMaxPicBuf();
+ if (pic_size_in_samples_y <= (max_luma_ps >> 2))
+ sps->max_dpb_size = std::min(4 * max_dpb_pic_buf, size_t{16});
+ else if (pic_size_in_samples_y <= (max_luma_ps >> 1))
+ sps->max_dpb_size = std::min(2 * max_dpb_pic_buf, size_t{16});
+ else if (pic_size_in_samples_y <= ((3 * max_luma_ps) >> 2))
+ sps->max_dpb_size = std::min((4 * max_dpb_pic_buf) / 3, size_t{16});
+ else
+ sps->max_dpb_size = max_dpb_pic_buf;
+
+ bool conformance_window_flag;
+ READ_BOOL_OR_RETURN(&conformance_window_flag);
+ if (conformance_window_flag) {
+ READ_UE_OR_RETURN(&sps->conf_win_left_offset);
+ READ_UE_OR_RETURN(&sps->conf_win_right_offset);
+ READ_UE_OR_RETURN(&sps->conf_win_top_offset);
+ READ_UE_OR_RETURN(&sps->conf_win_bottom_offset);
+ base::CheckedNumeric<int> width_crop = sps->conf_win_left_offset;
+ width_crop += sps->conf_win_right_offset;
+ width_crop *= sps->sub_width_c;
+ if (!width_crop.IsValid())
+ return kInvalidStream;
+ TRUE_OR_RETURN(width_crop.ValueOrDefault(0) <
+ sps->pic_width_in_luma_samples);
+ base::CheckedNumeric<int> height_crop = sps->conf_win_top_offset;
+ width_crop += sps->conf_win_bottom_offset;
+ width_crop *= sps->sub_height_c;
+ if (!height_crop.IsValid())
+ return kInvalidStream;
+ TRUE_OR_RETURN(height_crop.ValueOrDefault(0) <
+ sps->pic_height_in_luma_samples);
+ }
+ READ_UE_OR_RETURN(&sps->bit_depth_luma_minus8);
+ IN_RANGE_OR_RETURN(sps->bit_depth_luma_minus8, 0, 8);
+ sps->bit_depth_y = sps->bit_depth_luma_minus8 + 8;
+ READ_UE_OR_RETURN(&sps->bit_depth_chroma_minus8);
+ IN_RANGE_OR_RETURN(sps->bit_depth_chroma_minus8, 0, 8);
+ sps->bit_depth_c = sps->bit_depth_chroma_minus8 + 8;
+ READ_UE_OR_RETURN(&sps->log2_max_pic_order_cnt_lsb_minus4);
+ IN_RANGE_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4, 0, 12);
+ sps->max_pic_order_cnt_lsb =
+ std::pow(2, sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+ bool sps_sub_layer_ordering_info_present_flag;
+ READ_BOOL_OR_RETURN(&sps_sub_layer_ordering_info_present_flag);
+ for (int i = sps_sub_layer_ordering_info_present_flag
+ ? 0
+ : sps->sps_max_sub_layers_minus1;
+ i <= sps->sps_max_sub_layers_minus1; ++i) {
+ READ_UE_OR_RETURN(&sps->sps_max_dec_pic_buffering_minus1[i]);
+ IN_RANGE_OR_RETURN(sps->sps_max_dec_pic_buffering_minus1[i], 0,
+ static_cast<int>(sps->max_dpb_size) - 1);
+ READ_UE_OR_RETURN(&sps->sps_max_num_reorder_pics[i]);
+ IN_RANGE_OR_RETURN(sps->sps_max_num_reorder_pics[i], 0,
+ sps->sps_max_dec_pic_buffering_minus1[i]);
+ if (i > 0) {
+ TRUE_OR_RETURN(sps->sps_max_dec_pic_buffering_minus1[i] >=
+ sps->sps_max_dec_pic_buffering_minus1[i - 1]);
+ TRUE_OR_RETURN(sps->sps_max_num_reorder_pics[i] >=
+ sps->sps_max_num_reorder_pics[i - 1]);
+ }
+ READ_UE_OR_RETURN(&sps->sps_max_latency_increase_plus1[i]);
+ sps->sps_max_latency_pictures[i] = sps->sps_max_num_reorder_pics[i] +
+ sps->sps_max_latency_increase_plus1[i] -
+ 1;
+ }
+ if (!sps_sub_layer_ordering_info_present_flag) {
+ // Fill in the default values for the other sublayers.
+ for (int i = 0; i < sps->sps_max_sub_layers_minus1; ++i) {
+ sps->sps_max_dec_pic_buffering_minus1[i] =
+ sps->sps_max_dec_pic_buffering_minus1[sps->sps_max_sub_layers_minus1];
+ sps->sps_max_num_reorder_pics[i] =
+ sps->sps_max_num_reorder_pics[sps->sps_max_sub_layers_minus1];
+ sps->sps_max_latency_increase_plus1[i] =
+ sps->sps_max_latency_increase_plus1[sps->sps_max_sub_layers_minus1];
+ sps->sps_max_latency_pictures[i] =
+ sps->sps_max_num_reorder_pics[i] +
+ sps->sps_max_latency_increase_plus1[i] - 1;
+ }
+ }
+ READ_UE_OR_RETURN(&sps->log2_min_luma_coding_block_size_minus3);
+ READ_UE_OR_RETURN(&sps->log2_diff_max_min_luma_coding_block_size);
+
+ int min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3;
+ sps->ctb_log2_size_y =
+ min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size;
+ TRUE_OR_RETURN(min_cb_log2_size_y <= 31 && sps->ctb_log2_size_y <= 31);
+ int min_cb_size_y = 1 << min_cb_log2_size_y;
+ int ctb_size_y = 1 << sps->ctb_log2_size_y;
+ sps->pic_width_in_ctbs_y = base::ClampCeil(
+ static_cast<float>(sps->pic_width_in_luma_samples) / ctb_size_y);
+ sps->pic_height_in_ctbs_y = base::ClampCeil(
+ static_cast<float>(sps->pic_height_in_luma_samples) / ctb_size_y);
+ sps->pic_size_in_ctbs_y =
+ sps->pic_width_in_ctbs_y * sps->pic_height_in_ctbs_y;
+
+ TRUE_OR_RETURN(sps->pic_width_in_luma_samples % min_cb_size_y == 0);
+ TRUE_OR_RETURN(sps->pic_height_in_luma_samples % min_cb_size_y == 0);
+ READ_UE_OR_RETURN(&sps->log2_min_luma_transform_block_size_minus2);
+ int min_tb_log2_size_y = sps->log2_min_luma_transform_block_size_minus2 + 2;
+ TRUE_OR_RETURN(min_tb_log2_size_y < min_cb_log2_size_y);
+ READ_UE_OR_RETURN(&sps->log2_diff_max_min_luma_transform_block_size);
+ sps->max_tb_log2_size_y =
+ min_tb_log2_size_y + sps->log2_diff_max_min_luma_transform_block_size;
+ TRUE_OR_RETURN(sps->max_tb_log2_size_y <= std::min(sps->ctb_log2_size_y, 5));
+ READ_UE_OR_RETURN(&sps->max_transform_hierarchy_depth_inter);
+ IN_RANGE_OR_RETURN(sps->max_transform_hierarchy_depth_inter, 0,
+ sps->ctb_log2_size_y - min_tb_log2_size_y);
+ READ_UE_OR_RETURN(&sps->max_transform_hierarchy_depth_intra);
+ IN_RANGE_OR_RETURN(sps->max_transform_hierarchy_depth_intra, 0,
+ sps->ctb_log2_size_y - min_tb_log2_size_y);
+ READ_BOOL_OR_RETURN(&sps->scaling_list_enabled_flag);
+ if (sps->scaling_list_enabled_flag) {
+ READ_BOOL_OR_RETURN(&sps->sps_scaling_list_data_present_flag);
+ res = ParseScalingListData(&sps->scaling_list_data);
+ if (res != kOk)
+ return res;
+ } else {
+ // Fill it in with the default values.
+ for (int size_id = 0; size_id < 4; ++size_id) {
+ for (int matrix_id = 0; matrix_id < 6;
+ matrix_id += (size_id == 3) ? 3 : 1) {
+ FillInDefaultScalingListData(&sps->scaling_list_data, size_id,
+ matrix_id);
+ }
+ }
+ }
+ READ_BOOL_OR_RETURN(&sps->amp_enabled_flag);
+ READ_BOOL_OR_RETURN(&sps->sample_adaptive_offset_enabled_flag);
+ READ_BOOL_OR_RETURN(&sps->pcm_enabled_flag);
+ if (sps->pcm_enabled_flag) {
+ READ_BITS_OR_RETURN(4, &sps->pcm_sample_bit_depth_luma_minus1);
+ TRUE_OR_RETURN(sps->pcm_sample_bit_depth_luma_minus1 + 1 <=
+ sps->bit_depth_y);
+ READ_BITS_OR_RETURN(4, &sps->pcm_sample_bit_depth_chroma_minus1);
+ TRUE_OR_RETURN(sps->pcm_sample_bit_depth_chroma_minus1 + 1 <=
+ sps->bit_depth_c);
+ READ_UE_OR_RETURN(&sps->log2_min_pcm_luma_coding_block_size_minus3);
+ int log2_min_ipcm_cb_size_y =
+ sps->log2_min_pcm_luma_coding_block_size_minus3 + 3;
+ IN_RANGE_OR_RETURN(log2_min_ipcm_cb_size_y, std::min(min_cb_log2_size_y, 5),
+ std::min(sps->ctb_log2_size_y, 5));
+ READ_UE_OR_RETURN(&sps->log2_diff_max_min_pcm_luma_coding_block_size);
+ int log2_max_ipcm_cb_size_y =
+ log2_min_ipcm_cb_size_y +
+ sps->log2_diff_max_min_pcm_luma_coding_block_size;
+ TRUE_OR_RETURN(log2_max_ipcm_cb_size_y <=
+ std::min(sps->ctb_log2_size_y, 5));
+ READ_BOOL_OR_RETURN(&sps->pcm_loop_filter_disabled_flag);
+ }
+ READ_UE_OR_RETURN(&sps->num_short_term_ref_pic_sets);
+ IN_RANGE_OR_RETURN(sps->num_short_term_ref_pic_sets, 0,
+ kMaxShortTermRefPicSets);
+ for (int i = 0; i < sps->num_short_term_ref_pic_sets; ++i) {
+ res = ParseStRefPicSet(i, *sps, &sps->st_ref_pic_set[i]);
+ if (res != kOk)
+ return res;
+ }
+ READ_BOOL_OR_RETURN(&sps->long_term_ref_pics_present_flag);
+ if (sps->long_term_ref_pics_present_flag) {
+ READ_UE_OR_RETURN(&sps->num_long_term_ref_pics_sps);
+ IN_RANGE_OR_RETURN(sps->num_long_term_ref_pics_sps, 0,
+ kMaxLongTermRefPicSets);
+ for (int i = 0; i < sps->num_long_term_ref_pics_sps; ++i) {
+ READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
+ &sps->lt_ref_pic_poc_lsb_sps[i]);
+ READ_BOOL_OR_RETURN(&sps->used_by_curr_pic_lt_sps_flag[i]);
+ }
+ }
+ READ_BOOL_OR_RETURN(&sps->sps_temporal_mvp_enabled_flag);
+ READ_BOOL_OR_RETURN(&sps->strong_intra_smoothing_enabled_flag);
+ bool vui_parameters_present_flag;
+ READ_BOOL_OR_RETURN(&vui_parameters_present_flag);
+ if (vui_parameters_present_flag) {
+ res = ParseVuiParameters(*sps, &sps->vui_parameters);
+ if (res != kOk)
+ return res;
+ // Verify cropping parameters. We already verified the conformance window
+ // ranges previously.
+ base::CheckedNumeric<int> width_crop =
+ sps->conf_win_left_offset + sps->conf_win_right_offset;
+ width_crop += sps->vui_parameters.def_disp_win_left_offset;
+ width_crop += sps->vui_parameters.def_disp_win_right_offset;
+ width_crop *= sps->sub_width_c;
+ if (!width_crop.IsValid())
+ return kInvalidStream;
+ TRUE_OR_RETURN(width_crop.ValueOrDefault(0) <
+ sps->pic_width_in_luma_samples);
+ base::CheckedNumeric<int> height_crop =
+ sps->conf_win_top_offset + sps->conf_win_bottom_offset;
+ height_crop += sps->vui_parameters.def_disp_win_top_offset;
+ height_crop += sps->vui_parameters.def_disp_win_bottom_offset;
+ height_crop *= sps->sub_height_c;
+ if (!height_crop.IsValid())
+ return kInvalidStream;
+ TRUE_OR_RETURN(height_crop.ValueOrDefault(0) <
+ sps->pic_height_in_luma_samples);
+ }
+
+ bool sps_extension_present_flag;
+ bool sps_range_extension_flag = false;
+ bool sps_multilayer_extension_flag = false;
+ bool sps_3d_extension_flag = false;
+ bool sps_scc_extension_flag = false;
+ READ_BOOL_OR_RETURN(&sps_extension_present_flag);
+ if (sps_extension_present_flag) {
+ READ_BOOL_OR_RETURN(&sps_range_extension_flag);
+ READ_BOOL_OR_RETURN(&sps_multilayer_extension_flag);
+ READ_BOOL_OR_RETURN(&sps_3d_extension_flag);
+ READ_BOOL_OR_RETURN(&sps_scc_extension_flag);
+ SKIP_BITS_OR_RETURN(4); // sps_extension_4bits
+ }
+ if (sps_range_extension_flag) {
+ DVLOG(1) << "HEVC range extension not supported";
+ return kInvalidStream;
+ }
+ if (sps_multilayer_extension_flag) {
+ DVLOG(1) << "HEVC multilayer extension not supported";
+ return kInvalidStream;
+ }
+ if (sps_3d_extension_flag) {
+ DVLOG(1) << "HEVC 3D extension not supported";
+ return kInvalidStream;
+ }
+ if (sps_scc_extension_flag) {
+ DVLOG(1) << "HEVC SCC extension not supported";
+ return kInvalidStream;
+ }
+
+ // NOTE: The below 2 values are dependent upon the range extension if that is
+ // ever implemented.
+ sps->wp_offset_half_range_y = 1 << 7;
+ sps->wp_offset_half_range_c = 1 << 7;
+
+ // If an SPS with the same id already exists, replace it.
+ *sps_id = sps->sps_seq_parameter_set_id;
+ active_sps_[*sps_id] = std::move(sps);
+
+ return res;
+}
+
+H265Parser::Result H265Parser::ParsePPS(const H265NALU& nalu, int* pps_id) {
+ // 7.4.3.3
+ DVLOG(4) << "Parsing PPS";
+ Result res = kOk;
+
+ DCHECK(pps_id);
+ *pps_id = -1;
+ std::unique_ptr<H265PPS> pps = std::make_unique<H265PPS>();
+
+ pps->temporal_id = nalu.nuh_temporal_id_plus1 - 1;
+
+ // Set these defaults if they are not present here.
+ pps->loop_filter_across_tiles_enabled_flag = 1;
+
+ // 7.4.3.3.1
+ READ_UE_OR_RETURN(&pps->pps_pic_parameter_set_id);
+ IN_RANGE_OR_RETURN(pps->pps_pic_parameter_set_id, 0, 63);
+ READ_UE_OR_RETURN(&pps->pps_seq_parameter_set_id);
+ IN_RANGE_OR_RETURN(pps->pps_seq_parameter_set_id, 0, 15);
+ const H265SPS* sps = GetSPS(pps->pps_seq_parameter_set_id);
+ if (!sps) {
+ return kMissingParameterSet;
+ }
+ READ_BOOL_OR_RETURN(&pps->dependent_slice_segments_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->output_flag_present_flag);
+ READ_BITS_OR_RETURN(3, &pps->num_extra_slice_header_bits);
+ READ_BOOL_OR_RETURN(&pps->sign_data_hiding_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->cabac_init_present_flag);
+ READ_UE_OR_RETURN(&pps->num_ref_idx_l0_default_active_minus1);
+ IN_RANGE_OR_RETURN(pps->num_ref_idx_l0_default_active_minus1, 0,
+ kMaxRefIdxActive - 1);
+ READ_UE_OR_RETURN(&pps->num_ref_idx_l1_default_active_minus1);
+ IN_RANGE_OR_RETURN(pps->num_ref_idx_l1_default_active_minus1, 0,
+ kMaxRefIdxActive - 1);
+ READ_SE_OR_RETURN(&pps->init_qp_minus26);
+ pps->qp_bd_offset_y = 6 * sps->bit_depth_luma_minus8;
+ IN_RANGE_OR_RETURN(pps->init_qp_minus26, -(26 + pps->qp_bd_offset_y), 25);
+ READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag);
+ READ_BOOL_OR_RETURN(&pps->transform_skip_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->cu_qp_delta_enabled_flag);
+ if (pps->cu_qp_delta_enabled_flag) {
+ READ_UE_OR_RETURN(&pps->diff_cu_qp_delta_depth);
+ IN_RANGE_OR_RETURN(pps->diff_cu_qp_delta_depth, 0,
+ sps->log2_diff_max_min_luma_coding_block_size);
+ }
+ READ_SE_OR_RETURN(&pps->pps_cb_qp_offset);
+ IN_RANGE_OR_RETURN(pps->pps_cb_qp_offset, -12, 12);
+ READ_SE_OR_RETURN(&pps->pps_cr_qp_offset);
+ IN_RANGE_OR_RETURN(pps->pps_cr_qp_offset, -12, 12);
+ READ_BOOL_OR_RETURN(&pps->pps_slice_chroma_qp_offsets_present_flag);
+ READ_BOOL_OR_RETURN(&pps->weighted_pred_flag);
+ READ_BOOL_OR_RETURN(&pps->weighted_bipred_flag);
+ READ_BOOL_OR_RETURN(&pps->transquant_bypass_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->tiles_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->entropy_coding_sync_enabled_flag);
+ if (pps->tiles_enabled_flag) {
+ READ_UE_OR_RETURN(&pps->num_tile_columns_minus1);
+ IN_RANGE_OR_RETURN(pps->num_tile_columns_minus1, 0,
+ sps->pic_width_in_ctbs_y - 1);
+ TRUE_OR_RETURN(pps->num_tile_columns_minus1 <
+ H265PPS::kMaxNumTileColumnWidth);
+ READ_UE_OR_RETURN(&pps->num_tile_rows_minus1);
+ IN_RANGE_OR_RETURN(pps->num_tile_rows_minus1, 0,
+ sps->pic_height_in_ctbs_y - 1);
+ TRUE_OR_RETURN((pps->num_tile_columns_minus1 != 0) ||
+ (pps->num_tile_rows_minus1 != 0));
+ TRUE_OR_RETURN(pps->num_tile_rows_minus1 < H265PPS::kMaxNumTileRowHeight);
+ READ_BOOL_OR_RETURN(&pps->uniform_spacing_flag);
+ if (!pps->uniform_spacing_flag) {
+ pps->column_width_minus1[pps->num_tile_columns_minus1] =
+ sps->pic_width_in_ctbs_y - 1;
+ for (int i = 0; i < pps->num_tile_columns_minus1; ++i) {
+ READ_UE_OR_RETURN(&pps->column_width_minus1[i]);
+ pps->column_width_minus1[pps->num_tile_columns_minus1] -=
+ pps->column_width_minus1[i] + 1;
+ }
+ pps->row_height_minus1[pps->num_tile_rows_minus1] =
+ sps->pic_height_in_ctbs_y - 1;
+ for (int i = 0; i < pps->num_tile_rows_minus1; ++i) {
+ READ_UE_OR_RETURN(&pps->row_height_minus1[i]);
+ pps->row_height_minus1[pps->num_tile_rows_minus1] -=
+ pps->row_height_minus1[i] + 1;
+ }
+ }
+ READ_BOOL_OR_RETURN(&pps->loop_filter_across_tiles_enabled_flag);
+ }
+ READ_BOOL_OR_RETURN(&pps->pps_loop_filter_across_slices_enabled_flag);
+ bool deblocking_filter_control_present_flag;
+ READ_BOOL_OR_RETURN(&deblocking_filter_control_present_flag);
+ if (deblocking_filter_control_present_flag) {
+ READ_BOOL_OR_RETURN(&pps->deblocking_filter_override_enabled_flag);
+ READ_BOOL_OR_RETURN(&pps->pps_deblocking_filter_disabled_flag);
+ if (!pps->pps_deblocking_filter_disabled_flag) {
+ READ_SE_OR_RETURN(&pps->pps_beta_offset_div2);
+ IN_RANGE_OR_RETURN(pps->pps_beta_offset_div2, -6, 6);
+ READ_SE_OR_RETURN(&pps->pps_tc_offset_div2);
+ IN_RANGE_OR_RETURN(pps->pps_tc_offset_div2, -6, 6);
+ }
+ }
+ READ_BOOL_OR_RETURN(&pps->pps_scaling_list_data_present_flag);
+ if (pps->pps_scaling_list_data_present_flag) {
+ res = ParseScalingListData(&pps->scaling_list_data);
+ if (res != kOk)
+ return res;
+ }
+ READ_BOOL_OR_RETURN(&pps->lists_modification_present_flag);
+ READ_UE_OR_RETURN(&pps->log2_parallel_merge_level_minus2);
+ IN_RANGE_OR_RETURN(pps->log2_parallel_merge_level_minus2, 0,
+ sps->ctb_log2_size_y - 2);
+ READ_BOOL_OR_RETURN(&pps->slice_segment_header_extension_present_flag);
+ bool pps_extension_present_flag;
+ READ_BOOL_OR_RETURN(&pps_extension_present_flag);
+ bool pps_range_extension_flag = false;
+ bool pps_multilayer_extension_flag = false;
+ bool pps_3d_extension_flag = false;
+ bool pps_scc_extension_flag = false;
+ if (pps_extension_present_flag) {
+ READ_BOOL_OR_RETURN(&pps_range_extension_flag);
+ READ_BOOL_OR_RETURN(&pps_multilayer_extension_flag);
+ READ_BOOL_OR_RETURN(&pps_3d_extension_flag);
+ READ_BOOL_OR_RETURN(&pps_scc_extension_flag);
+ SKIP_BITS_OR_RETURN(4); // pps_extension_4bits
+ }
+
+ if (pps_range_extension_flag) {
+ DVLOG(1) << "HEVC range extension not supported";
+ return kInvalidStream;
+ }
+ if (pps_multilayer_extension_flag) {
+ DVLOG(1) << "HEVC multilayer extension not supported";
+ return kInvalidStream;
+ }
+ if (pps_3d_extension_flag) {
+ DVLOG(1) << "HEVC 3D extension not supported";
+ return kInvalidStream;
+ }
+ if (pps_scc_extension_flag) {
+ DVLOG(1) << "HEVC SCC extension not supported";
+ return kInvalidStream;
+ }
+
+ // If a PPS with the same id already exists, replace it.
+ *pps_id = pps->pps_pic_parameter_set_id;
+ active_pps_[*pps_id] = std::move(pps);
+
+ return res;
+}
+
+const H265SPS* H265Parser::GetSPS(int sps_id) const {
+ auto it = active_sps_.find(sps_id);
+ if (it == active_sps_.end()) {
+ DVLOG(1) << "Requested a nonexistent SPS id " << sps_id;
+ return nullptr;
+ }
+
+ return it->second.get();
+}
+
+const H265PPS* H265Parser::GetPPS(int pps_id) const {
+ auto it = active_pps_.find(pps_id);
+ if (it == active_pps_.end()) {
+ DVLOG(1) << "Requested a nonexistent PPS id " << pps_id;
+ return nullptr;
+ }
+
+ return it->second.get();
+}
+
+H265Parser::Result H265Parser::ParseSliceHeader(const H265NALU& nalu,
+ H265SliceHeader* shdr) {
+ // 7.4.7 Slice segment header
+ DVLOG(4) << "Parsing slice header";
+ Result res = kOk;
+ const H265SPS* sps;
+ const H265PPS* pps;
+
+ DCHECK(shdr);
+ shdr->nal_unit_type = nalu.nal_unit_type;
+ shdr->nalu_data = nalu.data;
+ shdr->nalu_size = nalu.size;
+
+ READ_BOOL_OR_RETURN(&shdr->first_slice_segment_in_pic_flag);
+ shdr->irap_pic = (shdr->nal_unit_type >= H265NALU::BLA_W_LP &&
+ shdr->nal_unit_type <= H265NALU::RSV_IRAP_VCL23);
+ if (shdr->irap_pic) {
+ READ_BOOL_OR_RETURN(&shdr->no_output_of_prior_pics_flag);
+ }
+ READ_UE_OR_RETURN(&shdr->slice_pic_parameter_set_id);
+ IN_RANGE_OR_RETURN(shdr->slice_pic_parameter_set_id, 0, 63);
+ pps = GetPPS(shdr->slice_pic_parameter_set_id);
+ if (!pps) {
+ return kMissingParameterSet;
+ }
+ sps = GetSPS(pps->pps_seq_parameter_set_id);
+ DCHECK(sps); // We already validated this when we parsed the PPS.
+
+ // Set these defaults if they are not present here.
+ shdr->pic_output_flag = 1;
+ 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;
+ shdr->collocated_from_l0_flag = 1;
+ shdr->slice_deblocking_filter_disabled_flag =
+ pps->pps_deblocking_filter_disabled_flag;
+ shdr->slice_beta_offset_div2 = pps->pps_beta_offset_div2;
+ shdr->slice_tc_offset_div2 = pps->pps_tc_offset_div2;
+ shdr->slice_loop_filter_across_slices_enabled_flag =
+ pps->pps_loop_filter_across_slices_enabled_flag;
+
+ if (!shdr->first_slice_segment_in_pic_flag) {
+ if (pps->dependent_slice_segments_enabled_flag)
+ READ_BOOL_OR_RETURN(&shdr->dependent_slice_segment_flag);
+ READ_BITS_OR_RETURN(base::bits::Log2Ceiling(sps->pic_size_in_ctbs_y),
+ &shdr->slice_segment_address);
+ IN_RANGE_OR_RETURN(shdr->slice_segment_address, 0,
+ sps->pic_size_in_ctbs_y - 1);
+ }
+ shdr->curr_rps_idx = sps->num_short_term_ref_pic_sets;
+ if (!shdr->dependent_slice_segment_flag) {
+ // slice_reserved_flag
+ SKIP_BITS_OR_RETURN(pps->num_extra_slice_header_bits);
+ READ_UE_OR_RETURN(&shdr->slice_type);
+ if ((shdr->irap_pic ||
+ sps->sps_max_dec_pic_buffering_minus1[pps->temporal_id] == 0) &&
+ nalu.nuh_layer_id == 0) {
+ TRUE_OR_RETURN(shdr->slice_type == 2);
+ }
+ if (pps->output_flag_present_flag)
+ READ_BOOL_OR_RETURN(&shdr->pic_output_flag);
+ if (sps->separate_colour_plane_flag) {
+ READ_BITS_OR_RETURN(2, &shdr->colour_plane_id);
+ IN_RANGE_OR_RETURN(shdr->colour_plane_id, 0, 2);
+ }
+ if (shdr->nal_unit_type != H265NALU::IDR_W_RADL &&
+ shdr->nal_unit_type != H265NALU::IDR_N_LP) {
+ READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
+ &shdr->slice_pic_order_cnt_lsb);
+ IN_RANGE_OR_RETURN(shdr->slice_pic_order_cnt_lsb, 0,
+ sps->max_pic_order_cnt_lsb - 1);
+ READ_BOOL_OR_RETURN(&shdr->short_term_ref_pic_set_sps_flag);
+ if (!shdr->short_term_ref_pic_set_sps_flag) {
+ off_t bits_left_prior = br_.NumBitsLeft();
+ size_t num_epb_prior = br_.NumEmulationPreventionBytesRead();
+ res = ParseStRefPicSet(sps->num_short_term_ref_pic_sets, *sps,
+ &shdr->st_ref_pic_set);
+ if (res != kOk)
+ return res;
+ shdr->st_rps_bits =
+ (bits_left_prior - br_.NumBitsLeft()) -
+ 8 * (br_.NumEmulationPreventionBytesRead() - num_epb_prior);
+ } else if (sps->num_short_term_ref_pic_sets > 1) {
+ READ_BITS_OR_RETURN(
+ base::bits::Log2Ceiling(sps->num_short_term_ref_pic_sets),
+ &shdr->short_term_ref_pic_set_idx);
+ IN_RANGE_OR_RETURN(shdr->short_term_ref_pic_set_idx, 0,
+ sps->num_short_term_ref_pic_sets - 1);
+ }
+
+ if (shdr->short_term_ref_pic_set_sps_flag)
+ shdr->curr_rps_idx = shdr->short_term_ref_pic_set_idx;
+
+ if (sps->long_term_ref_pics_present_flag) {
+ if (sps->num_long_term_ref_pics_sps > 0) {
+ READ_UE_OR_RETURN(&shdr->num_long_term_sps);
+ IN_RANGE_OR_RETURN(shdr->num_long_term_sps, 0,
+ sps->num_long_term_ref_pics_sps);
+ }
+ READ_UE_OR_RETURN(&shdr->num_long_term_pics);
+ if (nalu.nuh_layer_id == 0) {
+ TRUE_OR_RETURN(
+ shdr->num_long_term_pics <=
+ (sps->sps_max_dec_pic_buffering_minus1[pps->temporal_id] -
+ shdr->GetStRefPicSet(sps).num_negative_pics -
+ shdr->GetStRefPicSet(sps).num_positive_pics -
+ shdr->num_long_term_sps));
+ }
+ IN_RANGE_OR_RETURN(shdr->num_long_term_sps + shdr->num_long_term_pics,
+ 0, kMaxLongTermRefPicSets);
+ for (int i = 0; i < shdr->num_long_term_sps + shdr->num_long_term_pics;
+ ++i) {
+ if (i < shdr->num_long_term_sps) {
+ int lt_idx_sps = 0;
+ if (sps->num_long_term_ref_pics_sps > 1) {
+ READ_BITS_OR_RETURN(
+ base::bits::Log2Ceiling(sps->num_long_term_ref_pics_sps),
+ &lt_idx_sps);
+ IN_RANGE_OR_RETURN(lt_idx_sps, 0,
+ sps->num_long_term_ref_pics_sps - 1);
+ }
+ shdr->poc_lsb_lt[i] = sps->lt_ref_pic_poc_lsb_sps[lt_idx_sps];
+ shdr->used_by_curr_pic_lt[i] =
+ sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps];
+ } else {
+ READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4,
+ &shdr->poc_lsb_lt[i]);
+ READ_BOOL_OR_RETURN(&shdr->used_by_curr_pic_lt[i]);
+ }
+ READ_BOOL_OR_RETURN(&shdr->delta_poc_msb_present_flag[i]);
+ if (shdr->delta_poc_msb_present_flag[i]) {
+ READ_UE_OR_RETURN(&shdr->delta_poc_msb_cycle_lt[i]);
+ IN_RANGE_OR_RETURN(
+ shdr->delta_poc_msb_cycle_lt[i], 0,
+ std::pow(2, 32 - sps->log2_max_pic_order_cnt_lsb_minus4 - 4));
+ // Equation 7-52.
+ if (i != 0 && i != shdr->num_long_term_sps) {
+ shdr->delta_poc_msb_cycle_lt[i] =
+ shdr->delta_poc_msb_cycle_lt[i] +
+ shdr->delta_poc_msb_cycle_lt[i - 1];
+ }
+ }
+ }
+ }
+ if (sps->sps_temporal_mvp_enabled_flag)
+ READ_BOOL_OR_RETURN(&shdr->slice_temporal_mvp_enabled_flag);
+ }
+ if (sps->sample_adaptive_offset_enabled_flag) {
+ READ_BOOL_OR_RETURN(&shdr->slice_sao_luma_flag);
+ if (sps->chroma_array_type != 0)
+ READ_BOOL_OR_RETURN(&shdr->slice_sao_chroma_flag);
+ }
+ if (shdr->IsPSlice() || shdr->IsBSlice()) {
+ READ_BOOL_OR_RETURN(&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);
+ IN_RANGE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1, 0,
+ kMaxRefIdxActive - 1);
+ if (shdr->IsBSlice()) {
+ READ_UE_OR_RETURN(&shdr->num_ref_idx_l1_active_minus1);
+ IN_RANGE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1, 0,
+ kMaxRefIdxActive - 1);
+ }
+ }
+
+ shdr->num_pic_total_curr = 0;
+ const H265StRefPicSet& st_ref_pic = shdr->GetStRefPicSet(sps);
+ for (int i = 0; i < st_ref_pic.num_negative_pics; ++i) {
+ if (st_ref_pic.used_by_curr_pic_s0[i])
+ shdr->num_pic_total_curr++;
+ }
+ for (int i = 0; i < st_ref_pic.num_positive_pics; ++i) {
+ if (st_ref_pic.used_by_curr_pic_s1[i])
+ shdr->num_pic_total_curr++;
+ }
+ for (int i = 0; i < shdr->num_long_term_sps + shdr->num_long_term_pics;
+ ++i) {
+ if (shdr->used_by_curr_pic_lt[i])
+ shdr->num_pic_total_curr++;
+ }
+
+ if (pps->lists_modification_present_flag &&
+ shdr->num_pic_total_curr > 1) {
+ res = ParseRefPicListsModifications(*shdr,
+ &shdr->ref_pic_lists_modification);
+ if (res != kOk)
+ return res;
+ }
+ if (shdr->IsBSlice())
+ READ_BOOL_OR_RETURN(&shdr->mvd_l1_zero_flag);
+ if (pps->cabac_init_present_flag)
+ READ_BOOL_OR_RETURN(&shdr->cabac_init_flag);
+ if (shdr->slice_temporal_mvp_enabled_flag) {
+ if (shdr->IsBSlice())
+ READ_BOOL_OR_RETURN(&shdr->collocated_from_l0_flag);
+ if ((shdr->collocated_from_l0_flag &&
+ shdr->num_ref_idx_l0_active_minus1 > 0) ||
+ (!shdr->collocated_from_l0_flag &&
+ shdr->num_ref_idx_l1_active_minus1 > 0)) {
+ READ_UE_OR_RETURN(&shdr->collocated_ref_idx);
+ if ((shdr->IsPSlice() || shdr->IsBSlice()) &&
+ shdr->collocated_from_l0_flag) {
+ IN_RANGE_OR_RETURN(shdr->collocated_ref_idx, 0,
+ shdr->num_ref_idx_l0_active_minus1);
+ }
+ if (shdr->IsBSlice() && !shdr->collocated_from_l0_flag) {
+ IN_RANGE_OR_RETURN(shdr->collocated_ref_idx, 0,
+ shdr->num_ref_idx_l1_active_minus1);
+ }
+ }
+ }
+
+ if ((pps->weighted_pred_flag && shdr->IsPSlice()) ||
+ (pps->weighted_bipred_flag && shdr->IsBSlice())) {
+ res = ParsePredWeightTable(*sps, *shdr, &shdr->pred_weight_table);
+ if (res != kOk)
+ return res;
+ }
+ READ_UE_OR_RETURN(&shdr->five_minus_max_num_merge_cand);
+ IN_RANGE_OR_RETURN(5 - shdr->five_minus_max_num_merge_cand, 1, 5);
+ }
+ READ_SE_OR_RETURN(&shdr->slice_qp_delta);
+ IN_RANGE_OR_RETURN(26 + pps->init_qp_minus26 + shdr->slice_qp_delta,
+ -pps->qp_bd_offset_y, 51);
+
+ if (pps->pps_slice_chroma_qp_offsets_present_flag) {
+ READ_SE_OR_RETURN(&shdr->slice_cb_qp_offset);
+ IN_RANGE_OR_RETURN(shdr->slice_cb_qp_offset, -12, 12);
+ IN_RANGE_OR_RETURN(pps->pps_cb_qp_offset + shdr->slice_cb_qp_offset, -12,
+ 12);
+ READ_SE_OR_RETURN(&shdr->slice_cr_qp_offset);
+ IN_RANGE_OR_RETURN(shdr->slice_cr_qp_offset, -12, 12);
+ IN_RANGE_OR_RETURN(pps->pps_cr_qp_offset + shdr->slice_cr_qp_offset, -12,
+ 12);
+ }
+
+ // pps_slice_act_qp_offsets_present_flag is zero, we don't support SCC ext.
+
+ // chroma_qp_offset_list_enabled_flag is zero, we don't support range ext.
+
+ bool deblocking_filter_override_flag = false;
+ if (pps->deblocking_filter_override_enabled_flag)
+ READ_BOOL_OR_RETURN(&deblocking_filter_override_flag);
+ if (deblocking_filter_override_flag) {
+ READ_BOOL_OR_RETURN(&shdr->slice_deblocking_filter_disabled_flag);
+ if (!shdr->slice_deblocking_filter_disabled_flag) {
+ READ_SE_OR_RETURN(&shdr->slice_beta_offset_div2);
+ IN_RANGE_OR_RETURN(shdr->slice_beta_offset_div2, -6, 6);
+ READ_SE_OR_RETURN(&shdr->slice_tc_offset_div2);
+ IN_RANGE_OR_RETURN(shdr->slice_tc_offset_div2, -6, 6);
+ }
+ }
+ if (pps->pps_loop_filter_across_slices_enabled_flag &&
+ (shdr->slice_sao_luma_flag || shdr->slice_sao_chroma_flag ||
+ !shdr->slice_deblocking_filter_disabled_flag)) {
+ READ_BOOL_OR_RETURN(&shdr->slice_loop_filter_across_slices_enabled_flag);
+ }
+ }
+
+ if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) {
+ int num_entry_point_offsets;
+ READ_UE_OR_RETURN(&num_entry_point_offsets);
+ if (!pps->tiles_enabled_flag) {
+ IN_RANGE_OR_RETURN(num_entry_point_offsets, 0,
+ sps->pic_height_in_ctbs_y - 1);
+ } else if (!pps->entropy_coding_sync_enabled_flag) {
+ IN_RANGE_OR_RETURN(
+ num_entry_point_offsets, 0,
+ (pps->num_tile_columns_minus1 + 1) * (pps->num_tile_rows_minus1 + 1) -
+ 1);
+ } else { // both are true
+ IN_RANGE_OR_RETURN(
+ num_entry_point_offsets, 0,
+ (pps->num_tile_columns_minus1 + 1) * sps->pic_height_in_ctbs_y - 1);
+ }
+ if (num_entry_point_offsets > 0) {
+ int offset_len_minus1;
+ READ_UE_OR_RETURN(&offset_len_minus1);
+ IN_RANGE_OR_RETURN(offset_len_minus1, 0, 31);
+ SKIP_BITS_OR_RETURN(num_entry_point_offsets * (offset_len_minus1 + 1));
+ }
+ }
+
+ if (pps->slice_segment_header_extension_present_flag) {
+ int slice_segment_header_extension_length;
+ READ_UE_OR_RETURN(&slice_segment_header_extension_length);
+ IN_RANGE_OR_RETURN(slice_segment_header_extension_length, 0, 256);
+ SKIP_BITS_OR_RETURN(slice_segment_header_extension_length * 8);
+ }
+
+ // byte_alignment()
+ SKIP_BITS_OR_RETURN(1); // alignment bit
+ int bits_left_to_align = br_.NumBitsLeft() % 8;
+ if (bits_left_to_align)
+ SKIP_BITS_OR_RETURN(bits_left_to_align);
+
+ shdr->header_emulation_prevention_bytes =
+ br_.NumEmulationPreventionBytesRead();
+ shdr->header_size = shdr->nalu_size -
+ shdr->header_emulation_prevention_bytes -
+ br_.NumBitsLeft() / 8;
+ return res;
+}
+
+// static
+VideoCodecProfile H265Parser::ProfileIDCToVideoCodecProfile(int profile_idc) {
+ switch (profile_idc) {
+ case H265ProfileTierLevel::kProfileIdcMain:
+ return HEVCPROFILE_MAIN;
+ case H265ProfileTierLevel::kProfileIdcMain10:
+ return HEVCPROFILE_MAIN10;
+ case H265ProfileTierLevel::kProfileIdcMainStill:
+ return HEVCPROFILE_MAIN_STILL_PICTURE;
+ default:
+ DVLOG(1) << "unknown video profile: " << profile_idc;
+ return VIDEO_CODEC_PROFILE_UNKNOWN;
+ }
+}
+
+std::vector<SubsampleEntry> H265Parser::GetCurrentSubsamples() {
+ DCHECK_EQ(previous_nalu_range_.size(), 1u)
+ << "This should only be called after a "
+ "successful call to AdvanceToNextNalu()";
+
+ auto intersection = encrypted_ranges_.IntersectionWith(previous_nalu_range_);
+ return EncryptedRangesToSubsampleEntry(
+ previous_nalu_range_.start(0), previous_nalu_range_.end(0), intersection);
+}
+
+H265Parser::Result H265Parser::ParseProfileTierLevel(
+ bool profile_present,
+ int max_num_sub_layers_minus1,
+ H265ProfileTierLevel* profile_tier_level) {
+ // 7.4.4
+ DVLOG(4) << "Parsing profile_tier_level";
+ if (profile_present) {
+ int general_profile_space;
+ READ_BITS_OR_RETURN(2, &general_profile_space);
+ TRUE_OR_RETURN(general_profile_space == 0);
+ SKIP_BITS_OR_RETURN(1); // general_tier_flag
+ READ_BITS_OR_RETURN(5, &profile_tier_level->general_profile_idc);
+ IN_RANGE_OR_RETURN(profile_tier_level->general_profile_idc, 0, 11);
+ bool general_profile_compatibility_flag[32];
+ for (int j = 0; j < 32; ++j) {
+ READ_BOOL_OR_RETURN(&general_profile_compatibility_flag[j]);
+ }
+ bool general_progressive_source_flag;
+ bool general_interlaced_source_flag;
+ READ_BOOL_OR_RETURN(&general_progressive_source_flag);
+ READ_BOOL_OR_RETURN(&general_interlaced_source_flag);
+ if (!general_progressive_source_flag && general_interlaced_source_flag) {
+ DVLOG(1) << "Interlaced streams not supported";
+ return kUnsupportedStream;
+ }
+ SKIP_BITS_OR_RETURN(2); // general_{non_packed,frame_only}_constraint_flag
+ // Skip the compatibility flags, they are always 43 bits.
+ SKIP_BITS_OR_RETURN(43);
+ SKIP_BITS_OR_RETURN(1); // general_inbld_flag
+ }
+ READ_BITS_OR_RETURN(8, &profile_tier_level->general_level_idc);
+ bool sub_layer_profile_present_flag[8];
+ bool sub_layer_level_present_flag[8];
+ for (int i = 0; i < max_num_sub_layers_minus1; ++i) {
+ READ_BOOL_OR_RETURN(&sub_layer_profile_present_flag[i]);
+ READ_BOOL_OR_RETURN(&sub_layer_level_present_flag[i]);
+ }
+ if (max_num_sub_layers_minus1 > 0) {
+ for (int i = max_num_sub_layers_minus1; i < 8; i++) {
+ SKIP_BITS_OR_RETURN(2);
+ }
+ }
+ for (int i = 0; i < max_num_sub_layers_minus1; i++) {
+ if (sub_layer_profile_present_flag[i]) {
+ SKIP_BITS_OR_RETURN(2); // sub_layer_profile_space
+ SKIP_BITS_OR_RETURN(1); // sub_layer_tier_flag
+ SKIP_BITS_OR_RETURN(5); // sub_layer_profile_idc
+ SKIP_BITS_OR_RETURN(32); // sub_layer_profile_compatibility_flag
+ SKIP_BITS_OR_RETURN(2); // sub_layer_{progressive,interlaced}_source_flag
+ // Ignore sub_layer_non_packed_constraint_flag and
+ // sub_layer_frame_only_constraint_flag.
+ SKIP_BITS_OR_RETURN(2);
+ // Skip the compatibility flags, they are always 43 bits.
+ SKIP_BITS_OR_RETURN(43);
+ SKIP_BITS_OR_RETURN(1); // sub_layer_inbld_flag
+ }
+ if (sub_layer_level_present_flag[i]) {
+ SKIP_BITS_OR_RETURN(8); // sub_layer_level_idc
+ }
+ }
+
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseScalingListData(
+ H265ScalingListData* scaling_list_data) {
+ for (int size_id = 0; size_id < 4; ++size_id) {
+ for (int matrix_id = 0; matrix_id < 6;
+ matrix_id += (size_id == 3) ? 3 : 1) {
+ bool scaling_list_pred_mode_flag;
+ READ_BOOL_OR_RETURN(&scaling_list_pred_mode_flag);
+ if (!scaling_list_pred_mode_flag) {
+ int scaling_list_pred_matrix_id_delta;
+ READ_UE_OR_RETURN(&scaling_list_pred_matrix_id_delta);
+ if (size_id <= 2) {
+ IN_RANGE_OR_RETURN(scaling_list_pred_matrix_id_delta, 0, matrix_id);
+ } else { // size_id == 3
+ IN_RANGE_OR_RETURN(scaling_list_pred_matrix_id_delta, 0,
+ matrix_id / 3);
+ }
+ if (scaling_list_pred_matrix_id_delta == 0) {
+ FillInDefaultScalingListData(scaling_list_data, size_id, matrix_id);
+ } else {
+ int ref_matrix_id = matrix_id - scaling_list_pred_matrix_id_delta *
+ (size_id == 3 ? 3 : 1);
+ int* dst;
+ int* src;
+ int count = H265ScalingListData::kScalingListSizeId1To3Count;
+ switch (size_id) {
+ case 0:
+ src = scaling_list_data->scaling_list_4x4[ref_matrix_id];
+ dst = scaling_list_data->scaling_list_4x4[matrix_id];
+ count = H265ScalingListData::kScalingListSizeId0Count;
+ break;
+ case 1:
+ src = scaling_list_data->scaling_list_8x8[ref_matrix_id];
+ dst = scaling_list_data->scaling_list_8x8[matrix_id];
+ break;
+ case 2:
+ src = scaling_list_data->scaling_list_16x16[ref_matrix_id];
+ dst = scaling_list_data->scaling_list_16x16[matrix_id];
+ break;
+ case 3:
+ src = scaling_list_data->scaling_list_32x32[ref_matrix_id];
+ dst = scaling_list_data->scaling_list_32x32[matrix_id];
+ break;
+ }
+ memcpy(dst, src, count * sizeof(*src));
+
+ if (size_id == 2) {
+ scaling_list_data->scaling_list_dc_coef_16x16[matrix_id] =
+ scaling_list_data->scaling_list_dc_coef_16x16[ref_matrix_id];
+ } else if (size_id == 3) {
+ scaling_list_data->scaling_list_dc_coef_32x32[matrix_id] =
+ scaling_list_data->scaling_list_dc_coef_32x32[ref_matrix_id];
+ }
+ }
+ } else {
+ int next_coef = 8;
+ int coef_num = std::min(64, (1 << (4 + (size_id << 1))));
+ if (size_id > 1) {
+ if (size_id == 2) {
+ READ_SE_OR_RETURN(
+ &scaling_list_data->scaling_list_dc_coef_16x16[matrix_id]);
+ IN_RANGE_OR_RETURN(
+ scaling_list_data->scaling_list_dc_coef_16x16[matrix_id], -7,
+ 247);
+ // This is parsed as minus8;
+ scaling_list_data->scaling_list_dc_coef_16x16[matrix_id] += 8;
+ next_coef =
+ scaling_list_data->scaling_list_dc_coef_16x16[matrix_id];
+ } else { // size_id == 3
+ READ_SE_OR_RETURN(
+ &scaling_list_data->scaling_list_dc_coef_32x32[matrix_id]);
+ IN_RANGE_OR_RETURN(
+ scaling_list_data->scaling_list_dc_coef_32x32[matrix_id], -7,
+ 247);
+ // This is parsed as minus8;
+ scaling_list_data->scaling_list_dc_coef_32x32[matrix_id] += 8;
+ next_coef =
+ scaling_list_data->scaling_list_dc_coef_32x32[matrix_id];
+ }
+ }
+ for (int i = 0; i < coef_num; ++i) {
+ int scaling_list_delta_coef;
+ READ_SE_OR_RETURN(&scaling_list_delta_coef);
+ IN_RANGE_OR_RETURN(scaling_list_delta_coef, -128, 127);
+ next_coef = (next_coef + scaling_list_delta_coef + 256) % 256;
+ switch (size_id) {
+ case 0:
+ scaling_list_data->scaling_list_4x4[matrix_id][i] = next_coef;
+ break;
+ case 1:
+ scaling_list_data->scaling_list_8x8[matrix_id][i] = next_coef;
+ break;
+ case 2:
+ scaling_list_data->scaling_list_16x16[matrix_id][i] = next_coef;
+ break;
+ case 3:
+ scaling_list_data->scaling_list_32x32[matrix_id][i] = next_coef;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseStRefPicSet(
+ int st_rps_idx,
+ const H265SPS& sps,
+ H265StRefPicSet* st_ref_pic_set) {
+ // 7.4.8
+ bool inter_ref_pic_set_prediction_flag = false;
+ if (st_rps_idx != 0) {
+ READ_BOOL_OR_RETURN(&inter_ref_pic_set_prediction_flag);
+ }
+ if (inter_ref_pic_set_prediction_flag) {
+ int delta_idx_minus1 = 0;
+ if (st_rps_idx == sps.num_short_term_ref_pic_sets) {
+ READ_UE_OR_RETURN(&delta_idx_minus1);
+ IN_RANGE_OR_RETURN(delta_idx_minus1, 0, st_rps_idx - 1);
+ }
+ int ref_rps_idx = st_rps_idx - (delta_idx_minus1 + 1);
+ int delta_rps_sign;
+ int abs_delta_rps_minus1;
+ READ_BOOL_OR_RETURN(&delta_rps_sign);
+ READ_UE_OR_RETURN(&abs_delta_rps_minus1);
+ int delta_rps = (1 - 2 * delta_rps_sign) * (abs_delta_rps_minus1 + 1);
+ const H265StRefPicSet& ref_set = sps.st_ref_pic_set[ref_rps_idx];
+ bool used_by_curr_pic_flag[kMaxShortTermRefPicSets];
+ bool use_delta_flag[kMaxShortTermRefPicSets];
+ // 7.4.8 - use_delta_flag defaults to 1 if not present.
+ std::fill_n(use_delta_flag, kMaxShortTermRefPicSets, true);
+
+ for (int j = 0; j <= ref_set.num_delta_pocs; j++) {
+ READ_BOOL_OR_RETURN(&used_by_curr_pic_flag[j]);
+ if (!used_by_curr_pic_flag[j]) {
+ READ_BOOL_OR_RETURN(&use_delta_flag[j]);
+ }
+ }
+ // Calculate delta_poc_s{0,1}, used_by_curr_pic_s{0,1}, num_negative_pics
+ // and num_positive_pics.
+ // Equation 7-61
+ int i = 0;
+ for (int j = ref_set.num_positive_pics - 1; j >= 0; --j) {
+ int d_poc = ref_set.delta_poc_s1[j] + delta_rps;
+ if (d_poc < 0 && use_delta_flag[ref_set.num_negative_pics + j]) {
+ st_ref_pic_set->delta_poc_s0[i] = d_poc;
+ st_ref_pic_set->used_by_curr_pic_s0[i++] =
+ used_by_curr_pic_flag[ref_set.num_negative_pics + j];
+ }
+ }
+ if (delta_rps < 0 && use_delta_flag[ref_set.num_delta_pocs]) {
+ st_ref_pic_set->delta_poc_s0[i] = delta_rps;
+ st_ref_pic_set->used_by_curr_pic_s0[i++] =
+ used_by_curr_pic_flag[ref_set.num_delta_pocs];
+ }
+ for (int j = 0; j < ref_set.num_negative_pics; ++j) {
+ int d_poc = ref_set.delta_poc_s0[j] + delta_rps;
+ if (d_poc < 0 && use_delta_flag[j]) {
+ st_ref_pic_set->delta_poc_s0[i] = d_poc;
+ st_ref_pic_set->used_by_curr_pic_s0[i++] = used_by_curr_pic_flag[j];
+ }
+ }
+ st_ref_pic_set->num_negative_pics = i;
+ // Equation 7-62
+ i = 0;
+ for (int j = ref_set.num_negative_pics - 1; j >= 0; --j) {
+ int d_poc = ref_set.delta_poc_s0[j] + delta_rps;
+ if (d_poc > 0 && use_delta_flag[j]) {
+ st_ref_pic_set->delta_poc_s1[i] = d_poc;
+ st_ref_pic_set->used_by_curr_pic_s1[i++] = used_by_curr_pic_flag[j];
+ }
+ }
+ if (delta_rps > 0 && use_delta_flag[ref_set.num_delta_pocs]) {
+ st_ref_pic_set->delta_poc_s1[i] = delta_rps;
+ st_ref_pic_set->used_by_curr_pic_s1[i++] =
+ used_by_curr_pic_flag[ref_set.num_delta_pocs];
+ }
+ for (int j = 0; j < ref_set.num_positive_pics; ++j) {
+ int d_poc = ref_set.delta_poc_s1[j] + delta_rps;
+ if (d_poc > 0 && use_delta_flag[ref_set.num_negative_pics + j]) {
+ st_ref_pic_set->delta_poc_s1[i] = d_poc;
+ st_ref_pic_set->used_by_curr_pic_s1[i++] =
+ used_by_curr_pic_flag[ref_set.num_negative_pics + j];
+ }
+ }
+ st_ref_pic_set->num_positive_pics = i;
+ } else {
+ READ_UE_OR_RETURN(&st_ref_pic_set->num_negative_pics);
+ READ_UE_OR_RETURN(&st_ref_pic_set->num_positive_pics);
+ IN_RANGE_OR_RETURN(
+ st_ref_pic_set->num_negative_pics, 0,
+ sps.sps_max_dec_pic_buffering_minus1[sps.sps_max_sub_layers_minus1]);
+ IN_RANGE_OR_RETURN(
+ st_ref_pic_set->num_positive_pics, 0,
+ sps.sps_max_dec_pic_buffering_minus1[sps.sps_max_sub_layers_minus1] -
+ st_ref_pic_set->num_negative_pics);
+ for (int i = 0; i < st_ref_pic_set->num_negative_pics; ++i) {
+ int delta_poc_s0_minus1;
+ READ_UE_OR_RETURN(&delta_poc_s0_minus1);
+ if (i == 0) {
+ st_ref_pic_set->delta_poc_s0[i] = -(delta_poc_s0_minus1 + 1);
+ } else {
+ st_ref_pic_set->delta_poc_s0[i] =
+ st_ref_pic_set->delta_poc_s0[i - 1] - (delta_poc_s0_minus1 + 1);
+ }
+ READ_BOOL_OR_RETURN(&st_ref_pic_set->used_by_curr_pic_s0[i]);
+ }
+ for (int i = 0; i < st_ref_pic_set->num_positive_pics; ++i) {
+ int delta_poc_s1_minus1;
+ READ_UE_OR_RETURN(&delta_poc_s1_minus1);
+ if (i == 0) {
+ st_ref_pic_set->delta_poc_s1[i] = delta_poc_s1_minus1 + 1;
+ } else {
+ st_ref_pic_set->delta_poc_s1[i] =
+ st_ref_pic_set->delta_poc_s1[i - 1] + delta_poc_s1_minus1 + 1;
+ }
+ READ_BOOL_OR_RETURN(&st_ref_pic_set->used_by_curr_pic_s1[i]);
+ }
+ }
+ // Calculate num_delta_pocs.
+ st_ref_pic_set->num_delta_pocs =
+ st_ref_pic_set->num_negative_pics + st_ref_pic_set->num_positive_pics;
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseVuiParameters(const H265SPS& sps,
+ H265VUIParameters* vui) {
+ Result res = kOk;
+ bool aspect_ratio_info_present_flag;
+ READ_BOOL_OR_RETURN(&aspect_ratio_info_present_flag);
+ if (aspect_ratio_info_present_flag) {
+ int aspect_ratio_idc;
+ READ_BITS_OR_RETURN(8, &aspect_ratio_idc);
+ constexpr int kExtendedSar = 255;
+ if (aspect_ratio_idc == kExtendedSar) {
+ READ_BITS_OR_RETURN(16, &vui->sar_width);
+ READ_BITS_OR_RETURN(16, &vui->sar_height);
+ } else {
+ const int max_aspect_ratio_idc = base::size(kTableSarWidth) - 1;
+ IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc);
+ vui->sar_width = kTableSarWidth[aspect_ratio_idc];
+ vui->sar_height = kTableSarHeight[aspect_ratio_idc];
+ }
+ }
+
+ int data;
+ // Read and ignore overscan info.
+ READ_BOOL_OR_RETURN(&data); // overscan_info_present_flag
+ if (data)
+ SKIP_BITS_OR_RETURN(1); // overscan_appropriate_flag
+
+ bool video_signal_type_present_flag;
+ READ_BOOL_OR_RETURN(&video_signal_type_present_flag);
+ if (video_signal_type_present_flag) {
+ SKIP_BITS_OR_RETURN(3); // video_format
+ READ_BOOL_OR_RETURN(&vui->video_full_range_flag);
+ READ_BOOL_OR_RETURN(&vui->colour_description_present_flag);
+ if (vui->colour_description_present_flag) {
+ // color description syntax elements
+ READ_BITS_OR_RETURN(8, &vui->colour_primaries);
+ READ_BITS_OR_RETURN(8, &vui->transfer_characteristics);
+ READ_BITS_OR_RETURN(8, &vui->matrix_coeffs);
+ }
+ }
+
+ READ_BOOL_OR_RETURN(&data); // chroma_loc_info_present_flag
+ if (data) {
+ READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_top_field
+ READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_bottom_field
+ }
+
+ // Ignore neutral_chroma_indication_flag, field_seq_flag and
+ // frame_field_info_present_flag.
+ SKIP_BITS_OR_RETURN(3);
+
+ bool default_display_window_flag;
+ READ_BOOL_OR_RETURN(&default_display_window_flag);
+ if (default_display_window_flag) {
+ READ_UE_OR_RETURN(&vui->def_disp_win_left_offset);
+ READ_UE_OR_RETURN(&vui->def_disp_win_right_offset);
+ READ_UE_OR_RETURN(&vui->def_disp_win_top_offset);
+ READ_UE_OR_RETURN(&vui->def_disp_win_bottom_offset);
+ }
+
+ // Read and ignore timing info.
+ READ_BOOL_OR_RETURN(&data); // timing_info_present_flag
+ if (data) {
+ SKIP_BITS_OR_RETURN(32); // vui_num_units_in_tick
+ SKIP_BITS_OR_RETURN(32); // vui_time_scale
+ READ_BOOL_OR_RETURN(&data); // vui_poc_proportional_to_timing_flag
+ if (data)
+ READ_UE_OR_RETURN(&data); // vui_num_ticks_poc_diff_one_minus1
+ res = ParseAndIgnoreHrdParameters(true, sps.sps_max_sub_layers_minus1);
+ if (res != kOk)
+ return res;
+ }
+
+ bool bitstream_restriction_flag;
+ READ_BOOL_OR_RETURN(&bitstream_restriction_flag);
+ if (bitstream_restriction_flag) {
+ // Skip tiles_fixed_structure_flag, motion_vectors_over_pic_boundaries_flag
+ // and restricted_ref_pic_lists_flag.
+ SKIP_BITS_OR_RETURN(3);
+ READ_UE_OR_RETURN(&data); // min_spatial_segmentation_idc
+ READ_UE_OR_RETURN(&data); // max_bytes_per_pic_denom
+ READ_UE_OR_RETURN(&data); // max_bits_per_min_cu_denom
+ READ_UE_OR_RETURN(&data); // log2_max_mv_length_horizontal
+ READ_UE_OR_RETURN(&data); // log2_max_mv_length_vertical
+ }
+
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseAndIgnoreHrdParameters(
+ bool common_inf_present_flag,
+ int max_num_sub_layers_minus1) {
+ Result res = kOk;
+ int data;
+ READ_BOOL_OR_RETURN(&data); // present_flag
+ if (!data)
+ return res;
+
+ bool nal_hrd_parameters_present_flag = false;
+ bool vcl_hrd_parameters_present_flag = false;
+ bool sub_pic_hrd_params_present_flag = false;
+ if (common_inf_present_flag) {
+ READ_BOOL_OR_RETURN(&nal_hrd_parameters_present_flag);
+ READ_BOOL_OR_RETURN(&vcl_hrd_parameters_present_flag);
+ if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
+ READ_BOOL_OR_RETURN(&sub_pic_hrd_params_present_flag);
+ if (sub_pic_hrd_params_present_flag) {
+ SKIP_BITS_OR_RETURN(8); // tick_divisor_minus2
+ SKIP_BITS_OR_RETURN(5); // du_cpb_removal_delay_increment_length_minus1
+ SKIP_BITS_OR_RETURN(1); // sub_pic_cpb_params_in_pic_timing_sei_flag
+ SKIP_BITS_OR_RETURN(5); // dpb_output_delay_du_length_minus1
+ }
+ SKIP_BITS_OR_RETURN(4); // bit_rate_scale;
+ SKIP_BITS_OR_RETURN(4); // cpb_size_scale;
+ if (sub_pic_hrd_params_present_flag)
+ SKIP_BITS_OR_RETURN(4); // cpb_size_du_scale
+ SKIP_BITS_OR_RETURN(5); // initial_cpb_removal_delay_length_minus1
+ SKIP_BITS_OR_RETURN(5); // au_cpb_removal_delay_length_minus1
+ SKIP_BITS_OR_RETURN(5); // dpb_output_delay_length_minus1
+ }
+ }
+ for (int i = 0; i <= max_num_sub_layers_minus1; ++i) {
+ bool fixed_pic_rate_flag;
+ READ_BOOL_OR_RETURN(&fixed_pic_rate_flag); // general
+ if (!fixed_pic_rate_flag)
+ READ_BOOL_OR_RETURN(&fixed_pic_rate_flag); // within_cvs
+ bool low_delay_hrd_flag = false;
+ if (fixed_pic_rate_flag)
+ READ_UE_OR_RETURN(&data); // elemental_duration_in_tc_minus1
+ else
+ READ_BOOL_OR_RETURN(&low_delay_hrd_flag);
+ int cpb_cnt = 1;
+ if (!low_delay_hrd_flag) {
+ READ_UE_OR_RETURN(&cpb_cnt);
+ cpb_cnt += 1; // parsed as minus1
+ }
+ if (nal_hrd_parameters_present_flag) {
+ res = ParseAndIgnoreSubLayerHrdParameters(
+ cpb_cnt, sub_pic_hrd_params_present_flag);
+ if (res != kOk)
+ return res;
+ }
+ if (vcl_hrd_parameters_present_flag) {
+ res = ParseAndIgnoreSubLayerHrdParameters(
+ cpb_cnt, sub_pic_hrd_params_present_flag);
+ if (res != kOk)
+ return res;
+ }
+ }
+ return res;
+}
+
+H265Parser::Result H265Parser::ParseAndIgnoreSubLayerHrdParameters(
+ int cpb_cnt,
+ bool sub_pic_hrd_params_present_flag) {
+ int data;
+ for (int i = 0; i < cpb_cnt; ++i) {
+ READ_UE_OR_RETURN(&data); // bit_rate_value_minus1[i]
+ READ_UE_OR_RETURN(&data); // cpb_size_value_minus1[i]
+ if (sub_pic_hrd_params_present_flag) {
+ READ_UE_OR_RETURN(&data); // cpb_size_du_value_minus1[i]
+ READ_UE_OR_RETURN(&data); // bit_rate_du_value_minus1[i]
+ }
+ SKIP_BITS_OR_RETURN(1); // cbr_flag[i]
+ }
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParseRefPicListsModifications(
+ const H265SliceHeader& shdr,
+ H265RefPicListsModifications* rpl_mod) {
+ READ_BOOL_OR_RETURN(&rpl_mod->ref_pic_list_modification_flag_l0);
+ if (rpl_mod->ref_pic_list_modification_flag_l0) {
+ for (int i = 0; i <= shdr.num_ref_idx_l0_active_minus1; ++i) {
+ READ_BITS_OR_RETURN(base::bits::Log2Ceiling(shdr.num_pic_total_curr),
+ &rpl_mod->list_entry_l0[i]);
+ IN_RANGE_OR_RETURN(rpl_mod->list_entry_l0[i], 0,
+ shdr.num_pic_total_curr - 1);
+ }
+ }
+ if (shdr.IsBSlice()) {
+ READ_BOOL_OR_RETURN(&rpl_mod->ref_pic_list_modification_flag_l1);
+ if (rpl_mod->ref_pic_list_modification_flag_l1) {
+ for (int i = 0; i <= shdr.num_ref_idx_l1_active_minus1; ++i) {
+ READ_BITS_OR_RETURN(base::bits::Log2Ceiling(shdr.num_pic_total_curr),
+ &rpl_mod->list_entry_l1[i]);
+ IN_RANGE_OR_RETURN(rpl_mod->list_entry_l1[i], 0,
+ shdr.num_pic_total_curr - 1);
+ }
+ }
+ }
+ return kOk;
+}
+
+H265Parser::Result H265Parser::ParsePredWeightTable(
+ const H265SPS& sps,
+ const H265SliceHeader& shdr,
+ H265PredWeightTable* pred_weight_table) {
+ // 7.4.6.3 Weighted prediction parameters semantics
+ READ_UE_OR_RETURN(&pred_weight_table->luma_log2_weight_denom);
+ IN_RANGE_OR_RETURN(pred_weight_table->luma_log2_weight_denom, 0, 7);
+ if (sps.chroma_array_type) {
+ READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_log2_weight_denom);
+ pred_weight_table->chroma_log2_weight_denom =
+ pred_weight_table->delta_chroma_log2_weight_denom +
+ pred_weight_table->luma_log2_weight_denom;
+ IN_RANGE_OR_RETURN(pred_weight_table->chroma_log2_weight_denom, 0, 7);
+ }
+ bool luma_weight_flag[kMaxRefIdxActive];
+ bool chroma_weight_flag[kMaxRefIdxActive];
+ memset(chroma_weight_flag, 0, sizeof(chroma_weight_flag));
+ for (int i = 0; i <= shdr.num_ref_idx_l0_active_minus1; ++i) {
+ READ_BOOL_OR_RETURN(&luma_weight_flag[i]);
+ }
+ if (sps.chroma_array_type) {
+ for (int i = 0; i <= shdr.num_ref_idx_l0_active_minus1; ++i) {
+ READ_BOOL_OR_RETURN(&chroma_weight_flag[i]);
+ }
+ }
+ int sum_weight_l0_flags = 0;
+ for (int i = 0; i <= shdr.num_ref_idx_l0_active_minus1; ++i) {
+ if (luma_weight_flag[i]) {
+ sum_weight_l0_flags++;
+ READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l0[i]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l0[i], -128, 127);
+ READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l0[i]);
+ IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l0[i],
+ -sps.wp_offset_half_range_y,
+ sps.wp_offset_half_range_y - 1);
+ }
+ if (chroma_weight_flag[i]) {
+ sum_weight_l0_flags += 2;
+ for (int j = 0; j < 2; ++j) {
+ READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l0[i][j]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l0[i][j],
+ -128, 127);
+ READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l0[i][j]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l0[i][j],
+ -4 * sps.wp_offset_half_range_c,
+ 4 * sps.wp_offset_half_range_c - 1);
+ }
+ }
+ }
+ if (shdr.IsPSlice())
+ TRUE_OR_RETURN(sum_weight_l0_flags <= 24);
+ if (shdr.IsBSlice()) {
+ memset(chroma_weight_flag, 0, sizeof(chroma_weight_flag));
+ int sum_weight_l1_flags = 0;
+ for (int i = 0; i <= shdr.num_ref_idx_l1_active_minus1; ++i) {
+ READ_BOOL_OR_RETURN(&luma_weight_flag[i]);
+ }
+ if (sps.chroma_array_type) {
+ for (int i = 0; i <= shdr.num_ref_idx_l1_active_minus1; ++i) {
+ READ_BOOL_OR_RETURN(&chroma_weight_flag[i]);
+ }
+ }
+ for (int i = 0; i <= shdr.num_ref_idx_l1_active_minus1; ++i) {
+ if (luma_weight_flag[i]) {
+ sum_weight_l1_flags++;
+ READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l1[i]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l1[i], -128,
+ 127);
+ READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l1[i]);
+ IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l1[i],
+ -sps.wp_offset_half_range_y,
+ sps.wp_offset_half_range_y - 1);
+ }
+ if (chroma_weight_flag[i]) {
+ sum_weight_l1_flags += 2;
+ for (int j = 0; j < 2; ++j) {
+ READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l1[i][j]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l1[i][j],
+ -128, 127);
+ READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l1[i][j]);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l1[i][j],
+ -4 * sps.wp_offset_half_range_c,
+ 4 * sps.wp_offset_half_range_c - 1);
+ }
+ }
+ }
+ TRUE_OR_RETURN(sum_weight_l0_flags + sum_weight_l1_flags <= 24);
+ }
+
return kOk;
}