OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/video_frame.h" | 5 #include "media/base/video_frame.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/string_piece.h" | 8 #include "base/string_piece.h" |
9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
10 #include "media/base/video_util.h" | 10 #include "media/base/video_util.h" |
11 #if !defined(OS_ANDROID) | 11 #if !defined(OS_ANDROID) |
12 #include "media/ffmpeg/ffmpeg_common.h" | 12 #include "media/ffmpeg/ffmpeg_common.h" |
13 #endif | 13 #endif |
14 | 14 |
15 #include <algorithm> | 15 #include <algorithm> |
16 | 16 |
17 namespace media { | 17 namespace media { |
18 | 18 |
19 // static | 19 // static |
20 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 20 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
21 VideoFrame::Format format, | 21 VideoFrame::Format format, |
22 size_t width, | 22 const gfx::Size& size, |
23 size_t height, | 23 const gfx::Size& natural_size, |
24 base::TimeDelta timestamp) { | 24 base::TimeDelta timestamp) { |
25 DCHECK(IsValidConfig(format, width, height)); | 25 DCHECK(IsValidConfig(format, size)); |
26 scoped_refptr<VideoFrame> frame(new VideoFrame( | 26 scoped_refptr<VideoFrame> frame(new VideoFrame( |
27 format, width, height, timestamp)); | 27 format, size, natural_size, timestamp)); |
28 switch (format) { | 28 switch (format) { |
29 case VideoFrame::RGB32: | 29 case VideoFrame::RGB32: |
30 frame->AllocateRGB(4u); | 30 frame->AllocateRGB(4u); |
31 break; | 31 break; |
32 case VideoFrame::YV12: | 32 case VideoFrame::YV12: |
33 case VideoFrame::YV16: | 33 case VideoFrame::YV16: |
34 frame->AllocateYUV(); | 34 frame->AllocateYUV(); |
35 break; | 35 break; |
36 default: | 36 default: |
37 LOG(FATAL) << "Unsupported frame format: " << format; | 37 LOG(FATAL) << "Unsupported frame format: " << format; |
38 } | 38 } |
39 return frame; | 39 return frame; |
40 } | 40 } |
41 | 41 |
42 // static | 42 // static |
43 bool VideoFrame::IsValidConfig( | 43 bool VideoFrame::IsValidConfig(VideoFrame::Format format, |
44 VideoFrame::Format format, | 44 const gfx::Size& size) { |
Ami GONE FROM CHROMIUM
2012/08/02 17:34:45
shouldn't this now also inspect natural_size?
acolwell GONE FROM CHROMIUM
2012/08/02 20:20:21
Done.
| |
45 size_t width, | |
46 size_t height) { | |
47 | |
48 return (format != VideoFrame::INVALID && | 45 return (format != VideoFrame::INVALID && |
49 width > 0 && height > 0 && | 46 size.width() > 0 && size.height() > 0 && |
50 width <= limits::kMaxDimension && height <= limits::kMaxDimension && | 47 size.width() <= limits::kMaxDimension && |
51 width * height <= limits::kMaxCanvas); | 48 size.height() <= limits::kMaxDimension && |
49 size.width() * size.height() <= limits::kMaxCanvas); | |
52 } | 50 } |
53 | 51 |
54 // static | 52 // static |
55 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( | 53 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( |
56 uint32 texture_id, | 54 uint32 texture_id, |
57 uint32 texture_target, | 55 uint32 texture_target, |
58 size_t width, | 56 const gfx::Size& size, |
59 size_t height, | 57 const gfx::Size& natural_size, |
60 base::TimeDelta timestamp, | 58 base::TimeDelta timestamp, |
61 const base::Closure& no_longer_needed) { | 59 const base::Closure& no_longer_needed) { |
62 scoped_refptr<VideoFrame> frame( | 60 scoped_refptr<VideoFrame> frame( |
63 new VideoFrame(NATIVE_TEXTURE, width, height, timestamp)); | 61 new VideoFrame(NATIVE_TEXTURE, size, natural_size, timestamp)); |
64 frame->texture_id_ = texture_id; | 62 frame->texture_id_ = texture_id; |
65 frame->texture_target_ = texture_target; | 63 frame->texture_target_ = texture_target; |
66 frame->texture_no_longer_needed_ = no_longer_needed; | 64 frame->texture_no_longer_needed_ = no_longer_needed; |
67 return frame; | 65 return frame; |
68 } | 66 } |
69 | 67 |
70 // static | 68 // static |
71 scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() { | 69 scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() { |
72 return new VideoFrame( | 70 return new VideoFrame( |
73 VideoFrame::EMPTY, 0, 0, base::TimeDelta()); | 71 VideoFrame::EMPTY, gfx::Size(), gfx::Size(), base::TimeDelta()); |
74 } | 72 } |
75 | 73 |
76 // static | 74 // static |
77 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) { | 75 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) { |
78 DCHECK_GT(width, 0); | 76 DCHECK(IsValidConfig(VideoFrame::YV12, size)); |
79 DCHECK_GT(height, 0); | |
80 | 77 |
81 // Create our frame. | 78 // Create our frame. |
82 const base::TimeDelta kZero; | 79 const base::TimeDelta kZero; |
83 scoped_refptr<VideoFrame> frame = | 80 scoped_refptr<VideoFrame> frame = |
84 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero); | 81 VideoFrame::CreateFrame(VideoFrame::YV12, size, size, kZero); |
85 | 82 |
86 // Now set the data to YUV(0,128,128). | 83 // Now set the data to YUV(0,128,128). |
87 const uint8 kBlackY = 0x00; | 84 const uint8 kBlackY = 0x00; |
88 const uint8 kBlackUV = 0x80; | 85 const uint8 kBlackUV = 0x80; |
89 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); | 86 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); |
90 return frame; | 87 return frame; |
91 } | 88 } |
92 | 89 |
93 static inline size_t RoundUp(size_t value, size_t alignment) { | 90 static inline size_t RoundUp(size_t value, size_t alignment) { |
94 // Check that |alignment| is a power of 2. | 91 // Check that |alignment| is a power of 2. |
95 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | 92 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
96 return ((value + (alignment - 1)) & ~(alignment-1)); | 93 return ((value + (alignment - 1)) & ~(alignment-1)); |
97 } | 94 } |
98 | 95 |
99 static const int kFrameSizeAlignment = 16; | 96 static const int kFrameSizeAlignment = 16; |
100 // Allows faster SIMD YUV convert. Also, FFmpeg overreads/-writes occasionally. | 97 // Allows faster SIMD YUV convert. Also, FFmpeg overreads/-writes occasionally. |
101 static const int kFramePadBytes = 15; | 98 static const int kFramePadBytes = 15; |
102 | 99 |
103 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { | 100 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { |
104 // Round up to align at least at a 16-byte boundary for each row. | 101 // Round up to align at least at a 16-byte boundary for each row. |
105 // This is sufficient for MMX and SSE2 reads (movq/movdqa). | 102 // This is sufficient for MMX and SSE2 reads (movq/movdqa). |
106 size_t bytes_per_row = RoundUp(width_, kFrameSizeAlignment) * bytes_per_pixel; | 103 size_t bytes_per_row = RoundUp(size_.width(), |
107 size_t aligned_height = RoundUp(height_, kFrameSizeAlignment); | 104 kFrameSizeAlignment) * bytes_per_pixel; |
105 size_t aligned_height = RoundUp(size_.height(), kFrameSizeAlignment); | |
108 strides_[VideoFrame::kRGBPlane] = bytes_per_row; | 106 strides_[VideoFrame::kRGBPlane] = bytes_per_row; |
109 #if !defined(OS_ANDROID) | 107 #if !defined(OS_ANDROID) |
110 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery | 108 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery |
111 // doesn't need to be repeated in every single user of aligned data. | 109 // doesn't need to be repeated in every single user of aligned data. |
112 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>( | 110 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>( |
113 av_malloc(bytes_per_row * aligned_height + kFramePadBytes)); | 111 av_malloc(bytes_per_row * aligned_height + kFramePadBytes)); |
114 #else | 112 #else |
115 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height]; | 113 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height]; |
116 #endif | 114 #endif |
117 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); | 115 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); |
(...skipping 11 matching lines...) Expand all Loading... | |
129 // number to avoid any potential of faulting by code that attempts to access | 127 // number to avoid any potential of faulting by code that attempts to access |
130 // the Y values of the final row, but assumes that the last row of U & V | 128 // the Y values of the final row, but assumes that the last row of U & V |
131 // applies to a full two rows of Y. | 129 // applies to a full two rows of Y. |
132 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), | 130 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), |
133 kFrameSizeAlignment); | 131 kFrameSizeAlignment); |
134 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), | 132 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), |
135 kFrameSizeAlignment); | 133 kFrameSizeAlignment); |
136 // The *2 here is because some formats (e.g. h264) allow interlaced coding, | 134 // The *2 here is because some formats (e.g. h264) allow interlaced coding, |
137 // and then the size needs to be a multiple of two macroblocks (vertically). | 135 // and then the size needs to be a multiple of two macroblocks (vertically). |
138 // See libavcodec/utils.c:avcodec_align_dimensions2(). | 136 // See libavcodec/utils.c:avcodec_align_dimensions2(). |
139 size_t y_height = RoundUp(height_, kFrameSizeAlignment * 2); | 137 size_t y_height = RoundUp(size_.height(), kFrameSizeAlignment * 2); |
140 size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; | 138 size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; |
141 size_t y_bytes = y_height * y_stride; | 139 size_t y_bytes = y_height * y_stride; |
142 size_t uv_bytes = uv_height * uv_stride; | 140 size_t uv_bytes = uv_height * uv_stride; |
143 | 141 |
144 #if !defined(OS_ANDROID) | 142 #if !defined(OS_ANDROID) |
145 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery | 143 // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery |
146 // doesn't need to be repeated in every single user of aligned data. | 144 // doesn't need to be repeated in every single user of aligned data. |
147 // The extra line of UV being allocated is because h264 chroma MC | 145 // The extra line of UV being allocated is because h264 chroma MC |
148 // overreads by one line in some cases, see libavcodec/utils.c: | 146 // overreads by one line in some cases, see libavcodec/utils.c: |
149 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: | 147 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: |
150 // put_h264_chroma_mc4_ssse3(). | 148 // put_h264_chroma_mc4_ssse3(). |
151 uint8* data = reinterpret_cast<uint8*>( | 149 uint8* data = reinterpret_cast<uint8*>( |
152 av_malloc(y_bytes + (uv_bytes * 2 + uv_stride) + kFramePadBytes)); | 150 av_malloc(y_bytes + (uv_bytes * 2 + uv_stride) + kFramePadBytes)); |
153 #else | 151 #else |
154 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2)]; | 152 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2)]; |
155 #endif | 153 #endif |
156 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); | 154 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); |
157 data_[VideoFrame::kYPlane] = data; | 155 data_[VideoFrame::kYPlane] = data; |
158 data_[VideoFrame::kUPlane] = data + y_bytes; | 156 data_[VideoFrame::kUPlane] = data + y_bytes; |
159 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; | 157 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; |
160 strides_[VideoFrame::kYPlane] = y_stride; | 158 strides_[VideoFrame::kYPlane] = y_stride; |
161 strides_[VideoFrame::kUPlane] = uv_stride; | 159 strides_[VideoFrame::kUPlane] = uv_stride; |
162 strides_[VideoFrame::kVPlane] = uv_stride; | 160 strides_[VideoFrame::kVPlane] = uv_stride; |
163 } | 161 } |
164 | 162 |
165 VideoFrame::VideoFrame(VideoFrame::Format format, | 163 VideoFrame::VideoFrame(VideoFrame::Format format, |
166 size_t width, | 164 const gfx::Size& size, |
167 size_t height, | 165 const gfx::Size& natural_size, |
168 base::TimeDelta timestamp) | 166 base::TimeDelta timestamp) |
169 : format_(format), | 167 : format_(format), |
170 width_(width), | 168 size_(size), |
171 height_(height), | 169 natural_size_(natural_size), |
172 texture_id_(0), | 170 texture_id_(0), |
173 texture_target_(0), | 171 texture_target_(0), |
174 timestamp_(timestamp) { | 172 timestamp_(timestamp) { |
175 memset(&strides_, 0, sizeof(strides_)); | 173 memset(&strides_, 0, sizeof(strides_)); |
176 memset(&data_, 0, sizeof(data_)); | 174 memset(&data_, 0, sizeof(data_)); |
177 } | 175 } |
178 | 176 |
179 VideoFrame::~VideoFrame() { | 177 VideoFrame::~VideoFrame() { |
180 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { | 178 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { |
181 texture_no_longer_needed_.Run(); | 179 texture_no_longer_needed_.Run(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 return false; | 214 return false; |
217 } | 215 } |
218 | 216 |
219 int VideoFrame::stride(size_t plane) const { | 217 int VideoFrame::stride(size_t plane) const { |
220 DCHECK(IsValidPlane(plane)); | 218 DCHECK(IsValidPlane(plane)); |
221 return strides_[plane]; | 219 return strides_[plane]; |
222 } | 220 } |
223 | 221 |
224 int VideoFrame::row_bytes(size_t plane) const { | 222 int VideoFrame::row_bytes(size_t plane) const { |
225 DCHECK(IsValidPlane(plane)); | 223 DCHECK(IsValidPlane(plane)); |
224 int width = size_.width(); | |
226 switch (format_) { | 225 switch (format_) { |
227 // 32bpp. | 226 // 32bpp. |
228 case RGB32: | 227 case RGB32: |
229 return width_ * 4; | 228 return width * 4; |
230 | 229 |
231 // Planar, 8bpp. | 230 // Planar, 8bpp. |
232 case YV12: | 231 case YV12: |
233 case YV16: | 232 case YV16: |
234 if (plane == kYPlane) | 233 if (plane == kYPlane) |
235 return width_; | 234 return width; |
236 return RoundUp(width_, 2) / 2; | 235 return RoundUp(width, 2) / 2; |
237 | 236 |
238 default: | 237 default: |
239 break; | 238 break; |
240 } | 239 } |
241 | 240 |
242 // Intentionally leave out non-production formats. | 241 // Intentionally leave out non-production formats. |
243 NOTREACHED() << "Unsupported video frame format: " << format_; | 242 NOTREACHED() << "Unsupported video frame format: " << format_; |
244 return 0; | 243 return 0; |
245 } | 244 } |
246 | 245 |
247 int VideoFrame::rows(size_t plane) const { | 246 int VideoFrame::rows(size_t plane) const { |
248 DCHECK(IsValidPlane(plane)); | 247 DCHECK(IsValidPlane(plane)); |
248 int height = size_.height(); | |
249 switch (format_) { | 249 switch (format_) { |
250 case RGB32: | 250 case RGB32: |
251 case YV16: | 251 case YV16: |
252 return height_; | 252 return height; |
253 | 253 |
254 case YV12: | 254 case YV12: |
255 if (plane == kYPlane) | 255 if (plane == kYPlane) |
256 return height_; | 256 return height; |
257 return RoundUp(height_, 2) / 2; | 257 return RoundUp(height, 2) / 2; |
258 | 258 |
259 default: | 259 default: |
260 break; | 260 break; |
261 } | 261 } |
262 | 262 |
263 // Intentionally leave out non-production formats. | 263 // Intentionally leave out non-production formats. |
264 NOTREACHED() << "Unsupported video frame format: " << format_; | 264 NOTREACHED() << "Unsupported video frame format: " << format_; |
265 return 0; | 265 return 0; |
266 } | 266 } |
267 | 267 |
(...skipping 22 matching lines...) Expand all Loading... | |
290 break; | 290 break; |
291 for(int row = 0; row < rows(plane); row++) { | 291 for(int row = 0; row < rows(plane); row++) { |
292 base::MD5Update(context, base::StringPiece( | 292 base::MD5Update(context, base::StringPiece( |
293 reinterpret_cast<char*>(data(plane) + stride(plane) * row), | 293 reinterpret_cast<char*>(data(plane) + stride(plane) * row), |
294 row_bytes(plane))); | 294 row_bytes(plane))); |
295 } | 295 } |
296 } | 296 } |
297 } | 297 } |
298 | 298 |
299 } // namespace media | 299 } // namespace media |
OLD | NEW |