• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // libjingle
2 // Copyright 2010 Google Inc.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //  1. Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //  2. Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //  3. The name of the author may not be used to endorse or promote products
13 //     derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "talk/media/base/videocommon.h"
27 
28 #include <limits.h>  // For INT_MAX
29 #include <math.h>
30 #include <sstream>
31 
32 #include "webrtc/base/common.h"
33 
34 namespace cricket {
35 
36 struct FourCCAliasEntry {
37   uint32 alias;
38   uint32 canonical;
39 };
40 
41 static const FourCCAliasEntry kFourCCAliases[] = {
42   {FOURCC_IYUV, FOURCC_I420},
43   {FOURCC_YU16, FOURCC_I422},
44   {FOURCC_YU24, FOURCC_I444},
45   {FOURCC_YUYV, FOURCC_YUY2},
46   {FOURCC_YUVS, FOURCC_YUY2},
47   {FOURCC_HDYC, FOURCC_UYVY},
48   {FOURCC_2VUY, FOURCC_UYVY},
49   {FOURCC_JPEG, FOURCC_MJPG},  // Note: JPEG has DHT while MJPG does not.
50   {FOURCC_DMB1, FOURCC_MJPG},
51   {FOURCC_BA81, FOURCC_BGGR},
52   {FOURCC_RGB3, FOURCC_RAW},
53   {FOURCC_BGR3, FOURCC_24BG},
54   {FOURCC_CM32, FOURCC_BGRA},
55   {FOURCC_CM24, FOURCC_RAW},
56 };
57 
CanonicalFourCC(uint32 fourcc)58 uint32 CanonicalFourCC(uint32 fourcc) {
59   for (int i = 0; i < ARRAY_SIZE(kFourCCAliases); ++i) {
60     if (kFourCCAliases[i].alias == fourcc) {
61       return kFourCCAliases[i].canonical;
62     }
63   }
64   // Not an alias, so return it as-is.
65   return fourcc;
66 }
67 
68 static float kScaleFactors[] = {
69   1.f / 1.f,  // Full size.
70   1.f / 2.f,  // 1/2 scale.
71   1.f / 4.f,  // 1/4 scale.
72   1.f / 8.f,  // 1/8 scale.
73   1.f / 16.f  // 1/16 scale.
74 };
75 
76 static const int kNumScaleFactors = ARRAY_SIZE(kScaleFactors);
77 
78 // Finds the scale factor that, when applied to width and height, produces
79 // fewer than num_pixels.
FindLowerScale(int width,int height,int target_num_pixels)80 static float FindLowerScale(int width, int height, int target_num_pixels) {
81   if (!target_num_pixels) {
82     return 0.f;
83   }
84   int best_distance = INT_MAX;
85   int best_index = kNumScaleFactors - 1;  // Default to max scale.
86   for (int i = 0; i < kNumScaleFactors; ++i) {
87     int test_num_pixels = static_cast<int>(width * kScaleFactors[i] *
88                                            height * kScaleFactors[i]);
89     int diff = target_num_pixels - test_num_pixels;
90     if (diff >= 0 && diff < best_distance) {
91       best_distance = diff;
92       best_index = i;
93       if (best_distance == 0) {  // Found exact match.
94         break;
95       }
96     }
97   }
98   return kScaleFactors[best_index];
99 }
100 
101 // Computes a scale less to fit in max_pixels while maintaining aspect ratio.
ComputeScaleMaxPixels(int frame_width,int frame_height,int max_pixels,int * scaled_width,int * scaled_height)102 void ComputeScaleMaxPixels(int frame_width, int frame_height, int max_pixels,
103     int* scaled_width, int* scaled_height) {
104   ASSERT(scaled_width != NULL);
105   ASSERT(scaled_height != NULL);
106   ASSERT(max_pixels > 0);
107   // For VP8 the values for max width and height can be found here
108   // webrtc/src/video_engine/vie_defines.h (kViEMaxCodecWidth and
109   // kViEMaxCodecHeight)
110   const int kMaxWidth = 4096;
111   const int kMaxHeight = 3072;
112   int new_frame_width = frame_width;
113   int new_frame_height = frame_height;
114 
115   // Limit width.
116   if (new_frame_width > kMaxWidth) {
117     new_frame_height = new_frame_height * kMaxWidth / new_frame_width;
118     new_frame_width = kMaxWidth;
119   }
120   // Limit height.
121   if (new_frame_height > kMaxHeight) {
122     new_frame_width = new_frame_width * kMaxHeight / new_frame_height;
123     new_frame_height = kMaxHeight;
124   }
125   // Limit number of pixels.
126   if (new_frame_width * new_frame_height > max_pixels) {
127     // Compute new width such that width * height is less than maximum but
128     // maintains original captured frame aspect ratio.
129     new_frame_width = static_cast<int>(sqrtf(static_cast<float>(
130         max_pixels) * new_frame_width / new_frame_height));
131     new_frame_height = max_pixels / new_frame_width;
132   }
133   // Snap to a scale factor that is less than or equal to target pixels.
134   float scale = FindLowerScale(frame_width, frame_height,
135                                new_frame_width * new_frame_height);
136   *scaled_width = static_cast<int>(frame_width * scale + .5f);
137   *scaled_height = static_cast<int>(frame_height * scale + .5f);
138 }
139 
140 // Compute a size to scale frames to that is below maximum compression
141 // and rendering size with the same aspect ratio.
ComputeScale(int frame_width,int frame_height,int fps,int * scaled_width,int * scaled_height)142 void ComputeScale(int frame_width, int frame_height, int fps,
143                   int* scaled_width, int* scaled_height) {
144   // Maximum pixels limit is set to Retina MacBookPro 15" resolution of
145   // 2880 x 1800 as of 4/18/2013.
146   // For high fps, maximum pixels limit is set based on common 24" monitor
147   // resolution of 2048 x 1280 as of 6/13/2013. The Retina resolution is
148   // therefore reduced to 1440 x 900.
149   int max_pixels = (fps > 5) ? 2048 * 1280 : 2880 * 1800;
150   ComputeScaleMaxPixels(
151       frame_width, frame_height, max_pixels, scaled_width, scaled_height);
152 }
153 
154 // Compute size to crop video frame to.
155 // If cropped_format_* is 0, return the frame_* size as is.
ComputeCrop(int cropped_format_width,int cropped_format_height,int frame_width,int frame_height,int pixel_width,int pixel_height,int rotation,int * cropped_width,int * cropped_height)156 void ComputeCrop(int cropped_format_width, int cropped_format_height,
157                  int frame_width, int frame_height,
158                  int pixel_width, int pixel_height,
159                  int rotation,
160                  int* cropped_width, int* cropped_height) {
161   // Transform screen crop to camera space if rotated.
162   if (rotation == 90 || rotation == 270) {
163     std::swap(cropped_format_width, cropped_format_height);
164   }
165   ASSERT(cropped_format_width >= 0);
166   ASSERT(cropped_format_height >= 0);
167   ASSERT(frame_width > 0);
168   ASSERT(frame_height > 0);
169   ASSERT(pixel_width >= 0);
170   ASSERT(pixel_height >= 0);
171   ASSERT(rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270);
172   ASSERT(cropped_width != NULL);
173   ASSERT(cropped_height != NULL);
174   if (!pixel_width) {
175     pixel_width = 1;
176   }
177   if (!pixel_height) {
178     pixel_height = 1;
179   }
180   // if cropped_format is 0x0 disable cropping.
181   if (!cropped_format_height) {
182     cropped_format_height = 1;
183   }
184   float frame_aspect = static_cast<float>(frame_width * pixel_width) /
185       static_cast<float>(frame_height * pixel_height);
186   float crop_aspect = static_cast<float>(cropped_format_width) /
187       static_cast<float>(cropped_format_height);
188   // kAspectThresh is the maximum aspect ratio difference that we'll accept
189   // for cropping.  The value 1.34 allows cropping from 4:3 to 16:9.
190   // Set to zero to disable cropping entirely.
191   // TODO(fbarchard): crop to multiple of 16 width for better performance.
192   const float kAspectThresh = 1.34f;
193   // Wide aspect - crop horizontally
194   if (frame_aspect > crop_aspect &&
195       frame_aspect < crop_aspect * kAspectThresh) {
196     // Round width down to multiple of 4 to avoid odd chroma width.
197     // Width a multiple of 4 allows a half size image to have chroma channel
198     // that avoids rounding errors.
199     frame_width = static_cast<int>((crop_aspect * frame_height *
200         pixel_height) / pixel_width + 0.5f) & ~3;
201   } else if (frame_aspect < crop_aspect &&
202              frame_aspect > crop_aspect / kAspectThresh) {
203     frame_height = static_cast<int>((frame_width * pixel_width) /
204         (crop_aspect * pixel_height) + 0.5f) & ~1;
205   }
206   *cropped_width = frame_width;
207   *cropped_height = frame_height;
208 }
209 
210 // Compute the frame size that makes pixels square pixel aspect ratio.
ComputeScaleToSquarePixels(int in_width,int in_height,int pixel_width,int pixel_height,int * scaled_width,int * scaled_height)211 void ComputeScaleToSquarePixels(int in_width, int in_height,
212                                 int pixel_width, int pixel_height,
213                                 int* scaled_width, int* scaled_height) {
214   *scaled_width = in_width;  // Keep width the same.
215   *scaled_height = in_height * pixel_height / pixel_width;
216 }
217 
218 // The C++ standard requires a namespace-scope definition of static const
219 // integral types even when they are initialized in the declaration (see
220 // [class.static.data]/4), but MSVC with /Ze is non-conforming and treats that
221 // as a multiply defined symbol error. See Also:
222 // http://msdn.microsoft.com/en-us/library/34h23df8.aspx
223 #ifndef _MSC_EXTENSIONS
224 const int64 VideoFormat::kMinimumInterval;  // Initialized in header.
225 #endif
226 
ToString() const227 std::string VideoFormat::ToString() const {
228   std::string fourcc_name = GetFourccName(fourcc) + " ";
229   for (std::string::const_iterator i = fourcc_name.begin();
230       i < fourcc_name.end(); ++i) {
231     // Test character is printable; Avoid isprint() which asserts on negatives.
232     if (*i < 32 || *i >= 127) {
233       fourcc_name = "";
234       break;
235     }
236   }
237 
238   std::ostringstream ss;
239   ss << fourcc_name << width << "x" << height << "x"
240      << IntervalToFpsFloat(interval);
241   return ss.str();
242 }
243 
244 }  // namespace cricket
245