OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 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 #include "webrtc/modules/video_processing/content_analysis.h" | 10 #include "webrtc/modules/video_processing/content_analysis.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 // Compute spatial metrics: 3 spatial prediction errors. | 65 // Compute spatial metrics: 3 spatial prediction errors. |
66 (this->*ComputeSpatialMetrics)(); | 66 (this->*ComputeSpatialMetrics)(); |
67 | 67 |
68 // Compute motion metrics | 68 // Compute motion metrics |
69 if (first_frame_ == false) | 69 if (first_frame_ == false) |
70 ComputeMotionMetrics(); | 70 ComputeMotionMetrics(); |
71 | 71 |
72 // Saving current frame as previous one: Y only. | 72 // Saving current frame as previous one: Y only. |
73 memcpy(prev_frame_, orig_frame_, width_ * height_); | 73 memcpy(prev_frame_, orig_frame_, width_ * height_); |
74 | 74 |
75 first_frame_ = false; | 75 first_frame_ = false; |
76 ca_Init_ = true; | 76 ca_Init_ = true; |
77 | 77 |
78 return ContentMetrics(); | 78 return ContentMetrics(); |
79 } | 79 } |
80 | 80 |
81 int32_t VPMContentAnalysis::Release() { | 81 int32_t VPMContentAnalysis::Release() { |
82 if (content_metrics_ != NULL) { | 82 if (content_metrics_ != NULL) { |
83 delete content_metrics_; | 83 delete content_metrics_; |
84 content_metrics_ = NULL; | 84 content_metrics_ = NULL; |
85 } | 85 } |
86 | 86 |
87 if (prev_frame_ != NULL) { | 87 if (prev_frame_ != NULL) { |
88 delete [] prev_frame_; | 88 delete[] prev_frame_; |
89 prev_frame_ = NULL; | 89 prev_frame_ = NULL; |
90 } | 90 } |
91 | 91 |
92 width_ = 0; | 92 width_ = 0; |
93 height_ = 0; | 93 height_ = 0; |
94 first_frame_ = true; | 94 first_frame_ = true; |
95 | 95 |
96 return VPM_OK; | 96 return VPM_OK; |
97 } | 97 } |
98 | 98 |
99 int32_t VPMContentAnalysis::Initialize(int width, int height) { | 99 int32_t VPMContentAnalysis::Initialize(int width, int height) { |
100 width_ = width; | 100 width_ = width; |
101 height_ = height; | 101 height_ = height; |
102 first_frame_ = true; | 102 first_frame_ = true; |
103 | 103 |
104 // skip parameter: # of skipped rows: for complexity reduction | 104 // skip parameter: # of skipped rows: for complexity reduction |
105 // temporal also currently uses it for column reduction. | 105 // temporal also currently uses it for column reduction. |
106 skip_num_ = 1; | 106 skip_num_ = 1; |
107 | 107 |
108 // use skipNum = 2 for 4CIF, WHD | 108 // use skipNum = 2 for 4CIF, WHD |
109 if ( (height_ >= 576) && (width_ >= 704) ) { | 109 if ((height_ >= 576) && (width_ >= 704)) { |
110 skip_num_ = 2; | 110 skip_num_ = 2; |
111 } | 111 } |
112 // use skipNum = 4 for FULLL_HD images | 112 // use skipNum = 4 for FULLL_HD images |
113 if ( (height_ >= 1080) && (width_ >= 1920) ) { | 113 if ((height_ >= 1080) && (width_ >= 1920)) { |
114 skip_num_ = 4; | 114 skip_num_ = 4; |
115 } | 115 } |
116 | 116 |
117 if (content_metrics_ != NULL) { | 117 if (content_metrics_ != NULL) { |
118 delete content_metrics_; | 118 delete content_metrics_; |
119 } | 119 } |
120 | 120 |
121 if (prev_frame_ != NULL) { | 121 if (prev_frame_ != NULL) { |
122 delete [] prev_frame_; | 122 delete[] prev_frame_; |
123 } | 123 } |
124 | 124 |
125 // Spatial Metrics don't work on a border of 8. Minimum processing | 125 // Spatial Metrics don't work on a border of 8. Minimum processing |
126 // block size is 16 pixels. So make sure the width and height support this. | 126 // block size is 16 pixels. So make sure the width and height support this. |
127 if (width_ <= 32 || height_ <= 32) { | 127 if (width_ <= 32 || height_ <= 32) { |
128 ca_Init_ = false; | 128 ca_Init_ = false; |
129 return VPM_PARAMETER_ERROR; | 129 return VPM_PARAMETER_ERROR; |
130 } | 130 } |
131 | 131 |
132 content_metrics_ = new VideoContentMetrics(); | 132 content_metrics_ = new VideoContentMetrics(); |
133 if (content_metrics_ == NULL) { | 133 if (content_metrics_ == NULL) { |
134 return VPM_MEMORY; | 134 return VPM_MEMORY; |
135 } | 135 } |
136 | 136 |
137 prev_frame_ = new uint8_t[width_ * height_]; // Y only. | 137 prev_frame_ = new uint8_t[width_ * height_]; // Y only. |
138 if (prev_frame_ == NULL) return VPM_MEMORY; | 138 if (prev_frame_ == NULL) |
| 139 return VPM_MEMORY; |
139 | 140 |
140 return VPM_OK; | 141 return VPM_OK; |
141 } | 142 } |
142 | 143 |
143 | |
144 // Compute motion metrics: magnitude over non-zero motion vectors, | 144 // Compute motion metrics: magnitude over non-zero motion vectors, |
145 // and size of zero cluster | 145 // and size of zero cluster |
146 int32_t VPMContentAnalysis::ComputeMotionMetrics() { | 146 int32_t VPMContentAnalysis::ComputeMotionMetrics() { |
147 // Motion metrics: only one is derived from normalized | 147 // Motion metrics: only one is derived from normalized |
148 // (MAD) temporal difference | 148 // (MAD) temporal difference |
149 (this->*TemporalDiffMetric)(); | 149 (this->*TemporalDiffMetric)(); |
150 return VPM_OK; | 150 return VPM_OK; |
151 } | 151 } |
152 | 152 |
153 // Normalized temporal difference (MAD): used as a motion level metric | 153 // Normalized temporal difference (MAD): used as a motion level metric |
154 // Normalize MAD by spatial contrast: images with more contrast | 154 // Normalize MAD by spatial contrast: images with more contrast |
155 // (pixel variance) likely have larger temporal difference | 155 // (pixel variance) likely have larger temporal difference |
156 // To reduce complexity, we compute the metric for a reduced set of points. | 156 // To reduce complexity, we compute the metric for a reduced set of points. |
157 int32_t VPMContentAnalysis::TemporalDiffMetric_C() { | 157 int32_t VPMContentAnalysis::TemporalDiffMetric_C() { |
158 // size of original frame | 158 // size of original frame |
159 int sizei = height_; | 159 int sizei = height_; |
160 int sizej = width_; | 160 int sizej = width_; |
161 uint32_t tempDiffSum = 0; | 161 uint32_t tempDiffSum = 0; |
162 uint32_t pixelSum = 0; | 162 uint32_t pixelSum = 0; |
163 uint64_t pixelSqSum = 0; | 163 uint64_t pixelSqSum = 0; |
164 | 164 |
165 uint32_t num_pixels = 0; // Counter for # of pixels. | 165 uint32_t num_pixels = 0; // Counter for # of pixels. |
166 const int width_end = ((width_ - 2*border_) & -16) + border_; | 166 const int width_end = ((width_ - 2 * border_) & -16) + border_; |
167 | 167 |
168 for (int i = border_; i < sizei - border_; i += skip_num_) { | 168 for (int i = border_; i < sizei - border_; i += skip_num_) { |
169 for (int j = border_; j < width_end; j++) { | 169 for (int j = border_; j < width_end; j++) { |
170 num_pixels += 1; | 170 num_pixels += 1; |
171 int ssn = i * sizej + j; | 171 int ssn = i * sizej + j; |
172 | 172 |
173 uint8_t currPixel = orig_frame_[ssn]; | 173 uint8_t currPixel = orig_frame_[ssn]; |
174 uint8_t prevPixel = prev_frame_[ssn]; | 174 uint8_t prevPixel = prev_frame_[ssn]; |
175 | 175 |
176 tempDiffSum += (uint32_t)abs((int16_t)(currPixel - prevPixel)); | 176 tempDiffSum += |
177 pixelSum += (uint32_t) currPixel; | 177 static_cast<uint32_t>(abs((int16_t)(currPixel - prevPixel))); |
178 pixelSqSum += (uint64_t) (currPixel * currPixel); | 178 pixelSum += static_cast<uint32_t>(currPixel); |
| 179 pixelSqSum += static_cast<uint64_t>(currPixel * currPixel); |
179 } | 180 } |
180 } | 181 } |
181 | 182 |
182 // Default. | 183 // Default. |
183 motion_magnitude_ = 0.0f; | 184 motion_magnitude_ = 0.0f; |
184 | 185 |
185 if (tempDiffSum == 0) return VPM_OK; | 186 if (tempDiffSum == 0) |
| 187 return VPM_OK; |
186 | 188 |
187 // Normalize over all pixels. | 189 // Normalize over all pixels. |
188 float const tempDiffAvg = (float)tempDiffSum / (float)(num_pixels); | 190 float const tempDiffAvg = |
189 float const pixelSumAvg = (float)pixelSum / (float)(num_pixels); | 191 static_cast<float>(tempDiffSum) / static_cast<float>(num_pixels); |
190 float const pixelSqSumAvg = (float)pixelSqSum / (float)(num_pixels); | 192 float const pixelSumAvg = |
| 193 static_cast<float>(pixelSum) / static_cast<float>(num_pixels); |
| 194 float const pixelSqSumAvg = |
| 195 static_cast<float>(pixelSqSum) / static_cast<float>(num_pixels); |
191 float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg); | 196 float contrast = pixelSqSumAvg - (pixelSumAvg * pixelSumAvg); |
192 | 197 |
193 if (contrast > 0.0) { | 198 if (contrast > 0.0) { |
194 contrast = sqrt(contrast); | 199 contrast = sqrt(contrast); |
195 motion_magnitude_ = tempDiffAvg/contrast; | 200 motion_magnitude_ = tempDiffAvg / contrast; |
196 } | 201 } |
197 return VPM_OK; | 202 return VPM_OK; |
198 } | 203 } |
199 | 204 |
200 // Compute spatial metrics: | 205 // Compute spatial metrics: |
201 // To reduce complexity, we compute the metric for a reduced set of points. | 206 // To reduce complexity, we compute the metric for a reduced set of points. |
202 // The spatial metrics are rough estimates of the prediction error cost for | 207 // The spatial metrics are rough estimates of the prediction error cost for |
203 // each QM spatial mode: 2x2,1x2,2x1 | 208 // each QM spatial mode: 2x2,1x2,2x1 |
204 // The metrics are a simple estimate of the up-sampling prediction error, | 209 // The metrics are a simple estimate of the up-sampling prediction error, |
205 // estimated assuming sub-sampling for decimation (no filtering), | 210 // estimated assuming sub-sampling for decimation (no filtering), |
206 // and up-sampling back up with simple bilinear interpolation. | 211 // and up-sampling back up with simple bilinear interpolation. |
207 int32_t VPMContentAnalysis::ComputeSpatialMetrics_C() { | 212 int32_t VPMContentAnalysis::ComputeSpatialMetrics_C() { |
208 const int sizei = height_; | 213 const int sizei = height_; |
209 const int sizej = width_; | 214 const int sizej = width_; |
210 | 215 |
211 // Pixel mean square average: used to normalize the spatial metrics. | 216 // Pixel mean square average: used to normalize the spatial metrics. |
212 uint32_t pixelMSA = 0; | 217 uint32_t pixelMSA = 0; |
213 | 218 |
214 uint32_t spatialErrSum = 0; | 219 uint32_t spatialErrSum = 0; |
215 uint32_t spatialErrVSum = 0; | 220 uint32_t spatialErrVSum = 0; |
216 uint32_t spatialErrHSum = 0; | 221 uint32_t spatialErrHSum = 0; |
217 | 222 |
218 // make sure work section is a multiple of 16 | 223 // make sure work section is a multiple of 16 |
219 const int width_end = ((sizej - 2*border_) & -16) + border_; | 224 const int width_end = ((sizej - 2 * border_) & -16) + border_; |
220 | 225 |
221 for (int i = border_; i < sizei - border_; i += skip_num_) { | 226 for (int i = border_; i < sizei - border_; i += skip_num_) { |
222 for (int j = border_; j < width_end; j++) { | 227 for (int j = border_; j < width_end; j++) { |
223 int ssn1= i * sizej + j; | 228 int ssn1 = i * sizej + j; |
224 int ssn2 = (i + 1) * sizej + j; // bottom | 229 int ssn2 = (i + 1) * sizej + j; // bottom |
225 int ssn3 = (i - 1) * sizej + j; // top | 230 int ssn3 = (i - 1) * sizej + j; // top |
226 int ssn4 = i * sizej + j + 1; // right | 231 int ssn4 = i * sizej + j + 1; // right |
227 int ssn5 = i * sizej + j - 1; // left | 232 int ssn5 = i * sizej + j - 1; // left |
228 | 233 |
229 uint16_t refPixel1 = orig_frame_[ssn1] << 1; | 234 uint16_t refPixel1 = orig_frame_[ssn1] << 1; |
230 uint16_t refPixel2 = orig_frame_[ssn1] << 2; | 235 uint16_t refPixel2 = orig_frame_[ssn1] << 2; |
231 | 236 |
232 uint8_t bottPixel = orig_frame_[ssn2]; | 237 uint8_t bottPixel = orig_frame_[ssn2]; |
233 uint8_t topPixel = orig_frame_[ssn3]; | 238 uint8_t topPixel = orig_frame_[ssn3]; |
234 uint8_t rightPixel = orig_frame_[ssn4]; | 239 uint8_t rightPixel = orig_frame_[ssn4]; |
235 uint8_t leftPixel = orig_frame_[ssn5]; | 240 uint8_t leftPixel = orig_frame_[ssn5]; |
236 | 241 |
237 spatialErrSum += (uint32_t) abs((int16_t)(refPixel2 | 242 spatialErrSum += static_cast<uint32_t>(abs(static_cast<int16_t>( |
238 - (uint16_t)(bottPixel + topPixel + leftPixel + rightPixel))); | 243 refPixel2 - static_cast<uint16_t>(bottPixel + topPixel + leftPixel + |
239 spatialErrVSum += (uint32_t) abs((int16_t)(refPixel1 | 244 rightPixel)))); |
240 - (uint16_t)(bottPixel + topPixel))); | 245 spatialErrVSum += static_cast<uint32_t>(abs(static_cast<int16_t>( |
241 spatialErrHSum += (uint32_t) abs((int16_t)(refPixel1 | 246 refPixel1 - static_cast<uint16_t>(bottPixel + topPixel)))); |
242 - (uint16_t)(leftPixel + rightPixel))); | 247 spatialErrHSum += static_cast<uint32_t>(abs(static_cast<int16_t>( |
| 248 refPixel1 - static_cast<uint16_t>(leftPixel + rightPixel)))); |
243 pixelMSA += orig_frame_[ssn1]; | 249 pixelMSA += orig_frame_[ssn1]; |
244 } | 250 } |
245 } | 251 } |
246 | 252 |
247 // Normalize over all pixels. | 253 // Normalize over all pixels. |
248 const float spatialErr = (float)(spatialErrSum >> 2); | 254 const float spatialErr = static_cast<float>(spatialErrSum >> 2); |
249 const float spatialErrH = (float)(spatialErrHSum >> 1); | 255 const float spatialErrH = static_cast<float>(spatialErrHSum >> 1); |
250 const float spatialErrV = (float)(spatialErrVSum >> 1); | 256 const float spatialErrV = static_cast<float>(spatialErrVSum >> 1); |
251 const float norm = (float)pixelMSA; | 257 const float norm = static_cast<float>(pixelMSA); |
252 | 258 |
253 // 2X2: | 259 // 2X2: |
254 spatial_pred_err_ = spatialErr / norm; | 260 spatial_pred_err_ = spatialErr / norm; |
255 // 1X2: | 261 // 1X2: |
256 spatial_pred_err_h_ = spatialErrH / norm; | 262 spatial_pred_err_h_ = spatialErrH / norm; |
257 // 2X1: | 263 // 2X1: |
258 spatial_pred_err_v_ = spatialErrV / norm; | 264 spatial_pred_err_v_ = spatialErrV / norm; |
259 return VPM_OK; | 265 return VPM_OK; |
260 } | 266 } |
261 | 267 |
262 VideoContentMetrics* VPMContentAnalysis::ContentMetrics() { | 268 VideoContentMetrics* VPMContentAnalysis::ContentMetrics() { |
263 if (ca_Init_ == false) return NULL; | 269 if (ca_Init_ == false) |
| 270 return NULL; |
264 | 271 |
265 content_metrics_->spatial_pred_err = spatial_pred_err_; | 272 content_metrics_->spatial_pred_err = spatial_pred_err_; |
266 content_metrics_->spatial_pred_err_h = spatial_pred_err_h_; | 273 content_metrics_->spatial_pred_err_h = spatial_pred_err_h_; |
267 content_metrics_->spatial_pred_err_v = spatial_pred_err_v_; | 274 content_metrics_->spatial_pred_err_v = spatial_pred_err_v_; |
268 // Motion metric: normalized temporal difference (MAD). | 275 // Motion metric: normalized temporal difference (MAD). |
269 content_metrics_->motion_magnitude = motion_magnitude_; | 276 content_metrics_->motion_magnitude = motion_magnitude_; |
270 | 277 |
271 return content_metrics_; | 278 return content_metrics_; |
272 } | 279 } |
273 | 280 |
274 } // namespace webrtc | 281 } // namespace webrtc |
OLD | NEW |