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 
18 namespace webrtc {
19 
Scaler()20 Scaler::Scaler()
21     : method_(kScaleBox),
22       src_width_(0),
23       src_height_(0),
24       dst_width_(0),
25       dst_height_(0),
26       set_(false) {}
27 
~Scaler()28 Scaler::~Scaler() {}
29 
Set(int src_width,int src_height,int dst_width,int dst_height,VideoType src_video_type,VideoType dst_video_type,ScaleMethod method)30 int 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 
Scale(const VideoFrame & src_frame,VideoFrame * dst_frame)50 int 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 
SupportedVideoType(VideoType src_video_type,VideoType dst_video_type)99 bool 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