Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(909)

Side by Side Diff: media/base/video_frame.cc

Issue 10451051: Provide a Chrome-owned buffer to FFmpeg for video decoding, instead of (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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)
12 #include "media/ffmpeg/ffmpeg_common.h"
13 #endif
11 14
12 namespace media { 15 namespace media {
13 16
17 static inline size_t RoundUp(size_t value, size_t alignment) {
18 // Check that |alignment| is a power of 2.
19 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
20 return ((value + (alignment - 1)) & ~(alignment-1));
21 }
22
14 // static 23 // static
15 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( 24 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
16 VideoFrame::Format format, 25 VideoFrame::Format format,
17 size_t width, 26 size_t width,
18 size_t height, 27 size_t height,
28 size_t bytes_per_row,
29 size_t bytes_per_uv_row,
30 size_t aligned_height,
19 base::TimeDelta timestamp, 31 base::TimeDelta timestamp,
20 base::TimeDelta duration) { 32 base::TimeDelta duration) {
21 DCHECK(IsValidConfig(format, width, height)); 33 DCHECK(IsValidConfig(format, width, height, bytes_per_row, bytes_per_uv_row,
34 aligned_height));
22 scoped_refptr<VideoFrame> frame(new VideoFrame( 35 scoped_refptr<VideoFrame> frame(new VideoFrame(
23 format, width, height, timestamp, duration)); 36 format, width, height, timestamp, duration));
24 switch (format) { 37 switch (format) {
25 case VideoFrame::RGB32: 38 case VideoFrame::RGB32:
26 frame->AllocateRGB(4u); 39 frame->AllocateRGB(bytes_per_row ? bytes_per_row :
40 RoundUp(frame->row_bytes(VideoFrame::kRGBPlane),
41 8),
42 aligned_height ? aligned_height : height);
27 break; 43 break;
28 case VideoFrame::YV12: 44 case VideoFrame::YV12:
29 case VideoFrame::YV16: 45 case VideoFrame::YV16:
30 frame->AllocateYUV(); 46 frame->AllocateYUV(bytes_per_row ? bytes_per_row :
47 RoundUp(frame->row_bytes(VideoFrame::kYPlane), 4),
48 bytes_per_uv_row ? bytes_per_uv_row :
49 RoundUp(frame->row_bytes(VideoFrame::kUPlane), 4),
50 aligned_height ? aligned_height : height);
31 break; 51 break;
32 default: 52 default:
33 LOG(FATAL) << "Unsupported frame format: " << format; 53 LOG(FATAL) << "Unsupported frame format: " << format;
34 } 54 }
35 return frame; 55 return frame;
36 } 56 }
37 57
38 // static 58 // static
39 bool VideoFrame::IsValidConfig( 59 bool VideoFrame::IsValidConfig(
40 VideoFrame::Format format, 60 VideoFrame::Format format,
41 size_t width, 61 size_t width,
42 size_t height) { 62 size_t height,
63 size_t bytes_per_row,
64 size_t bytes_per_uv_row,
65 size_t aligned_height) {
43 66
44 return (format != VideoFrame::INVALID && 67 if (!(format != VideoFrame::INVALID &&
45 width > 0 && height > 0 && 68 width > 0 && height > 0 &&
46 width <= limits::kMaxDimension && height <= limits::kMaxDimension && 69 width <= limits::kMaxDimension && height <= limits::kMaxDimension &&
47 width * height <= limits::kMaxCanvas); 70 width * height <= limits::kMaxCanvas))
71 return false;
72
73 switch (format) {
74 case VideoFrame::RGB32:
75 if ((bytes_per_row != 0 && bytes_per_row < width) ||
76 (aligned_height != 0 && aligned_height < height))
77 return false;
78 break;
79 case VideoFrame::YV12:
80 case VideoFrame::YV16:
81 if ((bytes_per_row != 0 && bytes_per_row < width) ||
82 (bytes_per_uv_row != 0 && bytes_per_uv_row < RoundUp(width, 2) / 2) ||
83 (aligned_height != 0 && aligned_height < height))
84 return false;
85 break;
86 default:
87 break;
88 }
89
90 return true;
48 } 91 }
49 92
50 // static 93 // static
51 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( 94 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
52 uint32 texture_id, 95 uint32 texture_id,
53 uint32 texture_target, 96 uint32 texture_target,
54 size_t width, 97 size_t width,
55 size_t height, 98 size_t height,
56 base::TimeDelta timestamp, 99 base::TimeDelta timestamp,
57 base::TimeDelta duration, 100 base::TimeDelta duration,
(...skipping 13 matching lines...) Expand all
71 } 114 }
72 115
73 // static 116 // static
74 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) { 117 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(int width, int height) {
75 DCHECK_GT(width, 0); 118 DCHECK_GT(width, 0);
76 DCHECK_GT(height, 0); 119 DCHECK_GT(height, 0);
77 120
78 // Create our frame. 121 // Create our frame.
79 const base::TimeDelta kZero; 122 const base::TimeDelta kZero;
80 scoped_refptr<VideoFrame> frame = 123 scoped_refptr<VideoFrame> frame =
81 VideoFrame::CreateFrame(VideoFrame::YV12, width, height, kZero, kZero); 124 VideoFrame::CreateFrame(VideoFrame::YV12, width, height,
125 0, 0, 0, kZero, kZero);
82 126
83 // Now set the data to YUV(0,128,128). 127 // Now set the data to YUV(0,128,128).
84 const uint8 kBlackY = 0x00; 128 const uint8 kBlackY = 0x00;
85 const uint8 kBlackUV = 0x80; 129 const uint8 kBlackUV = 0x80;
86 FillYUV(frame, kBlackY, kBlackUV, kBlackUV); 130 FillYUV(frame, kBlackY, kBlackUV, kBlackUV);
87 return frame; 131 return frame;
88 } 132 }
89 133
90 static inline size_t RoundUp(size_t value, size_t alignment) { 134 void VideoFrame::AllocateRGB(size_t bytes_per_row, size_t aligned_height) {
91 // Check that |alignment| is a power of 2.
92 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
93 return ((value + (alignment - 1)) & ~(alignment-1));
94 }
95
96 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
97 // Round up to align at a 64-bit (8 byte) boundary for each row. This 135 // Round up to align at a 64-bit (8 byte) boundary for each row. This
98 // is sufficient for MMX reads (movq). 136 // is sufficient for MMX reads (movq).
99 size_t bytes_per_row = RoundUp(width_ * bytes_per_pixel, 8);
100 strides_[VideoFrame::kRGBPlane] = bytes_per_row; 137 strides_[VideoFrame::kRGBPlane] = bytes_per_row;
101 data_[VideoFrame::kRGBPlane] = new uint8[bytes_per_row * height_]; 138 #if !defined(OS_ANDROID)
139 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
140 // repeated in every single user of aligned data.
141 data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8 *>(
142 av_malloc(bytes_per_row * aligned_height));
143 #else
144 data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height];
145 #endif
102 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7)); 146 DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
103 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0); 147 COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
104 } 148 }
105 149
106 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert. 150 static const int kFramePadBytes = 15; // Allows faster SIMD YUV convert.
107 151
108 void VideoFrame::AllocateYUV() { 152 void VideoFrame::AllocateYUV(size_t y_stride, size_t uv_stride,
153 size_t aligned_height) {
109 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16); 154 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16);
110 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and 155 // Align Y rows at 32-bit (4 byte) boundaries. The stride for both YV12 and
111 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V 156 // YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for U and V
112 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the 157 // applies to two rows of Y (one byte of UV for 4 bytes of Y), so in the
113 // case of YV12 the strides are identical for the same width surface, but the 158 // case of YV12 the strides are identical for the same width surface, but the
114 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16. 159 // number of bytes allocated for YV12 is 1/2 the amount for U & V as YV16.
115 // We also round the height of the surface allocated to be an even number 160 // We also round the height of the surface allocated to be an even number
116 // to avoid any potential of faulting by code that attempts to access the Y 161 // to avoid any potential of faulting by code that attempts to access the Y
117 // values of the final row, but assumes that the last row of U & V applies to 162 // values of the final row, but assumes that the last row of U & V applies to
118 // a full two rows of Y. 163 // a full two rows of Y.
119 size_t y_height = rows(VideoFrame::kYPlane); 164 size_t y_height = aligned_height;
120 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane), 4); 165 size_t uv_height = format_ == VideoFrame::YV12 ?
121 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane), 4); 166 RoundUp(aligned_height, 2) / 2 : aligned_height;
122 size_t uv_height = rows(VideoFrame::kUPlane);
123 size_t y_bytes = y_height * y_stride; 167 size_t y_bytes = y_height * y_stride;
124 size_t uv_bytes = uv_height * uv_stride; 168 size_t uv_bytes = uv_height * uv_stride;
125 169
126 uint8* data = new uint8[y_bytes + (uv_bytes * 2) + kFramePadBytes]; 170 #if !defined(OS_ANDROID)
171 // TODO use DataAligned or so, so this #ifdef hackery doesn't need to be
172 // repeated in every single user of aligned data.
173 uint8* data = reinterpret_cast<uint8 *>(
174 av_malloc(y_bytes + (uv_bytes * 2) + kFramePadBytes));
175 #else
176 uint8* data = new uint8_t[y_bytes + (uv_bytes * 2) + kFramePadBytes];
177 #endif
127 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0); 178 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
128 data_[VideoFrame::kYPlane] = data; 179 data_[VideoFrame::kYPlane] = data;
129 data_[VideoFrame::kUPlane] = data + y_bytes; 180 data_[VideoFrame::kUPlane] = data + y_bytes;
130 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes; 181 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
131 strides_[VideoFrame::kYPlane] = y_stride; 182 strides_[VideoFrame::kYPlane] = y_stride;
132 strides_[VideoFrame::kUPlane] = uv_stride; 183 strides_[VideoFrame::kUPlane] = uv_stride;
133 strides_[VideoFrame::kVPlane] = uv_stride; 184 strides_[VideoFrame::kVPlane] = uv_stride;
134 } 185 }
135 186
136 VideoFrame::VideoFrame(VideoFrame::Format format, 187 VideoFrame::VideoFrame(VideoFrame::Format format,
(...skipping 14 matching lines...) Expand all
151 202
152 VideoFrame::~VideoFrame() { 203 VideoFrame::~VideoFrame() {
153 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) { 204 if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) {
154 texture_no_longer_needed_.Run(); 205 texture_no_longer_needed_.Run();
155 texture_no_longer_needed_.Reset(); 206 texture_no_longer_needed_.Reset();
156 } 207 }
157 208
158 // In multi-plane allocations, only a single block of memory is allocated 209 // In multi-plane allocations, only a single block of memory is allocated
159 // on the heap, and other |data| pointers point inside the same, single block 210 // on the heap, and other |data| pointers point inside the same, single block
160 // so just delete index 0. 211 // so just delete index 0.
161 delete[] data_[0]; 212 if (data_[0]) {
213 #if !defined(OS_ANDROID)
214 av_free(data_[0]);
215 #else
216 delete[] data_[0];
217 #endif
218 }
162 } 219 }
163 220
164 bool VideoFrame::IsValidPlane(size_t plane) const { 221 bool VideoFrame::IsValidPlane(size_t plane) const {
165 switch (format_) { 222 switch (format_) {
166 case RGB32: 223 case RGB32:
167 return plane == kRGBPlane; 224 return plane == kRGBPlane;
168 225
169 case YV12: 226 case YV12:
170 case YV16: 227 case YV16:
171 return plane == kYPlane || plane == kUPlane || plane == kVPlane; 228 return plane == kYPlane || plane == kUPlane || plane == kVPlane;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 break; 314 break;
258 for(int row = 0; row < rows(plane); row++) { 315 for(int row = 0; row < rows(plane); row++) {
259 base::MD5Update(context, base::StringPiece( 316 base::MD5Update(context, base::StringPiece(
260 reinterpret_cast<char*>(data(plane) + stride(plane) * row), 317 reinterpret_cast<char*>(data(plane) + stride(plane) * row),
261 row_bytes(plane))); 318 row_bytes(plane)));
262 } 319 }
263 } 320 }
264 } 321 }
265 322
266 } // namespace media 323 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698