22
33#include " media/PixelFormatUtils.h"
44
5+ #include < algorithm>
56#include < cstdint>
7+ #include < limits>
8+
9+ #include " util/VideoInfo.h"
610
711namespace cosmo {
812namespace media {
913
14+ namespace {
15+
16+ int GetWidthAlignment (PixelFormat format) {
17+ switch (format) {
18+ case PixelFormat::PIXEL_YUYV :
19+ case PixelFormat::PIXEL_YVYU :
20+ case PixelFormat::PIXEL_UYVY :
21+ case PixelFormat::PIXEL_I420 :
22+ case PixelFormat::PIXEL_NV12 :
23+ case PixelFormat::PIXEL_NV21 :
24+ return 2 ;
25+ default :
26+ return 1 ;
27+ }
28+ }
29+
30+ int GetHeightAlignment (PixelFormat format) {
31+ switch (format) {
32+ case PixelFormat::PIXEL_I420 :
33+ case PixelFormat::PIXEL_NV12 :
34+ case PixelFormat::PIXEL_NV21 :
35+ return 2 ;
36+ default :
37+ return 1 ;
38+ }
39+ }
40+
41+ bool ExpandAndAlignSpan (int64_t * start, int64_t * end, int64_t limit, int min_dimension,
42+ int max_dimension, int alignment) {
43+ const auto current_length = *end - *start;
44+ if (current_length <= 0 ) {
45+ return false ;
46+ }
47+
48+ int64_t target_length = std::max<int64_t >(current_length, min_dimension);
49+ const auto remainder = target_length % alignment;
50+ if (remainder != 0 ) {
51+ target_length += alignment - remainder;
52+ }
53+ if (target_length > max_dimension || target_length > limit) {
54+ return false ;
55+ }
56+
57+ auto remaining_growth = target_length - current_length;
58+ const auto desired_left_growth = remaining_growth / 2 ;
59+ const auto grow_left = std::min (desired_left_growth, *start);
60+ *start -= grow_left;
61+ remaining_growth -= grow_left;
62+
63+ const auto grow_right = std::min (remaining_growth, limit - *end);
64+ *end += grow_right;
65+ remaining_growth -= grow_right;
66+
67+ const auto extra_left_growth = std::min (remaining_growth, *start);
68+ *start -= extra_left_growth;
69+ remaining_growth -= extra_left_growth;
70+ return remaining_growth == 0 ;
71+ }
72+
73+ } // namespace
74+
1075 PixelBaseType PixelFormatUtils::PixelFormatBaseType (PixelFormat format) {
1176 switch (format) {
1277 case PixelFormat::PIXEL_BGR32F :
@@ -83,6 +148,95 @@ namespace media {
83148 return 0 ;
84149 }
85150
151+ std::optional<size_t > PixelFormatUtils::CalculateFrameSize (int width, int height, PixelFormat format) {
152+ if (width <= 0 || height <= 0 ) {
153+ return std::nullopt ;
154+ }
155+
156+ switch (format) {
157+ case PixelFormat::PIXEL_I420 :
158+ case PixelFormat::PIXEL_NV12 :
159+ case PixelFormat::PIXEL_NV21 :
160+ if ((width % 2 ) != 0 || (height % 2 ) != 0 ) {
161+ return std::nullopt ;
162+ }
163+ break ;
164+ case PixelFormat::PIXEL_YUYV :
165+ case PixelFormat::PIXEL_YVYU :
166+ case PixelFormat::PIXEL_UYVY :
167+ if ((width % 2 ) != 0 ) {
168+ return std::nullopt ;
169+ }
170+ break ;
171+ default :
172+ break ;
173+ }
174+
175+ const auto depth = PixelFormatDepth (format);
176+ if (depth == 0 ) {
177+ return std::nullopt ;
178+ }
179+
180+ const auto width_size = static_cast <size_t >(width);
181+ const auto height_size = static_cast <size_t >(height);
182+ if (width_size > std::numeric_limits<size_t >::max () / height_size) {
183+ return std::nullopt ;
184+ }
185+ const auto pixel_count = width_size * height_size;
186+
187+ if (pixel_count > std::numeric_limits<size_t >::max () / depth) {
188+ return std::nullopt ;
189+ }
190+ const auto bit_count = pixel_count * depth;
191+ constexpr size_t kBitsPerByte = 8 ;
192+ if ((bit_count % kBitsPerByte ) != 0 ) {
193+ return std::nullopt ;
194+ }
195+
196+ const auto frame_size = bit_count / kBitsPerByte ;
197+ if (frame_size == 0 || frame_size > static_cast <size_t >(kVideoFrameMaxSize )) {
198+ return std::nullopt ;
199+ }
200+ return frame_size;
201+ }
202+
203+ std::optional<util::Box> PixelFormatUtils::NormalizeCropRoi (int source_width, int source_height,
204+ PixelFormat format,
205+ const util::Box& requested_roi,
206+ int min_dimension, int max_dimension) {
207+ if (!CalculateFrameSize (source_width, source_height, format) || min_dimension <= 0 ||
208+ max_dimension < min_dimension || requested_roi.width <= 0 || requested_roi.height <= 0 ||
209+ requested_roi.width > max_dimension || requested_roi.height > max_dimension) {
210+ return std::nullopt ;
211+ }
212+
213+ const auto source_width_i64 = static_cast <int64_t >(source_width);
214+ const auto source_height_i64 = static_cast <int64_t >(source_height);
215+ int64_t left = std::max<int64_t >(0 , requested_roi.x );
216+ int64_t top = std::max<int64_t >(0 , requested_roi.y );
217+ int64_t right = std::min<int64_t >(source_width_i64, static_cast <int64_t >(requested_roi.x ) +
218+ static_cast <int64_t >(requested_roi.width ));
219+ int64_t bottom = std::min<int64_t >(source_height_i64, static_cast <int64_t >(requested_roi.y ) +
220+ static_cast <int64_t >(requested_roi.height ));
221+ if (left >= right || top >= bottom) {
222+ return std::nullopt ;
223+ }
224+
225+ if (!ExpandAndAlignSpan (&left, &right, source_width_i64, min_dimension, max_dimension,
226+ GetWidthAlignment (format)) ||
227+ !ExpandAndAlignSpan (&top, &bottom, source_height_i64, min_dimension, max_dimension,
228+ GetHeightAlignment (format))) {
229+ return std::nullopt ;
230+ }
231+
232+ util::Box normalized_roi{static_cast <int >(left), static_cast <int >(top),
233+ static_cast <int >(right - left), static_cast <int >(bottom - top)};
234+ if (!CalculateFrameSize (normalized_roi.width , normalized_roi.height , format)) {
235+ return std::nullopt ;
236+ }
237+ return normalized_roi;
238+ }
239+
86240 bool PixelFormatUtils::PixelFormatIsRGB (PixelFormat f) {
87241 if (f >= PixelFormat::PIXEL_RGB8 && f <= PixelFormat::PIXEL_RGBA32F )
88242 return true ;
@@ -105,4 +259,4 @@ namespace media {
105259 }
106260
107261} // namespace media
108- } // namespace cosmo
262+ } // namespace cosmo
0 commit comments