OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/rtp_rtcp/source/h264_sps_parser.h" | 11 #include "webrtc/modules/rtp_rtcp/source/h264/sps_parser.h" |
12 | 12 |
13 #include "webrtc/modules/rtp_rtcp/source/h264/h264_common.h" | |
13 #include "webrtc/base/bitbuffer.h" | 14 #include "webrtc/base/bitbuffer.h" |
14 #include "webrtc/base/bytebuffer.h" | 15 #include "webrtc/base/bytebuffer.h" |
15 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
16 | 17 |
18 typedef rtc::Optional<webrtc::SpsParser::SpsState> Sps; | |
stefan-webrtc
2016/05/22 23:11:50
Call this OptionalSps, or remove it and write the
sprang_webrtc
2016/05/25 09:06:03
Done.
| |
19 | |
17 #define RETURN_FALSE_ON_FAIL(x) \ | 20 #define RETURN_FALSE_ON_FAIL(x) \ |
18 if (!(x)) { \ | 21 if (!(x)) { \ |
19 return false; \ | 22 return Sps(); \ |
20 } | 23 } |
21 | 24 |
22 namespace webrtc { | 25 namespace webrtc { |
23 | 26 |
24 H264SpsParser::H264SpsParser(const uint8_t* sps, size_t byte_length) | 27 // General note: this is based off the 02/2014 version of the H.264 standard. |
25 : sps_(sps), byte_length_(byte_length), width_(), height_() { | 28 // You can find it on this page: |
29 // http://www.itu.int/rec/T-REC-H.264 | |
30 | |
31 // Unpack RBSP and parse SPS state from the supplied buffer. | |
32 rtc::Optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data, | |
33 size_t length) { | |
34 std::unique_ptr<rtc::Buffer> unpacked_buffer = | |
35 H264Common::ParseRbsp(data, length); | |
36 rtc::BitBuffer bit_buffer(unpacked_buffer->data(), unpacked_buffer->size()); | |
37 return ParseSpsUpToVui(&bit_buffer); | |
26 } | 38 } |
27 | 39 |
28 bool H264SpsParser::Parse() { | 40 rtc::Optional<SpsParser::SpsState> SpsParser::ParseSpsUpToVui( |
29 // General note: this is based off the 02/2014 version of the H.264 standard. | 41 rtc::BitBuffer* buffer) { |
30 // You can find it on this page: | |
31 // http://www.itu.int/rec/T-REC-H.264 | |
32 | |
33 const char* sps_bytes = reinterpret_cast<const char*>(sps_); | |
34 // First, parse out rbsp, which is basically the source buffer minus emulation | |
35 // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in | |
36 // section 7.3.1 of the H.264 standard. | |
37 rtc::ByteBufferWriter rbsp_buffer; | |
38 for (size_t i = 0; i < byte_length_;) { | |
39 // Be careful about over/underflow here. byte_length_ - 3 can underflow, and | |
40 // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_ | |
41 // above, and that expression will produce the number of bytes left in | |
42 // the stream including the byte at i. | |
43 if (byte_length_ - i >= 3 && sps_[i] == 0 && sps_[i + 1] == 0 && | |
44 sps_[i + 2] == 3) { | |
45 // Two rbsp bytes + the emulation byte. | |
46 rbsp_buffer.WriteBytes(sps_bytes + i, 2); | |
47 i += 3; | |
48 } else { | |
49 // Single rbsp byte. | |
50 rbsp_buffer.WriteBytes(sps_bytes + i, 1); | |
51 i++; | |
52 } | |
53 } | |
54 | |
55 // Now, we need to use a bit buffer to parse through the actual AVC SPS | 42 // Now, we need to use a bit buffer to parse through the actual AVC SPS |
56 // format. See Section 7.3.2.1.1 ("Sequence parameter set data syntax") of the | 43 // format. See Section 7.3.2.1.1 ("Sequence parameter set data syntax") of the |
57 // H.264 standard for a complete description. | 44 // H.264 standard for a complete description. |
58 // Since we only care about resolution, we ignore the majority of fields, but | 45 // Since we only care about resolution, we ignore the majority of fields, but |
59 // we still have to actively parse through a lot of the data, since many of | 46 // we still have to actively parse through a lot of the data, since many of |
60 // the fields have variable size. | 47 // the fields have variable size. |
61 // We're particularly interested in: | 48 // We're particularly interested in: |
62 // chroma_format_idc -> affects crop units | 49 // chroma_format_idc -> affects crop units |
63 // pic_{width,height}_* -> resolution of the frame in macroblocks (16x16). | 50 // pic_{width,height}_* -> resolution of the frame in macroblocks (16x16). |
64 // frame_crop_*_offset -> crop information | 51 // frame_crop_*_offset -> crop information |
65 rtc::BitBuffer parser(reinterpret_cast<const uint8_t*>(rbsp_buffer.Data()), | 52 |
66 rbsp_buffer.Length()); | 53 SpsState sps; |
67 | 54 |
68 // The golomb values we have to read, not just consume. | 55 // The golomb values we have to read, not just consume. |
69 uint32_t golomb_ignored; | 56 uint32_t golomb_ignored; |
70 | 57 |
71 // separate_colour_plane_flag is optional (assumed 0), but has implications | |
72 // about the ChromaArrayType, which modifies how we treat crop coordinates. | |
73 uint32_t separate_colour_plane_flag = 0; | |
74 // chroma_format_idc will be ChromaArrayType if separate_colour_plane_flag is | 58 // chroma_format_idc will be ChromaArrayType if separate_colour_plane_flag is |
75 // 0. It defaults to 1, when not specified. | 59 // 0. It defaults to 1, when not specified. |
76 uint32_t chroma_format_idc = 1; | 60 uint32_t chroma_format_idc = 1; |
77 | 61 |
78 // profile_idc: u(8). We need it to determine if we need to read/skip chroma | 62 // profile_idc: u(8). We need it to determine if we need to read/skip chroma |
79 // formats. | 63 // formats. |
80 uint8_t profile_idc; | 64 uint8_t profile_idc; |
81 RETURN_FALSE_ON_FAIL(parser.ReadUInt8(&profile_idc)); | 65 RETURN_FALSE_ON_FAIL(buffer->ReadUInt8(&profile_idc)); |
82 // constraint_set0_flag through constraint_set5_flag + reserved_zero_2bits | 66 // constraint_set0_flag through constraint_set5_flag + reserved_zero_2bits |
83 // 1 bit each for the flags + 2 bits = 8 bits = 1 byte. | 67 // 1 bit each for the flags + 2 bits = 8 bits = 1 byte. |
84 RETURN_FALSE_ON_FAIL(parser.ConsumeBytes(1)); | 68 RETURN_FALSE_ON_FAIL(buffer->ConsumeBytes(1)); |
85 // level_idc: u(8) | 69 // level_idc: u(8) |
86 RETURN_FALSE_ON_FAIL(parser.ConsumeBytes(1)); | 70 RETURN_FALSE_ON_FAIL(buffer->ConsumeBytes(1)); |
87 // seq_parameter_set_id: ue(v) | 71 // seq_parameter_set_id: ue(v) |
88 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 72 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
73 sps.separate_colour_plane_flag = 0; | |
89 // See if profile_idc has chroma format information. | 74 // See if profile_idc has chroma format information. |
90 if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || | 75 if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || |
91 profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || | 76 profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || |
92 profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || | 77 profile_idc == 86 || profile_idc == 118 || profile_idc == 128 || |
93 profile_idc == 138 || profile_idc == 139 || profile_idc == 134) { | 78 profile_idc == 138 || profile_idc == 139 || profile_idc == 134) { |
94 // chroma_format_idc: ue(v) | 79 // chroma_format_idc: ue(v) |
95 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&chroma_format_idc)); | 80 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&chroma_format_idc)); |
96 if (chroma_format_idc == 3) { | 81 if (chroma_format_idc == 3) { |
97 // separate_colour_plane_flag: u(1) | 82 // separate_colour_plane_flag: u(1) |
98 RETURN_FALSE_ON_FAIL(parser.ReadBits(&separate_colour_plane_flag, 1)); | 83 RETURN_FALSE_ON_FAIL( |
84 buffer->ReadBits(&sps.separate_colour_plane_flag, 1)); | |
99 } | 85 } |
100 // bit_depth_luma_minus8: ue(v) | 86 // bit_depth_luma_minus8: ue(v) |
101 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 87 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
102 // bit_depth_chroma_minus8: ue(v) | 88 // bit_depth_chroma_minus8: ue(v) |
103 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 89 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
104 // qpprime_y_zero_transform_bypass_flag: u(1) | 90 // qpprime_y_zero_transform_bypass_flag: u(1) |
105 RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); | 91 RETURN_FALSE_ON_FAIL(buffer->ConsumeBits(1)); |
106 // seq_scaling_matrix_present_flag: u(1) | 92 // seq_scaling_matrix_present_flag: u(1) |
107 uint32_t seq_scaling_matrix_present_flag; | 93 uint32_t seq_scaling_matrix_present_flag; |
108 RETURN_FALSE_ON_FAIL(parser.ReadBits(&seq_scaling_matrix_present_flag, 1)); | 94 RETURN_FALSE_ON_FAIL(buffer->ReadBits(&seq_scaling_matrix_present_flag, 1)); |
109 if (seq_scaling_matrix_present_flag) { | 95 if (seq_scaling_matrix_present_flag) { |
110 // seq_scaling_list_present_flags. Either 8 or 12, depending on | 96 // seq_scaling_list_present_flags. Either 8 or 12, depending on |
111 // chroma_format_idc. | 97 // chroma_format_idc. |
112 uint32_t seq_scaling_list_present_flags; | 98 uint32_t seq_scaling_list_present_flags; |
113 if (chroma_format_idc != 3) { | 99 if (chroma_format_idc != 3) { |
114 RETURN_FALSE_ON_FAIL( | 100 RETURN_FALSE_ON_FAIL( |
115 parser.ReadBits(&seq_scaling_list_present_flags, 8)); | 101 buffer->ReadBits(&seq_scaling_list_present_flags, 8)); |
116 } else { | 102 } else { |
117 RETURN_FALSE_ON_FAIL( | 103 RETURN_FALSE_ON_FAIL( |
118 parser.ReadBits(&seq_scaling_list_present_flags, 12)); | 104 buffer->ReadBits(&seq_scaling_list_present_flags, 12)); |
119 } | 105 } |
120 // We don't support reading the sequence scaling list, and we don't really | 106 // We don't support reading the sequence scaling list, and we don't really |
121 // see/use them in practice, so we'll just reject the full sps if we see | 107 // see/use them in practice, so we'll just reject the full sps if we see |
122 // any provided. | 108 // any provided. |
123 if (seq_scaling_list_present_flags > 0) { | 109 if (seq_scaling_list_present_flags > 0) { |
124 LOG(LS_WARNING) << "SPS contains scaling lists, which are unsupported."; | 110 LOG(LS_WARNING) << "SPS contains scaling lists, which are unsupported."; |
125 return false; | 111 return Sps(); |
126 } | 112 } |
127 } | 113 } |
128 } | 114 } |
129 // log2_max_frame_num_minus4: ue(v) | 115 // log2_max_frame_num_minus4: ue(v) |
130 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 116 RETURN_FALSE_ON_FAIL( |
117 buffer->ReadExponentialGolomb(&sps.log2_max_frame_num_minus4)); | |
131 // pic_order_cnt_type: ue(v) | 118 // pic_order_cnt_type: ue(v) |
132 uint32_t pic_order_cnt_type; | 119 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&sps.pic_order_cnt_type)); |
133 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&pic_order_cnt_type)); | 120 if (sps.pic_order_cnt_type == 0) { |
134 if (pic_order_cnt_type == 0) { | |
135 // log2_max_pic_order_cnt_lsb_minus4: ue(v) | 121 // log2_max_pic_order_cnt_lsb_minus4: ue(v) |
136 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 122 RETURN_FALSE_ON_FAIL( |
137 } else if (pic_order_cnt_type == 1) { | 123 buffer->ReadExponentialGolomb(&sps.log2_max_pic_order_cnt_lsb_minus4)); |
124 } else if (sps.pic_order_cnt_type == 1) { | |
138 // delta_pic_order_always_zero_flag: u(1) | 125 // delta_pic_order_always_zero_flag: u(1) |
139 RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); | 126 RETURN_FALSE_ON_FAIL( |
127 buffer->ReadBits(&sps.delta_pic_order_always_zero_flag, 1)); | |
140 // offset_for_non_ref_pic: se(v) | 128 // offset_for_non_ref_pic: se(v) |
141 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 129 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
142 // offset_for_top_to_bottom_field: se(v) | 130 // offset_for_top_to_bottom_field: se(v) |
143 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 131 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
144 // num_ref_frames_in_pic_order_cnt_cycle: ue(v) | 132 // num_ref_frames_in_pic_order_cnt_cycle: ue(v) |
145 uint32_t num_ref_frames_in_pic_order_cnt_cycle; | 133 uint32_t num_ref_frames_in_pic_order_cnt_cycle; |
146 RETURN_FALSE_ON_FAIL( | 134 RETURN_FALSE_ON_FAIL( |
147 parser.ReadExponentialGolomb(&num_ref_frames_in_pic_order_cnt_cycle)); | 135 buffer->ReadExponentialGolomb(&num_ref_frames_in_pic_order_cnt_cycle)); |
148 for (size_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { | 136 for (size_t i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { |
149 // offset_for_ref_frame[i]: se(v) | 137 // offset_for_ref_frame[i]: se(v) |
150 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 138 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&golomb_ignored)); |
151 } | 139 } |
152 } | 140 } |
153 // max_num_ref_frames: ue(v) | 141 // max_num_ref_frames: ue(v) |
154 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&golomb_ignored)); | 142 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&sps.max_num_ref_frames)); |
155 // gaps_in_frame_num_value_allowed_flag: u(1) | 143 // gaps_in_frame_num_value_allowed_flag: u(1) |
156 RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); | 144 RETURN_FALSE_ON_FAIL(buffer->ConsumeBits(1)); |
157 // | 145 // |
158 // IMPORTANT ONES! Now we're getting to resolution. First we read the pic | 146 // IMPORTANT ONES! Now we're getting to resolution. First we read the pic |
159 // width/height in macroblocks (16x16), which gives us the base resolution, | 147 // width/height in macroblocks (16x16), which gives us the base resolution, |
160 // and then we continue on until we hit the frame crop offsets, which are used | 148 // and then we continue on until we hit the frame crop offsets, which are used |
161 // to signify resolutions that aren't multiples of 16. | 149 // to signify resolutions that aren't multiples of 16. |
162 // | 150 // |
163 // pic_width_in_mbs_minus1: ue(v) | 151 // pic_width_in_mbs_minus1: ue(v) |
164 uint32_t pic_width_in_mbs_minus1; | 152 uint32_t pic_width_in_mbs_minus1; |
165 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&pic_width_in_mbs_minus1)); | 153 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&pic_width_in_mbs_minus1)); |
166 // pic_height_in_map_units_minus1: ue(v) | 154 // pic_height_in_map_units_minus1: ue(v) |
167 uint32_t pic_height_in_map_units_minus1; | 155 uint32_t pic_height_in_map_units_minus1; |
168 RETURN_FALSE_ON_FAIL( | 156 RETURN_FALSE_ON_FAIL( |
169 parser.ReadExponentialGolomb(&pic_height_in_map_units_minus1)); | 157 buffer->ReadExponentialGolomb(&pic_height_in_map_units_minus1)); |
170 // frame_mbs_only_flag: u(1) | 158 // frame_mbs_only_flag: u(1) |
171 uint32_t frame_mbs_only_flag; | 159 RETURN_FALSE_ON_FAIL(buffer->ReadBits(&sps.frame_mbs_only_flag, 1)); |
172 RETURN_FALSE_ON_FAIL(parser.ReadBits(&frame_mbs_only_flag, 1)); | 160 if (!sps.frame_mbs_only_flag) { |
173 if (!frame_mbs_only_flag) { | |
174 // mb_adaptive_frame_field_flag: u(1) | 161 // mb_adaptive_frame_field_flag: u(1) |
175 RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); | 162 RETURN_FALSE_ON_FAIL(buffer->ConsumeBits(1)); |
176 } | 163 } |
177 // direct_8x8_inference_flag: u(1) | 164 // direct_8x8_inference_flag: u(1) |
178 RETURN_FALSE_ON_FAIL(parser.ConsumeBits(1)); | 165 RETURN_FALSE_ON_FAIL(buffer->ConsumeBits(1)); |
179 // | 166 // |
180 // MORE IMPORTANT ONES! Now we're at the frame crop information. | 167 // MORE IMPORTANT ONES! Now we're at the frame crop information. |
181 // | 168 // |
182 // frame_cropping_flag: u(1) | 169 // frame_cropping_flag: u(1) |
183 uint32_t frame_cropping_flag; | 170 uint32_t frame_cropping_flag; |
184 uint32_t frame_crop_left_offset = 0; | 171 uint32_t frame_crop_left_offset = 0; |
185 uint32_t frame_crop_right_offset = 0; | 172 uint32_t frame_crop_right_offset = 0; |
186 uint32_t frame_crop_top_offset = 0; | 173 uint32_t frame_crop_top_offset = 0; |
187 uint32_t frame_crop_bottom_offset = 0; | 174 uint32_t frame_crop_bottom_offset = 0; |
188 RETURN_FALSE_ON_FAIL(parser.ReadBits(&frame_cropping_flag, 1)); | 175 RETURN_FALSE_ON_FAIL(buffer->ReadBits(&frame_cropping_flag, 1)); |
189 if (frame_cropping_flag) { | 176 if (frame_cropping_flag) { |
190 // frame_crop_{left, right, top, bottom}_offset: ue(v) | 177 // frame_crop_{left, right, top, bottom}_offset: ue(v) |
191 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&frame_crop_left_offset)); | |
192 RETURN_FALSE_ON_FAIL( | 178 RETURN_FALSE_ON_FAIL( |
193 parser.ReadExponentialGolomb(&frame_crop_right_offset)); | 179 buffer->ReadExponentialGolomb(&frame_crop_left_offset)); |
194 RETURN_FALSE_ON_FAIL(parser.ReadExponentialGolomb(&frame_crop_top_offset)); | |
195 RETURN_FALSE_ON_FAIL( | 180 RETURN_FALSE_ON_FAIL( |
196 parser.ReadExponentialGolomb(&frame_crop_bottom_offset)); | 181 buffer->ReadExponentialGolomb(&frame_crop_right_offset)); |
182 RETURN_FALSE_ON_FAIL(buffer->ReadExponentialGolomb(&frame_crop_top_offset)); | |
183 RETURN_FALSE_ON_FAIL( | |
184 buffer->ReadExponentialGolomb(&frame_crop_bottom_offset)); | |
197 } | 185 } |
186 // vui_parameters_present_flag: u(1) | |
187 RETURN_FALSE_ON_FAIL(buffer->ReadBits(&sps.vui_params_present, 1)); | |
198 | 188 |
199 // Far enough! We don't use the rest of the SPS. | 189 // Far enough! We don't use the rest of the SPS. |
200 | 190 |
201 // Start with the resolution determined by the pic_width/pic_height fields. | 191 // Start with the resolution determined by the pic_width/pic_height fields. |
202 int width = 16 * (pic_width_in_mbs_minus1 + 1); | 192 sps.width = 16 * (pic_width_in_mbs_minus1 + 1); |
203 int height = | 193 sps.height = |
204 16 * (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1); | 194 16 * (2 - sps.frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1); |
205 | 195 |
206 // Figure out the crop units in pixels. That's based on the chroma format's | 196 // Figure out the crop units in pixels. That's based on the chroma format's |
207 // sampling, which is indicated by chroma_format_idc. | 197 // sampling, which is indicated by chroma_format_idc. |
208 if (separate_colour_plane_flag || chroma_format_idc == 0) { | 198 if (sps.separate_colour_plane_flag || chroma_format_idc == 0) { |
209 frame_crop_bottom_offset *= (2 - frame_mbs_only_flag); | 199 frame_crop_bottom_offset *= (2 - sps.frame_mbs_only_flag); |
210 frame_crop_top_offset *= (2 - frame_mbs_only_flag); | 200 frame_crop_top_offset *= (2 - sps.frame_mbs_only_flag); |
211 } else if (!separate_colour_plane_flag && chroma_format_idc > 0) { | 201 } else if (!sps.separate_colour_plane_flag && chroma_format_idc > 0) { |
212 // Width multipliers for formats 1 (4:2:0) and 2 (4:2:2). | 202 // Width multipliers for formats 1 (4:2:0) and 2 (4:2:2). |
213 if (chroma_format_idc == 1 || chroma_format_idc == 2) { | 203 if (chroma_format_idc == 1 || chroma_format_idc == 2) { |
214 frame_crop_left_offset *= 2; | 204 frame_crop_left_offset *= 2; |
215 frame_crop_right_offset *= 2; | 205 frame_crop_right_offset *= 2; |
216 } | 206 } |
217 // Height multipliers for format 1 (4:2:0). | 207 // Height multipliers for format 1 (4:2:0). |
218 if (chroma_format_idc == 1) { | 208 if (chroma_format_idc == 1) { |
219 frame_crop_top_offset *= 2; | 209 frame_crop_top_offset *= 2; |
220 frame_crop_bottom_offset *= 2; | 210 frame_crop_bottom_offset *= 2; |
221 } | 211 } |
222 } | 212 } |
223 // Subtract the crop for each dimension. | 213 // Subtract the crop for each dimension. |
224 width -= (frame_crop_left_offset + frame_crop_right_offset); | 214 sps.width -= (frame_crop_left_offset + frame_crop_right_offset); |
225 height -= (frame_crop_top_offset + frame_crop_bottom_offset); | 215 sps.height -= (frame_crop_top_offset + frame_crop_bottom_offset); |
226 | 216 |
227 width_ = width; | 217 return Sps(sps); |
228 height_ = height; | |
229 return true; | |
230 } | 218 } |
231 | 219 |
232 } // namespace webrtc | 220 } // namespace webrtc |
OLD | NEW |