| 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? |
| 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) { |
| 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; |
| 122 } | 141 } |
| 123 return 0; | 142 return 0; |
| 124 } | 143 } |
| 125 | 144 |
| 126 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { | 145 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { |
| 127 assert(buffer); | 146 assert(buffer); |
| 128 if (input_frame.IsZeroSize()) | 147 if (input_frame.IsZeroSize()) |
| 129 return -1; | 148 return -1; |
| 130 size_t length = | 149 size_t length = |
| 131 CalcBufferSize(kI420, input_frame.width(), input_frame.height()); | 150 CalcBufferSize(kI420, input_frame.width(), input_frame.height()); |
| 132 if (size < length) { | 151 if (size < length) { |
| 133 return -1; | 152 return -1; |
| 134 } | 153 } |
| 135 | 154 |
| 136 int pos = 0; | 155 int width = input_frame.video_frame_buffer()->width(); |
| 137 uint8_t* buffer_ptr = buffer; | 156 int height = input_frame.video_frame_buffer()->height(); |
| 157 int chroma_width = (width + 1) / 2; |
| 158 int chroma_height = (height + 1) / 2; |
| 138 | 159 |
| 139 for (int plane = 0; plane < kNumOfPlanes; ++plane) { | 160 libyuv::I420Copy(input_frame.video_frame_buffer()->DataY(), |
| 140 int width = (plane ? (input_frame.width() + 1) / 2 : | 161 input_frame.video_frame_buffer()->StrideY(), |
| 141 input_frame.width()); | 162 input_frame.video_frame_buffer()->DataU(), |
| 142 int height = (plane ? (input_frame.height() + 1) / 2 : | 163 input_frame.video_frame_buffer()->StrideU(), |
| 143 input_frame.height()); | 164 input_frame.video_frame_buffer()->DataV(), |
| 144 const uint8_t* plane_ptr = input_frame.buffer( | 165 input_frame.video_frame_buffer()->StrideV(), |
| 145 static_cast<PlaneType>(plane)); | 166 buffer, width, |
| 146 for (int y = 0; y < height; y++) { | 167 buffer + width*height, chroma_width, |
| 147 memcpy(&buffer_ptr[pos], plane_ptr, width); | 168 buffer + width*height + chroma_width*chroma_height, |
| 148 pos += width; | 169 chroma_width, |
| 149 plane_ptr += input_frame.stride(static_cast<PlaneType>(plane)); | 170 width, height); |
| 150 } | 171 |
| 151 } | |
| 152 return static_cast<int>(length); | 172 return static_cast<int>(length); |
| 153 } | 173 } |
| 154 | 174 |
| 155 | 175 |
| 156 int ConvertNV12ToRGB565(const uint8_t* src_frame, | 176 int ConvertNV12ToRGB565(const uint8_t* src_frame, |
| 157 uint8_t* dst_frame, | 177 uint8_t* dst_frame, |
| 158 int width, int height) { | 178 int width, int height) { |
| 159 int abs_height = (height < 0) ? -height : height; | 179 int abs_height = (height < 0) ? -height : height; |
| 160 const uint8_t* yplane = src_frame; | 180 const uint8_t* yplane = src_frame; |
| 161 const uint8_t* uvInterlaced = src_frame + (width * abs_height); | 181 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; | 241 return libyuv::FOURCC_BGRA; |
| 222 case kARGB4444: | 242 case kARGB4444: |
| 223 return libyuv::FOURCC_R444; | 243 return libyuv::FOURCC_R444; |
| 224 case kARGB1555: | 244 case kARGB1555: |
| 225 return libyuv::FOURCC_RGBO; | 245 return libyuv::FOURCC_RGBO; |
| 226 } | 246 } |
| 227 assert(false); | 247 assert(false); |
| 228 return libyuv::FOURCC_ANY; | 248 return libyuv::FOURCC_ANY; |
| 229 } | 249 } |
| 230 | 250 |
| 251 // TODO(nisse): Delete this wrapper, let callers use libyuv directly. |
| 231 int ConvertToI420(VideoType src_video_type, | 252 int ConvertToI420(VideoType src_video_type, |
| 232 const uint8_t* src_frame, | 253 const uint8_t* src_frame, |
| 233 int crop_x, | 254 int crop_x, |
| 234 int crop_y, | 255 int crop_y, |
| 235 int src_width, | 256 int src_width, |
| 236 int src_height, | 257 int src_height, |
| 237 size_t sample_size, | 258 size_t sample_size, |
| 238 VideoRotation rotation, | 259 VideoRotation rotation, |
| 239 VideoFrame* dst_frame) { | 260 VideoFrame* dst_frame) { |
| 240 int dst_width = dst_frame->width(); | 261 int dst_width = dst_frame->width(); |
| 241 int dst_height = dst_frame->height(); | 262 int dst_height = dst_frame->height(); |
| 242 // LibYuv expects pre-rotation values for dst. | 263 // LibYuv expects pre-rotation values for dst. |
| 243 // Stride values should correspond to the destination values. | 264 // Stride values should correspond to the destination values. |
| 244 if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { | 265 if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { |
| 245 dst_width = dst_frame->height(); | 266 dst_width = dst_frame->height(); |
| 246 dst_height = dst_frame->width(); | 267 dst_height = dst_frame->width(); |
| 247 } | 268 } |
| 248 return libyuv::ConvertToI420(src_frame, sample_size, | 269 return libyuv::ConvertToI420( |
| 249 dst_frame->buffer(kYPlane), | 270 src_frame, sample_size, |
| 250 dst_frame->stride(kYPlane), | 271 dst_frame->video_frame_buffer()->MutableDataY(), |
| 251 dst_frame->buffer(kUPlane), | 272 dst_frame->video_frame_buffer()->StrideY(), |
| 252 dst_frame->stride(kUPlane), | 273 dst_frame->video_frame_buffer()->MutableDataU(), |
| 253 dst_frame->buffer(kVPlane), | 274 dst_frame->video_frame_buffer()->StrideU(), |
| 254 dst_frame->stride(kVPlane), | 275 dst_frame->video_frame_buffer()->MutableDataV(), |
| 255 crop_x, crop_y, | 276 dst_frame->video_frame_buffer()->StrideV(), |
| 256 src_width, src_height, | 277 crop_x, crop_y, |
| 257 dst_width, dst_height, | 278 src_width, src_height, |
| 258 ConvertRotationMode(rotation), | 279 dst_width, dst_height, |
| 259 ConvertVideoType(src_video_type)); | 280 ConvertRotationMode(rotation), |
| 281 ConvertVideoType(src_video_type)); |
| 260 } | 282 } |
| 261 | 283 |
| 262 int ConvertFromI420(const VideoFrame& src_frame, | 284 int ConvertFromI420(const VideoFrame& src_frame, |
| 263 VideoType dst_video_type, | 285 VideoType dst_video_type, |
| 264 int dst_sample_size, | 286 int dst_sample_size, |
| 265 uint8_t* dst_frame) { | 287 uint8_t* dst_frame) { |
| 266 return libyuv::ConvertFromI420(src_frame.buffer(kYPlane), | 288 return libyuv::ConvertFromI420( |
| 267 src_frame.stride(kYPlane), | 289 src_frame.video_frame_buffer()->DataY(), |
| 268 src_frame.buffer(kUPlane), | 290 src_frame.video_frame_buffer()->StrideY(), |
| 269 src_frame.stride(kUPlane), | 291 src_frame.video_frame_buffer()->DataU(), |
| 270 src_frame.buffer(kVPlane), | 292 src_frame.video_frame_buffer()->StrideU(), |
| 271 src_frame.stride(kVPlane), | 293 src_frame.video_frame_buffer()->DataV(), |
| 272 dst_frame, dst_sample_size, | 294 src_frame.video_frame_buffer()->StrideV(), |
| 273 src_frame.width(), src_frame.height(), | 295 dst_frame, dst_sample_size, |
| 274 ConvertVideoType(dst_video_type)); | 296 src_frame.width(), src_frame.height(), |
| 297 ConvertVideoType(dst_video_type)); |
| 275 } | 298 } |
| 276 | 299 |
| 277 // TODO(mikhal): Create a designated VideoFrame for non I420. | 300 // TODO(mikhal): Create a designated VideoFrame for non I420. |
| 278 int ConvertFromYV12(const VideoFrame& src_frame, | 301 int ConvertFromYV12(const VideoFrame& src_frame, |
| 279 VideoType dst_video_type, | 302 VideoType dst_video_type, |
| 280 int dst_sample_size, | 303 int dst_sample_size, |
| 281 uint8_t* dst_frame) { | 304 uint8_t* dst_frame) { |
| 282 // YV12 = Y, V, U | 305 // YV12 = Y, V, U |
| 283 return libyuv::ConvertFromI420(src_frame.buffer(kYPlane), | 306 return libyuv::ConvertFromI420( |
| 284 src_frame.stride(kYPlane), | 307 src_frame.video_frame_buffer()->DataY(), |
| 285 src_frame.buffer(kVPlane), | 308 src_frame.video_frame_buffer()->StrideY(), |
| 286 src_frame.stride(kVPlane), | 309 src_frame.video_frame_buffer()->DataV(), |
| 287 src_frame.buffer(kUPlane), | 310 src_frame.video_frame_buffer()->StrideV(), |
| 288 src_frame.stride(kUPlane), | 311 src_frame.video_frame_buffer()->DataU(), |
| 289 dst_frame, dst_sample_size, | 312 src_frame.video_frame_buffer()->StrideU(), |
| 290 src_frame.width(), src_frame.height(), | 313 dst_frame, dst_sample_size, |
| 291 ConvertVideoType(dst_video_type)); | 314 src_frame.width(), src_frame.height(), |
| 315 ConvertVideoType(dst_video_type)); |
| 292 } | 316 } |
| 293 | 317 |
| 294 // Compute PSNR for an I420 frame (all planes) | 318 // Compute PSNR for an I420 frame (all planes) |
| 295 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { | 319 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { |
| 296 if (!ref_frame || !test_frame) | 320 if (!ref_frame || !test_frame) |
| 297 return -1; | 321 return -1; |
| 298 else if ((ref_frame->width() != test_frame->width()) || | 322 else if ((ref_frame->width() != test_frame->width()) || |
| 299 (ref_frame->height() != test_frame->height())) | 323 (ref_frame->height() != test_frame->height())) |
| 300 return -1; | 324 return -1; |
| 301 else if (ref_frame->width() < 0 || ref_frame->height() < 0) | 325 else if (ref_frame->width() < 0 || ref_frame->height() < 0) |
| 302 return -1; | 326 return -1; |
| 303 | 327 |
| 304 double psnr = libyuv::I420Psnr(ref_frame->buffer(kYPlane), | 328 double psnr = libyuv::I420Psnr(ref_frame->video_frame_buffer()->DataY(), |
| 305 ref_frame->stride(kYPlane), | 329 ref_frame->video_frame_buffer()->StrideY(), |
| 306 ref_frame->buffer(kUPlane), | 330 ref_frame->video_frame_buffer()->DataU(), |
| 307 ref_frame->stride(kUPlane), | 331 ref_frame->video_frame_buffer()->StrideU(), |
| 308 ref_frame->buffer(kVPlane), | 332 ref_frame->video_frame_buffer()->DataV(), |
| 309 ref_frame->stride(kVPlane), | 333 ref_frame->video_frame_buffer()->StrideV(), |
| 310 test_frame->buffer(kYPlane), | 334 test_frame->video_frame_buffer()->DataY(), |
| 311 test_frame->stride(kYPlane), | 335 test_frame->video_frame_buffer()->StrideY(), |
| 312 test_frame->buffer(kUPlane), | 336 test_frame->video_frame_buffer()->DataU(), |
| 313 test_frame->stride(kUPlane), | 337 test_frame->video_frame_buffer()->StrideU(), |
| 314 test_frame->buffer(kVPlane), | 338 test_frame->video_frame_buffer()->DataV(), |
| 315 test_frame->stride(kVPlane), | 339 test_frame->video_frame_buffer()->StrideV(), |
| 316 test_frame->width(), test_frame->height()); | 340 test_frame->width(), test_frame->height()); |
| 317 // LibYuv sets the max psnr value to 128, we restrict it here. | 341 // 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. | 342 // In case of 0 mse in one frame, 128 can skew the results significantly. |
| 319 return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr; | 343 return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr; |
| 320 } | 344 } |
| 321 | 345 |
| 322 // Compute SSIM for an I420 frame (all planes) | 346 // Compute SSIM for an I420 frame (all planes) |
| 323 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { | 347 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { |
| 324 if (!ref_frame || !test_frame) | 348 if (!ref_frame || !test_frame) |
| 325 return -1; | 349 return -1; |
| 326 else if ((ref_frame->width() != test_frame->width()) || | 350 else if ((ref_frame->width() != test_frame->width()) || |
| 327 (ref_frame->height() != test_frame->height())) | 351 (ref_frame->height() != test_frame->height())) |
| 328 return -1; | 352 return -1; |
| 329 else if (ref_frame->width() < 0 || ref_frame->height() < 0) | 353 else if (ref_frame->width() < 0 || ref_frame->height() < 0) |
| 330 return -1; | 354 return -1; |
| 331 | 355 |
| 332 return libyuv::I420Ssim(ref_frame->buffer(kYPlane), | 356 return libyuv::I420Ssim(ref_frame->video_frame_buffer()->DataY(), |
| 333 ref_frame->stride(kYPlane), | 357 ref_frame->video_frame_buffer()->StrideY(), |
| 334 ref_frame->buffer(kUPlane), | 358 ref_frame->video_frame_buffer()->DataU(), |
| 335 ref_frame->stride(kUPlane), | 359 ref_frame->video_frame_buffer()->StrideU(), |
| 336 ref_frame->buffer(kVPlane), | 360 ref_frame->video_frame_buffer()->DataV(), |
| 337 ref_frame->stride(kVPlane), | 361 ref_frame->video_frame_buffer()->StrideV(), |
| 338 test_frame->buffer(kYPlane), | 362 test_frame->video_frame_buffer()->DataY(), |
| 339 test_frame->stride(kYPlane), | 363 test_frame->video_frame_buffer()->StrideY(), |
| 340 test_frame->buffer(kUPlane), | 364 test_frame->video_frame_buffer()->DataU(), |
| 341 test_frame->stride(kUPlane), | 365 test_frame->video_frame_buffer()->StrideU(), |
| 342 test_frame->buffer(kVPlane), | 366 test_frame->video_frame_buffer()->DataV(), |
| 343 test_frame->stride(kVPlane), | 367 test_frame->video_frame_buffer()->StrideV(), |
| 344 test_frame->width(), test_frame->height()); | 368 test_frame->width(), test_frame->height()); |
| 345 } | 369 } |
| 346 } // namespace webrtc | 370 } // namespace webrtc |
| OLD | NEW |