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 | 10 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 case kARGB: | 95 case kARGB: |
96 buffer_size = width * height * 4; | 96 buffer_size = width * height * 4; |
97 break; | 97 break; |
98 default: | 98 default: |
99 assert(false); | 99 assert(false); |
100 break; | 100 break; |
101 } | 101 } |
102 return buffer_size; | 102 return buffer_size; |
103 } | 103 } |
104 | 104 |
105 static int PrintPlane(const uint8_t* buf, | |
106 int width, | |
107 int height, | |
108 int stride, | |
109 FILE* file) { | |
110 for (int i = 0; i < height; i++, buf += stride) { | |
111 if (fwrite(buf, 1, width, file) != static_cast<unsigned int>(width)) | |
112 return -1; | |
113 } | |
114 return 0; | |
115 } | |
116 | |
117 // TODO(nisse): Belongs with the test code? | |
perkj_webrtc
2016/04/19 12:28:13
where is it used? Can it be moved there now?
nisse-webrtc
2016/04/19 13:55:38
It's used in various unittests, and in the command
| |
105 int PrintVideoFrame(const VideoFrame& frame, FILE* file) { | 118 int PrintVideoFrame(const VideoFrame& frame, FILE* file) { |
106 if (file == NULL) | 119 if (file == NULL) |
107 return -1; | 120 return -1; |
108 if (frame.IsZeroSize()) | 121 if (frame.IsZeroSize()) |
109 return -1; | 122 return -1; |
110 for (int planeNum = 0; planeNum < kNumOfPlanes; ++planeNum) { | 123 int width = frame.video_frame_buffer()->width(); |
111 int width = (planeNum ? (frame.width() + 1) / 2 : frame.width()); | 124 int height = frame.video_frame_buffer()->height(); |
112 int height = (planeNum ? (frame.height() + 1) / 2 : frame.height()); | 125 int chroma_width = (width + 1) / 2; |
113 PlaneType plane_type = static_cast<PlaneType>(planeNum); | 126 int chroma_height = (height + 1) / 2; |
114 const uint8_t* plane_buffer = frame.buffer(plane_type); | 127 |
115 for (int y = 0; y < height; y++) { | 128 if (PrintPlane(frame.video_frame_buffer()->DataY(), width, height, |
116 if (fwrite(plane_buffer, 1, width, file) != | 129 frame.video_frame_buffer()->StrideY(), file) < 0) |
117 static_cast<unsigned int>(width)) { | 130 return -1; |
118 return -1; | 131 |
119 } | 132 if (PrintPlane(frame.video_frame_buffer()->DataU(), |
120 plane_buffer += frame.stride(plane_type); | 133 chroma_width, chroma_height, |
121 } | 134 frame.video_frame_buffer()->StrideU(), file) < 0) |
122 } | 135 return -1; |
136 | |
137 if (PrintPlane(frame.video_frame_buffer()->DataV(), | |
138 chroma_width, chroma_height, | |
139 frame.video_frame_buffer()->StrideV(), file) < 0) | |
140 return -1; | |
141 | |
123 return 0; | 142 return 0; |
124 } | 143 } |
125 | 144 |
145 // TODO(nisse): Used only by I420Decoder, which in turn is mostly | |
perkj_webrtc
2016/04/19 12:28:13
now ?
nisse-webrtc
2016/04/19 13:55:39
As I wrote in a different comment, including libyu
| |
146 // unused. Delete and let that code call libyuv directly? | |
126 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { | 147 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { |
127 assert(buffer); | 148 assert(buffer); |
128 if (input_frame.IsZeroSize()) | 149 if (input_frame.IsZeroSize()) |
129 return -1; | 150 return -1; |
130 size_t length = | 151 size_t length = |
131 CalcBufferSize(kI420, input_frame.width(), input_frame.height()); | 152 CalcBufferSize(kI420, input_frame.width(), input_frame.height()); |
132 if (size < length) { | 153 if (size < length) { |
133 return -1; | 154 return -1; |
134 } | 155 } |
135 | 156 |
136 int pos = 0; | 157 int width = input_frame.video_frame_buffer()->width(); |
137 uint8_t* buffer_ptr = buffer; | 158 int height = input_frame.video_frame_buffer()->height(); |
159 int chroma_width = (width + 1) / 2; | |
160 int chroma_height = (height + 1) / 2; | |
138 | 161 |
139 for (int plane = 0; plane < kNumOfPlanes; ++plane) { | 162 libyuv::I420Copy(input_frame.video_frame_buffer()->DataY(), |
140 int width = (plane ? (input_frame.width() + 1) / 2 : | 163 input_frame.video_frame_buffer()->StrideY(), |
141 input_frame.width()); | 164 input_frame.video_frame_buffer()->DataU(), |
142 int height = (plane ? (input_frame.height() + 1) / 2 : | 165 input_frame.video_frame_buffer()->StrideU(), |
143 input_frame.height()); | 166 input_frame.video_frame_buffer()->DataV(), |
144 const uint8_t* plane_ptr = input_frame.buffer( | 167 input_frame.video_frame_buffer()->StrideV(), |
145 static_cast<PlaneType>(plane)); | 168 buffer, width, |
146 for (int y = 0; y < height; y++) { | 169 buffer + width*height, chroma_width, |
147 memcpy(&buffer_ptr[pos], plane_ptr, width); | 170 buffer + width*height + chroma_width*chroma_height, |
148 pos += width; | 171 chroma_width, |
149 plane_ptr += input_frame.stride(static_cast<PlaneType>(plane)); | 172 width, height); |
150 } | 173 |
151 } | |
152 return static_cast<int>(length); | 174 return static_cast<int>(length); |
153 } | 175 } |
154 | 176 |
155 | 177 |
156 int ConvertNV12ToRGB565(const uint8_t* src_frame, | 178 int ConvertNV12ToRGB565(const uint8_t* src_frame, |
157 uint8_t* dst_frame, | 179 uint8_t* dst_frame, |
158 int width, int height) { | 180 int width, int height) { |
159 int abs_height = (height < 0) ? -height : height; | 181 int abs_height = (height < 0) ? -height : height; |
160 const uint8_t* yplane = src_frame; | 182 const uint8_t* yplane = src_frame; |
161 const uint8_t* uvInterlaced = src_frame + (width * abs_height); | 183 const uint8_t* uvInterlaced = src_frame + (width * abs_height); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 return libyuv::FOURCC_BGRA; | 243 return libyuv::FOURCC_BGRA; |
222 case kARGB4444: | 244 case kARGB4444: |
223 return libyuv::FOURCC_R444; | 245 return libyuv::FOURCC_R444; |
224 case kARGB1555: | 246 case kARGB1555: |
225 return libyuv::FOURCC_RGBO; | 247 return libyuv::FOURCC_RGBO; |
226 } | 248 } |
227 assert(false); | 249 assert(false); |
228 return libyuv::FOURCC_ANY; | 250 return libyuv::FOURCC_ANY; |
229 } | 251 } |
230 | 252 |
253 // TODO(nisse): Delete this wrapper, let callers use libyuv directly. | |
231 int ConvertToI420(VideoType src_video_type, | 254 int ConvertToI420(VideoType src_video_type, |
232 const uint8_t* src_frame, | 255 const uint8_t* src_frame, |
233 int crop_x, | 256 int crop_x, |
234 int crop_y, | 257 int crop_y, |
235 int src_width, | 258 int src_width, |
236 int src_height, | 259 int src_height, |
237 size_t sample_size, | 260 size_t sample_size, |
238 VideoRotation rotation, | 261 VideoRotation rotation, |
239 VideoFrame* dst_frame) { | 262 VideoFrame* dst_frame) { |
240 int dst_width = dst_frame->width(); | 263 int dst_width = dst_frame->width(); |
241 int dst_height = dst_frame->height(); | 264 int dst_height = dst_frame->height(); |
242 // LibYuv expects pre-rotation values for dst. | 265 // LibYuv expects pre-rotation values for dst. |
243 // Stride values should correspond to the destination values. | 266 // Stride values should correspond to the destination values. |
244 if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { | 267 if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { |
245 dst_width = dst_frame->height(); | 268 dst_width = dst_frame->height(); |
246 dst_height = dst_frame->width(); | 269 dst_height = dst_frame->width(); |
247 } | 270 } |
248 return libyuv::ConvertToI420(src_frame, sample_size, | 271 return libyuv::ConvertToI420( |
249 dst_frame->buffer(kYPlane), | 272 src_frame, sample_size, |
250 dst_frame->stride(kYPlane), | 273 dst_frame->video_frame_buffer()->MutableDataY(), |
251 dst_frame->buffer(kUPlane), | 274 dst_frame->video_frame_buffer()->StrideY(), |
252 dst_frame->stride(kUPlane), | 275 dst_frame->video_frame_buffer()->MutableDataU(), |
253 dst_frame->buffer(kVPlane), | 276 dst_frame->video_frame_buffer()->StrideU(), |
254 dst_frame->stride(kVPlane), | 277 dst_frame->video_frame_buffer()->MutableDataV(), |
255 crop_x, crop_y, | 278 dst_frame->video_frame_buffer()->StrideV(), |
256 src_width, src_height, | 279 crop_x, crop_y, |
257 dst_width, dst_height, | 280 src_width, src_height, |
258 ConvertRotationMode(rotation), | 281 dst_width, dst_height, |
259 ConvertVideoType(src_video_type)); | 282 ConvertRotationMode(rotation), |
283 ConvertVideoType(src_video_type)); | |
260 } | 284 } |
261 | 285 |
262 int ConvertFromI420(const VideoFrame& src_frame, | 286 int ConvertFromI420(const VideoFrame& src_frame, |
263 VideoType dst_video_type, | 287 VideoType dst_video_type, |
264 int dst_sample_size, | 288 int dst_sample_size, |
265 uint8_t* dst_frame) { | 289 uint8_t* dst_frame) { |
266 return libyuv::ConvertFromI420(src_frame.buffer(kYPlane), | 290 return libyuv::ConvertFromI420( |
267 src_frame.stride(kYPlane), | 291 src_frame.video_frame_buffer()->DataY(), |
268 src_frame.buffer(kUPlane), | 292 src_frame.video_frame_buffer()->StrideY(), |
269 src_frame.stride(kUPlane), | 293 src_frame.video_frame_buffer()->DataU(), |
270 src_frame.buffer(kVPlane), | 294 src_frame.video_frame_buffer()->StrideU(), |
271 src_frame.stride(kVPlane), | 295 src_frame.video_frame_buffer()->DataV(), |
272 dst_frame, dst_sample_size, | 296 src_frame.video_frame_buffer()->StrideV(), |
273 src_frame.width(), src_frame.height(), | 297 dst_frame, dst_sample_size, |
274 ConvertVideoType(dst_video_type)); | 298 src_frame.width(), src_frame.height(), |
299 ConvertVideoType(dst_video_type)); | |
275 } | 300 } |
276 | 301 |
277 // TODO(mikhal): Create a designated VideoFrame for non I420. | 302 // TODO(mikhal): Create a designated VideoFrame for non I420. |
278 int ConvertFromYV12(const VideoFrame& src_frame, | 303 int ConvertFromYV12(const VideoFrame& src_frame, |
279 VideoType dst_video_type, | 304 VideoType dst_video_type, |
280 int dst_sample_size, | 305 int dst_sample_size, |
281 uint8_t* dst_frame) { | 306 uint8_t* dst_frame) { |
282 // YV12 = Y, V, U | 307 // YV12 = Y, V, U |
283 return libyuv::ConvertFromI420(src_frame.buffer(kYPlane), | 308 return libyuv::ConvertFromI420( |
284 src_frame.stride(kYPlane), | 309 src_frame.video_frame_buffer()->DataY(), |
285 src_frame.buffer(kVPlane), | 310 src_frame.video_frame_buffer()->StrideY(), |
286 src_frame.stride(kVPlane), | 311 src_frame.video_frame_buffer()->DataV(), |
287 src_frame.buffer(kUPlane), | 312 src_frame.video_frame_buffer()->StrideV(), |
288 src_frame.stride(kUPlane), | 313 src_frame.video_frame_buffer()->DataU(), |
289 dst_frame, dst_sample_size, | 314 src_frame.video_frame_buffer()->StrideU(), |
290 src_frame.width(), src_frame.height(), | 315 dst_frame, dst_sample_size, |
291 ConvertVideoType(dst_video_type)); | 316 src_frame.width(), src_frame.height(), |
317 ConvertVideoType(dst_video_type)); | |
292 } | 318 } |
293 | 319 |
294 // Compute PSNR for an I420 frame (all planes) | 320 // Compute PSNR for an I420 frame (all planes) |
295 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { | 321 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { |
296 if (!ref_frame || !test_frame) | 322 if (!ref_frame || !test_frame) |
297 return -1; | 323 return -1; |
298 else if ((ref_frame->width() != test_frame->width()) || | 324 else if ((ref_frame->width() != test_frame->width()) || |
299 (ref_frame->height() != test_frame->height())) | 325 (ref_frame->height() != test_frame->height())) |
300 return -1; | 326 return -1; |
301 else if (ref_frame->width() < 0 || ref_frame->height() < 0) | 327 else if (ref_frame->width() < 0 || ref_frame->height() < 0) |
302 return -1; | 328 return -1; |
303 | 329 |
304 double psnr = libyuv::I420Psnr(ref_frame->buffer(kYPlane), | 330 double psnr = libyuv::I420Psnr(ref_frame->video_frame_buffer()->DataY(), |
305 ref_frame->stride(kYPlane), | 331 ref_frame->video_frame_buffer()->StrideY(), |
306 ref_frame->buffer(kUPlane), | 332 ref_frame->video_frame_buffer()->DataU(), |
307 ref_frame->stride(kUPlane), | 333 ref_frame->video_frame_buffer()->StrideU(), |
308 ref_frame->buffer(kVPlane), | 334 ref_frame->video_frame_buffer()->DataV(), |
309 ref_frame->stride(kVPlane), | 335 ref_frame->video_frame_buffer()->StrideV(), |
310 test_frame->buffer(kYPlane), | 336 test_frame->video_frame_buffer()->DataY(), |
311 test_frame->stride(kYPlane), | 337 test_frame->video_frame_buffer()->StrideY(), |
312 test_frame->buffer(kUPlane), | 338 test_frame->video_frame_buffer()->DataU(), |
313 test_frame->stride(kUPlane), | 339 test_frame->video_frame_buffer()->StrideU(), |
314 test_frame->buffer(kVPlane), | 340 test_frame->video_frame_buffer()->DataV(), |
315 test_frame->stride(kVPlane), | 341 test_frame->video_frame_buffer()->StrideV(), |
316 test_frame->width(), test_frame->height()); | 342 test_frame->width(), test_frame->height()); |
317 // LibYuv sets the max psnr value to 128, we restrict it here. | 343 // LibYuv sets the max psnr value to 128, we restrict it here. |
318 // In case of 0 mse in one frame, 128 can skew the results significantly. | 344 // In case of 0 mse in one frame, 128 can skew the results significantly. |
319 return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr; | 345 return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr; |
320 } | 346 } |
321 | 347 |
322 // Compute SSIM for an I420 frame (all planes) | 348 // Compute SSIM for an I420 frame (all planes) |
323 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { | 349 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { |
324 if (!ref_frame || !test_frame) | 350 if (!ref_frame || !test_frame) |
325 return -1; | 351 return -1; |
326 else if ((ref_frame->width() != test_frame->width()) || | 352 else if ((ref_frame->width() != test_frame->width()) || |
327 (ref_frame->height() != test_frame->height())) | 353 (ref_frame->height() != test_frame->height())) |
328 return -1; | 354 return -1; |
329 else if (ref_frame->width() < 0 || ref_frame->height() < 0) | 355 else if (ref_frame->width() < 0 || ref_frame->height() < 0) |
330 return -1; | 356 return -1; |
331 | 357 |
332 return libyuv::I420Ssim(ref_frame->buffer(kYPlane), | 358 return libyuv::I420Ssim(ref_frame->video_frame_buffer()->DataY(), |
333 ref_frame->stride(kYPlane), | 359 ref_frame->video_frame_buffer()->StrideY(), |
334 ref_frame->buffer(kUPlane), | 360 ref_frame->video_frame_buffer()->DataU(), |
335 ref_frame->stride(kUPlane), | 361 ref_frame->video_frame_buffer()->StrideU(), |
336 ref_frame->buffer(kVPlane), | 362 ref_frame->video_frame_buffer()->DataV(), |
337 ref_frame->stride(kVPlane), | 363 ref_frame->video_frame_buffer()->StrideV(), |
338 test_frame->buffer(kYPlane), | 364 test_frame->video_frame_buffer()->DataY(), |
339 test_frame->stride(kYPlane), | 365 test_frame->video_frame_buffer()->StrideY(), |
340 test_frame->buffer(kUPlane), | 366 test_frame->video_frame_buffer()->DataU(), |
341 test_frame->stride(kUPlane), | 367 test_frame->video_frame_buffer()->StrideU(), |
342 test_frame->buffer(kVPlane), | 368 test_frame->video_frame_buffer()->DataV(), |
343 test_frame->stride(kVPlane), | 369 test_frame->video_frame_buffer()->StrideV(), |
344 test_frame->width(), test_frame->height()); | 370 test_frame->width(), test_frame->height()); |
345 } | 371 } |
346 } // namespace webrtc | 372 } // namespace webrtc |
OLD | NEW |