1/* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 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 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/common_video/libyuv/include/scaler.h" 12 13#include <algorithm> 14 15// NOTE(ajm): Path provided by gyp. 16#include "libyuv.h" // NOLINT 17 18namespace webrtc { 19 20Scaler::Scaler() 21 : method_(kScaleBox), 22 src_width_(0), 23 src_height_(0), 24 dst_width_(0), 25 dst_height_(0), 26 set_(false) {} 27 28Scaler::~Scaler() {} 29 30int Scaler::Set(int src_width, int src_height, 31 int dst_width, int dst_height, 32 VideoType src_video_type, VideoType dst_video_type, 33 ScaleMethod method) { 34 set_ = false; 35 if (src_width < 1 || src_height < 1 || dst_width < 1 || dst_height < 1) 36 return -1; 37 38 if (!SupportedVideoType(src_video_type, dst_video_type)) 39 return -1; 40 41 src_width_ = src_width; 42 src_height_ = src_height; 43 dst_width_ = dst_width; 44 dst_height_ = dst_height; 45 method_ = method; 46 set_ = true; 47 return 0; 48} 49 50int Scaler::Scale(const VideoFrame& src_frame, VideoFrame* dst_frame) { 51 assert(dst_frame); 52 if (src_frame.IsZeroSize()) 53 return -1; 54 if (!set_) 55 return -2; 56 57 // Making sure that destination frame is of sufficient size. 58 dst_frame->set_video_frame_buffer( 59 buffer_pool_.CreateBuffer(dst_width_, dst_height_)); 60 61 // We want to preserve aspect ratio instead of stretching the frame. 62 // Therefore, we need to crop the source frame. Calculate the largest center 63 // aligned region of the source frame that can be used. 64 const int cropped_src_width = 65 std::min(src_width_, dst_width_ * src_height_ / dst_height_); 66 const int cropped_src_height = 67 std::min(src_height_, dst_height_ * src_width_ / dst_width_); 68 // Make sure the offsets are even to avoid rounding errors for the U/V planes. 69 const int src_offset_x = ((src_width_ - cropped_src_width) / 2) & ~1; 70 const int src_offset_y = ((src_height_ - cropped_src_height) / 2) & ~1; 71 72 const uint8_t* y_ptr = src_frame.buffer(kYPlane) + 73 src_offset_y * src_frame.stride(kYPlane) + 74 src_offset_x; 75 const uint8_t* u_ptr = src_frame.buffer(kUPlane) + 76 src_offset_y / 2 * src_frame.stride(kUPlane) + 77 src_offset_x / 2; 78 const uint8_t* v_ptr = src_frame.buffer(kVPlane) + 79 src_offset_y / 2 * src_frame.stride(kVPlane) + 80 src_offset_x / 2; 81 82 return libyuv::I420Scale(y_ptr, 83 src_frame.stride(kYPlane), 84 u_ptr, 85 src_frame.stride(kUPlane), 86 v_ptr, 87 src_frame.stride(kVPlane), 88 cropped_src_width, cropped_src_height, 89 dst_frame->buffer(kYPlane), 90 dst_frame->stride(kYPlane), 91 dst_frame->buffer(kUPlane), 92 dst_frame->stride(kUPlane), 93 dst_frame->buffer(kVPlane), 94 dst_frame->stride(kVPlane), 95 dst_width_, dst_height_, 96 libyuv::FilterMode(method_)); 97} 98 99bool Scaler::SupportedVideoType(VideoType src_video_type, 100 VideoType dst_video_type) { 101 if (src_video_type != dst_video_type) 102 return false; 103 104 if ((src_video_type == kI420) || (src_video_type == kIYUV) || 105 (src_video_type == kYV12)) 106 return true; 107 108 return false; 109} 110 111} // namespace webrtc 112