Index: webrtc/common_video/h264/sps_parser.cc |
diff --git a/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc b/webrtc/common_video/h264/sps_parser.cc |
similarity index 51% |
rename from webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc |
rename to webrtc/common_video/h264/sps_parser.cc |
index 904a9e2562b50ef6c8393b22c709572188578030..cf4b36d1238b798025792d6569e11a3c32011e44 100644 |
--- a/webrtc/modules/rtp_rtcp/source/h264_sps_parser.cc |
+++ b/webrtc/common_video/h264/sps_parser.cc |
@@ -1,5 +1,5 @@ |
/* |
- * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
* |
* Use of this source code is governed by a BSD-style license |
* that can be found in the LICENSE file in the root of the source |
@@ -8,50 +8,36 @@ |
* be found in the AUTHORS file in the root of the source tree. |
*/ |
-#include "webrtc/modules/rtp_rtcp/source/h264_sps_parser.h" |
+#include "webrtc/common_video/h264/sps_parser.h" |
+#include "webrtc/common_video/h264/h264_common.h" |
#include "webrtc/base/bitbuffer.h" |
#include "webrtc/base/bytebuffer.h" |
#include "webrtc/base/logging.h" |
-#define RETURN_FALSE_ON_FAIL(x) \ |
+typedef rtc::Optional<webrtc::SpsParser::SpsState> OptionalSps; |
+ |
+#define RETURN_EMPTY_ON_FAIL(x) \ |
if (!(x)) { \ |
- return false; \ |
+ return OptionalSps(); \ |
} |
namespace webrtc { |
-H264SpsParser::H264SpsParser(const uint8_t* sps, size_t byte_length) |
- : sps_(sps), byte_length_(byte_length), width_(), height_() { |
-} |
+// General note: this is based off the 02/2014 version of the H.264 standard. |
+// You can find it on this page: |
+// http://www.itu.int/rec/T-REC-H.264 |
-bool H264SpsParser::Parse() { |
- // General note: this is based off the 02/2014 version of the H.264 standard. |
- // You can find it on this page: |
- // http://www.itu.int/rec/T-REC-H.264 |
- |
- const char* sps_bytes = reinterpret_cast<const char*>(sps_); |
- // First, parse out rbsp, which is basically the source buffer minus emulation |
- // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in |
- // section 7.3.1 of the H.264 standard. |
- rtc::ByteBufferWriter rbsp_buffer; |
- for (size_t i = 0; i < byte_length_;) { |
- // Be careful about over/underflow here. byte_length_ - 3 can underflow, and |
- // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_ |
- // above, and that expression will produce the number of bytes left in |
- // the stream including the byte at i. |
- if (byte_length_ - i >= 3 && sps_[i] == 0 && sps_[i + 1] == 0 && |
- sps_[i + 2] == 3) { |
- // Two rbsp bytes + the emulation byte. |
- rbsp_buffer.WriteBytes(sps_bytes + i, 2); |
- i += 3; |
- } else { |
- // Single rbsp byte. |
- rbsp_buffer.WriteBytes(sps_bytes + i, 1); |
- i++; |
- } |
- } |
+// Unpack RBSP and parse SPS state from the supplied buffer. |
+rtc::Optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data, |
+ size_t length) { |
+ std::unique_ptr<rtc::Buffer> unpacked_buffer = H264::ParseRbsp(data, length); |
+ rtc::BitBuffer bit_buffer(unpacked_buffer->data(), unpacked_buffer->size()); |
+ return ParseSpsUpToVui(&bit_buffer); |
+} |
+rtc::Optional<SpsParser::SpsState> SpsParser::ParseSpsUpToVui( |
+ rtc::BitBuffer* buffer) { |
// Now, we need to use a bit buffer to parse through the actual AVC SPS |
// format. See Section 7.3.2.1.1 ("Sequence parameter set data syntax") of the |
// H.264 standard for a complete description. |
@@ -62,15 +48,12 @@ bool H264SpsParser::Parse() { |
// chroma_format_idc -> affects crop units |
// pic_{width,height}_* -> resolution of the frame in macroblocks (16x16). |
// frame_crop_*_offset -> crop information |
- rtc::BitBuffer parser(reinterpret_cast<const uint8_t*>(rbsp_buffer.Data()), |
- rbsp_buffer.Length()); |
+ |
+ SpsState sps; |
// The golomb values we have to read, not just consume. |
uint32_t golomb_ignored; |
- // separate_colour_plane_flag is optional (assumed 0), but has implications |
- // about the ChromaArrayType, which modifies how we treat crop coordinates. |
- uint32_t separate_colour_plane_flag = 0; |
// chroma_format_idc will be ChromaArrayType if separate_colour_plane_flag is |
// 0. It defaults to 1, when not specified. |
uint32_t chroma_format_idc = 1; |
@@ -78,82 +61,86 @@ bool H264SpsParser::Parse() { |
// profile_idc: u(8). We need it to determine if we need to read/skip chroma |
// formats. |
uint8_t profile_idc; |
- RETURN_FALSE_ON_FAIL(parser.ReadUInt8(&profile_idc)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadUInt8(&profile_idc)); |
// constraint_set0_flag through constraint_set5_flag + reserved_zero_2bits |
// 1 bit each for the flags + 2 bits = 8 bits = 1 byte. |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBytes(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBytes(1)); |
// level_idc: u(8) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBytes(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBytes(1)); |
// seq_parameter_set_id: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
+ sps.separate_colour_plane_flag = 0; |
// See if profile_idc has chroma format information. |
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || |
profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || |
profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || |
profile_idc == 138 || profile_idc == 139 || profile_idc == 134) { |
// chroma_format_idc: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&chroma_format_idc)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&chroma_format_idc)); |
if (chroma_format_idc == 3) { |
// separate_colour_plane_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ReadBits(&separate_colour_plane_flag, 1)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadBits(&sps.separate_colour_plane_flag, 1)); |
} |
// bit_depth_luma_minus8: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
// bit_depth_chroma_minus8: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
// qpprime_y_zero_transform_bypass_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBits(1)); |
// seq_scaling_matrix_present_flag: u(1) |
uint32_t seq_scaling_matrix_present_flag; |
- RETURN_FALSE_ON_FAIL(parser.ReadBits(&seq_scaling_matrix_present_flag, 1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadBits(&seq_scaling_matrix_present_flag, 1)); |
if (seq_scaling_matrix_present_flag) { |
// seq_scaling_list_present_flags. Either 8 or 12, depending on |
// chroma_format_idc. |
uint32_t seq_scaling_list_present_flags; |
if (chroma_format_idc != 3) { |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadBits(&seq_scaling_list_present_flags, 8)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadBits(&seq_scaling_list_present_flags, 8)); |
} else { |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadBits(&seq_scaling_list_present_flags, 12)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadBits(&seq_scaling_list_present_flags, 12)); |
} |
// We don't support reading the sequence scaling list, and we don't really |
// see/use them in practice, so we'll just reject the full sps if we see |
// any provided. |
if (seq_scaling_list_present_flags > 0) { |
LOG(LS_WARNING) << "SPS contains scaling lists, which are unsupported."; |
- return false; |
+ return OptionalSps(); |
} |
} |
} |
// log2_max_frame_num_minus4: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&sps.log2_max_frame_num_minus4)); |
// pic_order_cnt_type: ue(v) |
- uint32_t pic_order_cnt_type; |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&pic_order_cnt_type)); |
- if (pic_order_cnt_type == 0) { |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&sps.pic_order_cnt_type)); |
+ if (sps.pic_order_cnt_type == 0) { |
// log2_max_pic_order_cnt_lsb_minus4: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
- } else if (pic_order_cnt_type == 1) { |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&sps.log2_max_pic_order_cnt_lsb_minus4)); |
+ } else if (sps.pic_order_cnt_type == 1) { |
// delta_pic_order_always_zero_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadBits(&sps.delta_pic_order_always_zero_flag, 1)); |
// offset_for_non_ref_pic: se(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
// offset_for_top_to_bottom_field: se(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
// num_ref_frames_in_pic_order_cnt_cycle: ue(v) |
uint32_t num_ref_frames_in_pic_order_cnt_cycle; |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadExponentialGolomb(&num_ref_frames_in_pic_order_cnt_cycle)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&num_ref_frames_in_pic_order_cnt_cycle)); |
for (size_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { |
// offset_for_ref_frame[i]: se(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
} |
} |
// max_num_ref_frames: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&sps.max_num_ref_frames)); |
// gaps_in_frame_num_value_allowed_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBits(1)); |
// |
// IMPORTANT ONES! Now we're getting to resolution. First we read the pic |
// width/height in macroblocks (16x16), which gives us the base resolution, |
@@ -162,20 +149,19 @@ bool H264SpsParser::Parse() { |
// |
// pic_width_in_mbs_minus1: ue(v) |
uint32_t pic_width_in_mbs_minus1; |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&pic_width_in_mbs_minus1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&pic_width_in_mbs_minus1)); |
// pic_height_in_map_units_minus1: ue(v) |
uint32_t pic_height_in_map_units_minus1; |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadExponentialGolomb(&pic_height_in_map_units_minus1)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&pic_height_in_map_units_minus1)); |
// frame_mbs_only_flag: u(1) |
- uint32_t frame_mbs_only_flag; |
- RETURN_FALSE_ON_FAIL(parser.ReadBits(&frame_mbs_only_flag, 1)); |
- if (!frame_mbs_only_flag) { |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadBits(&sps.frame_mbs_only_flag, 1)); |
+ if (!sps.frame_mbs_only_flag) { |
// mb_adaptive_frame_field_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBits(1)); |
} |
// direct_8x8_inference_flag: u(1) |
- RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ConsumeBits(1)); |
// |
// MORE IMPORTANT ONES! Now we're at the frame crop information. |
// |
@@ -185,30 +171,33 @@ bool H264SpsParser::Parse() { |
uint32_t frame_crop_right_offset = 0; |
uint32_t frame_crop_top_offset = 0; |
uint32_t frame_crop_bottom_offset = 0; |
- RETURN_FALSE_ON_FAIL(parser.ReadBits(&frame_cropping_flag, 1)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadBits(&frame_cropping_flag, 1)); |
if (frame_cropping_flag) { |
// frame_crop_{left, right, top, bottom}_offset: ue(v) |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&frame_crop_left_offset)); |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadExponentialGolomb(&frame_crop_right_offset)); |
- RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&frame_crop_top_offset)); |
- RETURN_FALSE_ON_FAIL( |
- parser.ReadExponentialGolomb(&frame_crop_bottom_offset)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&frame_crop_left_offset)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&frame_crop_right_offset)); |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadExponentialGolomb(&frame_crop_top_offset)); |
+ RETURN_EMPTY_ON_FAIL( |
+ buffer->ReadExponentialGolomb(&frame_crop_bottom_offset)); |
} |
+ // vui_parameters_present_flag: u(1) |
+ RETURN_EMPTY_ON_FAIL(buffer->ReadBits(&sps.vui_params_present, 1)); |
// Far enough! We don't use the rest of the SPS. |
// Start with the resolution determined by the pic_width/pic_height fields. |
- int width = 16 * (pic_width_in_mbs_minus1 + 1); |
- int height = |
- 16 * (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1); |
+ sps.width = 16 * (pic_width_in_mbs_minus1 + 1); |
+ sps.height = |
+ 16 * (2 - sps.frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1); |
// Figure out the crop units in pixels. That's based on the chroma format's |
// sampling, which is indicated by chroma_format_idc. |
- if (separate_colour_plane_flag || chroma_format_idc == 0) { |
- frame_crop_bottom_offset *= (2 - frame_mbs_only_flag); |
- frame_crop_top_offset *= (2 - frame_mbs_only_flag); |
- } else if (!separate_colour_plane_flag && chroma_format_idc > 0) { |
+ if (sps.separate_colour_plane_flag || chroma_format_idc == 0) { |
+ frame_crop_bottom_offset *= (2 - sps.frame_mbs_only_flag); |
+ frame_crop_top_offset *= (2 - sps.frame_mbs_only_flag); |
+ } else if (!sps.separate_colour_plane_flag && chroma_format_idc > 0) { |
// Width multipliers for formats 1 (4:2:0) and 2 (4:2:2). |
if (chroma_format_idc == 1 || chroma_format_idc == 2) { |
frame_crop_left_offset *= 2; |
@@ -221,12 +210,10 @@ bool H264SpsParser::Parse() { |
} |
} |
// Subtract the crop for each dimension. |
- width -= (frame_crop_left_offset + frame_crop_right_offset); |
- height -= (frame_crop_top_offset + frame_crop_bottom_offset); |
+ sps.width -= (frame_crop_left_offset + frame_crop_right_offset); |
+ sps.height -= (frame_crop_top_offset + frame_crop_bottom_offset); |
- width_ = width; |
- height_ = height; |
- return true; |
+ return OptionalSps(sps); |
} |
} // namespace webrtc |